clang-tools  3.9.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 "../utils/LexerUtils.h"
12 
13 using namespace clang::ast_matchers;
14 
15 namespace clang {
16 namespace tidy {
17 namespace modernize {
18 
19 void UseUsingCheck::registerMatchers(MatchFinder *Finder) {
20  if (!getLangOpts().CPlusPlus11)
21  return;
22  Finder->addMatcher(typedefDecl().bind("typedef"), this);
23 }
24 
25 // Checks if 'typedef' keyword can be removed - we do it only if
26 // it is the only declaration in a declaration chain.
27 static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart,
28  const SourceLocation &LocEnd, ASTContext &Context,
29  SourceRange &ResultRange) {
30  FileID FID = SM.getFileID(LocEnd);
31  llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd);
32  Lexer DeclLexer(SM.getLocForStartOfFile(FID), Context.getLangOpts(),
33  Buffer->getBufferStart(), SM.getCharacterData(LocStart),
34  Buffer->getBufferEnd());
35  Token DeclToken;
36  bool result = false;
37  int parenthesisLevel = 0;
38 
39  while (!DeclLexer.LexFromRawLexer(DeclToken)) {
40  if (DeclToken.getKind() == tok::TokenKind::l_paren)
41  parenthesisLevel++;
42  if (DeclToken.getKind() == tok::TokenKind::r_paren)
43  parenthesisLevel--;
44  if (DeclToken.getKind() == tok::TokenKind::semi)
45  break;
46  // if there is comma and we are not between open parenthesis then it is
47  // two or more declatarions in this chain
48  if (parenthesisLevel == 0 && DeclToken.getKind() == tok::TokenKind::comma)
49  return false;
50 
51  if (DeclToken.isOneOf(tok::TokenKind::identifier,
52  tok::TokenKind::raw_identifier)) {
53  auto TokenStr = DeclToken.getRawIdentifier().str();
54 
55  if (TokenStr == "typedef") {
56  ResultRange =
57  SourceRange(DeclToken.getLocation(), DeclToken.getEndLoc());
58  result = true;
59  }
60  }
61  }
62  // assert if there was keyword 'typedef' in declaration
63  assert(result && "No typedef found");
64 
65  return result;
66 }
67 
68 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) {
69  const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>("typedef");
70  if (MatchedDecl->getLocation().isInvalid())
71  return;
72 
73  auto &Context = *Result.Context;
74  auto &SM = *Result.SourceManager;
75 
76  auto Diag =
77  diag(MatchedDecl->getLocStart(), "use 'using' instead of 'typedef'");
78  if (MatchedDecl->getLocStart().isMacroID()) {
79  return;
80  }
81  SourceRange RemovalRange;
82  if (CheckRemoval(SM, MatchedDecl->getLocStart(), MatchedDecl->getLocEnd(),
83  Context, RemovalRange)) {
84  Diag << FixItHint::CreateReplacement(
85  MatchedDecl->getSourceRange(),
86  "using " + MatchedDecl->getNameAsString() + " = " +
87  MatchedDecl->getUnderlyingType().getAsString(getLangOpts()));
88  }
89 }
90 
91 } // namespace modernize
92 } // namespace tidy
93 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:210
SourceManager & SM
ClangTidyContext & Context
Definition: ClangTidy.cpp:93
static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart, const SourceLocation &LocEnd, ASTContext &Context, SourceRange &ResultRange)
const NamedDecl * Result
Definition: USRFinder.cpp:137