Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.

Commit 400fe8b

Browse files
committed
Another (improved?) version.
1 parent abc67c7 commit 400fe8b

File tree

1 file changed

+65
-60
lines changed

1 file changed

+65
-60
lines changed

lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 65 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -115,83 +115,91 @@ static bool IsStructurallyEquivalent(const DeclarationName Name1,
115115

116116
using ContextVector = llvm::SmallVector<const DeclContext *, 4>;
117117

118-
static void GetContexts(ContextVector &Contexts, const NamedDecl *ND) {
118+
static void GetContextsForEquivalenceCheck(ContextVector &Contexts,
119+
const NamedDecl *ND) {
119120
const DeclContext *Ctx = ND->getDeclContext();
120121

121122
// For ObjC methods, look through categories and use the interface as context.
122123
if (auto *MD = dyn_cast<ObjCMethodDecl>(ND))
123124
if (auto *ID = MD->getClassInterface())
124125
Ctx = ID;
125126

126-
while (Ctx && Ctx->isFunctionOrMethod())
127-
Ctx = Ctx->getParent();
128-
129127
// Collect named contexts.
128+
// Function contexts are ignored, this behavior is enough for ASTImporter.
129+
// FIXME: Add assertion if different (non equivalent) functions are
130+
// encountered on the paths (except the first)?
130131
while (Ctx) {
131-
if (isa<NamedDecl>(Ctx))
132+
if (isa<NamedDecl>(Ctx) && !isa<FunctionDecl>(Ctx))
132133
Contexts.push_back(Ctx);
133134
Ctx = Ctx->getParent();
134135
}
135136
}
136137

137-
static bool IsEquivalentContext(StructuralEquivalenceContext &Context, const ContextVector &Contexts1, const ContextVector &Contexts2) {
138+
static bool IsEquivalentDeclContext(StructuralEquivalenceContext &Context,
139+
const DeclContext *DC1,
140+
const DeclContext *DC2) {
141+
if (const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
142+
const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
143+
if (!Spec2)
144+
return false;
145+
if (!IsStructurallyEquivalent(Spec1->getDeclName(), Spec2->getDeclName()))
146+
return false;
147+
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs(),
148+
Spec2->getTemplateArgs()))
149+
return false;
150+
} else if (const auto *ND1 = dyn_cast<NamespaceDecl>(DC1)) {
151+
const auto *ND2 = dyn_cast<NamespaceDecl>(DC2);
152+
if (!ND2)
153+
return false;
154+
if (ND1->isAnonymousNamespace() != ND2->isAnonymousNamespace())
155+
return false;
156+
if (ND1->isInline() != ND2->isInline())
157+
return false;
158+
if (ND1->isAnonymousNamespace() || ND1->isInlineNamespace())
159+
return true;
160+
if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName()))
161+
return false;
162+
} else if (const auto *RD1 = dyn_cast<RecordDecl>(DC1)) {
163+
const auto *RD2 = dyn_cast<RecordDecl>(DC2);
164+
if (!RD2)
165+
return false;
166+
if (!IsStructurallyEquivalent(RD1->getDeclName(), RD2->getDeclName()))
167+
return false;
168+
} else if (const auto *ED1 = dyn_cast<EnumDecl>(DC1)) {
169+
const auto *ED2 = dyn_cast<EnumDecl>(DC2);
170+
if (!ED2)
171+
return false;
172+
if (ED1->isScoped() != ED2->isScoped())
173+
return false;
174+
} else if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {
175+
const auto *ND2 = cast<NamedDecl>(DC2);
176+
if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName()))
177+
return false;
178+
} else
179+
llvm_unreachable("Context should be NamedDecl.");
180+
181+
return true;
182+
}
183+
184+
/// This function checks for equivalent "context" (scope) of an entity.
185+
/// This should check if the scope of two names is equivalent.
186+
/// Functions are excluded from this scope check because there is no use case
187+
/// when entities from different functions are compared.
188+
static bool IsEquivalentContext(StructuralEquivalenceContext &Context,
189+
const NamedDecl *ND1, const NamedDecl *ND2) {
190+
ContextVector Contexts1, Contexts2;
191+
GetContextsForEquivalenceCheck(Contexts1, ND1);
192+
GetContextsForEquivalenceCheck(Contexts2, ND2);
193+
138194
auto DC2I = Contexts2.begin();
139195
for (const DeclContext *DC1 : Contexts1) {
140196
if (DC2I == Contexts2.end())
141197
return false;
142198
const DeclContext *DC2 = *DC2I;
143199
++DC2I;
144200

145-
if (const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
146-
const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
147-
if (!Spec2)
148-
return false;
149-
if (!IsStructurallyEquivalent(Spec1->getDeclName(), Spec2->getDeclName()))
150-
return false;
151-
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs(), Spec2->getTemplateArgs()))
152-
return false;
153-
} else if (const auto *ND1 = dyn_cast<NamespaceDecl>(DC1)) {
154-
const auto *ND2 = dyn_cast<NamespaceDecl>(DC2);
155-
if (!ND2)
156-
return false;
157-
if (ND1->isAnonymousNamespace() != ND2->isAnonymousNamespace())
158-
return false;
159-
if (ND1->isInline() != ND2->isInline())
160-
return false;
161-
if (ND1->isAnonymousNamespace() || ND1->isInlineNamespace())
162-
continue;
163-
if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName()))
164-
return false;
165-
} else if (const auto *RD1 = dyn_cast<RecordDecl>(DC1)) {
166-
const auto *RD2 = dyn_cast<RecordDecl>(DC2);
167-
if (!RD2)
168-
return false;
169-
if (!IsStructurallyEquivalent(RD1->getDeclName(), RD2->getDeclName()))
170-
return false;
171-
} else if (const auto *FD1 = dyn_cast<FunctionDecl>(DC1)) {
172-
const auto *FD2 = dyn_cast<FunctionDecl>(DC2);
173-
if (!FD2)
174-
return false;
175-
if (!IsStructurallyEquivalent(Context, const_cast<FunctionDecl *>(FD1), const_cast<FunctionDecl *>(FD2)))
176-
return false;
177-
/*} else if (const auto *ED = dyn_cast<EnumDecl>(DC)) {
178-
// C++ [dcl.enum]p10: Each enum-name and each unscoped
179-
// enumerator is declared in the scope that immediately contains
180-
// the enum-specifier. Each scoped enumerator is declared in the
181-
// scope of the enumeration.
182-
// For the case of unscoped enumerator, do not include in the qualified
183-
// name any information about its enum enclosing scope, as its visibility
184-
// is global.
185-
if (ED->isScoped())
186-
OS << *ED;
187-
else
188-
continue;*/
189-
} else if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {
190-
const auto *ND2 = cast<NamedDecl>(DC2);
191-
if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName()))
192-
return false;
193-
} else
194-
llvm_unreachable("Context should be NamedDecl.");
201+
if (!IsEquivalentDeclContext(Context, DC1, DC2))
202+
return false;
195203
}
196204

197205
if (DC2I != Contexts2.end())
@@ -1789,10 +1797,7 @@ bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
17891797
auto *ND2 = dyn_cast<NamedDecl>(D2);
17901798
if (!ND2)
17911799
return false;
1792-
ContextVector Contexts1, Contexts2;
1793-
GetContexts(Contexts1, ND1);
1794-
GetContexts(Contexts2, ND2);
1795-
if (!IsEquivalentContext(*this, Contexts1, Contexts2))
1800+
if (!IsEquivalentContext(*this, ND1, ND2))
17961801
return false;
17971802
}
17981803

0 commit comments

Comments
 (0)