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