35 StringRef CastBindName = {}) {
39 auto IntTypeExpr = expr(hasType(hasCanonicalType(qualType(
40 IsSigned ? isSignedInteger() : isUnsignedInteger(),
41 unless(isActualChar()), unless(booleanType()), unless(enumType())))));
43 const auto ImplicitCastExpr =
44 CastBindName.empty() ? implicitCastExpr(hasSourceExpression(IntTypeExpr))
45 : implicitCastExpr(hasSourceExpression(IntTypeExpr))
48 const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
49 const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
50 const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
52 return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr,
110 const MatchFinder::MatchResult &Result) {
111 const auto *SignedCastExpression =
112 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"sIntCastExpression");
113 assert(SignedCastExpression);
116 Expr::EvalResult EVResult;
117 if (!SignedCastExpression->isValueDependent() &&
118 SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
120 EVResult.Val.getInt().isNonNegative())
123 const auto *BinaryOp =
124 Result.Nodes.getNodeAs<BinaryOperator>(
"intComparison");
127 const Expr *LHS = BinaryOp->getLHS()->IgnoreImpCasts();
128 const Expr *RHS = BinaryOp->getRHS()->IgnoreImpCasts();
129 const Expr *SubExprLHS =
nullptr;
130 const Expr *SubExprRHS =
nullptr;
131 SourceRange R1(LHS->getBeginLoc());
132 SourceRange R2(BinaryOp->getOperatorLoc());
133 SourceRange R3(Lexer::getLocForEndOfToken(
134 RHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
135 if (
const auto *LHSCast = dyn_cast<ExplicitCastExpr>(LHS)) {
136 SubExprLHS = LHSCast->getSubExpr();
137 R1.setEnd(SubExprLHS->getBeginLoc().getLocWithOffset(-1));
138 R2.setBegin(Lexer::getLocForEndOfToken(
139 SubExprLHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
141 if (
const auto *RHSCast = dyn_cast<ExplicitCastExpr>(RHS)) {
142 SubExprRHS = RHSCast->getSubExpr();
143 R2.setEnd(SubExprRHS->getBeginLoc().getLocWithOffset(-1));
144 R3.setBegin(Lexer::getLocForEndOfToken(
145 SubExprRHS->getEndLoc(), 0, *Result.SourceManager, getLangOpts()));
147 const DiagnosticBuilder Diag =
148 diag(BinaryOp->getBeginLoc(),
149 "comparison between 'signed' and 'unsigned' integers");
150 StringRef CmpNamespace;
153 if (getLangOpts().CPlusPlus20) {
154 CmpHeader =
"<utility>";
155 CmpNamespace =
"std::";
156 }
else if (getLangOpts().CPlusPlus17 && EnableQtSupport) {
157 CmpHeader =
"<QtCore/q20utility.h>";
158 CmpNamespace =
"q20::";
162 Diag << FixItHint::CreateReplacement(
163 CharSourceRange(R1, SubExprLHS !=
nullptr),
164 Twine(CmpNamespace +
parseOpCode(BinaryOp->getOpcode()) +
"(").str());
165 Diag << FixItHint::CreateReplacement(R2,
",");
166 Diag << FixItHint::CreateReplacement(CharSourceRange::getCharRange(R3),
")");
169 Diag << IncludeInserter.createIncludeInsertion(
170 Result.SourceManager->getFileID(BinaryOp->getBeginLoc()), CmpHeader);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.