12#include "clang/Frontend/CompilerInstance.h"
13#include "clang/Lex/Preprocessor.h"
14#include "llvm/ADT/SmallString.h"
15#include "llvm/Support/ConvertUTF.h"
22#include "Confusables.inc"
51 SmallString<64U> Skeleton;
52 Skeleton.reserve(1U +
Name.size());
54 const char *Curr =
Name.data();
55 const char *End = Curr +
Name.size();
58 const char *Prev = Curr;
60 ConversionResult Result = convertUTF8Sequence(
61 reinterpret_cast<const UTF8 **
>(&Curr),
62 reinterpret_cast<const UTF8 *
>(End), &CodePoint, strictConversion);
63 if (Result != conversionOK) {
64 errs() <<
"Unicode conversion issue\n";
68 StringRef Key(Prev, Curr - Prev);
69 auto Where = llvm::lower_bound(ConfusableEntries, CodePoint,
70 [](
decltype(ConfusableEntries[0]) x,
71 UTF32 y) {
return x.codepoint < y; });
72 if (
Where == std::end(ConfusableEntries) || CodePoint !=
Where->codepoint) {
73 Skeleton.append(Prev, Curr);
76 UTF8 *BufferStart = std::begin(Buffer);
77 UTF8 *IBuffer = BufferStart;
78 const UTF32 *ValuesStart = std::begin(
Where->values);
79 const UTF32 *ValuesEnd = llvm::find(
Where->values,
'\0');
80 if (ConvertUTF32toUTF8(&ValuesStart, ValuesEnd, &IBuffer,
82 strictConversion) != conversionOK) {
83 errs() <<
"Unicode conversion issue\n";
86 Skeleton.append((
char *)BufferStart, (
char *)IBuffer);
92static bool mayShadowImpl(
const DeclContext *DC0,
const DeclContext *DC1) {
93 return DC0 && DC0 == DC1;
97 return isa<TemplateTypeParmDecl>(ND0) || isa<TemplateTypeParmDecl>(ND1);
116 const NamedDecl *ND1,
119 if (!DC0->
Bases.empty() && !DC1->
Bases.empty()) {
123 if (ND1->getAccess() != AS_private &&
isMemberOf(DC1, DC0))
126 if (ND0->getAccess() != AS_private &&
isMemberOf(DC0, DC1))
137const ConfusableIdentifierCheck::ContextInfo *
138ConfusableIdentifierCheck::getContextInfo(
const DeclContext *DC) {
139 const DeclContext *PrimaryContext = DC->getPrimaryContext();
140 auto It = ContextInfos.find(PrimaryContext);
141 if (It != ContextInfos.end())
144 ContextInfo &
Info = ContextInfos[PrimaryContext];
145 Info.PrimaryContext = PrimaryContext;
146 Info.NonTransparentContext = PrimaryContext;
148 while (
Info.NonTransparentContext->isTransparentContext()) {
149 Info.NonTransparentContext =
Info.NonTransparentContext->getParent();
150 if (!
Info.NonTransparentContext)
154 if (
Info.NonTransparentContext)
155 Info.NonTransparentContext =
156 Info.NonTransparentContext->getPrimaryContext();
159 if (!isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC))
160 Info.PrimaryContexts.push_back(DC->getPrimaryContext());
161 DC = DC->getParent();
164 if (
const auto *RD = dyn_cast<CXXRecordDecl>(PrimaryContext)) {
165 RD = RD->getDefinition();
167 Info.Bases.push_back(RD);
168 RD->forallBases([&](
const CXXRecordDecl *Base) {
169 Info.Bases.push_back(Base);
179 const ast_matchers::MatchFinder::MatchResult &Result) {
180 const auto *ND = Result.Nodes.getNodeAs<NamedDecl>(
"nameddecl");
184 IdentifierInfo *NDII = ND->getIdentifier();
188 StringRef NDName = NDII->getName();
194 llvm::SmallVector<Entry> &Mapped = Mapper[
skeleton(NDName)];
195 for (
const Entry &
E : Mapped) {
199 const IdentifierInfo *ONDII =
E.Declaration->getIdentifier();
200 StringRef ONDName = ONDII->getName();
201 if (ONDName == NDName)
204 diag(ND->getLocation(),
"%0 is confusable with %1") << ND <<
E.Declaration;
205 diag(
E.Declaration->getLocation(),
"other declaration found here",
206 DiagnosticIDs::Note);
209 Mapped.push_back({ND,
Info});
214 ContextInfos.clear();
218 ast_matchers::MatchFinder *Finder) {
219 Finder->addMatcher(ast_matchers::namedDecl().bind(
"nameddecl"),
this);
llvm::SmallString< 256U > Name
const CXXCtorInitializer * Where
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
~ConfusableIdentifierCheck()
void onEndOfTranslationUnit() override
ConfusableIdentifierCheck(StringRef Name, ClangTidyContext *Context)
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
static bool isMemberOf(const ConfusableIdentifierCheck::ContextInfo *DC0, const ConfusableIdentifierCheck::ContextInfo *DC1)
static bool mayShadow(const NamedDecl *ND0, const ConfusableIdentifierCheck::ContextInfo *DC0, const NamedDecl *ND1, const ConfusableIdentifierCheck::ContextInfo *DC1)
static bool enclosesContext(const ConfusableIdentifierCheck::ContextInfo *DC0, const ConfusableIdentifierCheck::ContextInfo *DC1)
static bool mayShadowImpl(const DeclContext *DC0, const DeclContext *DC1)
static llvm::SmallString< 64U > skeleton(StringRef Name)
Some operations such as code completion produce a set of candidates.
llvm::SmallVector< const DeclContext * > PrimaryContexts
const DeclContext * NonTransparentContext
const DeclContext * PrimaryContext
llvm::SmallVector< const CXXRecordDecl * > Bases