Skip to content

Commit 8fdedcd

Browse files
committed
[clang-tidy] Optimize misc-confusable-identifiers
This is final optimization for this check. Main improvements comes from changing a logic order in mayShadow function, to first validate result of mayShadowImpl, then search primary context in a vectors. Secondary improvement comes from excluding all implicit code by using TK_IgnoreUnlessSpelledInSource. All other changes are just cosmetic improvements. Tested on Cataclysm-DDA open source project, result in check execution time reduction from 3682 seconds to 100 seconds (~0.25s per TU). That's 97.2% reduction for this change alone. Resulting in cumulative improvement for this check around -99.6%, finally bringing this check into a cheap category. Reviewed By: serge-sans-paille Differential Revision: https://reviews.llvm.org/D151594
1 parent 7ffeb8e commit 8fdedcd

File tree

2 files changed

+60
-36
lines changed

2 files changed

+60
-36
lines changed

clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.cpp

+56-36
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "clang/Frontend/CompilerInstance.h"
1313
#include "clang/Lex/Preprocessor.h"
14+
#include "llvm/ADT/SmallString.h"
1415
#include "llvm/Support/ConvertUTF.h"
1516

1617
namespace {
@@ -45,14 +46,13 @@ ConfusableIdentifierCheck::~ConfusableIdentifierCheck() = default;
4546
// We're skipping 1. and 3. for the sake of simplicity, but this can lead to
4647
// false positive.
4748

48-
static std::string skeleton(StringRef Name) {
49+
static llvm::SmallString<64U> skeleton(StringRef Name) {
4950
using namespace llvm;
50-
std::string SName = Name.str();
51-
std::string Skeleton;
52-
Skeleton.reserve(1 + Name.size());
51+
SmallString<64U> Skeleton;
52+
Skeleton.reserve(1U + Name.size());
5353

54-
const char *Curr = SName.c_str();
55-
const char *End = Curr + SName.size();
54+
const char *Curr = Name.data();
55+
const char *End = Curr + Name.size();
5656
while (Curr < End) {
5757

5858
const char *Prev = Curr;
@@ -99,8 +99,6 @@ static bool mayShadowImpl(const NamedDecl *ND0, const NamedDecl *ND1) {
9999

100100
static bool isMemberOf(const ConfusableIdentifierCheck::ContextInfo *DC0,
101101
const ConfusableIdentifierCheck::ContextInfo *DC1) {
102-
if (DC0->Bases.empty())
103-
return false;
104102
return llvm::is_contained(DC1->Bases, DC0->PrimaryContext);
105103
}
106104

@@ -117,16 +115,23 @@ static bool mayShadow(const NamedDecl *ND0,
117115
const ConfusableIdentifierCheck::ContextInfo *DC0,
118116
const NamedDecl *ND1,
119117
const ConfusableIdentifierCheck::ContextInfo *DC1) {
120-
if (!DC0->Bases.empty() && ND1->getAccess() != AS_private &&
121-
isMemberOf(DC1, DC0))
122-
return true;
123-
if (!DC1->Bases.empty() && ND0->getAccess() != AS_private &&
124-
isMemberOf(DC0, DC1))
125-
return true;
126118

127-
return enclosesContext(DC0, DC1) &&
128-
(mayShadowImpl(ND0, ND1) || mayShadowImpl(DC0->NonTransparentContext,
129-
DC1->NonTransparentContext));
119+
if (!DC0->Bases.empty() && !DC1->Bases.empty()) {
120+
// if any of the declaration is a non-private member of the other
121+
// declaration, it's shadowed by the former
122+
123+
if (ND1->getAccess() != AS_private && isMemberOf(DC1, DC0))
124+
return true;
125+
126+
if (ND0->getAccess() != AS_private && isMemberOf(DC0, DC1))
127+
return true;
128+
}
129+
130+
if (!mayShadowImpl(DC0->NonTransparentContext, DC1->NonTransparentContext) &&
131+
!mayShadowImpl(ND0, ND1))
132+
return false;
133+
134+
return enclosesContext(DC0, DC1);
130135
}
131136

132137
const ConfusableIdentifierCheck::ContextInfo *
@@ -172,26 +177,41 @@ ConfusableIdentifierCheck::getContextInfo(const DeclContext *DC) {
172177

173178
void ConfusableIdentifierCheck::check(
174179
const ast_matchers::MatchFinder::MatchResult &Result) {
175-
if (const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("nameddecl")) {
176-
if (IdentifierInfo *NDII = ND->getIdentifier()) {
177-
const ContextInfo *Info = getContextInfo(ND->getDeclContext());
178-
StringRef NDName = NDII->getName();
179-
llvm::SmallVector<Entry> &Mapped = Mapper[skeleton(NDName)];
180-
for (const Entry &E : Mapped) {
181-
const IdentifierInfo *ONDII = E.Declaration->getIdentifier();
182-
if (mayShadow(ND, Info, E.Declaration, E.Info)) {
183-
StringRef ONDName = ONDII->getName();
184-
if (ONDName != NDName) {
185-
diag(ND->getLocation(), "%0 is confusable with %1")
186-
<< ND << E.Declaration;
187-
diag(E.Declaration->getLocation(), "other declaration found here",
188-
DiagnosticIDs::Note);
189-
}
190-
}
191-
}
192-
Mapped.push_back({ND, Info});
193-
}
180+
const auto *ND = Result.Nodes.getNodeAs<NamedDecl>("nameddecl");
181+
if (!ND)
182+
return;
183+
184+
IdentifierInfo *NDII = ND->getIdentifier();
185+
if (!NDII)
186+
return;
187+
188+
StringRef NDName = NDII->getName();
189+
if (NDName.empty())
190+
return;
191+
192+
const ContextInfo *Info = getContextInfo(ND->getDeclContext());
193+
194+
llvm::SmallVector<Entry> &Mapped = Mapper[skeleton(NDName)];
195+
for (const Entry &E : Mapped) {
196+
if (!mayShadow(ND, Info, E.Declaration, E.Info))
197+
continue;
198+
199+
const IdentifierInfo *ONDII = E.Declaration->getIdentifier();
200+
StringRef ONDName = ONDII->getName();
201+
if (ONDName == NDName)
202+
continue;
203+
204+
diag(ND->getLocation(), "%0 is confusable with %1") << ND << E.Declaration;
205+
diag(E.Declaration->getLocation(), "other declaration found here",
206+
DiagnosticIDs::Note);
194207
}
208+
209+
Mapped.push_back({ND, Info});
210+
}
211+
212+
void ConfusableIdentifierCheck::onEndOfTranslationUnit() {
213+
Mapper.clear();
214+
ContextInfos.clear();
195215
}
196216

197217
void ConfusableIdentifierCheck::registerMatchers(

clang-tools-extra/clang-tidy/misc/ConfusableIdentifierCheck.h

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class ConfusableIdentifierCheck : public ClangTidyCheck {
2626

2727
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
2828
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
29+
void onEndOfTranslationUnit() override;
30+
std::optional<TraversalKind> getCheckTraversalKind() const override {
31+
return TK_IgnoreUnlessSpelledInSource;
32+
}
2933

3034
struct ContextInfo {
3135
const DeclContext *PrimaryContext;

0 commit comments

Comments
 (0)