10#include "../utils/LexerUtils.h"
11#include "clang/AST/DeclGroup.h"
12#include "clang/Basic/LangOptions.h"
13#include "clang/Basic/SourceLocation.h"
14#include "clang/Basic/SourceManager.h"
15#include "clang/Basic/TokenKinds.h"
16#include "clang/Lex/Lexer.h"
22AST_MATCHER(clang::LinkageSpecDecl, isExternCLinkage) {
23 return Node.getLanguage() == clang::LinkageSpecLanguageIDs::C;
37 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)),
38 IgnoreExternC(Options.get(
"IgnoreExternC", false)) {}
48 unless(isInstantiated()),
49 optionally(hasAncestor(
60 anyOf(allOf(unless(anyOf(isImplicit(),
61 classTemplateSpecializationDecl())),
66 classTemplateSpecializationDecl(hasAncestor(classTemplateDecl(
77 const auto *ParentDeclStmt = Result.Nodes.getNodeAs<DeclStmt>(
DeclStmtName);
79 if (ParentDeclStmt->isSingleDecl())
80 ParentDecl = ParentDeclStmt->getSingleDecl();
83 ParentDeclStmt->getDeclGroup().getDeclGroup()
84 [ParentDeclStmt->getDeclGroup().getDeclGroup().size() - 1];
91 const SourceManager &SM = *Result.SourceManager;
96 const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(
TagDeclName);
103 if (MatchedTagDecl->isThisDeclarationADefinition())
104 LastTagDeclRanges[ParentDecl] = MatchedTagDecl->getSourceRange();
108 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>(
TypedefName);
109 if (MatchedDecl->getLocation().isInvalid())
112 const auto *ExternCDecl =
114 if (ExternCDecl && IgnoreExternC)
117 SourceLocation StartLoc = MatchedDecl->getBeginLoc();
119 if (StartLoc.isMacroID() && IgnoreMacros)
122 static const char *UseUsingWarning =
"use 'using' instead of 'typedef'";
125 if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID()) {
126 diag(StartLoc, UseUsingWarning);
130 const TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc();
132 auto [
Type, QualifierStr] = [MatchedDecl,
this, &TL, &SM,
133 &LO]() -> std::pair<std::string, std::string> {
134 SourceRange TypeRange = TL.getSourceRange();
138 if (TypeRange.fullyContains(MatchedDecl->getLocation())) {
139 const auto RangeLeftOfIdentifier = CharSourceRange::getCharRange(
140 TypeRange.getBegin(), MatchedDecl->getLocation());
141 const auto RangeRightOfIdentifier = CharSourceRange::getCharRange(
142 Lexer::getLocForEndOfToken(MatchedDecl->getLocation(), 0, SM, LO),
143 Lexer::getLocForEndOfToken(TypeRange.getEnd(), 0, SM, LO));
144 const std::string VerbatimType =
145 (Lexer::getSourceText(RangeLeftOfIdentifier, SM, LO) +
146 Lexer::getSourceText(RangeRightOfIdentifier, SM, LO))
148 return {VerbatimType,
""};
151 StringRef ExtraReference =
"";
152 if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) {
157 MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star,
158 tok::TokenKind::amp, tok::TokenKind::comma,
159 tok::TokenKind::kw_typedef);
161 ExtraReference = Lexer::getSourceText(
162 CharSourceRange::getCharRange(Tok, Tok.getLocWithOffset(1)), SM, LO);
164 if (ExtraReference !=
"*" && ExtraReference !=
"&")
167 TypeRange.setEnd(MainTypeEndLoc);
170 Lexer::getSourceText(CharSourceRange::getTokenRange(TypeRange), SM, LO)
172 ExtraReference.str()};
174 StringRef
Name = MatchedDecl->getName();
175 SourceRange ReplaceRange = MatchedDecl->getSourceRange();
183 std::string Using =
"using ";
184 if (ReplaceRange.getBegin().isMacroID() ||
185 (Result.SourceManager->getFileID(ReplaceRange.getBegin()) !=
186 Result.SourceManager->getFileID(LastReplacementEnd)) ||
187 (ReplaceRange.getBegin() >= LastReplacementEnd)) {
190 FirstTypedefType =
Type;
191 FirstTypedefName =
Name.str();
192 MainTypeEndLoc = TL.getEndLoc();
196 ReplaceRange.setBegin(LastReplacementEnd);
202 if (
Type == FirstTypedefType && !QualifierStr.empty())
203 Type = FirstTypedefName;
206 if (!ReplaceRange.getEnd().isMacroID()) {
207 const SourceLocation::IntTy
Offset =
208 MatchedDecl->getFunctionType() ? 0 :
Name.size();
209 LastReplacementEnd = ReplaceRange.getEnd().getLocWithOffset(
Offset);
212 auto Diag =
diag(ReplaceRange.getBegin(), UseUsingWarning);
215 auto LastTagDeclRange = LastTagDeclRanges.find(ParentDecl);
216 if (LastTagDeclRange != LastTagDeclRanges.end() &&
217 LastTagDeclRange->second.isValid() &&
218 ReplaceRange.fullyContains(LastTagDeclRange->second)) {
219 Type = std::string(Lexer::getSourceText(
220 CharSourceRange::getTokenRange(LastTagDeclRange->second), SM, LO));
225 std::string Replacement = (Using +
Name +
" = " +
Type + QualifierStr).str();
226 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
SourceLocation findPreviousAnyTokenKind(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts, TokenKind TK, TokenKinds... TKs)
llvm::StringMap< ClangTidyValue > OptionMap