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