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 94