clang-tools 8.0.0

UseUsingCheck.cpp
Go to the documentation of this file.
1 //===--- UseUsingCheck.cpp - clang-tidy------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "UseUsingCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/Lex/Lexer.h"
13
14 using namespace clang::ast_matchers;
15
16 namespace clang {
17 namespace tidy {
18 namespace modernize {
19
20 UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context)
21 : ClangTidyCheck(Name, Context),
22 IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {}
23
24 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
25 if (!getLangOpts().CPlusPlus11)
26 return;
27 Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"),
28 this);
29 }
30
31 // Checks if 'typedef' keyword can be removed - we do it only if
32 // it is the only declaration in a declaration chain.
33 static bool CheckRemoval(SourceManager &SM, SourceLocation StartLoc,
34 ASTContext &Context) {
35 assert(StartLoc.isFileID() && "StartLoc must not be in a macro");
36 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(StartLoc);
37 StringRef File = SM.getBufferData(LocInfo.first);
38 const char *TokenBegin = File.data() + LocInfo.second;
39 Lexer DeclLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(),
40 File.begin(), TokenBegin, File.end());
41
42 Token Tok;
43 int ParenLevel = 0;
44 bool FoundTypedef = false;
45
46 while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) {
47 switch (Tok.getKind()) {
48 case tok::l_brace:
49 case tok::r_brace:
50 // This might be the `typedef struct {...} T;` case.
51 return false;
52 case tok::l_paren:
53 ParenLevel++;
54 break;
55 case tok::r_paren:
56 ParenLevel--;
57 break;
58 case tok::comma:
59 if (ParenLevel == 0) {
60 // If there is comma and we are not between open parenthesis then it is
61 // two or more declarations in this chain.
62 return false;
63 }
64 break;
65 case tok::raw_identifier:
66 if (Tok.getRawIdentifier() == "typedef") {
67 FoundTypedef = true;
68 }
69 break;
70 default:
71 break;
72 }
73 }
74
75 // Sanity check against weird macro cases.
76 return FoundTypedef;
77 }
78
79 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
80 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
81 if (MatchedDecl->getLocation().isInvalid())
82 return;
83
84 auto &Context = *Result.Context;
85 auto &SM = *Result.SourceManager;
86
87 SourceLocation StartLoc = MatchedDecl->getBeginLoc();
88
89 if (StartLoc.isMacroID() && IgnoreMacros)
90 return;
91
92 auto Diag =
93 diag(StartLoc, "use 'using' instead of 'typedef'");
94
95 // do not fix if there is macro or array
96 if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID())
97 return;
98
99 if (CheckRemoval(SM, StartLoc, Context)) {
100 auto printPolicy = PrintingPolicy(getLangOpts());
101 printPolicy.SuppressScope = true;
102 printPolicy.ConstantArraySizeAsWritten = true;
103 printPolicy.UseVoidForZeroParams = false;
104
105 Diag << FixItHint::CreateReplacement(
106 MatchedDecl->getSourceRange(),
107 "using " + MatchedDecl->getNameAsString() + " = " +
108 MatchedDecl->getUnderlyingType().getAsString(printPolicy));
109 }
110 }
111
112 } // namespace modernize
113 } // namespace tidy
114 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:15
clang::tidy::ClangTidyCheck::getLangOpts
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
clang::tidy::modernize::UseUsingCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: UseUsingCheck.cpp:79
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidy.h:127
clang::tidy::modernize::UseUsingCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: UseUsingCheck.cpp:24
UseUsingCheck.h
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
Result
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
Definition: ClangdServer.cpp:60
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:100
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:438
clang::tidy::modernize::CheckRemoval
static bool CheckRemoval(SourceManager &SM, SourceLocation StartLoc, ASTContext &Context)
Definition: UseUsingCheck.cpp:33