10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
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,
"\"");
172 Diag << FixItHint::CreateInsertion(
Loc, IsWideCharType ?
"std::to_wstring("
174 << FixItHint::CreateInsertion(EndLoc,
")");
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
bool isLikelyCharExpression(const Expr *E) const
CharExpressionDetector(QualType CharType, const ASTContext &Ctx)
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.