88
99#include " ConfusableIdentifierCheck.h"
1010
11+ #include " clang/ASTMatchers/ASTMatchers.h"
1112#include " clang/Frontend/CompilerInstance.h"
1213#include " clang/Lex/Preprocessor.h"
1314#include " llvm/ADT/SmallString.h"
@@ -91,16 +92,22 @@ static llvm::SmallString<64U> skeleton(StringRef Name) {
9192namespace {
9293struct Entry {
9394 const NamedDecl *ND;
95+ const Decl *Parent;
9496 bool FromDerivedClass;
9597};
9698} // namespace
9799
100+ // Map from a context to the declarations in that context with the current
101+ // skeleton. At most one entry per distinct identifier is tracked. The
102+ // context is usually a `DeclContext`, but can also be a template declaration
103+ // that has no corresponding context, such as an alias template or variable
104+ // template.
98105using DeclsWithinContextMap =
99- llvm::DenseMap<const DeclContext *, llvm::SmallVector<Entry, 1 >>;
106+ llvm::DenseMap<const Decl *, llvm::SmallVector<Entry, 1 >>;
100107
101108static bool addToContext (DeclsWithinContextMap &DeclsWithinContext,
102- const DeclContext *DC , Entry E) {
103- auto &Decls = DeclsWithinContext[DC ];
109+ const Decl *Context , Entry E) {
110+ auto &Decls = DeclsWithinContext[Context ];
104111 if (!Decls.empty () &&
105112 Decls.back ().ND ->getIdentifier () == E.ND ->getIdentifier ()) {
106113 // Already have a declaration with this identifier in this context. Don't
@@ -120,23 +127,30 @@ static bool addToContext(DeclsWithinContextMap &DeclsWithinContext,
120127}
121128
122129static void addToEnclosingContexts (DeclsWithinContextMap &DeclsWithinContext,
123- const DeclContext *DC, const NamedDecl *ND) {
124- while (DC) {
125- DC = DC->getNonTransparentContext ()->getPrimaryContext ();
126- if (!addToContext (DeclsWithinContext, DC, {ND, false }))
130+ const Decl *Parent,
131+ const NamedDecl *ND) {
132+ const Decl *Outer = Parent;
133+ while (Outer) {
134+ if (const auto *NS = dyn_cast<NamespaceDecl>(Outer))
135+ Outer = NS->getCanonicalDecl ();
136+
137+ if (!addToContext (DeclsWithinContext, Outer, {ND, Parent, false }))
127138 return ;
128139
129- if (const auto *RD = dyn_cast<CXXRecordDecl>(DC )) {
140+ if (const auto *RD = dyn_cast<CXXRecordDecl>(Outer )) {
130141 RD = RD->getDefinition ();
131142 if (RD) {
132143 RD->forallBases ([&](const CXXRecordDecl *Base) {
133- addToContext (DeclsWithinContext, Base, {ND, true });
144+ addToContext (DeclsWithinContext, Base, {ND, Parent, true });
134145 return true ;
135146 });
136147 }
137148 }
138149
139- DC = DC->getParent ();
150+ auto *OuterDC = Outer->getDeclContext ();
151+ if (!OuterDC)
152+ break ;
153+ Outer = cast_or_null<Decl>(OuterDC->getNonTransparentContext ());
140154 }
141155}
142156
@@ -146,6 +160,24 @@ void ConfusableIdentifierCheck::check(
146160 if (!ND)
147161 return ;
148162
163+ addDeclToCheck (ND, cast<Decl>(ND->getDeclContext ()
164+ ->getNonTransparentContext ()));
165+
166+ // Associate template parameters with this declaration of this template.
167+ if (const auto *TD = dyn_cast<TemplateDecl>(ND)) {
168+ for (const NamedDecl *Param : *TD->getTemplateParameters ())
169+ addDeclToCheck (Param, TD->getTemplatedDecl ());
170+ }
171+
172+ // Associate function parameters with this declaration of this function.
173+ if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
174+ for (const NamedDecl *Param : FD->parameters ())
175+ addDeclToCheck (Param, ND);
176+ }
177+ }
178+
179+ void ConfusableIdentifierCheck::addDeclToCheck (const NamedDecl *ND,
180+ const Decl *Parent) {
149181 const IdentifierInfo *NDII = ND->getIdentifier ();
150182 if (!NDII)
151183 return ;
@@ -154,7 +186,7 @@ void ConfusableIdentifierCheck::check(
154186 if (NDName.empty ())
155187 return ;
156188
157- NameToDecls[NDII].push_back (ND );
189+ NameToDecls[NDII].push_back ({ND, Parent} );
158190}
159191
160192void ConfusableIdentifierCheck::onEndOfTranslationUnit () {
@@ -173,20 +205,17 @@ void ConfusableIdentifierCheck::onEndOfTranslationUnit() {
173205 // Find the declaration contexts that transitively contain each identifier.
174206 DeclsWithinContextMap DeclsWithinContext;
175207 for (const IdentifierInfo *II : Idents) {
176- for (const NamedDecl *ND : NameToDecls[II]) {
177- addToEnclosingContexts (DeclsWithinContext, ND-> getDeclContext () , ND);
208+ for (auto [ND, Parent] : NameToDecls[II]) {
209+ addToEnclosingContexts (DeclsWithinContext, Parent , ND);
178210 }
179211 }
180212
181213 // Check to see if any declaration is declared in a context that
182214 // transitively contains another declaration with a different identifier but
183215 // the same skeleton.
184216 for (const IdentifierInfo *II : Idents) {
185- for (const NamedDecl *OuterND : NameToDecls[II]) {
186- const DeclContext *OuterDC = OuterND->getDeclContext ()
187- ->getNonTransparentContext ()
188- ->getPrimaryContext ();
189- for (Entry Inner : DeclsWithinContext[OuterDC]) {
217+ for (auto [OuterND, OuterParent] : NameToDecls[II]) {
218+ for (Entry Inner : DeclsWithinContext[OuterParent]) {
190219 // Don't complain if the identifiers are the same.
191220 if (OuterND->getIdentifier () == Inner.ND ->getIdentifier ())
192221 continue ;
@@ -198,8 +227,7 @@ void ConfusableIdentifierCheck::onEndOfTranslationUnit() {
198227
199228 // If the declarations are in the same context, only diagnose the
200229 // later one.
201- if (OuterDC->Equals (
202- Inner.ND ->getDeclContext ()->getNonTransparentContext ()) &&
230+ if (OuterParent == Inner.Parent &&
203231 Inner.ND ->getASTContext ()
204232 .getSourceManager ()
205233 .isBeforeInTranslationUnit (Inner.ND ->getLocation (),
@@ -220,7 +248,17 @@ void ConfusableIdentifierCheck::onEndOfTranslationUnit() {
220248
221249void ConfusableIdentifierCheck::registerMatchers (
222250 ast_matchers::MatchFinder *Finder) {
223- Finder->addMatcher (ast_matchers::namedDecl ().bind (" nameddecl" ), this );
251+ // Parameter declarations sometimes use the translation unit or some outer
252+ // enclosing context as their `DeclContext`, instead of their parent, so
253+ // we handle them specially in `check`.
254+ auto AnyParamDecl = ast_matchers::anyOf (
255+ ast_matchers::parmVarDecl (), ast_matchers::templateTypeParmDecl (),
256+ ast_matchers::nonTypeTemplateParmDecl (),
257+ ast_matchers::templateTemplateParmDecl ());
258+ Finder->addMatcher (
259+ ast_matchers::namedDecl (ast_matchers::unless (AnyParamDecl))
260+ .bind (" nameddecl" ),
261+ this );
224262}
225263
226264} // namespace clang::tidy::misc
0 commit comments