[index] Add indexing for unresolved-using declarations

In dependent contexts we end up referencing these, so make sure they
have USRs, and have their declarations indexed. For the most part they
behave like typedefs, but we also need to worry about having multiple
using declarations with the same "name".

rdar://problem/33883650

llvm-svn: 311053
This commit is contained in:
Ben Langmuir 2017-08-16 23:12:21 +00:00
parent 4abc3f6036
commit fd6e39c40b
7 changed files with 137 additions and 16 deletions

View File

@ -53,6 +53,7 @@ enum class SymbolKind : uint8_t {
ConversionFunction,
Parameter,
Using,
};
enum class SymbolLanguage {
@ -69,6 +70,8 @@ enum class SymbolSubKind {
CXXMoveConstructor,
AccessorGetter,
AccessorSetter,
UsingTypename,
UsingValue,
};
/// Set of properties that provide additional info about a symbol.

View File

@ -611,6 +611,24 @@ public:
SymbolRoleSet());
}
bool VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
TRY_DECL(D, IndexCtx.handleDecl(D));
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
D->getLexicalDeclContext());
return true;
}
bool VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
TRY_DECL(D, IndexCtx.handleDecl(D));
const DeclContext *DC = D->getDeclContext()->getRedeclContext();
const NamedDecl *Parent = dyn_cast<NamedDecl>(DC);
IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent,
D->getLexicalDeclContext());
return true;
}
bool VisitClassTemplateSpecializationDecl(const
ClassTemplateSpecializationDecl *D) {
// FIXME: Notify subsequent callbacks if info comes from implicit

View File

@ -300,6 +300,18 @@ SymbolInfo index::getSymbolInfo(const Decl *D) {
Info.Kind = SymbolKind::TypeAlias;
Info.Lang = SymbolLanguage::CXX;
break;
case Decl::UnresolvedUsingTypename:
Info.Kind = SymbolKind::Using;
Info.SubKind = SymbolSubKind::UsingTypename;
Info.Lang = SymbolLanguage::CXX;
Info.Properties |= (unsigned)SymbolProperty::Generic;
break;
case Decl::UnresolvedUsingValue:
Info.Kind = SymbolKind::Using;
Info.SubKind = SymbolSubKind::UsingValue;
Info.Lang = SymbolLanguage::CXX;
Info.Properties |= (unsigned)SymbolProperty::Generic;
break;
case Decl::Binding:
Info.Kind = SymbolKind::Variable;
Info.Lang = SymbolLanguage::CXX;
@ -448,6 +460,7 @@ StringRef index::getSymbolKindString(SymbolKind K) {
case SymbolKind::Destructor: return "destructor";
case SymbolKind::ConversionFunction: return "coversion-func";
case SymbolKind::Parameter: return "param";
case SymbolKind::Using: return "using";
}
llvm_unreachable("invalid symbol kind");
}
@ -459,6 +472,8 @@ StringRef index::getSymbolSubKindString(SymbolSubKind K) {
case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor";
case SymbolSubKind::AccessorGetter: return "acc-get";
case SymbolSubKind::AccessorSetter: return "acc-set";
case SymbolSubKind::UsingTypename: return "using-typename";
case SymbolSubKind::UsingValue: return "using-value";
}
llvm_unreachable("invalid symbol subkind");
}

View File

@ -99,6 +99,8 @@ public:
void VisitVarDecl(const VarDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
void VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
IgnoreResults = true;
@ -112,14 +114,6 @@ public:
IgnoreResults = true;
}
void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
IgnoreResults = true;
}
void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
IgnoreResults = true;
}
bool ShouldGenerateLocation(const NamedDecl *D);
bool isLocal(const NamedDecl *D) {
@ -609,6 +603,16 @@ bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) {
return IgnoreResults;
}
static void printQualifier(llvm::raw_ostream &Out, ASTContext &Ctx, NestedNameSpecifier *NNS) {
// FIXME: Encode the qualifier, don't just print it.
PrintingPolicy PO(Ctx.getLangOpts());
PO.SuppressTagKeyword = true;
PO.SuppressUnwrittenScope = true;
PO.ConstantArraySizeAsWritten = false;
PO.AnonymousTagLocations = false;
NNS->print(Out, PO);
}
void USRGenerator::VisitType(QualType T) {
// This method mangles in USR information for types. It can possibly
// just reuse the naming-mangling logic used by codegen, although the
@ -797,13 +801,7 @@ void USRGenerator::VisitType(QualType T) {
}
if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {
Out << '^';
// FIXME: Encode the qualifier, don't just print it.
PrintingPolicy PO(Ctx.getLangOpts());
PO.SuppressTagKeyword = true;
PO.SuppressUnwrittenScope = true;
PO.ConstantArraySizeAsWritten = false;
PO.AnonymousTagLocations = false;
DNT->getQualifier()->print(Out, PO);
printQualifier(Out, Ctx, DNT->getQualifier());
Out << ':' << DNT->getIdentifier()->getName();
return;
}
@ -912,6 +910,26 @@ void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) {
}
}
void USRGenerator::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
VisitDeclContext(D->getDeclContext());
Out << "@UUV@";
printQualifier(Out, D->getASTContext(), D->getQualifier());
EmitDeclName(D);
}
void USRGenerator::VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
if (ShouldGenerateLocation(D) && GenLoc(D, /*IncludeOffset=*/isLocal(D)))
return;
VisitDeclContext(D->getDeclContext());
Out << "@UUT@";
printQualifier(Out, D->getASTContext(), D->getQualifier());
Out << D->getName(); // Simple name.
}
//===----------------------------------------------------------------------===//
// USR generation functions.
//===----------------------------------------------------------------------===//

View File

@ -158,3 +158,69 @@ void infiniteTraitRecursion(Trait<T> &t) {
// Shouldn't crash!
t.lookup;
}
template <typename T>
struct UsingA {
// CHECK: [[@LINE+1]]:15 | type-alias/C | Type | c:index-dependent-source.cpp@ST>1#T@UsingA@T@Type | <no-cgname> | Def,RelChild | rel: 1
typedef int Type;
// CHECK: [[@LINE+1]]:15 | static-method/C++ | func | c:@ST>1#T@UsingA@F@func#S | <no-cgname> | Decl,RelChild | rel: 1
static void func();
// CHECK: [[@LINE+1]]:8 | instance-method/C++ | operator() | c:@ST>1#T@UsingA@F@operator()#I# | <no-cgname> | Decl,RelChild | rel: 1
void operator()(int);
// CHECK: [[@LINE+1]]:8 | instance-method/C++ | operator+ | c:@ST>1#T@UsingA@F@operator+#&1>@ST>1#T@UsingA1t0.0# | <no-cgname> | Decl,RelChild | rel: 1
void operator+(const UsingA &);
};
template <typename T>
struct OtherUsing {};
template <typename T>
struct UsingB : public UsingA<T> {
// CHECK: [[@LINE+2]]:40 | type-alias/C | TypeB | c:index-dependent-source.cpp@ST>1#T@UsingB@T@TypeB | <no-cgname> | Def,RelChild | rel: 1
// CHECK: [[@LINE+1]]:20 | struct(Gen)/C++ | OtherUsing | c:@ST>1#T@OtherUsing | <no-cgname> | Ref,RelCont | rel: 1
typedef typename OtherUsing<T>::Type TypeB;
// CHECK: [[@LINE+2]]:29 | using/using-typename(Gen)/C++ | Type | c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | Decl,RelChild | rel: 1
// CHECK: [[@LINE+1]]:18 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
using typename UsingA<T>::Type;
// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | func | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::func | <no-cgname> | Decl,RelChild | rel: 1
// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
using UsingA<T>::func;
// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | operator() | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::operator() | <no-cgname> | Decl,RelChild | rel: 1
// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
using UsingA<T>::operator();
// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | operator+ | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::operator+ | <no-cgname> | Decl,RelChild | rel: 1
// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingA | c:@ST>1#T@UsingA | <no-cgname> | Ref,RelCont | rel: 1
using UsingA<T>::operator+;
};
template <typename T>
struct UsingC : public UsingB<T> {
static void test() {
// CHECK: [[@LINE+2]]:25 | type-alias/C | TypeB | c:index-dependent-source.cpp@ST>1#T@UsingB@T@TypeB | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE+1]]:14 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | <no-cgname> | Ref,RelCont | rel: 1
typename UsingB<T>::TypeB value1;
// CHECK: [[@LINE+2]]:25 | using/using-typename(Gen)/C++ | Type | c:index-dependent-source.cpp@ST>1#T@UsingB@UUT@UsingA<T>::Type | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE+1]]:14 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | <no-cgname> | Ref,RelCont | rel: 1
typename UsingB<T>::Type value2;
// CHECK: [[@LINE+2]]:16 | using/using-value(Gen)/C++ | func | c:index-dependent-source.cpp@ST>1#T@UsingB@UUV@UsingA<T>::func | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
// CHECK: [[@LINE+1]]:5 | struct(Gen)/C++ | UsingB | c:@ST>1#T@UsingB | <no-cgname> | Ref,RelCont | rel: 1
UsingB<T>::func();
}
};
template <typename T>
struct UsingD {
// CHECK: [[@LINE+1]]:8 | instance-method/C++ | foo | c:@ST>1#T@UsingD@F@foo#t0.0# | <no-cgname> | Decl,RelChild | rel: 1
void foo(T);
};
template <typename T, typename U>
struct UsingE : public UsingD<T>, public UsingD<U> {
// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | foo | c:index-dependent-source.cpp@ST>2#T#T@UsingE@UUV@UsingD<T>::foo | <no-cgname> | Decl,RelChild | rel: 1
// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingD | c:@ST>1#T@UsingD | <no-cgname> | Ref,RelCont | rel: 1
using UsingD<T>::foo;
// CHECK: [[@LINE+2]]:20 | using/using-value(Gen)/C++ | foo | c:index-dependent-source.cpp@ST>2#T#T@UsingE@UUV@UsingD<U>::foo | <no-cgname> | Decl,RelChild | rel: 1
// CHECK: [[@LINE+1]]:9 | struct(Gen)/C++ | UsingD | c:@ST>1#T@UsingD | <no-cgname> | Ref,RelCont | rel: 1
using UsingD<U>::foo;
};

View File

@ -219,6 +219,6 @@ using alias = T;
// CHECK-USRS: index-templates.cpp c:@ST>2#T#T@Y Extent=[27:1 - 31:2]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@443 Extent=[27:10 - 27:20]
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@455 Extent=[27:22 - 27:32]
// CHECK-USRS-NOT: type
// CHECK-USRS: index-templates.cpp c:index-templates.cpp@ST>2#T#T@Y@UUT@T::type Extent=[29:3 - 29:25]
// CHECK-USRS: index-templates.cpp c:@S@Z3 Extent=[33:1 - 33:14]
// CHECK-USRS: index-templates.cpp c:@F@f#$@S@map>#$@S@Z4#$@S@Pair>#I#S1_#$@S@compare>#$@S@Pair>#S1_#S2_#$@S@allocator>#S4_#

View File

@ -1258,6 +1258,7 @@ static CXIdxEntityKind getEntityKindFromSymbolKind(SymbolKind K, SymbolLanguage
case SymbolKind::Module:
case SymbolKind::Macro:
case SymbolKind::ClassProperty:
case SymbolKind::Using:
return CXIdxEntity_Unexposed;
case SymbolKind::Enum: return CXIdxEntity_Enum;