10#include "../utils/OptionsUtils.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
15using namespace clang::ast_matchers::internal;
24 CharTypdefsToIgnoreList(Options.get(
"CharTypdefsToIgnore",
"")),
25 DiagnoseSignedUnsignedCharComparisons(
26 Options.get(
"DiagnoseSignedUnsignedCharComparisons", true)) {}
29 Options.
store(Opts,
"CharTypdefsToIgnore", CharTypdefsToIgnoreList);
30 Options.
store(Opts,
"DiagnoseSignedUnsignedCharComparisons",
31 DiagnoseSignedUnsignedCharComparisons);
35BindableMatcher<clang::Stmt> SignedCharMisuseCheck::charCastExpression(
36 bool IsSigned,
const Matcher<clang::QualType> &IntegerType,
37 const std::string &CastBindName)
const {
41 const auto IntTypedef = qualType(hasDeclaration(typedefDecl(
44 auto CharTypeExpr = expr();
46 CharTypeExpr = expr(hasType(
47 qualType(isAnyCharacter(), isSignedInteger(), unless(IntTypedef))));
49 CharTypeExpr = expr(hasType(qualType(
50 isAnyCharacter(), unless(isSignedInteger()), unless(IntTypedef))));
53 const auto ImplicitCastExpr =
54 implicitCastExpr(hasSourceExpression(CharTypeExpr),
55 hasImplicitDestinationType(IntegerType))
58 const auto CStyleCastExpr = cStyleCastExpr(has(ImplicitCastExpr));
59 const auto StaticCastExpr = cxxStaticCastExpr(has(ImplicitCastExpr));
60 const auto FunctionalCastExpr = cxxFunctionalCastExpr(has(ImplicitCastExpr));
65 return traverse(TK_AsIs, expr(anyOf(ImplicitCastExpr, CStyleCastExpr,
66 StaticCastExpr, FunctionalCastExpr)));
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");
79 const auto AssignmentOperatorExpr =
80 expr(binaryOperator(hasOperatorName(
"="), hasLHS(hasType(IntegerType)),
81 hasRHS(SignedCharCastExpr)));
83 Finder->addMatcher(AssignmentOperatorExpr,
this);
86 const auto Declaration = varDecl(isDefinition(), hasType(IntegerType),
87 hasInitializer(SignedCharCastExpr));
89 Finder->addMatcher(Declaration,
this);
91 if (DiagnoseSignedUnsignedCharComparisons) {
93 const auto CompareOperator =
94 expr(binaryOperator(hasAnyOperatorName(
"==",
"!="),
95 anyOf(allOf(hasLHS(SignedCharCastExpr),
96 hasRHS(UnSignedCharCastExpr)),
97 allOf(hasLHS(UnSignedCharCastExpr),
98 hasRHS(SignedCharCastExpr)))))
101 Finder->addMatcher(CompareOperator,
this);
106 const auto CArraySubscript =
107 arraySubscriptExpr(hasIndex(SignedCharCastExpr)).bind(
"arraySubscript");
109 Finder->addMatcher(CArraySubscript,
this);
112 const auto STDArraySubscript =
114 hasOverloadedOperatorName(
"[]"),
115 hasArgument(0, hasType(cxxRecordDecl(hasName(
"::std::array")))),
116 hasArgument(1, SignedCharCastExpr))
117 .bind(
"arraySubscript");
119 Finder->addMatcher(STDArraySubscript,
this);
123 const auto *SignedCastExpression =
124 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"signedCastExpression");
125 const auto *IntegerType = Result.Nodes.getNodeAs<QualType>(
"integerType");
126 assert(SignedCastExpression);
131 Expr::EvalResult EVResult;
132 if (!SignedCastExpression->isValueDependent() &&
133 SignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
135 llvm::APSInt Value = EVResult.Val.getInt();
136 if (Value.isNonNegative())
140 if (
const auto *Comparison = Result.Nodes.getNodeAs<Expr>(
"comparison")) {
141 const auto *UnSignedCastExpression =
142 Result.Nodes.getNodeAs<ImplicitCastExpr>(
"unsignedCastExpression");
145 Expr::EvalResult EVResult;
146 if (!UnSignedCastExpression->isValueDependent() &&
147 UnSignedCastExpression->getSubExpr()->EvaluateAsInt(EVResult,
149 llvm::APSInt Value = EVResult.Val.getInt();
154 diag(Comparison->getBeginLoc(),
155 "comparison between 'signed char' and 'unsigned char'");
156 }
else if (Result.Nodes.getNodeAs<Expr>(
"arraySubscript")) {
157 diag(SignedCastExpression->getBeginLoc(),
158 "'signed char' to %0 conversion in array subscript; "
159 "consider casting to 'unsigned char' first.")
162 diag(SignedCastExpression->getBeginLoc(),
163 "'signed char' to %0 conversion; "
164 "consider casting to 'unsigned char' first.")
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.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
SignedCharMisuseCheck(StringRef Name, ClangTidyContext *Context)
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static constexpr int UnsignedASCIIUpperBound
std::vector< StringRef > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
llvm::StringMap< ClangTidyValue > OptionMap