48static llvm::SmallString<64U>
skeleton(StringRef Name) {
50 SmallString<64U> Skeleton;
51 Skeleton.reserve(1U + Name.size());
53 const char *Curr = Name.data();
54 const char *End = Curr + Name.size();
56 const char *Prev = Curr;
58 const ConversionResult Result = convertUTF8Sequence(
59 reinterpret_cast<const UTF8 **
>(&Curr),
60 reinterpret_cast<const UTF8 *
>(End), &CodePoint, strictConversion);
61 if (Result != conversionOK) {
62 errs() <<
"Unicode conversion issue\n";
66 const StringRef Key(Prev, Curr - Prev);
67 auto *Where = llvm::lower_bound(ConfusableEntries, CodePoint,
68 [](
decltype(ConfusableEntries[0])
X,
69 UTF32 Y) {
return X.codepoint < Y; });
70 if (Where == std::end(ConfusableEntries) || CodePoint != Where->codepoint) {
71 Skeleton.append(Prev, Curr);
74 UTF8 *BufferStart = std::begin(Buffer);
75 UTF8 *IBuffer = BufferStart;
76 const UTF32 *ValuesStart = std::begin(Where->values);
77 const UTF32 *ValuesEnd = llvm::find(Where->values,
'\0');
78 if (ConvertUTF32toUTF8(&ValuesStart, ValuesEnd, &IBuffer,
80 strictConversion) != conversionOK) {
81 errs() <<
"Unicode conversion issue\n";
84 Skeleton.append(
reinterpret_cast<char *
>(BufferStart),
85 reinterpret_cast<char *
>(IBuffer));
129 const Decl *Parent,
const NamedDecl *ND) {
130 const Decl *Outer = Parent;
132 if (
const auto *NS = dyn_cast<NamespaceDecl>(Outer))
133 Outer = NS->getCanonicalDecl();
135 if (!
addToContext(DeclsWithinContext, Outer, {ND, Parent,
false}))
138 if (
const auto *RD = dyn_cast<CXXRecordDecl>(Outer)) {
139 RD = RD->getDefinition();
141 RD->forallBases([&](
const CXXRecordDecl *Base) {
142 addToContext(DeclsWithinContext, Base, {ND, Parent,
true});
148 auto *OuterDC = Outer->getDeclContext();
151 Outer = cast_or_null<Decl>(OuterDC->getNonTransparentContext());
156 const ast_matchers::MatchFinder::MatchResult &Result) {
157 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>(
"nameddecl");
162 cast<Decl>(ND->getDeclContext()->getNonTransparentContext()));
165 if (
const auto *TD = dyn_cast<TemplateDecl>(ND))
166 for (
const NamedDecl *Param : *TD->getTemplateParameters())
167 addDeclToCheck(Param, TD->getTemplatedDecl());
170 if (
const auto *FD = dyn_cast<FunctionDecl>(ND))
171 for (
const NamedDecl *Param : FD->parameters())
172 addDeclToCheck(Param, ND);
192 llvm::StringMap<llvm::SmallVector<const IdentifierInfo *, 1>> SkeletonToNames;
194 for (
auto &[Ident, Decls] : NameToDecls)
195 SkeletonToNames[
skeleton(Ident->getName())].push_back(Ident);
198 for (
auto &[Skel, Idents] : SkeletonToNames) {
199 if (Idents.size() < 2)
204 for (
const IdentifierInfo *II : Idents)
205 for (
auto [ND, Parent] : NameToDecls[II])
211 for (
const IdentifierInfo *II : Idents) {
212 for (
auto [OuterND, OuterParent] : NameToDecls[II]) {
213 for (
const Entry Inner : DeclsWithinContext[OuterParent]) {
215 if (OuterND->getIdentifier() == Inner.ND->getIdentifier())
220 if (OuterND->getAccess() == AS_private && Inner.FromDerivedClass)
225 if (OuterParent == Inner.Parent &&
226 Inner.ND->getASTContext()
228 .isBeforeInTranslationUnit(Inner.ND->getLocation(),
229 OuterND->getLocation()))
232 diag(Inner.ND->getLocation(),
"%0 is confusable with %1")
233 << Inner.ND << OuterND;
234 diag(OuterND->getLocation(),
"other declaration found here",
235 DiagnosticIDs::Note);
245 ast_matchers::MatchFinder *Finder) {
249 auto AnyParamDecl = ast_matchers::anyOf(
250 ast_matchers::parmVarDecl(), ast_matchers::templateTypeParmDecl(),
251 ast_matchers::nonTypeTemplateParmDecl(),
252 ast_matchers::templateTemplateParmDecl());
253 Finder->addMatcher(ast_matchers::namedDecl(ast_matchers::unless(AnyParamDecl))