arphaman updated this revision to Diff 95940.
arphaman added a comment.
Updated the relationship to be 'overrideOf | specializationOf' to differentiate
it from regular 'overrideOf'.
Repository:
rL LLVM
https://reviews.llvm.org/D32020
Files:
lib/Index/IndexDecl.cpp
lib/Index/IndexingContext.cpp
lib/Index/IndexingContext.h
test/Index/Core/index-source.cpp
Index: test/Index/Core/index-source.cpp
===================================================================
--- test/Index/Core/index-source.cpp
+++ 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: lib/Index/IndexingContext.h
===================================================================
--- lib/Index/IndexingContext.h
+++ lib/Index/IndexingContext.h
@@ -48,6 +48,8 @@
void setASTContext(ASTContext &ctx) { Ctx = &ctx; }
+ const LangOptions &getLangOpts() const;
+
bool shouldSuppressRefs() const {
return false;
}
Index: lib/Index/IndexingContext.cpp
===================================================================
--- lib/Index/IndexingContext.cpp
+++ lib/Index/IndexingContext.cpp
@@ -17,6 +17,10 @@
using namespace clang;
using namespace index;
+const LangOptions &IndexingContext::getLangOpts() const {
+ return Ctx->getLangOpts();
+}
+
bool IndexingContext::shouldIndexFunctionLocalSymbols() const {
return IndexOpts.IndexFunctionLocals;
}
Index: lib/Index/IndexDecl.cpp
===================================================================
--- lib/Index/IndexDecl.cpp
+++ lib/Index/IndexDecl.cpp
@@ -138,6 +138,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;
@@ -152,6 +199,7 @@
Relations.emplace_back((unsigned)SymbolRole::RelationOverrideOf, *I);
}
}
+ gatherTemplatePseudoOverrides(D, Relations);
if (!IndexCtx.handleDecl(D, Roles, Relations))
return false;
@@ -189,15 +237,19 @@
}
bool VisitVarDecl(const VarDecl *D) {
- if (!IndexCtx.handleDecl(D))
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ if (!IndexCtx.handleDecl(D, SymbolRoleSet(), Relations))
return false;
handleDeclarator(D);
IndexCtx.indexBody(D->getInit(), D);
return true;
}
bool VisitFieldDecl(const FieldDecl *D) {
- if (!IndexCtx.handleDecl(D))
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ if (!IndexCtx.handleDecl(D, SymbolRoleSet(), Relations))
return false;
handleDeclarator(D);
if (D->isBitField())
@@ -231,18 +283,23 @@
}
bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
- if (!D->isTransparentTag())
- if (!IndexCtx.handleDecl(D))
+ if (!D->isTransparentTag()) {
+ SmallVector<SymbolRelation, 4> Relations;
+ gatherTemplatePseudoOverrides(D, Relations);
+ if (!IndexCtx.handleDecl(D, SymbolRoleSet(), Relations))
return false;
+ }
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
return true;
}
bool VisitTagDecl(const TagDecl *D) {
// 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,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits