65 return traverse(TK_AsIs, expr(anyOf(ImplicitCastExpr, CStyleCastExpr,
70 const auto IntegerType =
71 qualType(isInteger(), unless(isAnyCharacter()), unless(booleanType()))
73 const auto SignedCharCastExpr =
74 charCastExpression(
true, IntegerType,
"signedCastExpression");
75 const auto UnSignedCharCastExpr =
76 charCastExpression(
false, IntegerType,
"unsignedCastExpression");
77 const bool IsC23 = getLangOpts().C23;
81 const auto AssignmentOperatorExpr =
82 expr(binaryOperator(hasOperatorName(
"="), hasLHS(hasType(IntegerType)),
83 hasRHS(SignedCharCastExpr)),
84 IsC23 ? unless(binaryOperator(
85 hasLHS(hasType(hasCanonicalType(enumType())))))
86 : Matcher<Stmt>(anything()));
88 Finder->addMatcher(AssignmentOperatorExpr,
this);
92 const auto Declaration = varDecl(
93 isDefinition(), hasType(IntegerType), hasInitializer(SignedCharCastExpr),
94 IsC23 ? unless(hasType(hasCanonicalType(enumType())))
95 : Matcher<VarDecl>(anything()));
97 Finder->addMatcher(Declaration,
this);
99 if (DiagnoseSignedUnsignedCharComparisons) {
101 const auto CompareOperator =
102 expr(binaryOperator(hasAnyOperatorName(
"==",
"!="),
103 anyOf(allOf(hasLHS(SignedCharCastExpr),
104 hasRHS(UnSignedCharCastExpr)),
105 allOf(hasLHS(UnSignedCharCastExpr),
106 hasRHS(SignedCharCastExpr)))))
109 Finder->addMatcher(CompareOperator,
this);
114 const auto CArraySubscript =
115 arraySubscriptExpr(hasIndex(SignedCharCastExpr)).bind(
"arraySubscript");
117 Finder->addMatcher(CArraySubscript,
this);
120 const auto STDArraySubscript =
122 hasOverloadedOperatorName(
"[]"),
123 hasArgument(0, hasType(cxxRecordDecl(hasName(
"::std::array")))),
124 hasArgument(1, SignedCharCastExpr))
125 .bind(
"arraySubscript");
127 Finder->addMatcher(STDArraySubscript,
this);
131 const auto *SignedCastExpression =
132 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"signedCastExpression");
133 const auto *IntegerType = Result.Nodes.getNodeAs<QualType>(
"integerType");
134 assert(SignedCastExpression);
139 Expr::EvalResult EVResult;
140 if (!SignedCastExpression->isValueDependent() &&
141 SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
143 llvm::APSInt Value = EVResult.Val.getInt();
144 if (Value.isNonNegative())
148 if (
const auto *Comparison = Result.Nodes.getNodeAs<Expr>(
"comparison")) {
149 const auto *UnSignedCastExpression =
150 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"unsignedCastExpression");
153 Expr::EvalResult EVResult;
154 if (!UnSignedCastExpression->isValueDependent() &&
155 UnSignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
157 llvm::APSInt Value = EVResult.Val.getInt();
162 diag(Comparison->getBeginLoc(),
163 "comparison between 'signed char' and 'unsigned char'");
164 }
else if (Result.Nodes.getNodeAs<Expr>(
"arraySubscript")) {
165 diag(SignedCastExpression->getBeginLoc(),
166 "'signed char' to %0 conversion in array subscript; "
167 "consider casting to 'unsigned char' first.")
170 diag(SignedCastExpression->getBeginLoc(),
171 "'signed char' to %0 conversion; "
172 "consider casting to 'unsigned char' first.")
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.