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