diff options
| author | Kadir Cetinkaya <kadircet@google.com> | 2020-01-16 11:37:58 +0100 |
|---|---|---|
| committer | Hans Wennborg <hans@chromium.org> | 2020-02-19 14:08:13 +0100 |
| commit | d5f8656a68c25e93c5c8f03e0670fecb16609d40 (patch) | |
| tree | ce0da689ef262f09ea11a368c954101196339c38 | |
| parent | 222de784df453659144c6d07b530e7858c980021 (diff) | |
| download | bcm5719-llvm-d5f8656a68c25e93c5c8f03e0670fecb16609d40.tar.gz bcm5719-llvm-d5f8656a68c25e93c5c8f03e0670fecb16609d40.zip | |
[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
(cherry picked from commit d54d71b67e602674a255e299a22fe31dee1f3619)
| -rw-r--r-- | clang-tools-extra/clangd/FindTarget.cpp | 81 |
1 files changed, 49 insertions, 32 deletions
diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index d8ce0b69283..82a2e8c27d5 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -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> |

