10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
21 bool isConcatenatedLiteralsOnPurpose(ASTContext *
Ctx,
22 const StringLiteral *Lit) {
26 TraversalKindScope RAII(*
Ctx, ast_type_traits::TK_AsIs);
40 const SourceManager &SM =
Ctx->getSourceManager();
41 bool IndentedCorrectly =
true;
42 SourceLocation FirstToken = Lit->getStrTokenLoc(0);
43 FileID BaseFID = SM.getFileID(FirstToken);
44 unsigned int BaseIndent = SM.getSpellingColumnNumber(FirstToken);
45 unsigned int BaseLine = SM.getSpellingLineNumber(FirstToken);
46 for (
unsigned int TokNum = 1; TokNum < Lit->getNumConcatenated(); ++TokNum) {
47 SourceLocation Token = Lit->getStrTokenLoc(TokNum);
48 FileID FID = SM.getFileID(Token);
49 unsigned int Indent = SM.getSpellingColumnNumber(Token);
50 unsigned int Line = SM.getSpellingLineNumber(Token);
51 if (FID != BaseFID ||
Line != BaseLine + TokNum || Indent <= BaseIndent) {
52 IndentedCorrectly =
false;
56 if (IndentedCorrectly)
64 MaxConcatenatedTokens) {
65 return Node.getNumConcatenated() > 1 &&
66 Node.getNumConcatenated() < MaxConcatenatedTokens &&
67 !isConcatenatedLiteralsOnPurpose(&Finder->getASTContext(), &Node);
72 SuspiciousMissingCommaCheck::SuspiciousMissingCommaCheck(
75 SizeThreshold(Options.get(
"SizeThreshold", 5U)),
76 RatioThreshold(std::stod(Options.get(
"RatioThreshold",
".2"))),
77 MaxConcatenatedTokens(Options.get(
"MaxConcatenatedTokens", 5U)) {}
82 Options.
store(Opts,
"RatioThreshold", std::to_string(RatioThreshold));
83 Options.
store(Opts,
"MaxConcatenatedTokens", MaxConcatenatedTokens);
87 const auto ConcatenatedStringLiteral =
88 stringLiteral(isConcatenatedLiteral(MaxConcatenatedTokens)).bind(
"str");
90 const auto StringsInitializerList =
91 initListExpr(hasType(constantArrayType()),
92 has(ignoringParenImpCasts(expr(ConcatenatedStringLiteral))));
94 Finder->addMatcher(StringsInitializerList.bind(
"list"),
this);
98 const MatchFinder::MatchResult &Result) {
99 const auto *InitializerList = Result.Nodes.getNodeAs<InitListExpr>(
"list");
100 const auto *ConcatenatedLiteral =
101 Result.Nodes.getNodeAs<StringLiteral>(
"str");
102 assert(InitializerList && ConcatenatedLiteral);
105 unsigned int Size = InitializerList->getNumInits();
106 if (Size < SizeThreshold)
110 unsigned int Count = 0;
111 for (
unsigned int i = 0; i < Size; ++i) {
112 const Expr *Child = InitializerList->getInit(i)->IgnoreImpCasts();
113 if (
const auto *Literal = dyn_cast<StringLiteral>(Child)) {
114 if (Literal->getNumConcatenated() > 1)
121 if (
double(Count) / Size > RatioThreshold)
124 diag(ConcatenatedLiteral->getBeginLoc(),
125 "suspicious string literal, probably missing a comma");