Skip to content

Commit d54d71b

Browse files
committed
[clangd] Make output order of allTargetDecls deterministic
Summary: Makes use of insertion order to stabilize output for multiple decls. Fixes https://bugs.llvm.org/show_bug.cgi?id=44564 Reviewers: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, usaxena95, cfe-commits, aemerson Tags: #clang Differential Revision: https://reviews.llvm.org/D72826
1 parent 23a887b commit d54d71b

File tree

1 file changed

+49
-32
lines changed

1 file changed

+49
-32
lines changed

clang-tools-extra/clangd/FindTarget.cpp

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "llvm/Support/Compiler.h"
3636
#include "llvm/Support/raw_ostream.h"
3737
#include <utility>
38+
#include <vector>
3839

3940
namespace clang {
4041
namespace clangd {
@@ -134,6 +135,35 @@ const Type *getPointeeType(const Type *T) {
134135
return FirstArg.getAsType().getTypePtrOrNull();
135136
}
136137

138+
const NamedDecl *getTemplatePattern(const NamedDecl *D) {
139+
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
140+
return CRD->getTemplateInstantiationPattern();
141+
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
142+
return FD->getTemplateInstantiationPattern();
143+
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
144+
// Hmm: getTIP returns its arg if it's not an instantiation?!
145+
VarDecl *T = VD->getTemplateInstantiationPattern();
146+
return (T == D) ? nullptr : T;
147+
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
148+
return ED->getInstantiatedFromMemberEnum();
149+
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
150+
if (const auto *Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
151+
if (const DeclContext *ParentPat =
152+
dyn_cast_or_null<DeclContext>(getTemplatePattern(Parent)))
153+
for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
154+
if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
155+
return BaseND;
156+
} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
157+
if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
158+
if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
159+
for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
160+
return BaseECD;
161+
}
162+
}
163+
}
164+
return nullptr;
165+
}
166+
137167
// TargetFinder locates the entities that an AST node refers to.
138168
//
139169
// Typically this is (possibly) one declaration and (possibly) one type, but
@@ -167,37 +197,12 @@ const Type *getPointeeType(const Type *T) {
167197
struct TargetFinder {
168198
using RelSet = DeclRelationSet;
169199
using Rel = DeclRelation;
170-
llvm::SmallDenseMap<const NamedDecl *, RelSet> Decls;
171-
RelSet Flags;
172200

173-
static const NamedDecl *getTemplatePattern(const NamedDecl *D) {
174-
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
175-
return CRD->getTemplateInstantiationPattern();
176-
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
177-
return FD->getTemplateInstantiationPattern();
178-
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
179-
// Hmm: getTIP returns its arg if it's not an instantiation?!
180-
VarDecl *T = VD->getTemplateInstantiationPattern();
181-
return (T == D) ? nullptr : T;
182-
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
183-
return ED->getInstantiatedFromMemberEnum();
184-
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
185-
if (const auto *Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
186-
if (const DeclContext *ParentPat =
187-
dyn_cast_or_null<DeclContext>(getTemplatePattern(Parent)))
188-
for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
189-
if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
190-
return BaseND;
191-
} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
192-
if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
193-
if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
194-
for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
195-
return BaseECD;
196-
}
197-
}
198-
}
199-
return nullptr;
200-
}
201+
private:
202+
llvm::SmallDenseMap<const NamedDecl *,
203+
std::pair<RelSet, /*InsertionOrder*/ size_t>>
204+
Decls;
205+
RelSet Flags;
201206

202207
template <typename T> void debug(T &Node, RelSet Flags) {
203208
dlog("visit [{0}] {1}", Flags,
@@ -207,10 +212,22 @@ struct TargetFinder {
207212
void report(const NamedDecl *D, RelSet Flags) {
208213
dlog("--> [{0}] {1}", Flags,
209214
nodeToString(ast_type_traits::DynTypedNode::create(*D)));
210-
Decls[D] |= Flags;
215+
auto It = Decls.try_emplace(D, std::make_pair(Flags, Decls.size()));
216+
// If already exists, update the flags.
217+
if (!It.second)
218+
It.first->second.first |= Flags;
211219
}
212220

213221
public:
222+
llvm::SmallVector<std::pair<const NamedDecl *, RelSet>, 1> takeDecls() const {
223+
using ValTy = std::pair<const NamedDecl *, RelSet>;
224+
llvm::SmallVector<ValTy, 1> Result;
225+
Result.resize(Decls.size());
226+
for (const auto &Elem : Decls)
227+
Result[Elem.second.second] = {Elem.first, Elem.second.first};
228+
return Result;
229+
}
230+
214231
void add(const Decl *Dcl, RelSet Flags) {
215232
const NamedDecl *D = llvm::dyn_cast<NamedDecl>(Dcl);
216233
if (!D)
@@ -485,7 +502,7 @@ allTargetDecls(const ast_type_traits::DynTypedNode &N) {
485502
else if (const CXXCtorInitializer *CCI = N.get<CXXCtorInitializer>())
486503
Finder.add(CCI, Flags);
487504

488-
return {Finder.Decls.begin(), Finder.Decls.end()};
505+
return Finder.takeDecls();
489506
}
490507

491508
llvm::SmallVector<const NamedDecl *, 1>

0 commit comments

Comments
 (0)