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", 1) != 0),
30 LargeLengthThreshold(Options.get(
"LargeLengthThreshold", 0x800000)) {}
33 Options.
store(Opts,
"WarnOnLargeLength", WarnOnLargeLength);
34 Options.
store(Opts,
"LargeLengthThreshold", LargeLengthThreshold);
41 const auto ZeroExpr = expr(ignoringParenImpCasts(integerLiteral(equals(0))));
42 const auto CharExpr = expr(ignoringParenImpCasts(characterLiteral()));
43 const auto NegativeExpr = expr(ignoringParenImpCasts(
44 unaryOperator(hasOperatorName(
"-"),
45 hasUnaryOperand(integerLiteral(unless(equals(0)))))));
46 const auto LargeLengthExpr = expr(ignoringParenImpCasts(
47 integerLiteral(isBiggerThan(LargeLengthThreshold))));
48 const auto CharPtrType = type(anyOf(pointerType(), arrayType()));
51 const auto BoundStringLiteral = stringLiteral().bind(
"str");
52 const auto ConstStrLiteralDecl = varDecl(
53 isDefinition(), hasType(constantArrayType()), hasType(isConstQualified()),
54 hasInitializer(ignoringParenImpCasts(BoundStringLiteral)));
55 const auto ConstPtrStrLiteralDecl = varDecl(
57 hasType(pointerType(pointee(isAnyCharacter(), isConstQualified()))),
58 hasInitializer(ignoringParenImpCasts(BoundStringLiteral)));
59 const auto ConstStrLiteral = expr(ignoringParenImpCasts(anyOf(
60 BoundStringLiteral, declRefExpr(hasDeclaration(anyOf(
61 ConstPtrStrLiteralDecl, ConstStrLiteralDecl))))));
67 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
68 hasArgument(0, hasType(qualType(isInteger()))),
69 hasArgument(1, hasType(qualType(isInteger()))),
72 hasArgument(0, CharExpr.bind(
"swapped-parameter")),
74 hasArgument(0, ZeroExpr.bind(
"empty-string")),
76 hasArgument(0, NegativeExpr.bind(
"negative-length")),
78 hasArgument(0, LargeLengthExpr.bind(
"large-length"))))
86 hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
87 hasArgument(0, hasType(CharPtrType)),
88 hasArgument(1, hasType(isInteger())),
91 hasArgument(1, ZeroExpr.bind(
"empty-string")),
93 hasArgument(1, NegativeExpr.bind(
"negative-length")),
95 hasArgument(1, LargeLengthExpr.bind(
"large-length")),
97 allOf(hasArgument(0, ConstStrLiteral.bind(
"literal-with-length")),
98 hasArgument(1, ignoringParenImpCasts(
99 integerLiteral().bind(
"int"))))))
100 .bind(
"constructor"),
106 cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName(
"basic_string"))),
107 hasArgument(0, expr().bind(
"from-ptr")),
108 hasArgument(1, unless(hasType(isInteger()))))
109 .bind(
"constructor"),
114 const ASTContext &
Ctx = *Result.Context;
115 const auto *E = Result.Nodes.getNodeAs<CXXConstructExpr>(
"constructor");
116 assert(E &&
"missing constructor expression");
117 SourceLocation
Loc = E->getBeginLoc();
119 if (Result.Nodes.getNodeAs<Expr>(
"swapped-parameter")) {
120 const Expr *P0 = E->getArg(0);
121 const Expr *P1 = E->getArg(1);
122 diag(Loc,
"string constructor parameters are probably swapped;" 123 " expecting string(count, character)")
124 << tooling::fixit::createReplacement(*P0, *P1, Ctx)
125 << tooling::fixit::createReplacement(*P1, *P0, Ctx);
126 }
else if (Result.Nodes.getNodeAs<Expr>(
"empty-string")) {
127 diag(Loc,
"constructor creating an empty string");
128 }
else if (Result.Nodes.getNodeAs<Expr>(
"negative-length")) {
129 diag(Loc,
"negative value used as length parameter");
130 }
else if (Result.Nodes.getNodeAs<Expr>(
"large-length")) {
131 if (WarnOnLargeLength)
132 diag(Loc,
"suspicious large length parameter");
133 }
else if (Result.Nodes.getNodeAs<Expr>(
"literal-with-length")) {
134 const auto *Str = Result.Nodes.getNodeAs<StringLiteral>(
"str");
135 const auto *Lit = Result.Nodes.getNodeAs<IntegerLiteral>(
"int");
136 if (Lit->getValue().ugt(Str->getLength())) {
137 diag(Loc,
"length is bigger than string literal size");
139 }
else if (
const auto *Ptr = Result.Nodes.getNodeAs<Expr>(
"from-ptr")) {
140 Expr::EvalResult ConstPtr;
141 if (!Ptr->isInstantiationDependent() &&
142 Ptr->EvaluateAsRValue(ConstPtr, Ctx) &&
143 ((ConstPtr.Val.isInt() && ConstPtr.Val.getInt().isNullValue()) ||
144 (ConstPtr.Val.isLValue() && ConstPtr.Val.isNullPointer()))) {
145 diag(Loc,
"constructing string from nullptr is undefined behaviour");
SourceLocation Loc
'#' location in the include directive
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Base class for all clang-tidy checks.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
AST_MATCHER_P(CXXMethodDecl, hasCanonicalDecl, ast_matchers::internal::Matcher< CXXMethodDecl >, InnerMatcher)