21 hasAnyOverloadedOperatorName(
"=",
"+="),
22 callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
23 hasName(
"::std::basic_string"),
24 hasTemplateArgument(0, refersToType(hasCanonicalType(
25 qualType().bind(
"type")))))))),
29 expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
31 unless(callExpr(callee(functionDecl(
32 hasAnyName(
"tolower",
"std::tolower",
"toupper",
36 unless(hasType(qualType(
37 hasCanonicalType(equalsBoundNode(
"type"))))))
39 unless(isInTemplateInstantiation())),
46 : CharType(CharType), Ctx(Ctx) {}
52 if (
const auto *BinOp = dyn_cast<BinaryOperator>(E)) {
53 const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
54 const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
56 if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
57 return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
58 handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
60 if (BinOp->getOpcode() == BO_Rem)
61 return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
67 if (
const auto *CondOp = dyn_cast<AbstractConditionalOperator>(E))
69 CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
71 CondOp->getTrueExpr()->IgnoreParenImpCasts());
76 bool handleBinaryOp(clang::BinaryOperatorKind Opcode,
const Expr *
const LHS,
77 const Expr *
const RHS)
const {
81 if (isCharTyped(LHS) && isCharTyped(RHS))
86 if ((Opcode == BO_And || Opcode == BO_Rem) && isCharValuedConstant(RHS))
91 if (Opcode == BO_Or && isCharTyped(LHS) && isCharValuedConstant(RHS))
103 bool isCharConstant(
const Expr *E)
const {
104 return isCharTyped(E) && isCharValuedConstant(E);
108 bool isCharValuedConstant(
const Expr *E)
const {
109 if (E->isInstantiationDependent())
111 Expr::EvalResult EvalResult;
112 if (!E->EvaluateAsInt(EvalResult, Ctx, Expr::SE_AllowSideEffects))
114 return EvalResult.Val.getInt().getActiveBits() <= Ctx.getTypeSize(CharType);
118 bool isCharTyped(
const Expr *E)
const {
119 return E->getType().getCanonicalType().getTypePtr() ==
120 CharType.getTypePtr();
123 const QualType CharType;
124 const ASTContext &Ctx;
128 const MatchFinder::MatchResult &Result) {
129 const auto *Argument = Result.Nodes.getNodeAs<Expr>(
"expr");
130 const auto CharType =
131 Result.Nodes.getNodeAs<QualType>(
"type")->getCanonicalType();
132 SourceLocation Loc = Argument->getBeginLoc();
140 diag(Loc,
"an integer is interpreted as a character code when assigning "
141 "it to a string; if this is intended, cast the integer to the "
142 "appropriate character type; if you want a string "
143 "representation, use the appropriate conversion facility");
148 bool IsWideCharType = CharType->isWideCharType();
149 if (!CharType->isCharType() && !IsWideCharType)
151 bool IsOneDigit =
false;
152 bool IsLiteral =
false;
153 if (
const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
154 IsOneDigit = Literal->getValue().getLimitedValue() < 10;
158 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
159 Argument->getEndLoc(), 0, *Result.SourceManager, getLangOpts());
161 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ?
"L'" :
"'")
162 << FixItHint::CreateInsertion(EndLoc,
"'");
166 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ?
"L\"" :
"\"")
167 << FixItHint::CreateInsertion(EndLoc,
"\"");
171 if (getLangOpts().CPlusPlus11) {
172 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ?
"std::to_wstring("
174 << FixItHint::CreateInsertion(EndLoc,
")");