diff --git a/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.h b/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.h --- a/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.h +++ b/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_CONFUSABLE_IDENTIFIER_CHECK_H #include "../ClangTidyCheck.h" +#include namespace clang::tidy::misc { @@ -26,9 +27,23 @@ void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + struct ContextInfo { + const DeclContext *PrimaryContext; + const DeclContext *NonTransparentContext; + llvm::SmallVector PrimaryContexts; + llvm::SmallVector Bases; + }; + private: - std::string skeleton(StringRef); - llvm::StringMap> Mapper; + struct Entry { + const NamedDecl *Declaration; + const ContextInfo *Info; + }; + + const ContextInfo *getContextInfo(const DeclContext *DC); + + llvm::StringMap> Mapper; + std::unordered_map ContextInfos; }; } // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp b/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp --- a/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp @@ -45,7 +45,7 @@ // We're skipping 1. and 3. for the sake of simplicity, but this can lead to // false positive. -std::string ConfusableIdentifierCheck::skeleton(StringRef Name) { +static std::string skeleton(StringRef Name) { using namespace llvm; std::string SName = Name.str(); std::string Skeleton; @@ -89,75 +89,107 @@ return Skeleton; } -static bool mayShadowImpl(const NamedDecl *ND0, const NamedDecl *ND1) { - const DeclContext *DC0 = ND0->getDeclContext()->getPrimaryContext(); - const DeclContext *DC1 = ND1->getDeclContext()->getPrimaryContext(); +static bool mayShadowImpl(const DeclContext *DC0, const DeclContext *DC1) { + return DC0 && DC0 == DC1; +} - if (isa(ND0) || isa(ND0)) - return true; +static bool mayShadowImpl(const NamedDecl *ND0, const NamedDecl *ND1) { + return isa(ND0) || isa(ND1); +} - while (DC0->isTransparentContext()) - DC0 = DC0->getParent(); - while (DC1->isTransparentContext()) - DC1 = DC1->getParent(); +static bool isMemberOf(const ConfusableIdentifierCheck::ContextInfo *DC0, + const ConfusableIdentifierCheck::ContextInfo *DC1) { + if (DC0->Bases.empty()) + return false; + return llvm::is_contained(DC1->Bases, DC0->PrimaryContext); +} - if (DC0->Equals(DC1)) +static bool enclosesContext(const ConfusableIdentifierCheck::ContextInfo *DC0, + const ConfusableIdentifierCheck::ContextInfo *DC1) { + if (DC0->PrimaryContext == DC1->PrimaryContext) return true; - return false; + return llvm::is_contained(DC0->PrimaryContexts, DC1->PrimaryContext) || + llvm::is_contained(DC1->PrimaryContexts, DC0->PrimaryContext); } -static bool isMemberOf(const NamedDecl *ND, const CXXRecordDecl *RD) { - const DeclContext *NDParent = ND->getDeclContext(); - if (!NDParent || !isa(NDParent)) - return false; - if (NDParent == RD) +static bool mayShadow(const NamedDecl *ND0, + const ConfusableIdentifierCheck::ContextInfo *DC0, + const NamedDecl *ND1, + const ConfusableIdentifierCheck::ContextInfo *DC1) { + if (!DC0->Bases.empty() && ND1->getAccess() != AS_private && + isMemberOf(DC1, DC0)) return true; - return !RD->forallBases( - [NDParent](const CXXRecordDecl *Base) { return NDParent != Base; }); + if (!DC1->Bases.empty() && ND0->getAccess() != AS_private && + isMemberOf(DC0, DC1)) + return true; + + return enclosesContext(DC0, DC1) && + (mayShadowImpl(ND0, ND1) || mayShadowImpl(DC0->NonTransparentContext, + DC1->NonTransparentContext)); } -static bool mayShadow(const NamedDecl *ND0, const NamedDecl *ND1) { +const ConfusableIdentifierCheck::ContextInfo * +ConfusableIdentifierCheck::getContextInfo(const DeclContext *DC) { + const DeclContext *PrimaryContext = DC->getPrimaryContext(); + auto It = ContextInfos.find(PrimaryContext); + if (It != ContextInfos.end()) + return &It->second; + + ContextInfo &Info = ContextInfos[PrimaryContext]; + Info.PrimaryContext = PrimaryContext; + Info.NonTransparentContext = PrimaryContext; + + while (Info.NonTransparentContext->isTransparentContext()) { + Info.NonTransparentContext = Info.NonTransparentContext->getParent(); + if (!Info.NonTransparentContext) + break; + } - const DeclContext *DC0 = ND0->getDeclContext()->getPrimaryContext(); - const DeclContext *DC1 = ND1->getDeclContext()->getPrimaryContext(); + if (Info.NonTransparentContext) + Info.NonTransparentContext = + Info.NonTransparentContext->getPrimaryContext(); - if (const CXXRecordDecl *RD0 = dyn_cast(DC0)) { - RD0 = RD0->getDefinition(); - if (RD0 && ND1->getAccess() != AS_private && isMemberOf(ND1, RD0)) - return true; + while (DC) { + if (!isa(DC) && !isa(DC)) + Info.PrimaryContexts.push_back(DC->getPrimaryContext()); + DC = DC->getParent(); } - if (const CXXRecordDecl *RD1 = dyn_cast(DC1)) { - RD1 = RD1->getDefinition(); - if (RD1 && ND0->getAccess() != AS_private && isMemberOf(ND0, RD1)) - return true; + + if (const CXXRecordDecl *RD = dyn_cast(PrimaryContext)) { + RD = RD->getDefinition(); + if (RD) { + Info.Bases.push_back(RD); + RD->forallBases([&](const CXXRecordDecl *Base) { + Info.Bases.push_back(Base); + return false; + }); + } } - if (DC0->Encloses(DC1)) - return mayShadowImpl(ND0, ND1); - if (DC1->Encloses(DC0)) - return mayShadowImpl(ND1, ND0); - return false; + return &Info; } void ConfusableIdentifierCheck::check( const ast_matchers::MatchFinder::MatchResult &Result) { if (const auto *ND = Result.Nodes.getNodeAs("nameddecl")) { if (IdentifierInfo *NDII = ND->getIdentifier()) { + const ContextInfo *Info = getContextInfo(ND->getDeclContext()); StringRef NDName = NDII->getName(); - llvm::SmallVector &Mapped = Mapper[skeleton(NDName)]; - for (const NamedDecl *OND : Mapped) { - const IdentifierInfo *ONDII = OND->getIdentifier(); - if (mayShadow(ND, OND)) { + llvm::SmallVector &Mapped = Mapper[skeleton(NDName)]; + for (const Entry &E : Mapped) { + const IdentifierInfo *ONDII = E.Declaration->getIdentifier(); + if (mayShadow(ND, Info, E.Declaration, E.Info)) { StringRef ONDName = ONDII->getName(); if (ONDName != NDName) { - diag(ND->getLocation(), "%0 is confusable with %1") << ND << OND; - diag(OND->getLocation(), "other declaration found here", + diag(ND->getLocation(), "%0 is confusable with %1") + << ND << E.Declaration; + diag(E.Declaration->getLocation(), "other declaration found here", DiagnosticIDs::Note); } } } - Mapped.push_back(ND); + Mapped.push_back({ND, Info}); } } }