1 //===--- IntegerTypesCheck.cpp - clang-tidy -------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "IntegerTypesCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Basic/AttrKinds.h"
14 #include "clang/Basic/CharInfo.h"
15 #include "clang/Basic/IdentifierTable.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "clang/Lex/Lexer.h"
21 using namespace ast_matchers
;
23 static Token
getTokenAtLoc(SourceLocation Loc
,
24 const MatchFinder::MatchResult
&MatchResult
,
25 IdentifierTable
&IdentTable
) {
27 if (Lexer::getRawToken(Loc
, Tok
, *MatchResult
.SourceManager
,
28 MatchResult
.Context
->getLangOpts(), false))
31 if (Tok
.is(tok::raw_identifier
)) {
32 IdentifierInfo
&Info
= IdentTable
.get(Tok
.getRawIdentifier());
33 Tok
.setIdentifierInfo(&Info
);
34 Tok
.setKind(Info
.getTokenID());
39 namespace tidy::google::runtime
{
41 IntegerTypesCheck::IntegerTypesCheck(StringRef Name
, ClangTidyContext
*Context
)
42 : ClangTidyCheck(Name
, Context
),
43 UnsignedTypePrefix(Options
.get("UnsignedTypePrefix", "uint")),
44 SignedTypePrefix(Options
.get("SignedTypePrefix", "int")),
45 TypeSuffix(Options
.get("TypeSuffix", "")) {}
47 void IntegerTypesCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
48 Options
.store(Opts
, "UnsignedTypePrefix", UnsignedTypePrefix
);
49 Options
.store(Opts
, "SignedTypePrefix", SignedTypePrefix
);
50 Options
.store(Opts
, "TypeSuffix", TypeSuffix
);
53 void IntegerTypesCheck::registerMatchers(MatchFinder
*Finder
) {
54 // Match any integer types, unless they are passed to a printf-based API:
56 // http://google.github.io/styleguide/cppguide.html#64-bit_Portability
57 // "Where possible, avoid passing arguments of types specified by
58 // bitwidth typedefs to printf-based APIs."
59 Finder
->addMatcher(typeLoc(loc(isInteger()),
60 unless(hasAncestor(callExpr(
61 callee(functionDecl(hasAttr(attr::Format
)))))))
64 IdentTable
= std::make_unique
<IdentifierTable
>(getLangOpts());
67 void IntegerTypesCheck::check(const MatchFinder::MatchResult
&Result
) {
68 auto TL
= *Result
.Nodes
.getNodeAs
<TypeLoc
>("tl");
69 SourceLocation Loc
= TL
.getBeginLoc();
71 if (Loc
.isInvalid() || Loc
.isMacroID())
74 // Look through qualification.
75 if (auto QualLoc
= TL
.getAs
<QualifiedTypeLoc
>())
76 TL
= QualLoc
.getUnqualifiedLoc();
78 auto BuiltinLoc
= TL
.getAs
<BuiltinTypeLoc
>();
82 Token Tok
= getTokenAtLoc(Loc
, Result
, *IdentTable
);
83 // Ensure the location actually points to one of the builting integral type
84 // names we're interested in. Otherwise, we might be getting this match from
85 // implicit code (e.g. an implicit assignment operator of a class containing
86 // an array of non-POD types).
87 if (!Tok
.isOneOf(tok::kw_short
, tok::kw_long
, tok::kw_unsigned
,
91 bool IsSigned
= false;
93 const TargetInfo
&TargetInfo
= Result
.Context
->getTargetInfo();
95 // Look for uses of short, long, long long and their unsigned versions.
96 switch (BuiltinLoc
.getTypePtr()->getKind()) {
97 case BuiltinType::Short
:
98 Width
= TargetInfo
.getShortWidth();
101 case BuiltinType::Long
:
102 Width
= TargetInfo
.getLongWidth();
105 case BuiltinType::LongLong
:
106 Width
= TargetInfo
.getLongLongWidth();
109 case BuiltinType::UShort
:
110 Width
= TargetInfo
.getShortWidth();
113 case BuiltinType::ULong
:
114 Width
= TargetInfo
.getLongWidth();
117 case BuiltinType::ULongLong
:
118 Width
= TargetInfo
.getLongLongWidth();
125 // We allow "unsigned short port" as that's reasonably common and required by
127 const StringRef Port
= "unsigned short port";
128 const char *Data
= Result
.SourceManager
->getCharacterData(Loc
);
129 if (!std::strncmp(Data
, Port
.data(), Port
.size()) &&
130 !isAsciiIdentifierContinue(Data
[Port
.size()]))
133 std::string Replacement
=
134 ((IsSigned
? SignedTypePrefix
: UnsignedTypePrefix
) + Twine(Width
) +
138 // We don't add a fix-it as changing the type can easily break code,
139 // e.g. when a function requires a 'long' argument on all platforms.
140 // QualTypes are printed with implicit quotes.
141 diag(Loc
, "consider replacing %0 with '%1'") << BuiltinLoc
.getType()
145 } // namespace tidy::google::runtime