10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Lex/Lexer.h"
20 void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
23 hasAnyOverloadedOperatorName(
"=",
"+="),
24 callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
25 hasName(
"::std::basic_string"),
26 hasTemplateArgument(0, refersToType(hasCanonicalType(
27 qualType().bind(
"type")))))))),
31 expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
33 unless(callExpr(callee(functionDecl(
34 hasAnyName(
"tolower",
"std::tolower",
"toupper",
38 unless(hasType(qualType(
39 hasCanonicalType(equalsBoundNode(
"type"))))))
41 unless(isInTemplateInstantiation())),
54 if (
const auto *BinOp = dyn_cast<BinaryOperator>(
E)) {
55 const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
56 const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
58 if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
59 return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
60 handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
62 if (BinOp->getOpcode() == BO_Rem)
63 return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
69 if (
const auto *CondOp = dyn_cast<AbstractConditionalOperator>(
E))
70 return isLikelyCharExpression(
71 CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
72 isLikelyCharExpression(
73 CondOp->getTrueExpr()->IgnoreParenImpCasts());
78 bool handleBinaryOp(clang::BinaryOperatorKind Opcode,
const Expr *
const LHS,
79 const Expr *
const RHS)
const {
83 if (isCharTyped(LHS) && isCharTyped(RHS))
88 if ((Opcode == BO_And || Opcode == BO_Rem) && isCharValuedConstant(RHS))
93 if (Opcode == BO_Or && isCharTyped(LHS) && isCharValuedConstant(RHS))
99 return isCharConstant(LHS) && isLikelyCharExpression(RHS);
105 bool isCharConstant(
const Expr *
E)
const {
106 return isCharTyped(
E) && isCharValuedConstant(
E);
110 bool isCharValuedConstant(
const Expr *
E)
const {
111 if (
E->isInstantiationDependent())
113 Expr::EvalResult EvalResult;
114 if (!
E->EvaluateAsInt(EvalResult,
Ctx, Expr::SE_AllowSideEffects))
116 return EvalResult.Val.getInt().getActiveBits() <=
Ctx.getTypeSize(
CharType);
120 bool isCharTyped(
const Expr *
E)
const {
121 return E->getType().getCanonicalType().getTypePtr() ==
126 const ASTContext &
Ctx;
129 void StringIntegerAssignmentCheck::check(
130 const MatchFinder::MatchResult &Result) {
131 const auto *Argument = Result.Nodes.getNodeAs<Expr>(
"expr");
133 Result.Nodes.getNodeAs<QualType>(
"type")->getCanonicalType();
134 SourceLocation
Loc = Argument->getBeginLoc();
142 diag(
Loc,
"an integer is interpreted as a character code when assigning "
143 "it to a string; if this is intended, cast the integer to the "
144 "appropriate character type; if you want a string "
145 "representation, use the appropriate conversion facility");
150 bool IsWideCharType =
CharType->isWideCharType();
151 if (!
CharType->isCharType() && !IsWideCharType)
153 bool IsOneDigit =
false;
154 bool IsLiteral =
false;
155 if (
const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
156 IsOneDigit = Literal->getValue().getLimitedValue() < 10;
160 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
161 Argument->getEndLoc(), 0, *Result.SourceManager, getLangOpts());
163 Diag << FixItHint::CreateInsertion(
Loc, IsWideCharType ?
"L'" :
"'")
164 << FixItHint::CreateInsertion(EndLoc,
"'");
168 Diag << FixItHint::CreateInsertion(
Loc, IsWideCharType ?
"L\"" :
"\"")
169 << FixItHint::CreateInsertion(EndLoc,
"\"");
173 if (getLangOpts().CPlusPlus11) {
174 Diag << FixItHint::CreateInsertion(
Loc, IsWideCharType ?
"std::to_wstring("
176 << FixItHint::CreateInsertion(EndLoc,
")");