r302632 - [index] Index simple dependent declaration references
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Wed May 10 02:47:41 PDT 2017
Author: arphaman
Date: Wed May 10 04:47:41 2017
New Revision: 302632
URL: http://llvm.org/viewvc/llvm-project?rev=302632&view=rev
Log:
[index] Index simple dependent declaration references
This commit implements basic support for indexing of dependent declaration
references. Now the indexer tries to find a suitable match in the base template
for a dependent member ref/decl ref/dependent type.
rdar://29158210
Differential Revision: https://reviews.llvm.org/D32972
Added:
cfe/trunk/test/Index/Core/index-dependent-source.cpp
Modified:
cfe/trunk/include/clang/AST/CXXInheritance.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/CXXInheritance.cpp
cfe/trunk/lib/Index/IndexBody.cpp
cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp
Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=302632&r1=302631&r2=302632&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
+++ cfe/trunk/include/clang/AST/CXXInheritance.h Wed May 10 04:47:41 2017
@@ -161,7 +161,8 @@ class CXXBasePaths {
void ComputeDeclsFound();
bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record,
- CXXRecordDecl::BaseMatchesCallback BaseMatches);
+ CXXRecordDecl::BaseMatchesCallback BaseMatches,
+ bool LookupInDependent = false);
public:
typedef std::list<CXXBasePath>::iterator paths_iterator;
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=302632&r1=302631&r2=302632&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed May 10 04:47:41 2017
@@ -1563,10 +1563,13 @@ public:
/// \param Paths used to record the paths from this class to its base class
/// subobjects that match the search criteria.
///
+ /// \param LookupInDependent can be set to true to extend the search to
+ /// dependent base classes.
+ ///
/// \returns true if there exists any path from this class to a base class
/// subobject that matches the search criteria.
- bool lookupInBases(BaseMatchesCallback BaseMatches,
- CXXBasePaths &Paths) const;
+ bool lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths,
+ bool LookupInDependent = false) const;
/// \brief Base-class lookup callback that determines whether the given
/// base class specifier refers to a specific class declaration.
@@ -1608,6 +1611,16 @@ public:
CXXBasePath &Path, DeclarationName Name);
/// \brief Base-class lookup callback that determines whether there exists
+ /// a member with the given name.
+ ///
+ /// This callback can be used with \c lookupInBases() to find members
+ /// of the given name within a C++ class hierarchy, including dependent
+ /// classes.
+ static bool
+ FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, DeclarationName Name);
+
+ /// \brief Base-class lookup callback that determines whether there exists
/// an OpenMP declare reduction member with the given name.
///
/// This callback can be used with \c lookupInBases() to find members
@@ -1633,6 +1646,14 @@ public:
/// \brief Get the indirect primary bases for this class.
void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const;
+ /// Performs an imprecise lookup of a dependent name in this class.
+ ///
+ /// This function does not follow strict semantic rules and should be used
+ /// only when lookup rules can be relaxed, e.g. indexing.
+ std::vector<const NamedDecl *>
+ lookupDependentName(const DeclarationName &Name,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter);
+
/// Renders and displays an inheritance diagram
/// for this C++ class and all of its base classes (transitively) using
/// GraphViz.
Modified: cfe/trunk/lib/AST/CXXInheritance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CXXInheritance.cpp?rev=302632&r1=302631&r2=302632&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CXXInheritance.cpp (original)
+++ cfe/trunk/lib/AST/CXXInheritance.cpp Wed May 10 04:47:41 2017
@@ -13,6 +13,7 @@
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SetVector.h"
#include <algorithm>
@@ -174,9 +175,10 @@ bool CXXRecordDecl::forallBases(ForallBa
return AllMatches;
}
-bool CXXBasePaths::lookupInBases(
- ASTContext &Context, const CXXRecordDecl *Record,
- CXXRecordDecl::BaseMatchesCallback BaseMatches) {
+bool CXXBasePaths::lookupInBases(ASTContext &Context,
+ const CXXRecordDecl *Record,
+ CXXRecordDecl::BaseMatchesCallback BaseMatches,
+ bool LookupInDependent) {
bool FoundPath = false;
// The access of the path down to this record.
@@ -194,7 +196,7 @@ bool CXXBasePaths::lookupInBases(
// the base class scope is not examined during unqualified name lookup
// either at the point of definition of the class template or member or
// during an instantiation of the class tem- plate or member.
- if (BaseType->isDependentType())
+ if (!LookupInDependent && BaseType->isDependentType())
continue;
// Determine whether we need to visit this base class at all,
@@ -262,10 +264,26 @@ bool CXXBasePaths::lookupInBases(
return FoundPath;
}
} else if (VisitBase) {
- CXXRecordDecl *BaseRecord
- = cast<CXXRecordDecl>(BaseSpec.getType()->castAs<RecordType>()
- ->getDecl());
- if (lookupInBases(Context, BaseRecord, BaseMatches)) {
+ CXXRecordDecl *BaseRecord;
+ if (LookupInDependent) {
+ BaseRecord = nullptr;
+ const TemplateSpecializationType *TST =
+ BaseSpec.getType()->getAs<TemplateSpecializationType>();
+ if (!TST) {
+ if (auto *RT = BaseSpec.getType()->getAs<RecordType>())
+ BaseRecord = cast<CXXRecordDecl>(RT->getDecl());
+ } else {
+ TemplateName TN = TST->getTemplateName();
+ if (auto *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()))
+ BaseRecord = TD->getTemplatedDecl();
+ }
+ } else {
+ BaseRecord = cast<CXXRecordDecl>(
+ BaseSpec.getType()->castAs<RecordType>()->getDecl());
+ }
+ if (BaseRecord &&
+ lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
// C++ [class.member.lookup]p2:
// A member name f in one sub-object B hides a member name f in
// a sub-object A if A is a base class sub-object of B. Any
@@ -299,9 +317,11 @@ bool CXXBasePaths::lookupInBases(
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,
- CXXBasePaths &Paths) const {
+ CXXBasePaths &Paths,
+ bool LookupInDependent) const {
// If we didn't find anything, report that.
- if (!Paths.lookupInBases(getASTContext(), this, BaseMatches))
+ if (!Paths.lookupInBases(getASTContext(), this, BaseMatches,
+ LookupInDependent))
return false;
// If we're not recording paths or we won't ever find ambiguities,
@@ -387,23 +407,49 @@ bool CXXRecordDecl::FindTagMember(const
return false;
}
-bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
- CXXBasePath &Path,
- DeclarationName Name) {
- RecordDecl *BaseRecord =
- Specifier->getType()->castAs<RecordType>()->getDecl();
-
- const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
+static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path,
+ DeclarationName Name) {
+ const unsigned IDNS = clang::Decl::IDNS_Ordinary | clang::Decl::IDNS_Tag |
+ clang::Decl::IDNS_Member;
for (Path.Decls = BaseRecord->lookup(Name);
!Path.Decls.empty();
Path.Decls = Path.Decls.slice(1)) {
if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
return true;
}
-
+
return false;
}
+bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ DeclarationName Name) {
+ RecordDecl *BaseRecord =
+ Specifier->getType()->castAs<RecordType>()->getDecl();
+ return findOrdinaryMember(BaseRecord, Path, Name);
+}
+
+bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
+ const CXXBaseSpecifier *Specifier, CXXBasePath &Path,
+ DeclarationName Name) {
+ const TemplateSpecializationType *TST =
+ Specifier->getType()->getAs<TemplateSpecializationType>();
+ if (!TST) {
+ auto *RT = Specifier->getType()->getAs<RecordType>();
+ if (!RT)
+ return false;
+ return findOrdinaryMember(RT->getDecl(), Path, Name);
+ }
+ TemplateName TN = TST->getTemplateName();
+ const auto *TD = dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return false;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ if (!RD)
+ return false;
+ return findOrdinaryMember(RD, Path, Name);
+}
+
bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
DeclarationName Name) {
@@ -438,6 +484,36 @@ FindNestedNameSpecifierMember(const CXXB
return false;
}
+std::vector<const NamedDecl *> CXXRecordDecl::lookupDependentName(
+ const DeclarationName &Name,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
+ std::vector<const NamedDecl *> Results;
+ // Lookup in the class.
+ DeclContext::lookup_result DirectResult = lookup(Name);
+ if (!DirectResult.empty()) {
+ for (const NamedDecl *ND : DirectResult) {
+ if (Filter(ND))
+ Results.push_back(ND);
+ }
+ return Results;
+ }
+ // Perform lookup into our base classes.
+ CXXBasePaths Paths;
+ Paths.setOrigin(this);
+ if (!lookupInBases(
+ [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
+ return CXXRecordDecl::FindOrdinaryMemberInDependentClasses(
+ Specifier, Path, Name);
+ },
+ Paths, /*LookupInDependent=*/true))
+ return Results;
+ for (const NamedDecl *ND : Paths.front().Decls) {
+ if (Filter(ND))
+ Results.push_back(ND);
+ }
+ return Results;
+}
+
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
Modified: cfe/trunk/lib/Index/IndexBody.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexBody.cpp?rev=302632&r1=302631&r2=302632&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexBody.cpp (original)
+++ cfe/trunk/lib/Index/IndexBody.cpp Wed May 10 04:47:41 2017
@@ -150,6 +150,50 @@ public:
Parent, ParentDC, Roles, Relations, E);
}
+ bool indexDependentReference(
+ const Expr *E, const Type *T, const DeclarationNameInfo &NameInfo,
+ llvm::function_ref<bool(const NamedDecl *ND)> Filter) {
+ if (!T)
+ return true;
+ const TemplateSpecializationType *TST =
+ T->getAs<TemplateSpecializationType>();
+ if (!TST)
+ return true;
+ TemplateName TN = TST->getTemplateName();
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return true;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ std::vector<const NamedDecl *> Symbols =
+ RD->lookupDependentName(NameInfo.getName(), Filter);
+ // FIXME: Improve overload handling.
+ if (Symbols.size() != 1)
+ return true;
+ SourceLocation Loc = NameInfo.getLoc();
+ if (Loc.isInvalid())
+ Loc = E->getLocStart();
+ SmallVector<SymbolRelation, 4> Relations;
+ SymbolRoleSet Roles = getRolesForRef(E, Relations);
+ return IndexCtx.handleReference(Symbols[0], Loc, Parent, ParentDC, Roles,
+ Relations, E);
+ }
+
+ bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
+ const DeclarationNameInfo &Info = E->getMemberNameInfo();
+ return indexDependentReference(
+ E, E->getBaseType().getTypePtrOrNull(), Info,
+ [](const NamedDecl *D) { return D->isCXXInstanceMember(); });
+ }
+
+ bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+ const DeclarationNameInfo &Info = E->getNameInfo();
+ const NestedNameSpecifier *NNS = E->getQualifier();
+ return indexDependentReference(
+ E, NNS->getAsType(), Info,
+ [](const NamedDecl *D) { return !D->isCXXInstanceMember(); });
+ }
+
bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
for (DesignatedInitExpr::Designator &D : llvm::reverse(E->designators())) {
if (D.isFieldDesignator() && D.getField())
Modified: cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp?rev=302632&r1=302631&r2=302632&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp (original)
+++ cfe/trunk/lib/Index/IndexTypeSourceInfo.cpp Wed May 10 04:47:41 2017
@@ -141,6 +141,31 @@ public:
return true;
}
+ bool VisitDependentNameTypeLoc(DependentNameTypeLoc TL) {
+ const DependentNameType *DNT = TL.getTypePtr();
+ const NestedNameSpecifier *NNS = DNT->getQualifier();
+ const Type *T = NNS->getAsType();
+ if (!T)
+ return true;
+ const TemplateSpecializationType *TST =
+ T->getAs<TemplateSpecializationType>();
+ if (!TST)
+ return true;
+ TemplateName TN = TST->getTemplateName();
+ const ClassTemplateDecl *TD =
+ dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl());
+ if (!TD)
+ return true;
+ CXXRecordDecl *RD = TD->getTemplatedDecl();
+ DeclarationName Name(DNT->getIdentifier());
+ std::vector<const NamedDecl *> Symbols = RD->lookupDependentName(
+ Name, [](const NamedDecl *ND) { return isa<TypeDecl>(ND); });
+ if (Symbols.size() != 1)
+ return true;
+ return IndexCtx.handleReference(Symbols[0], TL.getNameLoc(), Parent,
+ ParentDC, SymbolRoleSet(), Relations);
+ }
+
bool TraverseStmt(Stmt *S) {
IndexCtx.indexBody(S, Parent, ParentDC);
return true;
Added: cfe/trunk/test/Index/Core/index-dependent-source.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/Core/index-dependent-source.cpp?rev=302632&view=auto
==============================================================================
--- cfe/trunk/test/Index/Core/index-dependent-source.cpp (added)
+++ cfe/trunk/test/Index/Core/index-dependent-source.cpp Wed May 10 04:47:41 2017
@@ -0,0 +1,124 @@
+// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
+
+int invalid;
+
+class Base {
+ void baseFunction();
+
+ int baseField;
+
+ static void staticBaseFunction();
+};
+
+template<typename T>
+class BaseTemplate {
+public:
+ T baseTemplateFunction();
+
+ T baseTemplateField;
+
+ static T baseTemplateVariable;
+};
+
+template<typename T, typename S>
+class TemplateClass: public Base , public BaseTemplate<T> {
+public:
+ ~TemplateClass();
+
+ T function() { }
+
+ static void staticFunction() { }
+
+ T field;
+
+ static T variable;
+
+ struct Struct { };
+
+ enum Enum { EnumValue };
+
+ using TypeAlias = S;
+ typedef T Typedef;
+
+ void overload1(const T &);
+ void overload1(const S &);
+};
+
+template<typename T, typename S>
+void indexSimpleDependentDeclarations(const TemplateClass<T, S> &object) {
+ // Valid instance members:
+ object.function();
+// CHECK: [[@LINE-1]]:10 | instance-method/C++ | function | c:@ST>2#T#T at TemplateClass@F at function# | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+ object.field;
+// CHECK: [[@LINE-1]]:10 | field/C++ | field | c:@ST>2#T#T at TemplateClass@FI at field | <no-cgname> | Ref,RelCont | rel: 1
+ object.baseFunction();
+// CHECK: [[@LINE-1]]:10 | instance-method/C++ | baseFunction | c:@S at Base@F at baseFunction# | __ZN4Base12baseFunctionEv | Ref,Call,RelCall,RelCont | rel: 1
+ object.baseField;
+// CHECK: [[@LINE-1]]:10 | field/C++ | baseField | c:@S at Base@FI at baseField | <no-cgname> | Ref,RelCont | rel: 1
+ object.baseTemplateFunction();
+// CHECK: [[@LINE-1]]:10 | instance-method/C++ | baseTemplateFunction | c:@ST>1#T at BaseTemplate@F at baseTemplateFunction# | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+ object.baseTemplateField;
+// CHECK: [[@LINE-1]]:10 | field/C++ | baseTemplateField | c:@ST>1#T at BaseTemplate@FI at baseTemplateField | <no-cgname> | Ref,RelCont | rel: 1
+
+ // Invalid instance members:
+ object.variable;
+// CHECK-NOT: [[@LINE-1]]:10
+ object.staticFunction();
+// CHECK-NOT: [[@LINE-1]]:10
+ object.Struct;
+// CHECK-NOT: [[@LINE-1]]:10
+ object.EnumValue;
+// CHECK-NOT: [[@LINE-1]]:10
+
+ // Valid static members:
+ TemplateClass<T, S>::staticFunction();
+// CHECK: [[@LINE-1]]:24 | static-method/C++ | staticFunction | c:@ST>2#T#T at TemplateClass@F at staticFunction#S | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+ TemplateClass<T, S>::variable;
+// CHECK: [[@LINE-1]]:24 | static-property/C++ | variable | c:@ST>2#T#T at TemplateClass@variable | __ZN13TemplateClass8variableE | Ref,RelCont | rel: 1
+ TemplateClass<T, S>::staticBaseFunction();
+// CHECK: [[@LINE-1]]:24 | static-method/C++ | staticBaseFunction | c:@S at Base@F at staticBaseFunction#S | __ZN4Base18staticBaseFunctionEv | Ref,Call,RelCall,RelCont | rel: 1
+ TemplateClass<T, S>::baseTemplateVariable;
+// CHECK: [[@LINE-1]]:24 | static-property/C++ | baseTemplateVariable | c:@ST>1#T at BaseTemplate@baseTemplateVariable | __ZN12BaseTemplate20baseTemplateVariableE | Ref,RelCont | rel: 1
+ TemplateClass<T, S>::EnumValue;
+// CHECK: [[@LINE-1]]:24 | enumerator/C | EnumValue | c:@ST>2#T#T at TemplateClass@E at Enum@EnumValue | <no-cgname> | Ref,RelCont | rel: 1
+ TemplateClass<T, S>::Struct();
+// CHECK: [[@LINE-1]]:24 | struct/C | Struct | c:@ST>2#T#T at TemplateClass@S at Struct | <no-cgname> | Ref,Call,RelCall,RelCont | rel: 1
+
+ // Invalid static members:
+ TemplateClass<T, S>::field;
+// CHECK-NOT: [[@LINE-1]]:24
+ TemplateClass<T, S>::function();
+// CHECK-NOT: [[@LINE-1]]:24
+
+ // Valid type names:
+ typename TemplateClass<T, S>::Struct Val;
+// CHECK: [[@LINE-1]]:33 | struct/C | Struct | c:@ST>2#T#T at TemplateClass@S at Struct | <no-cgname> | Ref,RelCont | rel: 1
+ typename TemplateClass<T, S>::Enum EnumVal;
+// CHECK: [[@LINE-1]]:33 | enum/C | Enum | c:@ST>2#T#T at TemplateClass@E at Enum | <no-cgname> | Ref,RelCont | rel: 1
+ typename TemplateClass<T, S>::TypeAlias Val2;
+// CHECK: [[@LINE-1]]:33 | type-alias/C++ | TypeAlias | c:@ST>2#T#T at TemplateClass@TypeAlias | <no-cgname> | Ref,RelCont | rel: 1
+ typename TemplateClass<T, S>::Typedef Val3;
+// CHECK: [[@LINE-1]]:33 | type-alias/C | Typedef | c:{{.*}}index-dependent-source.cpp at ST>2#T#T at TemplateClass@T at Typedef | <no-cgname> | Ref,RelCont | rel: 1
+
+ // Invalid type names:
+ typename TemplateClass<T, S>::field Val4;
+// CHECK-NOT: [[@LINE-1]]:33
+ typename TemplateClass<T, S>::staticFunction Val5;
+// CHECK-NOT: [[@LINE-1]]:33
+
+
+ object.invalid;
+// CHECK-NOT: [[@LINE-1]]:10
+ TemplateClass<T, S>::invalid;
+// CHECK-NOT: [[@LINE-1]]:24
+}
+
+template<typename T, typename S, typename Y>
+void indexDependentOverloads(const TemplateClass<T, S> &object) {
+ object.overload1(T());
+// CHECK-NOT: [[@LINE-1]]
+ object.overload1(S());
+// CHECK-NOT: [[@LINE-1]]
+ object.overload1(Y());
+// CHECK-NOT: [[@LINE-1]]
+}
More information about the cfe-commits
mailing list