10#include "clang/AST/Expr.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
15using namespace clang::ast_matchers::internal;
22 using namespace clang;
23 const Type *DesugaredType = Ty->getUnqualifiedDesugaredType();
24 if (
const auto *BT = llvm::dyn_cast<BuiltinType>(DesugaredType))
25 return (BT->getKind() == BuiltinType::Char_U ||
26 BT->getKind() == BuiltinType::Char_S);
36static BindableMatcher<clang::Stmt>
38 const std::string &CastBindName = std::string()) {
42 auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
43 isInteger(), IsSigned ? isSignedInteger() : isUnsignedInteger(),
44 unless(isActualChar()), unless(booleanType()), unless(enumType())))));
46 const auto ImplicitCastExpr =
47 CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
48 : implicitCastExpr(hasSourceExpression(IntTypeExpr))
51 const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
52 const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
53 const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
55 return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
66 return "cmp_less_equal";
68 return "cmp_greater_equal";
72 return "cmp_not_equal";
81 IncludeInserter(Options.getLocalOrGlobal(
"IncludeStyle",
82 utils::IncludeSorter::IS_LLVM),
83 areDiagsSelfContained()) {}
96 const auto CompareOperator =
97 binaryOperator(hasAnyOperatorName(
"==",
"<=",
">=",
"<",
">",
"!="),
98 hasOperands(SignedIntCastExpr, UnSignedIntCastExpr),
99 unless(isInTemplateInstantiation()))
100 .bind(
"intComparison");
102 Finder->addMatcher(CompareOperator,
this);
106 const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
111 const MatchFinder::MatchResult &Result) {
112 const auto *SignedCastExpression =
113 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"sIntCastExpression");
114 assert(SignedCastExpression);
117 Expr::EvalResult EVResult;
118 if (!SignedCastExpression->isValueDependent() &&
119 SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
121 const llvm::APSInt SValue = EVResult.Val.getInt();
122 if (SValue.isNonNegative())
126 const auto *BinaryOp =
127 Result.Nodes.getNodeAs<BinaryOperator>(
"intComparison");
128 if (BinaryOp ==
nullptr)
131 const BinaryOperator::Opcode OpCode = BinaryOp->getOpcode();
133 const Expr *LHS = BinaryOp->getLHS()->IgnoreImpCasts();
134 const Expr *RHS = BinaryOp->getRHS()->IgnoreImpCasts();
135 if (LHS ==
nullptr || RHS ==
nullptr)
137 const Expr *SubExprLHS =
nullptr;
138 const Expr *SubExprRHS =
nullptr;
139 SourceRange R1 = SourceRange(LHS->getBeginLoc());
140 SourceRange R2 = SourceRange(BinaryOp->getOperatorLoc());
141 SourceRange R3 = SourceRange(Lexer::getLocForEndOfToken(
142 RHS->getEndLoc(), 0, *Result.SourceManager,
getLangOpts()));
143 if (
const auto *LHSCast = llvm::dyn_cast<ExplicitCastExpr>(LHS)) {
144 SubExprLHS = LHSCast->getSubExpr();
145 R1 = SourceRange(LHS->getBeginLoc(),
146 SubExprLHS->getBeginLoc().getLocWithOffset(-1));
147 R2.setBegin(Lexer::getLocForEndOfToken(
148 SubExprLHS->getEndLoc(), 0, *Result.SourceManager,
getLangOpts()));
150 if (
const auto *RHSCast = llvm::dyn_cast<ExplicitCastExpr>(RHS)) {
151 SubExprRHS = RHSCast->getSubExpr();
152 R2.setEnd(SubExprRHS->getBeginLoc().getLocWithOffset(-1));
154 DiagnosticBuilder Diag =
155 diag(BinaryOp->getBeginLoc(),
156 "comparison between 'signed' and 'unsigned' integers");
157 const std::string CmpNamespace = (
"std::" +
parseOpCode(OpCode)).str();
158 const std::string CmpHeader =
"<utility>";
160 Diag << FixItHint::CreateReplacement(
161 CharSourceRange(R1, SubExprLHS !=
nullptr),
162 llvm::Twine(CmpNamespace +
"(").str());
163 Diag << FixItHint::CreateReplacement(R2,
",");
164 Diag << FixItHint::CreateReplacement(CharSourceRange::getCharRange(R3),
")");
168 Result.SourceManager->getFileID(BinaryOp->getBeginLoc()), CmpHeader);
llvm::SmallString< 256U > Name
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) override
Override this to register PPCallbacks in the preprocessor.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
UseIntegerSignComparisonCheck(StringRef Name, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void registerPreprocessor(Preprocessor *PP)
Registers this with the Preprocessor PP, must be called before this class is used.
std::optional< FixItHint > createIncludeInsertion(FileID FileID, llvm::StringRef Header)
Creates a Header inclusion directive fixit in the File FileID.
IncludeSorter::IncludeStyle getStyle() const
AST_MATCHER(Expr, isMacroID)
static BindableMatcher< clang::Stmt > intCastExpression(bool IsSigned, const std::string &CastBindName=std::string())
static bool isActualCharType(const clang::QualType &Ty)
Find if the passed type is the actual "char" type, not applicable to explicit "signed char" or "unsig...
static StringRef parseOpCode(BinaryOperator::Opcode Code)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::StringMap< ClangTidyValue > OptionMap