10#include "clang/AST/ASTContext.h"
11#include "clang/Lex/Lexer.h"
23 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)) {}
30 Finder->addMatcher(typedefDecl(unless(isInstantiated()),
39 anyOf(allOf(unless(anyOf(isImplicit(),
40 classTemplateSpecializationDecl())),
44 classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
57 const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(
TagDeclName);
64 LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
68 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>(
TypedefName);
69 if (MatchedDecl->getLocation().isInvalid())
72 SourceLocation StartLoc = MatchedDecl->getBeginLoc();
74 if (StartLoc.isMacroID() && IgnoreMacros)
77 static const char *UseUsingWarning =
"use 'using' instead of 'typedef'";
80 if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID()) {
81 diag(StartLoc, UseUsingWarning);
86 PrintPolicy.SuppressScope =
true;
87 PrintPolicy.ConstantArraySizeAsWritten =
true;
88 PrintPolicy.UseVoidForZeroParams =
false;
89 PrintPolicy.PrintInjectedClassNameWithArguments =
false;
91 std::string
Type = MatchedDecl->getUnderlyingType().getAsString(PrintPolicy);
92 std::string
Name = MatchedDecl->getNameAsString();
93 SourceRange ReplaceRange = MatchedDecl->getSourceRange();
101 std::string Using =
"using ";
102 if (ReplaceRange.getBegin().isMacroID() ||
103 (Result.SourceManager->getFileID(ReplaceRange.getBegin()) !=
104 Result.SourceManager->getFileID(LastReplacementEnd)) ||
105 (ReplaceRange.getBegin() >= LastReplacementEnd)) {
108 FirstTypedefType =
Type;
109 FirstTypedefName =
Name;
113 ReplaceRange.setBegin(LastReplacementEnd);
119 if (
Type.size() > FirstTypedefType.size() &&
120 Type.substr(0, FirstTypedefType.size()) == FirstTypedefType)
121 Type = FirstTypedefName +
Type.substr(FirstTypedefType.size() + 1);
123 if (!ReplaceRange.getEnd().isMacroID()) {
124 const SourceLocation::IntTy
Offset = MatchedDecl->getFunctionType() ? 0 :
Name.size();
125 LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(
Offset);
128 auto Diag =
diag(ReplaceRange.getBegin(), UseUsingWarning);
131 auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
132 if (LastTagDeclRange != LastTagDeclRanges.end() &&
133 LastTagDeclRange->second.isValid() &&
134 ReplaceRange.fullyContains(LastTagDeclRange->second)) {
135 Type = std::string(Lexer::getSourceText(
136 CharSourceRange::getTokenRange(LastTagDeclRange->second),
142 std::string Replacement = Using +
Name +
" = " +
Type;
143 Diag << FixItHint::CreateReplacement(ReplaceRange, Replacement);
const FunctionDecl * Decl
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
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.
const LangOptions & getLangOpts() const
Returns the language options from the context.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
UseUsingCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static constexpr llvm::StringLiteral ParentDeclName
static constexpr llvm::StringLiteral TagDeclName
static constexpr llvm::StringLiteral TypedefName
llvm::StringMap< ClangTidyValue > OptionMap