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 UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context) 21 : ClangTidyCheck(Name, Context), 22 IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {} 23 24 void UseUsingCheck::registerMatchers(MatchFinder *Finder) { 25 if (!getLangOpts().CPlusPlus11) 26 return; 27 Finder->addMatcher(typedefDecl(unless(isInstantiated())).bind("typedef"), 28 this); 29 } 30 31 // Checks if 'typedef' keyword can be removed - we do it only if 32 // it is the only declaration in a declaration chain. 33 static bool CheckRemoval(SourceManager &SM, SourceLocation StartLoc, 34 ASTContext &Context) { 35 assert(StartLoc.isFileID() && "StartLoc must not be in a macro"); 36 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(StartLoc); 37 StringRef File = SM.getBufferData(LocInfo.first); 38 const char *TokenBegin = File.data() + LocInfo.second; 39 Lexer DeclLexer(SM.getLocForStartOfFile(LocInfo.first), Context.getLangOpts(), 40 File.begin(), TokenBegin, File.end()); 41 42 Token Tok; 43 int ParenLevel = 0; 44 bool FoundTypedef = false; 45 46 while (!DeclLexer.LexFromRawLexer(Tok) && !Tok.is(tok::semi)) { 47 switch (Tok.getKind()) { 48 case tok::l_brace: 49 case tok::r_brace: 50 // This might be the `typedef struct {...} T;` case. 51 return false; 52 case tok::l_paren: 53 ParenLevel++; 54 break; 55 case tok::r_paren: 56 ParenLevel--; 57 break; 58 case tok::comma: 59 if (ParenLevel == 0) { 60 // If there is comma and we are not between open parenthesis then it is 61 // two or more declarations in this chain. 62 return false; 63 } 64 break; 65 case tok::raw_identifier: 66 if (Tok.getRawIdentifier() == "typedef") { 67 FoundTypedef = true; 68 } 69 break; 70 default: 71 break; 72 } 73 } 74 75 // Sanity check against weird macro cases. 76 return FoundTypedef; 77 } 78 79 void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { 80 const auto *MatchedDecl = Result.Nodes.getNodeAs<TypedefDecl>("typedef"); 81 if (MatchedDecl->getLocation().isInvalid()) 82 return; 83 84 auto &Context = *Result.Context; 85 auto &SM = *Result.SourceManager; 86 87 SourceLocation StartLoc = MatchedDecl->getBeginLoc(); 88 89 if (StartLoc.isMacroID() && IgnoreMacros) 90 return; 91 92 auto Diag = 93 diag(StartLoc, "use 'using' instead of 'typedef'"); 94 95 // do not fix if there is macro or array 96 if (MatchedDecl->getUnderlyingType()->isArrayType() || StartLoc.isMacroID()) 97 return; 98 99 if (CheckRemoval(SM, StartLoc, Context)) { 100 auto printPolicy = PrintingPolicy(getLangOpts()); 101 printPolicy.SuppressScope = true; 102 printPolicy.ConstantArraySizeAsWritten = true; 103 printPolicy.UseVoidForZeroParams = false; 104 105 Diag << FixItHint::CreateReplacement( 106 MatchedDecl->getSourceRange(), 107 "using " + MatchedDecl->getNameAsString() + " = " + 108 MatchedDecl->getUnderlyingType().getAsString(printPolicy)); 109 } 110 } 111 112 } // namespace modernize 113 } // namespace tidy 114 } // namespace clang 115