57static SmallString<64U>
skeleton(StringRef Name) {
59 SmallString<64U> Skeleton;
60 Skeleton.reserve(1U + Name.size());
62 const char *Curr = Name.data();
63 const char *End = Curr + Name.size();
65 const char *Prev = Curr;
67 const ConversionResult Result = convertUTF8Sequence(
68 reinterpret_cast<const UTF8 **
>(&Curr),
69 reinterpret_cast<const UTF8 *
>(End), &CodePoint, strictConversion);
70 if (Result != conversionOK) {
71 errs() <<
"Unicode conversion issue\n";
75 auto *Where = llvm::lower_bound(
76 ConfusableEntries, CodePoint,
77 [](
const ConfusableEntry &
X, UTF32 Y) {
return X.CodePoint < Y; });
78 if (Where == std::end(ConfusableEntries) || CodePoint != Where->CodePoint) {
79 Skeleton.append(Prev, Curr);
82 StringRef(ConfusableReplacementData + Where->Offset, Where->Length));
126 const Decl *Parent,
const NamedDecl *ND) {
127 const Decl *Outer = Parent;
129 if (
const auto *NS = dyn_cast<NamespaceDecl>(Outer))
130 Outer = NS->getCanonicalDecl();
132 if (!
addToContext(DeclsWithinContext, Outer, {ND, Parent,
false}))
135 if (
const auto *RD = dyn_cast<CXXRecordDecl>(Outer)) {
136 RD = RD->getDefinition();
138 RD->forallBases([&](
const CXXRecordDecl *Base) {
139 addToContext(DeclsWithinContext, Base, {ND, Parent,
true});
145 auto *OuterDC = Outer->getDeclContext();
148 Outer = cast_or_null<Decl>(OuterDC->getNonTransparentContext());
153 const ast_matchers::MatchFinder::MatchResult &Result) {
154 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>(
"nameddecl");
159 cast<Decl>(ND->getDeclContext()->getNonTransparentContext()));
162 if (
const auto *TD = dyn_cast<TemplateDecl>(ND))
163 for (
const NamedDecl *Param : *TD->getTemplateParameters())
164 addDeclToCheck(Param, TD->getTemplatedDecl());
167 if (
const auto *FD = dyn_cast<FunctionDecl>(ND))
168 for (
const NamedDecl *Param : FD->parameters())
169 addDeclToCheck(Param, ND);
189 llvm::StringMap<SmallVector<const IdentifierInfo *, 1>> SkeletonToNames;
191 for (
auto &[Ident, Decls] : NameToDecls)
192 SkeletonToNames[
skeleton(Ident->getName())].push_back(Ident);
195 for (
auto &[Skel, Idents] : SkeletonToNames) {
196 if (Idents.size() < 2)
201 for (
const IdentifierInfo *II : Idents)
202 for (
auto [ND, Parent] : NameToDecls[II])
208 for (
const IdentifierInfo *II : Idents) {
209 for (
auto [OuterND, OuterParent] : NameToDecls[II]) {
210 for (
const Entry Inner : DeclsWithinContext[OuterParent]) {
212 if (OuterND->getIdentifier() == Inner.ND->getIdentifier())
217 if (OuterND->getAccess() == AS_private && Inner.FromDerivedClass)
222 if (OuterParent == Inner.Parent &&
223 Inner.ND->getASTContext()
225 .isBeforeInTranslationUnit(Inner.ND->getLocation(),
226 OuterND->getLocation()))
229 diag(Inner.ND->getLocation(),
"%0 is confusable with %1")
230 << Inner.ND << OuterND;
231 diag(OuterND->getLocation(),
"other declaration found here",
232 DiagnosticIDs::Note);
242 ast_matchers::MatchFinder *Finder) {
246 auto AnyParamDecl = ast_matchers::anyOf(
247 ast_matchers::parmVarDecl(), ast_matchers::templateTypeParmDecl(),
248 ast_matchers::nonTypeTemplateParmDecl(),
249 ast_matchers::templateTemplateParmDecl());
250 Finder->addMatcher(ast_matchers::namedDecl(ast_matchers::unless(AnyParamDecl))
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.