@@ -89,90 +89,56 @@ static llvm::SmallString<64U> skeleton(StringRef Name) {
8989 return Skeleton;
9090}
9191
92- static bool mayShadowImpl (const DeclContext *DC0, const DeclContext *DC1) {
93- return DC0 && DC0 == DC1;
94- }
95-
96- static bool mayShadowImpl (const NamedDecl *ND0, const NamedDecl *ND1) {
97- return isa<TemplateTypeParmDecl>(ND0) || isa<TemplateTypeParmDecl>(ND1);
98- }
99-
100- static bool isMemberOf (const ConfusableIdentifierCheck::ContextInfo *DC0,
101- const ConfusableIdentifierCheck::ContextInfo *DC1) {
102- return llvm::is_contained (DC1->Bases , DC0->PrimaryContext );
103- }
104-
105- static bool enclosesContext (const ConfusableIdentifierCheck::ContextInfo *DC0,
106- const ConfusableIdentifierCheck::ContextInfo *DC1) {
107- if (DC0->PrimaryContext == DC1->PrimaryContext )
108- return true ;
109-
110- return llvm::is_contained (DC0->PrimaryContexts , DC1->PrimaryContext ) ||
111- llvm::is_contained (DC1->PrimaryContexts , DC0->PrimaryContext );
92+ namespace {
93+ struct Entry {
94+ const NamedDecl *ND;
95+ bool FromDerivedClass;
96+ };
11297}
11398
114- static bool mayShadow (const NamedDecl *ND0,
115- const ConfusableIdentifierCheck::ContextInfo *DC0,
116- const NamedDecl *ND1,
117- const ConfusableIdentifierCheck::ContextInfo *DC1) {
118-
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))
99+ using DeclsWithinContextMap =
100+ llvm::DenseMap<const DeclContext *, llvm::SmallVector<Entry, 1 >>;
101+
102+ static bool addToContext (DeclsWithinContextMap &DeclsWithinContext,
103+ const DeclContext *DC, Entry E) {
104+ auto &Decls = DeclsWithinContext[DC];
105+ if (!Decls.empty () &&
106+ Decls.back ().ND ->getIdentifier () == E.ND ->getIdentifier ()) {
107+ // Already have a declaration with this identifier in this context. Don't
108+ // track another one. This means that if an outer name is confusable with an
109+ // inner name, we'll only diagnose the outer name once, pointing at the
110+ // first inner declaration with that name.
111+ if (Decls.back ().FromDerivedClass && !E.FromDerivedClass ) {
112+ // Prefer the declaration that's not from the derived class, because that
113+ // conflicts with more declarations.
114+ Decls.back () = E;
127115 return true ;
128- }
129-
130- if (!mayShadowImpl (DC0->NonTransparentContext , DC1->NonTransparentContext ) &&
131- !mayShadowImpl (ND0, ND1))
116+ }
132117 return false ;
133-
134- return enclosesContext (DC0, DC1);
135- }
136-
137- const ConfusableIdentifierCheck::ContextInfo *
138- ConfusableIdentifierCheck::getContextInfo (const DeclContext *DC) {
139- const DeclContext *PrimaryContext = DC->getPrimaryContext ();
140- auto [It, Inserted] = ContextInfos.try_emplace (PrimaryContext);
141- if (!Inserted)
142- return &It->second ;
143-
144- ContextInfo &Info = It->second ;
145- Info.PrimaryContext = PrimaryContext;
146- Info.NonTransparentContext = PrimaryContext;
147-
148- while (Info.NonTransparentContext ->isTransparentContext ()) {
149- Info.NonTransparentContext = Info.NonTransparentContext ->getParent ();
150- if (!Info.NonTransparentContext )
151- break ;
152118 }
119+ Decls.push_back (E);
120+ return true ;
121+ }
153122
154- if (Info.NonTransparentContext )
155- Info.NonTransparentContext =
156- Info.NonTransparentContext ->getPrimaryContext ();
157-
123+ static void addToEnclosingContexts (DeclsWithinContextMap &DeclsWithinContext,
124+ const DeclContext *DC, const NamedDecl *ND) {
158125 while (DC) {
159- if (!isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC))
160- Info.PrimaryContexts .push_back (DC->getPrimaryContext ());
161- DC = DC->getParent ();
162- }
163-
164- if (const auto *RD = dyn_cast<CXXRecordDecl>(PrimaryContext)) {
165- RD = RD->getDefinition ();
166- if (RD) {
167- Info.Bases .push_back (RD);
168- RD->forallBases ([&](const CXXRecordDecl *Base) {
169- Info.Bases .push_back (Base);
170- return false ;
171- });
126+ DC = DC->getNonTransparentContext ()->getPrimaryContext ();
127+ if (!addToContext (DeclsWithinContext, DC, {ND, false }))
128+ return ;
129+
130+ if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) {
131+ RD = RD->getDefinition ();
132+ if (RD) {
133+ RD->forallBases ([&](const CXXRecordDecl *Base) {
134+ addToContext (DeclsWithinContext, Base, {ND, true });
135+ return true ;
136+ });
137+ }
172138 }
173- }
174139
175- return &Info;
140+ DC = DC->getParent ();
141+ }
176142}
177143
178144void ConfusableIdentifierCheck::check (
@@ -181,37 +147,76 @@ void ConfusableIdentifierCheck::check(
181147 if (!ND)
182148 return ;
183149
184- IdentifierInfo *NDII = ND->getIdentifier ();
150+ const IdentifierInfo *NDII = ND->getIdentifier ();
185151 if (!NDII)
186152 return ;
187153
188154 StringRef NDName = NDII->getName ();
189155 if (NDName.empty ())
190156 return ;
191157
192- const ContextInfo *Info = getContextInfo (ND->getDeclContext ());
158+ NameToDecls[NDII].push_back (ND);
159+ }
193160
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 ;
161+ void ConfusableIdentifierCheck::onEndOfTranslationUnit () {
162+ llvm::StringMap<llvm::SmallVector<const IdentifierInfo*, 1 >> SkeletonToNames;
163+ // Compute the skeleton for each identifier.
164+ for (auto &[Ident, Decls] : NameToDecls) {
165+ SkeletonToNames[skeleton (Ident->getName ())].push_back (Ident);
166+ }
198167
199- const IdentifierInfo *ONDII = E. Declaration -> getIdentifier ();
200- StringRef ONDName = ONDII-> getName ();
201- if (ONDName == NDName)
168+ // Visit each skeleton with more than one identifier.
169+ for ( auto &[Skel, Idents] : SkeletonToNames) {
170+ if (Idents. size () < 2 ) {
202171 continue ;
172+ }
203173
204- diag (ND->getLocation (), " %0 is confusable with %1" ) << ND << E.Declaration ;
205- diag (E.Declaration ->getLocation (), " other declaration found here" ,
206- DiagnosticIDs::Note);
207- }
174+ // Find the declaration contexts that transitively contain each identifier.
175+ DeclsWithinContextMap DeclsWithinContext;
176+ for (const IdentifierInfo *II : Idents) {
177+ for (const NamedDecl *ND : NameToDecls[II]) {
178+ addToEnclosingContexts (DeclsWithinContext, ND->getDeclContext (), ND);
179+ }
180+ }
208181
209- Mapped.push_back ({ND, Info});
210- }
182+ // Check to see if any declaration is declared in a context that
183+ // transitively contains another declaration with a different identifier but
184+ // the same skeleton.
185+ for (const IdentifierInfo *II : Idents) {
186+ for (const NamedDecl *OuterND : NameToDecls[II]) {
187+ const DeclContext *OuterDC = OuterND->getDeclContext ()
188+ ->getNonTransparentContext ()
189+ ->getPrimaryContext ();
190+ for (Entry Inner : DeclsWithinContext[OuterDC]) {
191+ // Don't complain if the identifiers are the same.
192+ if (OuterND->getIdentifier () == Inner.ND ->getIdentifier ())
193+ continue ;
194+
195+ // Don't complain about a derived-class name shadowing a base class
196+ // private member.
197+ if (OuterND->getAccess () == AS_private && Inner.FromDerivedClass )
198+ continue ;
199+
200+ // If the declarations are in the same context, only diagnose the
201+ // later one.
202+ if (OuterDC->Equals (
203+ Inner.ND ->getDeclContext ()->getNonTransparentContext ()) &&
204+ Inner.ND ->getASTContext ()
205+ .getSourceManager ()
206+ .isBeforeInTranslationUnit (Inner.ND ->getLocation (),
207+ OuterND->getLocation ()))
208+ continue ;
209+
210+ diag (Inner.ND ->getLocation (), " %0 is confusable with %1" )
211+ << Inner.ND << OuterND;
212+ diag (OuterND->getLocation (), " other declaration found here" ,
213+ DiagnosticIDs::Note);
214+ }
215+ }
216+ }
217+ }
211218
212- void ConfusableIdentifierCheck::onEndOfTranslationUnit () {
213- Mapper.clear ();
214- ContextInfos.clear ();
219+ NameToDecls.clear ();
215220}
216221
217222void ConfusableIdentifierCheck::registerMatchers (
0 commit comments