r301180 - [index] The relation between the declarations in template specializations

Alex Lorenz via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 24 07:04:58 PDT 2017


Author: arphaman
Date: Mon Apr 24 09:04:58 2017
New Revision: 301180

URL: http://llvm.org/viewvc/llvm-project?rev=301180&view=rev
Log:
[index] The relation between the declarations in template specializations
that 'override' declarations in the base template should be recorded

This can be used for improved "go to definition" feature in Xcode.

rdar://31604739

Differential Revision: https://reviews.llvm.org/D32020

Modified:
    cfe/trunk/lib/Index/IndexDecl.cpp
    cfe/trunk/lib/Index/IndexingContext.cpp
    cfe/trunk/lib/Index/IndexingContext.h
    cfe/trunk/test/Index/Core/index-source.cpp

Modified: cfe/trunk/lib/Index/IndexDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexDecl.cpp?rev=301180&r1=301179&r2=301180&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexDecl.cpp (original)
+++ cfe/trunk/lib/Index/IndexDecl.cpp Mon Apr 24 09:04:58 2017
@@ -144,6 +144,53 @@ public:
     return true;
   }
 
+  /// Gather the declarations which the given declaration \D overrides in a
+  /// pseudo-override manner.
+  ///
+  /// Pseudo-overrides occur when a class template specialization declares
+  /// a declaration that has the same name as a similar declaration in the
+  /// non-specialized template.
+  void
+  gatherTemplatePseudoOverrides(const NamedDecl *D,
+                                SmallVectorImpl<SymbolRelation> &Relations) {
+    if (!IndexCtx.getLangOpts().CPlusPlus)
+      return;
+    const auto *CTSD =
+        dyn_cast<ClassTemplateSpecializationDecl>(D->getLexicalDeclContext());
+    if (!CTSD)
+      return;
+    llvm::PointerUnion<ClassTemplateDecl *,
+                       ClassTemplatePartialSpecializationDecl *>
+        Template = CTSD->getSpecializedTemplateOrPartial();
+    if (const auto *CTD = Template.dyn_cast<ClassTemplateDecl *>()) {
+      const CXXRecordDecl *Pattern = CTD->getTemplatedDecl();
+      bool TypeOverride = isa<TypeDecl>(D);
+      for (const NamedDecl *ND : Pattern->lookup(D->getDeclName())) {
+        if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
+          ND = CTD->getTemplatedDecl();
+        if (ND->isImplicit())
+          continue;
+        // Types can override other types.
+        if (!TypeOverride) {
+          if (ND->getKind() != D->getKind())
+            continue;
+        } else if (!isa<TypeDecl>(ND))
+          continue;
+        if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+          const auto *DFD = cast<FunctionDecl>(D);
+          // Function overrides are approximated using the number of parameters.
+          if (FD->getStorageClass() != DFD->getStorageClass() ||
+              FD->getNumParams() != DFD->getNumParams())
+            continue;
+        }
+        Relations.emplace_back(
+            SymbolRoleSet(SymbolRole::RelationOverrideOf) |
+                SymbolRoleSet(SymbolRole::RelationSpecializationOf),
+            ND);
+      }
+    }
+  }
+
   bool VisitFunctionDecl(const FunctionDecl *D) {
     if (D->isDeleted())
       return true;
@@ -158,6 +205,7 @@ public:
         Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
       }
     }
+    gatherTemplatePseudoOverrides(D, Relations);
 
     TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations));
     handleDeclarator(D);
@@ -194,14 +242,18 @@ public:
   }
 
   bool VisitVarDecl(const VarDecl *D) {
-    TRY_DECL(D, IndexCtx.handleDecl(D));
+    SmallVector<SymbolRelation, 4> Relations;
+    gatherTemplatePseudoOverrides(D, Relations);
+    TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
     handleDeclarator(D);
     IndexCtx.indexBody(D->getInit(), D);
     return true;
   }
 
   bool VisitFieldDecl(const FieldDecl *D) {
-    TRY_DECL(D, IndexCtx.handleDecl(D));
+    SmallVector<SymbolRelation, 4> Relations;
+    gatherTemplatePseudoOverrides(D, Relations);
+    TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
     handleDeclarator(D);
     if (D->isBitField())
       IndexCtx.indexBody(D->getBitWidth(), D);
@@ -233,7 +285,9 @@ public:
 
   bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
     if (!D->isTransparentTag()) {
-      TRY_DECL(D, IndexCtx.handleDecl(D));
+      SmallVector<SymbolRelation, 4> Relations;
+      gatherTemplatePseudoOverrides(D, Relations);
+      TRY_DECL(D, IndexCtx.handleDecl(D, SymbolRoleSet(), Relations));
       IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
     }
     return true;
@@ -243,7 +297,9 @@ public:
     // Non-free standing tags are handled in indexTypeSourceInfo.
     if (D->isFreeStanding()) {
       if (D->isThisDeclarationADefinition()) {
-        IndexCtx.indexTagDecl(D);
+        SmallVector<SymbolRelation, 4> Relations;
+        gatherTemplatePseudoOverrides(D, Relations);
+        IndexCtx.indexTagDecl(D, Relations);
       } else {
         auto *Parent = dyn_cast<NamedDecl>(D->getDeclContext());
         return IndexCtx.handleReference(D, D->getLocation(), Parent,

Modified: cfe/trunk/lib/Index/IndexingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexingContext.cpp?rev=301180&r1=301179&r2=301180&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexingContext.cpp (original)
+++ cfe/trunk/lib/Index/IndexingContext.cpp Mon Apr 24 09:04:58 2017
@@ -28,6 +28,10 @@ bool IndexingContext::shouldIndex(const
   return !isGeneratedDecl(D);
 }
 
+const LangOptions &IndexingContext::getLangOpts() const {
+  return Ctx->getLangOpts();
+}
+
 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
   return IndexOpts.IndexFunctionLocals;
 }

Modified: cfe/trunk/lib/Index/IndexingContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexingContext.h?rev=301180&r1=301179&r2=301180&view=diff
==============================================================================
--- cfe/trunk/lib/Index/IndexingContext.h (original)
+++ cfe/trunk/lib/Index/IndexingContext.h Mon Apr 24 09:04:58 2017
@@ -50,6 +50,8 @@ public:
 
   bool shouldIndex(const Decl *D);
 
+  const LangOptions &getLangOpts() const;
+
   bool shouldSuppressRefs() const {
     return false;
   }

Modified: cfe/trunk/test/Index/Core/index-source.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/Core/index-source.cpp?rev=301180&r1=301179&r2=301180&view=diff
==============================================================================
--- cfe/trunk/test/Index/Core/index-source.cpp (original)
+++ cfe/trunk/test/Index/Core/index-source.cpp Mon Apr 24 09:04:58 2017
@@ -111,3 +111,112 @@ template<>
 class PartialSpecilizationClass<int, int> { };
 // CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S at PartialSpecilizationClass>#I#I | <no-cgname> | Def,RelSpecialization | rel: 1
 // CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T at PartialSpecilizationClass
+
+template<typename T, typename S>
+class PseudoOverridesInSpecializations {
+  void function() { }
+  void function(int) { }
+
+  static void staticFunction() { }
+
+  int field;
+  static int variable;
+
+  typedef T TypeDef;
+  using TypeAlias = T;
+
+  enum anEnum { };
+
+  struct Struct { };
+  union Union { };
+
+  using TypealiasOrRecord = void;
+
+  template<typename U> struct InnerTemplate { };
+  template<typename U> struct InnerTemplate <U*> { };
+};
+
+template<>
+class PseudoOverridesInSpecializations<double, int> {
+  void function() { }
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | function | c:@S at PseudoOverridesInSpecializations>#d#I at F@function# | __ZN32PseudoOverridesInSpecializationsIdiE8functionEv | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | function | c:@ST>2#T#T at PseudoOverridesInSpecializations@F at function#
+
+  void staticFunction() { }
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | staticFunction | c:@S at PseudoOverridesInSpecializations>#d#I at F@staticFunction# | __ZN32PseudoOverridesInSpecializationsIdiE14staticFunctionEv | Def,RelChild | rel: 1
+// CHECK-NOT: RelOver
+
+  int notOverridingField = 0;
+
+// CHECK-LABEL: checLabelBreak
+  int checLabelBreak = 0;
+
+  int field = 0;
+// CHECK: [[@LINE-1]]:7 | field/C++ | field | c:@S at PseudoOverridesInSpecializations>#d#I at FI@field | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | field | c:@ST>2#T#T at PseudoOverridesInSpecializations@FI at field
+
+  static double variable;
+// CHECK: [[@LINE-1]]:17 | static-property/C++ | variable | c:@S at PseudoOverridesInSpecializations>#d#I at variable | __ZN32PseudoOverridesInSpecializationsIdiE8variableE | Decl,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | variable | c:@ST>2#T#T at PseudoOverridesInSpecializations@variable
+
+  typedef double TypeDef;
+// CHECK: [[@LINE-1]]:18 | type-alias/C | TypeDef | c:index-source.cpp at S@PseudoOverridesInSpecializations>#d#I at T@TypeDef | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypeDef | c:index-source.cpp at ST>2#T#T at PseudoOverridesInSpecializations@T at TypeDef
+
+  using TypeAlias = int;
+// CHECK: [[@LINE-1]]:9 | type-alias/C++ | TypeAlias | c:@S at PseudoOverridesInSpecializations>#d#I at TypeAlias | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypeAlias | c:@ST>2#T#T at PseudoOverridesInSpecializations@TypeAlias
+
+  enum anEnum { };
+// CHECK: [[@LINE-1]]:8 | enum/C | anEnum | c:@S at PseudoOverridesInSpecializations>#d#I at E@anEnum | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | anEnum | c:@ST>2#T#T at PseudoOverridesInSpecializations@E at anEnum
+  class Struct { };
+// CHECK: [[@LINE-1]]:9 | class/C++ | Struct | c:@S at PseudoOverridesInSpecializations>#d#I at S@Struct | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | Struct | c:@ST>2#T#T at PseudoOverridesInSpecializations@S at Struct
+  union Union { };
+// CHECK: [[@LINE-1]]:9 | union/C | Union | c:@S at PseudoOverridesInSpecializations>#d#I at U@Union | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | Union | c:@ST>2#T#T at PseudoOverridesInSpecializations@U at Union
+
+  struct TypealiasOrRecord { };
+// CHECK: [[@LINE-1]]:10 | struct/C | TypealiasOrRecord | c:@S at PseudoOverridesInSpecializations>#d#I at S@TypealiasOrRecord | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T at PseudoOverridesInSpecializations@TypealiasOrRecord
+
+  template<typename U> struct InnerTemplate { };
+// CHECK: [[@LINE-1]]:31 | struct(Gen)/C++ | InnerTemplate | c:@S at PseudoOverridesInSpecializations>#d#I at ST>1#T at InnerTemplate | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | InnerTemplate | c:@ST>2#T#T at PseudoOverridesInSpecializations@ST>1#T at InnerTemplate
+  template<typename U> struct InnerTemplate <U*> { };
+// CHECK-NOT: RelOver
+};
+
+template<typename S>
+class PseudoOverridesInSpecializations<float, S> {
+  typedef float TypealiasOrRecord;
+// CHECK: [[@LINE-1]]:17 | type-alias/C | TypealiasOrRecord | c:index-source.cpp at SP>1#T at PseudoOverridesInSpecializations>#f#t0.0 at T@TypealiasOrRecord | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T at PseudoOverridesInSpecializations@TypealiasOrRecord
+};
+
+template<typename T, typename U>
+class ConflictingPseudoOverridesInSpecialization {
+  void foo(T x);
+  void foo(U x);
+};
+
+template<typename T>
+class ConflictingPseudoOverridesInSpecialization<int, T> {
+  void foo(T x);
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | foo | c:@SP>1#T at ConflictingPseudoOverridesInSpecialization>#I#t0.0 at F@foo#S0_# | <no-cgname> | Decl,RelChild,RelOver,RelSpecialization | rel: 3
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | foo | c:@ST>2#T#T at ConflictingPseudoOverridesInSpecialization@F at foo#t0.0#
+// CHECK-NEXT: RelOver,RelSpecialization | foo | c:@ST>2#T#T at ConflictingPseudoOverridesInSpecialization@F at foo#t0.1#
+};




More information about the cfe-commits mailing list