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((
char *)BufferStart, (
char *)IBuffer);
128 const Decl *Parent,
const NamedDecl *ND) {
129 const Decl *Outer = Parent;
131 if (
const auto *NS = dyn_cast<NamespaceDecl>(Outer))
132 Outer = NS->getCanonicalDecl();
134 if (!
addToContext(DeclsWithinContext, Outer, {ND, Parent,
false}))
137 if (
const auto *RD = dyn_cast<CXXRecordDecl>(Outer)) {
138 RD = RD->getDefinition();
140 RD->forallBases([&](
const CXXRecordDecl *Base) {
141 addToContext(DeclsWithinContext, Base, {ND, Parent,
true});
147 auto *OuterDC = Outer->getDeclContext();
150 Outer = cast_or_null<Decl>(OuterDC->getNonTransparentContext());
155 const ast_matchers::MatchFinder::MatchResult &Result) {
156 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>(
"nameddecl");
161 cast<Decl>(ND->getDeclContext()->getNonTransparentContext()));
164 if (
const auto *TD = dyn_cast<TemplateDecl>(ND)) {
165 for (
const NamedDecl *Param : *TD->getTemplateParameters())
166 addDeclToCheck(Param, TD->getTemplatedDecl());
170 if (
const auto *FD = dyn_cast<FunctionDecl>(ND)) {
171 for (
const NamedDecl *Param : FD->parameters())
172 addDeclToCheck(Param, ND);
193 llvm::StringMap<llvm::SmallVector<const IdentifierInfo *, 1>> SkeletonToNames;
195 for (
auto &[Ident, Decls] : NameToDecls) {
196 SkeletonToNames[
skeleton(Ident->getName())].push_back(Ident);
200 for (
auto &[Skel, Idents] : SkeletonToNames) {
201 if (Idents.size() < 2) {
207 for (
const IdentifierInfo *II : Idents) {
208 for (
auto [ND, Parent] : NameToDecls[II]) {
216 for (
const IdentifierInfo *II : Idents) {
217 for (
auto [OuterND, OuterParent] : NameToDecls[II]) {
218 for (
const Entry Inner : DeclsWithinContext[OuterParent]) {
220 if (OuterND->getIdentifier() == Inner.ND->getIdentifier())
225 if (OuterND->getAccess() == AS_private && Inner.FromDerivedClass)
230 if (OuterParent == Inner.Parent &&
231 Inner.ND->getASTContext()
233 .isBeforeInTranslationUnit(Inner.ND->getLocation(),
234 OuterND->getLocation()))
237 diag(Inner.ND->getLocation(),
"%0 is confusable with %1")
238 << Inner.ND << OuterND;
239 diag(OuterND->getLocation(),
"other declaration found here",
240 DiagnosticIDs::Note);
250 ast_matchers::MatchFinder *Finder) {
254 auto AnyParamDecl = ast_matchers::anyOf(
255 ast_matchers::parmVarDecl(), ast_matchers::templateTypeParmDecl(),
256 ast_matchers::nonTypeTemplateParmDecl(),
257 ast_matchers::templateTemplateParmDecl());
258 Finder->addMatcher(ast_matchers::namedDecl(ast_matchers::unless(AnyParamDecl))