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, SourceLocation StartLoc, 29 ASTContext &Context) { 30 assert(StartLoc.isFileID() && "StartLoc must not be in a macro"); 31 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(StartLoc); 32 StringRef File = SM.getBufferData(LocInfo.first); 33 const char *TokenBegin = File.data() + LocInfo.second; 34 Lexer DeclLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(), 35 File.begin(), TokenBegin, File.end()); 36 37 Token Tok; 38 int ParenLevel = 0; 39 bool FoundTypedef = false; 40 41 while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) { 42 switch (Tok.getKind()) { 43 case tok::l_brace: 44 case tok::r_brace: 45 // This might be the `typedef struct {...} T;` case. 46 return false; 47 case tok::l_paren: 48 ParenLevel++; 49 break; 50 case tok::r_paren: 51 ParenLevel--; 52 break; 53 case tok::comma: 54 if (ParenLevel == 0) { 55 // If there is comma and we are not between open parenthesis then it is 56 // two or more declarations in this chain. 57 return false; 58 } 59 break; 60 case tok::raw_identifier: 61 if (Tok.getRawIdentifier() == "typedef") { 62 FoundTypedef = true; 63 } 64 break; 65 default: 66 break; 67 } 68 } 69 70 // Sanity check against weird macro cases. 71 return FoundTypedef; 72 } 73 74 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { 75 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>("typedef"); 76 if (MatchedDecl->getLocation().isInvalid()) 77 return; 78 79 auto &Context = *Result.Context; 80 auto &SM = *Result.SourceManager; 81 82 if (auto *D = MatchedDecl->getUnderlyingType()->getAsCXXRecordDecl()) { 83 //TypeLoc TL = MatchedDecl->getTypeSourceInfo()->getTypeLoc(); 84 llvm::errs() << D->getNameAsString() << "\n"; 85 } 86 87 auto Diag = 88 diag(MatchedDecl->getLocStart(), "use 'using' instead of 'typedef'"); 89 90 SourceLocation StartLoc = MatchedDecl->getLocStart(); 91 if (StartLoc.isMacroID()) 92 return; 93 94 if (CheckRemoval(SM, StartLoc, Context)) { 95 Diag << FixItHint::CreateReplacement( 96 MatchedDecl->getSourceRange(), 97 "using " + MatchedDecl->getNameAsString() + " = " + 98 MatchedDecl->getUnderlyingType().getAsString(getLangOpts())); 99 } 100 } 101 102 } // namespace modernize 103 } // namespace tidy 104 } // namespace clang 105