10#include "clang/AST/ASTContext.h"
11#include "clang/AST/DeclGroup.h"
12#include "clang/Lex/Lexer.h"
17AST_MATCHER(clang::LinkageSpecDecl, isExternCLinkage) {
18 return Node.getLanguage() == clang::LinkageSpecLanguageIDs::C;
32 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)),
33 IgnoreExternC(Options.get(
"IgnoreExternC", false)) {}
43 unless(isInstantiated()),
44 optionally(hasAncestor(
55 anyOf(allOf(unless(anyOf(isImplicit(),
56 classTemplateSpecializationDecl())),
61 classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
72 const auto *ParentDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
DeclStmtName);
74 if (ParentDeclStmt->isSingleDecl())
75 ParentDecl = ParentDeclStmt->getSingleDecl();
78 ParentDeclStmt->getDeclGroup().getDeclGroup()
79 [ParentDeclStmt->getDeclGroup().getDeclGroup().size() - 1];
88 const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(
TagDeclName);
95 if (MatchedTagDecl->isThisDeclarationADefinition())
96 LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
100 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>(
TypedefName);
101 if (MatchedDecl->getLocation().isInvalid())
104 const auto *ExternCDecl =
106 if (ExternCDecl && IgnoreExternC)
109 SourceLocation StartLoc = MatchedDecl->getBeginLoc();
111 if (StartLoc.isMacroID() && IgnoreMacros)
114 static const char *UseUsingWarning =
"use 'using' instead of 'typedef'";
117 if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID()) {
118 diag(StartLoc, UseUsingWarning);
123 PrintPolicy.SuppressScope =
true;
124 PrintPolicy.ConstantArraySizeAsWritten =
true;
125 PrintPolicy.UseVoidForZeroParams =
false;
126 PrintPolicy.PrintInjectedClassNameWithArguments =
false;
128 std::string
Type = MatchedDecl->getUnderlyingType().getAsString(PrintPolicy);
129 std::string
Name = MatchedDecl->getNameAsString();
130 SourceRange ReplaceRange = MatchedDecl->getSourceRange();
138 std::string Using =
"using ";
139 if (ReplaceRange.getBegin().isMacroID() ||
140 (Result.SourceManager->getFileID(ReplaceRange.getBegin()) !=
141 Result.SourceManager->getFileID(LastReplacementEnd)) ||
142 (ReplaceRange.getBegin() >= LastReplacementEnd)) {
145 FirstTypedefType =
Type;
146 FirstTypedefName =
Name;
150 ReplaceRange.setBegin(LastReplacementEnd);
156 if (
Type.size() > FirstTypedefType.size() &&
157 Type.substr(0, FirstTypedefType.size()) == FirstTypedefType)
158 Type = FirstTypedefName +
Type.substr(FirstTypedefType.size() + 1);
160 if (!ReplaceRange.getEnd().isMacroID()) {
161 const SourceLocation::IntTy
Offset =
162 MatchedDecl->getFunctionType() ? 0 :
Name.size();
163 LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(
Offset);
166 auto Diag =
diag(ReplaceRange.getBegin(), UseUsingWarning);
169 auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
170 if (LastTagDeclRange != LastTagDeclRanges.end() &&
171 LastTagDeclRange->second.isValid() &&
172 ReplaceRange.fullyContains(LastTagDeclRange->second)) {
173 Type = std::string(Lexer::getSourceText(
174 CharSourceRange::getTokenRange(LastTagDeclRange->second),
180 std::string Replacement = Using +
Name +
" = " +
Type;
181 Diag << FixItHint::CreateReplacement(ReplaceRange, Replacement);
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
::clang::DynTypedNode Node
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.
AST_MATCHER(Expr, isMacroID)
static constexpr llvm::StringLiteral DeclStmtName
static constexpr llvm::StringLiteral ParentDeclName
static constexpr llvm::StringLiteral ExternCDeclName
static constexpr llvm::StringLiteral TagDeclName
static constexpr llvm::StringLiteral TypedefName
llvm::StringMap< ClangTidyValue > OptionMap