This revision was automatically updated to reflect the committed changes.
Closed by commit rL301180: [index] The relation between the declarations in 
template specializations (authored by arphaman).

Changed prior to commit:
  https://reviews.llvm.org/D32020?vs=95940&id=96396#toc

Repository:
  rL LLVM

https://reviews.llvm.org/D32020

Files:
  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

Index: cfe/trunk/test/Index/Core/index-source.cpp
===================================================================
--- cfe/trunk/test/Index/Core/index-source.cpp
+++ cfe/trunk/test/Index/Core/index-source.cpp
@@ -111,3 +111,112 @@
 class PartialSpecilizationClass<int, int> { };
 // CHECK: [[@LINE-1]]:7 | class(Gen,TS)/C++ | PartialSpecilizationClass | c:@S@PartialSpecilizationClass>#I#I | <no-cgname> | Def,RelSpecialization | rel: 1
 // CHECK-NEXT: RelSpecialization | PartialSpecilizationClass | c:@ST>2#T#T@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@PseudoOverridesInSpecializations>#d#I@F@function# | __ZN32PseudoOverridesInSpecializationsIdiE8functionEv | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | function | c:@ST>2#T#T@PseudoOverridesInSpecializations@F@function#
+
+  void staticFunction() { }
+// CHECK: [[@LINE-1]]:8 | instance-method/C++ | staticFunction | c:@S@PseudoOverridesInSpecializations>#d#I@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@PseudoOverridesInSpecializations>#d#I@FI@field | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | field | c:@ST>2#T#T@PseudoOverridesInSpecializations@FI@field
+
+  static double variable;
+// CHECK: [[@LINE-1]]:17 | static-property/C++ | variable | c:@S@PseudoOverridesInSpecializations>#d#I@variable | __ZN32PseudoOverridesInSpecializationsIdiE8variableE | Decl,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | variable | c:@ST>2#T#T@PseudoOverridesInSpecializations@variable
+
+  typedef double TypeDef;
+// CHECK: [[@LINE-1]]:18 | type-alias/C | TypeDef | c:index-source.cpp@S@PseudoOverridesInSpecializations>#d#I@T@TypeDef | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypeDef | c:index-source.cpp@ST>2#T#T@PseudoOverridesInSpecializations@T@TypeDef
+
+  using TypeAlias = int;
+// CHECK: [[@LINE-1]]:9 | type-alias/C++ | TypeAlias | c:@S@PseudoOverridesInSpecializations>#d#I@TypeAlias | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypeAlias | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypeAlias
+
+  enum anEnum { };
+// CHECK: [[@LINE-1]]:8 | enum/C | anEnum | c:@S@PseudoOverridesInSpecializations>#d#I@E@anEnum | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | anEnum | c:@ST>2#T#T@PseudoOverridesInSpecializations@E@anEnum
+  class Struct { };
+// CHECK: [[@LINE-1]]:9 | class/C++ | Struct | c:@S@PseudoOverridesInSpecializations>#d#I@S@Struct | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | Struct | c:@ST>2#T#T@PseudoOverridesInSpecializations@S@Struct
+  union Union { };
+// CHECK: [[@LINE-1]]:9 | union/C | Union | c:@S@PseudoOverridesInSpecializations>#d#I@U@Union | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | Union | c:@ST>2#T#T@PseudoOverridesInSpecializations@U@Union
+
+  struct TypealiasOrRecord { };
+// CHECK: [[@LINE-1]]:10 | struct/C | TypealiasOrRecord | c:@S@PseudoOverridesInSpecializations>#d#I@S@TypealiasOrRecord | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T@PseudoOverridesInSpecializations@TypealiasOrRecord
+
+  template<typename U> struct InnerTemplate { };
+// CHECK: [[@LINE-1]]:31 | struct(Gen)/C++ | InnerTemplate | c:@S@PseudoOverridesInSpecializations>#d#I@ST>1#T@InnerTemplate | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | InnerTemplate | c:@ST>2#T#T@PseudoOverridesInSpecializations@ST>1#T@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@SP>1#T@PseudoOverridesInSpecializations>#f#t0.0@T@TypealiasOrRecord | <no-cgname> | Def,RelChild,RelOver,RelSpecialization | rel: 2
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | TypealiasOrRecord | c:@ST>2#T#T@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@ConflictingPseudoOverridesInSpecialization>#I#t0.0@F@foo#S0_# | <no-cgname> | Decl,RelChild,RelOver,RelSpecialization | rel: 3
+// CHECK-NEXT: RelChild
+// CHECK-NEXT: RelOver,RelSpecialization | foo | c:@ST>2#T#T@ConflictingPseudoOverridesInSpecialization@F@foo#t0.0#
+// CHECK-NEXT: RelOver,RelSpecialization | foo | c:@ST>2#T#T@ConflictingPseudoOverridesInSpecialization@F@foo#t0.1#
+};
Index: cfe/trunk/lib/Index/IndexingContext.h
===================================================================
--- cfe/trunk/lib/Index/IndexingContext.h
+++ cfe/trunk/lib/Index/IndexingContext.h
@@ -50,6 +50,8 @@
 
   bool shouldIndex(const Decl *D);
 
+  const LangOptions &getLangOpts() const;
+
   bool shouldSuppressRefs() const {
     return false;
   }
Index: cfe/trunk/lib/Index/IndexDecl.cpp
===================================================================
--- cfe/trunk/lib/Index/IndexDecl.cpp
+++ cfe/trunk/lib/Index/IndexDecl.cpp
@@ -144,6 +144,53 @@
     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 @@
         Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
       }
     }
+    gatherTemplatePseudoOverrides(D, Relations);
 
     TRY_DECL(D, IndexCtx.handleDecl(D, Roles, Relations));
     handleDeclarator(D);
@@ -194,14 +242,18 @@
   }
 
   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 @@
 
   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 @@
     // 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,
Index: cfe/trunk/lib/Index/IndexingContext.cpp
===================================================================
--- cfe/trunk/lib/Index/IndexingContext.cpp
+++ cfe/trunk/lib/Index/IndexingContext.cpp
@@ -28,6 +28,10 @@
   return !isGeneratedDecl(D);
 }
 
+const LangOptions &IndexingContext::getLangOpts() const {
+  return Ctx->getLangOpts();
+}
+
 bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
   return IndexOpts.IndexFunctionLocals;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to