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 95