10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 20 void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
21 if (!getLangOpts().CPlusPlus)
25 anyOf(hasOverloadedOperatorName(
"="),
26 hasOverloadedOperatorName(
"+=")),
27 callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
28 hasName(
"::std::basic_string"),
29 hasTemplateArgument(0, refersToType(hasCanonicalType(
30 qualType().bind(
"type")))))))),
34 expr(hasType(isInteger()), unless(hasType(isAnyCharacter())),
36 unless(callExpr(callee(functionDecl(
37 hasAnyName(
"tolower",
"std::tolower",
"toupper",
41 unless(hasType(qualType(
42 hasCanonicalType(equalsBoundNode(
"type"))))))
44 unless(isInTemplateInstantiation())),
51 : CharType(CharType), Ctx(Ctx) {}
57 if (
const auto *BinOp = dyn_cast<BinaryOperator>(E)) {
58 const auto *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
59 const auto *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
61 if (BinOp->isAdditiveOp() || BinOp->isBitwiseOp())
62 return handleBinaryOp(BinOp->getOpcode(), LHS, RHS) ||
63 handleBinaryOp(BinOp->getOpcode(), RHS, LHS);
65 if (BinOp->getOpcode() == BO_Rem)
66 return handleBinaryOp(BinOp->getOpcode(), LHS, RHS);
72 if (
const auto *CondOp = dyn_cast<AbstractConditionalOperator>(E))
73 return isLikelyCharExpression(
74 CondOp->getFalseExpr()->IgnoreParenImpCasts()) ||
75 isLikelyCharExpression(
76 CondOp->getTrueExpr()->IgnoreParenImpCasts());
81 bool handleBinaryOp(clang::BinaryOperatorKind Opcode,
const Expr *
const LHS,
82 const Expr *
const RHS)
const {
86 if (isCharTyped(LHS) && isCharTyped(RHS))
91 if ((Opcode == BO_And || Opcode == BO_Rem) && isCharValuedConstant(RHS))
96 if (Opcode == BO_Or && isCharTyped(LHS) && isCharValuedConstant(RHS))
101 if (Opcode == BO_Add)
102 return isCharConstant(LHS) && isLikelyCharExpression(RHS);
108 bool isCharConstant(
const Expr *E)
const {
109 return isCharTyped(E) && isCharValuedConstant(E);
113 bool isCharValuedConstant(
const Expr *E)
const {
114 if (E->isInstantiationDependent())
116 Expr::EvalResult EvalResult;
117 if (!E->EvaluateAsInt(EvalResult,
Ctx, Expr::SE_AllowSideEffects))
119 return EvalResult.Val.getInt().getActiveBits() <=
Ctx.getTypeSize(
CharType);
123 bool isCharTyped(
const Expr *E)
const {
124 return E->getType().getCanonicalType().getTypePtr() ==
129 const ASTContext &
Ctx;
132 void StringIntegerAssignmentCheck::check(
133 const MatchFinder::MatchResult &
Result) {
134 const auto *Argument = Result.Nodes.getNodeAs<Expr>(
"expr");
136 Result.Nodes.getNodeAs<QualType>(
"type")->getCanonicalType();
137 SourceLocation
Loc = Argument->getBeginLoc();
145 diag(Loc,
"an integer is interpreted as a character code when assigning " 146 "it to a string; if this is intended, cast the integer to the " 147 "appropriate character type; if you want a string " 148 "representation, use the appropriate conversion facility");
153 bool IsWideCharType = CharType->isWideCharType();
154 if (!CharType->isCharType() && !IsWideCharType)
156 bool IsOneDigit =
false;
157 bool IsLiteral =
false;
158 if (
const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
159 IsOneDigit = Literal->getValue().getLimitedValue() < 10;
163 SourceLocation EndLoc = Lexer::getLocForEndOfToken(
164 Argument->getEndLoc(), 0, *Result.SourceManager, getLangOpts());
166 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ?
"L'" :
"'")
167 << FixItHint::CreateInsertion(EndLoc,
"'");
171 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ?
"L\"" :
"\"")
172 << FixItHint::CreateInsertion(EndLoc,
"\"");
176 if (getLangOpts().CPlusPlus11) {
177 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ?
"std::to_wstring(" 179 << FixItHint::CreateInsertion(EndLoc,
")");
SourceLocation Loc
'#' location in the include directive
CharExpressionDetector(QualType CharType, const ASTContext &Ctx)
bool isLikelyCharExpression(const Expr *E) const
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result