10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Tooling/FixIt.h"
22 return Node.getValue().getZExtValue() > N;
26 StringConstructorCheck::StringConstructorCheck(StringRef
Name,
29 WarnOnLargeLength(Options.get(
"WarnOnLargeLength", true)),
30 LargeLengthThreshold(Options.get(
"LargeLengthThreshold", 0x800000)) {}
33 Options.
store(Opts,
"WarnOnLargeLength", WarnOnLargeLength);
34 Options.
store(Opts,
"LargeLengthThreshold", LargeLengthThreshold);
38 const auto ZeroExpr = expr(ignoringParenImpCasts(integerLiteral(equals(0))));
39 const auto CharExpr = expr(ignoringParenImpCasts(characterLiteral()));
40 const auto NegativeExpr = expr(ignoringParenImpCasts(
41 unaryOperator(hasOperatorName(
"-"),
42 hasUnaryOperand(integerLiteral(unless(equals(0)))))));
43 const auto LargeLengthExpr = expr(ignoringParenImpCasts(
44 integerLiteral(isBiggerThan(LargeLengthThreshold))));
45 const auto CharPtrType = type(anyOf(pointerType(), arrayType()));
48 const auto BoundStringLiteral = stringLiteral().bind(
"str");
49 const auto ConstStrLiteralDecl = varDecl(
50 isDefinition(), hasType(constantArrayType()), hasType(isConstQualified()),
51 hasInitializer(ignoringParenImpCasts(BoundStringLiteral)));
52 const auto ConstPtrStrLiteralDecl = varDecl(
54 hasType(pointerType(pointee(isAnyCharacter(), isConstQualified()))),
55 hasInitializer(ignoringParenImpCasts(BoundStringLiteral)));
56 const auto ConstStrLiteral = expr(ignoringParenImpCasts(anyOf(
57 BoundStringLiteral, declRefExpr(hasDeclaration(anyOf(
58 ConstPtrStrLiteralDecl, ConstStrLiteralDecl))))));
64 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
65 hasArgument(0, hasType(qualType(isInteger()))),
66 hasArgument(1, hasType(qualType(isInteger()))),
69 hasArgument(0, CharExpr.bind(
"swapped-parameter")),
71 hasArgument(0, ZeroExpr.bind(
"empty-string")),
73 hasArgument(0, NegativeExpr.bind(
"negative-length")),
75 hasArgument(0, LargeLengthExpr.bind(
"large-length"))))
83 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
84 hasArgument(0, hasType(CharPtrType)),
85 hasArgument(1, hasType(isInteger())),
88 hasArgument(1, ZeroExpr.bind(
"empty-string")),
90 hasArgument(1, NegativeExpr.bind(
"negative-length")),
92 hasArgument(1, LargeLengthExpr.bind(
"large-length")),
94 allOf(hasArgument(0, ConstStrLiteral.bind(
"literal-with-length")),
95 hasArgument(1, ignoringParenImpCasts(
96 integerLiteral().bind(
"int"))))))
104 cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
105 hasArgument(0, expr().bind(
"from-ptr")),
106 hasArgument(1, unless(hasType(isInteger()))))
107 .bind(
"constructor")),
112 const ASTContext &
Ctx = *Result.Context;
113 const auto *
E = Result.Nodes.getNodeAs<CXXConstructExpr>(
"constructor");
114 assert(
E &&
"missing constructor expression");
115 SourceLocation
Loc =
E->getBeginLoc();
117 if (Result.Nodes.getNodeAs<Expr>(
"swapped-parameter")) {
118 const Expr *P0 =
E->getArg(0);
119 const Expr *P1 =
E->getArg(1);
120 diag(
Loc,
"string constructor parameters are probably swapped;"
121 " expecting string(count, character)")
122 << tooling::fixit::createReplacement(*P0, *P1,
Ctx)
123 << tooling::fixit::createReplacement(*P1, *P0,
Ctx);
124 }
else if (Result.Nodes.getNodeAs<Expr>(
"empty-string")) {
125 diag(
Loc,
"constructor creating an empty string");
126 }
else if (Result.Nodes.getNodeAs<Expr>(
"negative-length")) {
127 diag(
Loc,
"negative value used as length parameter");
128 }
else if (Result.Nodes.getNodeAs<Expr>(
"large-length")) {
129 if (WarnOnLargeLength)
130 diag(
Loc,
"suspicious large length parameter");
131 }
else if (Result.Nodes.getNodeAs<Expr>(
"literal-with-length")) {
132 const auto *Str = Result.Nodes.getNodeAs<StringLiteral>(
"str");
133 const auto *Lit = Result.Nodes.getNodeAs<IntegerLiteral>(
"int");
134 if (Lit->getValue().ugt(Str->getLength())) {
135 diag(
Loc,
"length is bigger than string literal size");
137 }
else if (
const auto *Ptr = Result.Nodes.getNodeAs<Expr>(
"from-ptr")) {
138 Expr::EvalResult ConstPtr;
139 if (!Ptr->isInstantiationDependent() &&
140 Ptr->EvaluateAsRValue(ConstPtr,
Ctx) &&
141 ((ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
142 (ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer()))) {
143 diag(
Loc,
"constructing string from nullptr is undefined behaviour");