1 //===--- IntegerTypesCheck.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 "IntegerTypesCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 #include "clang/Basic/CharInfo.h" 15 #include "clang/Basic/TargetInfo.h" 16 17 namespace clang { 18 namespace tidy { 19 namespace google { 20 namespace runtime { 21 22 using namespace ast_matchers; 23 24 IntegerTypesCheck::IntegerTypesCheck(StringRef Name, ClangTidyContext *Context) 25 : ClangTidyCheck(Name, Context), 26 UnsignedTypePrefix(Options.get("UnsignedTypePrefix", "uint")), 27 SignedTypePrefix(Options.get("SignedTypePrefix", "int")), 28 TypeSuffix(Options.get("TypeSuffix", "")) {} 29 30 void IntegerTypesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 31 Options.store(Opts, "UnsignedTypePrefix", UnsignedTypePrefix); 32 Options.store(Opts, "SignedTypePrefix", SignedTypePrefix); 33 Options.store(Opts, "TypeSuffix", TypeSuffix); 34 } 35 36 void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) { 37 // Find all TypeLocs. The relevant Style Guide rule only applies to C++. 38 if (getLangOpts().CPlusPlus) 39 Finder->addMatcher(typeLoc(loc(isInteger())).bind("tl"), this); 40 } 41 42 void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) { 43 auto TL = *Result.Nodes.getNodeAs<TypeLoc>("tl"); 44 SourceLocation Loc = TL.getLocStart(); 45 46 if (Loc.isInvalid() || Loc.isMacroID()) 47 return; 48 49 // Look through qualification. 50 if (auto QualLoc = TL.getAs<QualifiedTypeLoc>()) 51 TL = QualLoc.getUnqualifiedLoc(); 52 53 auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>(); 54 if (!BuiltinLoc) 55 return; 56 57 bool IsSigned; 58 unsigned Width; 59 const TargetInfo &TargetInfo = Result.Context->getTargetInfo(); 60 61 // Look for uses of short, long, long long and their unsigned versions. 62 switch (BuiltinLoc.getTypePtr()->getKind()) { 63 case BuiltinType::Short: 64 Width = TargetInfo.getShortWidth(); 65 IsSigned = true; 66 break; 67 case BuiltinType::Long: 68 Width = TargetInfo.getLongWidth(); 69 IsSigned = true; 70 break; 71 case BuiltinType::LongLong: 72 Width = TargetInfo.getLongLongWidth(); 73 IsSigned = true; 74 break; 75 case BuiltinType::UShort: 76 Width = TargetInfo.getShortWidth(); 77 IsSigned = false; 78 break; 79 case BuiltinType::ULong: 80 Width = TargetInfo.getLongWidth(); 81 IsSigned = false; 82 break; 83 case BuiltinType::ULongLong: 84 Width = TargetInfo.getLongLongWidth(); 85 IsSigned = false; 86 break; 87 default: 88 return; 89 } 90 91 // We allow "unsigned short port" as that's reasonably common and required by 92 // the sockets API. 93 const StringRef Port = "unsigned short port"; 94 const char *Data = Result.SourceManager->getCharacterData(Loc); 95 if (!std::strncmp(Data, Port.data(), Port.size()) && 96 !isIdentifierBody(Data[Port.size()])) 97 return; 98 99 std::string Replacement = 100 ((IsSigned ? SignedTypePrefix : UnsignedTypePrefix) + Twine(Width) + 101 TypeSuffix) 102 .str(); 103 104 // We don't add a fix-it as changing the type can easily break code, 105 // e.g. when a function requires a 'long' argument on all platforms. 106 // QualTypes are printed with implicit quotes. 107 diag(Loc, "consider replacing %0 with '%1'") << BuiltinLoc.getType() 108 << Replacement; 109 } 110 111 } // namespace runtime 112 } // namespace google 113 } // namespace tidy 114 } // namespace clang 115