forked from OSchip/llvm-project
[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
This commit is contained in:
parent
23a887b0dd
commit
d54d71b67e
|
@ -35,6 +35,7 @@
|
|||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace clangd {
|
||||
|
@ -134,6 +135,35 @@ const Type *getPointeeType(const Type *T) {
|
|||
return FirstArg.getAsType().getTypePtrOrNull();
|
||||
}
|
||||
|
||||
const NamedDecl *getTemplatePattern(const NamedDecl *D) {
|
||||
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
|
||||
return CRD->getTemplateInstantiationPattern();
|
||||
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
return FD->getTemplateInstantiationPattern();
|
||||
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
// Hmm: getTIP returns its arg if it's not an instantiation?!
|
||||
VarDecl *T = VD->getTemplateInstantiationPattern();
|
||||
return (T == D) ? nullptr : T;
|
||||
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
|
||||
return ED->getInstantiatedFromMemberEnum();
|
||||
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
|
||||
if (const auto *Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
|
||||
if (const DeclContext *ParentPat =
|
||||
dyn_cast_or_null<DeclContext>(getTemplatePattern(Parent)))
|
||||
for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
|
||||
if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
|
||||
return BaseND;
|
||||
} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
|
||||
if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
|
||||
if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
|
||||
for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
|
||||
return BaseECD;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TargetFinder locates the entities that an AST node refers to.
|
||||
//
|
||||
// Typically this is (possibly) one declaration and (possibly) one type, but
|
||||
|
@ -167,37 +197,12 @@ const Type *getPointeeType(const Type *T) {
|
|||
struct TargetFinder {
|
||||
using RelSet = DeclRelationSet;
|
||||
using Rel = DeclRelation;
|
||||
llvm::SmallDenseMap<const NamedDecl *, RelSet> Decls;
|
||||
RelSet Flags;
|
||||
|
||||
static const NamedDecl *getTemplatePattern(const NamedDecl *D) {
|
||||
if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) {
|
||||
return CRD->getTemplateInstantiationPattern();
|
||||
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
return FD->getTemplateInstantiationPattern();
|
||||
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
// Hmm: getTIP returns its arg if it's not an instantiation?!
|
||||
VarDecl *T = VD->getTemplateInstantiationPattern();
|
||||
return (T == D) ? nullptr : T;
|
||||
} else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
|
||||
return ED->getInstantiatedFromMemberEnum();
|
||||
} else if (isa<FieldDecl>(D) || isa<TypedefNameDecl>(D)) {
|
||||
if (const auto *Parent = llvm::dyn_cast<NamedDecl>(D->getDeclContext()))
|
||||
if (const DeclContext *ParentPat =
|
||||
dyn_cast_or_null<DeclContext>(getTemplatePattern(Parent)))
|
||||
for (const NamedDecl *BaseND : ParentPat->lookup(D->getDeclName()))
|
||||
if (!BaseND->isImplicit() && BaseND->getKind() == D->getKind())
|
||||
return BaseND;
|
||||
} else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
|
||||
if (const auto *ED = dyn_cast<EnumDecl>(ECD->getDeclContext())) {
|
||||
if (const EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
|
||||
for (const NamedDecl *BaseECD : Pattern->lookup(ECD->getDeclName()))
|
||||
return BaseECD;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
private:
|
||||
llvm::SmallDenseMap<const NamedDecl *,
|
||||
std::pair<RelSet, /*InsertionOrder*/ size_t>>
|
||||
Decls;
|
||||
RelSet Flags;
|
||||
|
||||
template <typename T> void debug(T &Node, RelSet Flags) {
|
||||
dlog("visit [{0}] {1}", Flags,
|
||||
|
@ -207,10 +212,22 @@ struct TargetFinder {
|
|||
void report(const NamedDecl *D, RelSet Flags) {
|
||||
dlog("--> [{0}] {1}", Flags,
|
||||
nodeToString(ast_type_traits::DynTypedNode::create(*D)));
|
||||
Decls[D] |= Flags;
|
||||
auto It = Decls.try_emplace(D, std::make_pair(Flags, Decls.size()));
|
||||
// If already exists, update the flags.
|
||||
if (!It.second)
|
||||
It.first->second.first |= Flags;
|
||||
}
|
||||
|
||||
public:
|
||||
llvm::SmallVector<std::pair<const NamedDecl *, RelSet>, 1> takeDecls() const {
|
||||
using ValTy = std::pair<const NamedDecl *, RelSet>;
|
||||
llvm::SmallVector<ValTy, 1> Result;
|
||||
Result.resize(Decls.size());
|
||||
for (const auto &Elem : Decls)
|
||||
Result[Elem.second.second] = {Elem.first, Elem.second.first};
|
||||
return Result;
|
||||
}
|
||||
|
||||
void add(const Decl *Dcl, RelSet Flags) {
|
||||
const NamedDecl *D = llvm::dyn_cast<NamedDecl>(Dcl);
|
||||
if (!D)
|
||||
|
@ -485,7 +502,7 @@ allTargetDecls(const ast_type_traits::DynTypedNode &N) {
|
|||
else if (const CXXCtorInitializer *CCI = N.get<CXXCtorInitializer>())
|
||||
Finder.add(CCI, Flags);
|
||||
|
||||
return {Finder.Decls.begin(), Finder.Decls.end()};
|
||||
return Finder.takeDecls();
|
||||
}
|
||||
|
||||
llvm::SmallVector<const NamedDecl *, 1>
|
||||
|
|
Loading…
Reference in New Issue