11 #include "clang/AST/CXXInheritance.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 #include "clang/Lex/PPCallbacks.h"
15 #include "clang/Lex/Preprocessor.h"
16 #include "llvm/ADT/DenseMapInfo.h"
17 #include "llvm/ADT/PointerIntPair.h"
19 #define DEBUG_TYPE "clang-tidy"
32 clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-1)),
38 clang::SourceLocation::getFromRawEncoding(static_cast<unsigned>(-2)),
43 assert(Val != getEmptyKey() &&
"Cannot hash the empty key!");
44 assert(Val != getTombstoneKey() &&
"Cannot hash the tombstone key!");
46 std::hash<NamingCheckId::second_type> SecondHash;
47 return Val.first.getRawEncoding() + SecondHash(Val.second);
51 if (RHS == getEmptyKey())
52 return LHS == getEmptyKey();
53 if (RHS == getTombstoneKey())
54 return LHS == getTombstoneKey();
67 class RenamerClangTidyCheckPPCallbacks :
public PPCallbacks {
69 RenamerClangTidyCheckPPCallbacks(Preprocessor *PP,
70 RenamerClangTidyCheck *Check)
71 : PP(PP), Check(Check) {}
74 void MacroDefined(
const Token &MacroNameTok,
75 const MacroDirective *
MD)
override {
76 if (
MD->getMacroInfo()->isBuiltinMacro())
78 if (PP->getSourceManager().isWrittenInBuiltinFile(
79 MacroNameTok.getLocation()))
81 if (PP->getSourceManager().isWrittenInCommandLineFile(
82 MacroNameTok.getLocation()))
84 Check->checkMacro(PP->getSourceManager(), MacroNameTok,
MD->getMacroInfo());
88 void MacroExpands(
const Token &MacroNameTok,
const MacroDefinition &
MD,
90 const MacroArgs * )
override {
91 Check->expandMacro(MacroNameTok,
MD.getMacroInfo());
96 RenamerClangTidyCheck *Check;
101 RenamerClangTidyCheck::RenamerClangTidyCheck(StringRef CheckName,
104 AggressiveDependentMemberLookup(
105 Options.getLocalOrGlobal(
"AggressiveDependentMemberLookup", false)) {}
110 AggressiveDependentMemberLookup);
114 Finder->addMatcher(namedDecl().bind(
"decl"),
this);
115 Finder->addMatcher(usingDecl().bind(
"using"),
this);
116 Finder->addMatcher(declRefExpr().bind(
"declRef"),
this);
117 Finder->addMatcher(cxxConstructorDecl(unless(isImplicit())).bind(
"classRef"),
119 Finder->addMatcher(cxxDestructorDecl(unless(isImplicit())).bind(
"classRef"),
121 Finder->addMatcher(typeLoc().bind(
"typeLoc"),
this);
122 Finder->addMatcher(nestedNameSpecifierLoc().bind(
"nestedNameLoc"),
this);
123 auto MemberRestrictions =
124 unless(forFunction(anyOf(isDefaulted(), isImplicit())));
125 Finder->addMatcher(memberExpr(MemberRestrictions).bind(
"memberExpr"),
this);
127 cxxDependentScopeMemberExpr(MemberRestrictions).bind(
"depMemberExpr"),
132 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
133 ModuleExpanderPP->addPPCallbacks(
134 std::make_unique<RenamerClangTidyCheckPPCallbacks>(ModuleExpanderPP,
142 if (
Range.isInvalid())
149 SourceLocation FixLocation =
Range.getBegin();
151 FixLocation =
SourceMgr->getSpellingLoc(FixLocation);
152 if (FixLocation.isInvalid())
158 NamingCheckFailures[
Decl];
169 Failure.
RawUsageLocs.insert(FixLocation.getRawEncoding());
174 Decl = cast<NamedDecl>(
Decl->getCanonicalDecl());
176 Decl->getNameAsString()),
180 const NamedDecl *
findDecl(
const RecordDecl &RecDecl, StringRef DeclName) {
181 for (
const Decl *D : RecDecl.decls()) {
182 if (
const auto *ND = dyn_cast<NamedDecl>(D)) {
183 if (ND->getDeclName().isIdentifier() && ND->getName().equals(DeclName))
192 llvm::PointerIntPair<const NamedDecl *, 1, bool> Data;
195 explicit NameLookup(
const NamedDecl *ND) : Data(ND, false) {}
196 explicit NameLookup(llvm::NoneType) : Data(nullptr, true) {}
197 explicit NameLookup(std::nullptr_t) : Data(nullptr, false) {}
198 NameLookup() : NameLookup(nullptr) {}
200 bool hasMultipleResolutions()
const {
return Data.getInt(); }
201 const NamedDecl *getDecl()
const {
202 assert(!hasMultipleResolutions() &&
"Found multiple decls");
203 return Data.getPointer();
205 operator bool()
const {
return !hasMultipleResolutions(); }
206 const NamedDecl *operator*()
const {
return getDecl(); }
216 bool AggressiveTemplateLookup) {
217 if (!
Parent.hasDefinition())
218 return NameLookup(
nullptr);
220 return NameLookup(InClassRef);
221 const NamedDecl *Found =
nullptr;
223 for (CXXBaseSpecifier
Base :
Parent.bases()) {
224 const auto *
Record =
Base.getType()->getAsCXXRecordDecl();
225 if (!
Record && AggressiveTemplateLookup) {
226 if (
const auto *TST =
227 Base.getType()->getAs<TemplateSpecializationType>()) {
228 if (
const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>(
229 TST->getTemplateName().getAsTemplateDecl()))
230 Record = TD->getTemplatedDecl();
245 return NameLookup(llvm::None);
247 return NameLookup(Found);
251 if (
const auto *
Decl =
252 Result.Nodes.getNodeAs<CXXConstructorDecl>(
"classRef")) {
255 Result.SourceManager);
257 for (
const auto *Init :
Decl->inits()) {
258 if (!Init->isWritten() || Init->isInClassMemberInitializer())
260 if (
const FieldDecl *FD = Init->getAnyMember())
261 addUsage(FD, SourceRange(Init->getMemberLocation()),
262 Result.SourceManager);
269 if (
const auto *
Decl =
270 Result.Nodes.getNodeAs<CXXDestructorDecl>(
"classRef")) {
272 SourceRange
Range =
Decl->getNameInfo().getSourceRange();
273 if (
Range.getBegin().isInvalid())
277 Range.setBegin(CharSourceRange::getTokenRange(
Range).getEnd());
283 if (
const auto *
Loc = Result.Nodes.getNodeAs<TypeLoc>(
"typeLoc")) {
284 UnqualTypeLoc Unqual =
Loc->getUnqualifiedLoc();
285 NamedDecl *
Decl =
nullptr;
286 if (
const auto &Ref = Unqual.getAs<TagTypeLoc>())
287 Decl = Ref.getDecl();
288 else if (
const auto &Ref = Unqual.getAs<InjectedClassNameTypeLoc>())
289 Decl = Ref.getDecl();
290 else if (
const auto &Ref = Unqual.getAs<UnresolvedUsingTypeLoc>())
291 Decl = Ref.getDecl();
292 else if (
const auto &Ref = Unqual.getAs<TemplateTypeParmTypeLoc>())
293 Decl = Ref.getDecl();
301 if (
const auto &Ref =
Loc->getAs<TemplateSpecializationTypeLoc>()) {
302 const TemplateDecl *
Decl =
303 Ref.getTypePtr()->getTemplateName().getAsTemplateDecl();
305 SourceRange
Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc());
306 if (
const auto *ClassDecl = dyn_cast<TemplateDecl>(
Decl)) {
307 if (
const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
313 if (
const auto &Ref =
314 Loc->getAs<DependentTemplateSpecializationTypeLoc>()) {
315 if (
const TagDecl *
Decl = Ref.getTypePtr()->getAsTagDecl())
321 if (
const auto *
Loc =
322 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
"nestedNameLoc")) {
323 if (
const NestedNameSpecifier *Spec =
Loc->getNestedNameSpecifier()) {
324 if (
const NamespaceDecl *
Decl = Spec->getAsNamespace()) {
331 if (
const auto *
Decl = Result.Nodes.getNodeAs<UsingDecl>(
"using")) {
332 for (
const auto *Shadow :
Decl->shadows())
333 addUsage(Shadow->getTargetDecl(),
Decl->getNameInfo().getSourceRange(),
334 Result.SourceManager);
338 if (
const auto *
DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>(
"declRef")) {
339 SourceRange
Range =
DeclRef->getNameInfo().getSourceRange();
344 if (
const auto *MemberRef =
345 Result.Nodes.getNodeAs<MemberExpr>(
"memberExpr")) {
346 SourceRange
Range = MemberRef->getMemberNameInfo().getSourceRange();
347 addUsage(MemberRef->getMemberDecl(),
Range, Result.SourceManager);
351 if (
const auto *DepMemberRef =
352 Result.Nodes.getNodeAs<CXXDependentScopeMemberExpr>(
354 QualType BaseType = DepMemberRef->isArrow()
355 ? DepMemberRef->getBaseType()->getPointeeType()
356 : DepMemberRef->getBaseType();
357 if (BaseType.isNull())
359 const CXXRecordDecl *
Base = BaseType.getTypePtr()->getAsCXXRecordDecl();
362 DeclarationName DeclName = DepMemberRef->getMemberNameInfo().getName();
363 if (!DeclName.isIdentifier())
365 StringRef DependentName = DeclName.getAsIdentifierInfo()->getName();
368 *
Base, DependentName, AggressiveDependentMemberLookup)) {
370 addUsage(*Resolved, DepMemberRef->getMemberNameInfo().getSourceRange(),
371 Result.SourceManager);
376 if (
const auto *
Decl = Result.Nodes.getNodeAs<NamedDecl>(
"decl")) {
378 if (
const auto *UsingNS = dyn_cast<UsingDirectiveDecl>(
Decl))
379 addUsage(UsingNS->getNominatedNamespaceAsWritten(),
380 UsingNS->getIdentLocation(), Result.SourceManager);
382 if (!
Decl->getIdentifier() ||
Decl->getName().empty() ||
Decl->isImplicit())
385 const auto *Canonical = cast<NamedDecl>(
Decl->getCanonicalDecl());
386 if (Canonical !=
Decl) {
387 addUsage(Canonical,
Decl->getLocation(), Result.SourceManager);
392 if (
const auto *Value = Result.Nodes.getNodeAs<ValueDecl>(
"decl")) {
393 if (
const Type *TypePtr = Value->getType().getTypePtrOrNull()) {
394 if (
const auto *Typedef = TypePtr->getAs<TypedefType>())
395 addUsage(Typedef->getDecl(), Value->getSourceRange(),
396 Result.SourceManager);
401 if (
const auto *Value = Result.Nodes.getNodeAs<FunctionDecl>(
"decl")) {
402 if (
const auto *Typedef =
403 Value->getReturnType().getTypePtr()->getAs<TypedefType>())
404 addUsage(Typedef->getDecl(), Value->getSourceRange(),
405 Result.SourceManager);
406 for (
const ParmVarDecl *Param : Value->parameters()) {
407 if (
const TypedefType *Typedef =
408 Param->getType().getTypePtr()->getAs<TypedefType>())
409 addUsage(Typedef->getDecl(), Value->getSourceRange(),
410 Result.SourceManager);
416 if (isa<ClassTemplateSpecializationDecl>(
Decl))
419 Optional<FailureInfo> MaybeFailure =
425 Decl->getLocation(),
Decl->getNameAsString())];
427 DeclarationNameInfo(
Decl->getDeclName(),
Decl->getLocation())
430 const IdentifierTable &Idents =
Decl->getASTContext().Idents;
431 auto CheckNewIdentifier = Idents.find(
Info.Fixup);
432 if (CheckNewIdentifier != Idents.end()) {
433 const IdentifierInfo *Ident = CheckNewIdentifier->second;
436 else if (Ident->hasMacroDefinition())
446 const Token &MacroNameTok,
447 const MacroInfo *MI) {
448 Optional<FailureInfo> MaybeFailure =
453 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
456 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
458 Failure.Info = std::move(
Info);
463 const MacroInfo *MI) {
464 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
467 auto Failure = NamingCheckFailures.find(ID);
468 if (Failure == NamingCheckFailures.end())
471 SourceRange
Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
477 const std::string &Fixup) {
479 return "; cannot be fixed automatically";
486 return "; cannot be fixed because '" + Fixup +
487 "' would conflict with a keyword";
490 return "; cannot be fixed because '" + Fixup +
491 "' would conflict with a macro definition";
493 llvm_unreachable(
"invalid ShouldFixStatus");
497 for (
const auto &Pair : NamingCheckFailures) {
523 Diag << FixItHint::CreateReplacement(
524 SourceRange(SourceLocation::getFromRawEncoding(
Loc)),