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