11
11
#include " clang/ASTMatchers/ASTMatchFinder.h"
12
12
#include " clang/Lex/Lexer.h"
13
13
#include " clang/Lex/Token.h"
14
+
14
15
#include " ../utils/LexerUtils.h"
15
16
16
17
using namespace clang ::ast_matchers;
@@ -23,17 +24,37 @@ ArgumentCommentCheck::ArgumentCommentCheck(StringRef Name,
23
24
ClangTidyContext *Context)
24
25
: ClangTidyCheck(Name, Context),
25
26
StrictMode (Options.getLocalOrGlobal(" StrictMode" , 0 ) != 0),
27
+ CommentBoolLiterals(Options.getLocalOrGlobal(" CommentBoolLiterals" , 0 ) !=
28
+ 0),
29
+ CommentIntegerLiterals(
30
+ Options.getLocalOrGlobal(" CommentIntegerLiterals" , 0 ) != 0),
31
+ CommentFloatLiterals(
32
+ Options.getLocalOrGlobal(" CommentFloatLiterals" , 0 ) != 0),
33
+ CommentStringLiterals(
34
+ Options.getLocalOrGlobal(" CommentStringLiterals" , 0 ) != 0),
35
+ CommentUserDefinedLiterals(
36
+ Options.getLocalOrGlobal(" CommentUserDefinedLiterals" , 0 ) != 0),
37
+ CommentCharacterLiterals(
38
+ Options.getLocalOrGlobal(" CommentCharacterLiterals" , 0 ) != 0),
39
+ CommentNullPtrs(Options.getLocalOrGlobal(" CommentNullPtrs" , 0 ) != 0),
26
40
IdentRE(" ^(/\\ * *)([_A-Za-z][_A-Za-z0-9]*)( *= *\\ */)$" ) {}
27
41
28
42
void ArgumentCommentCheck::storeOptions (ClangTidyOptions::OptionMap &Opts) {
29
43
Options.store (Opts, " StrictMode" , StrictMode);
44
+ Options.store (Opts, " CommentBoolLiterals" , CommentBoolLiterals);
45
+ Options.store (Opts, " CommentIntegerLiterals" , CommentIntegerLiterals);
46
+ Options.store (Opts, " CommentFloatLiterals" , CommentFloatLiterals);
47
+ Options.store (Opts, " CommentStringLiterals" , CommentStringLiterals);
48
+ Options.store (Opts, " CommentUserDefinedLiterals" , CommentUserDefinedLiterals);
49
+ Options.store (Opts, " CommentCharacterLiterals" , CommentCharacterLiterals);
50
+ Options.store (Opts, " CommentNullPtrs" , CommentNullPtrs);
30
51
}
31
52
32
53
void ArgumentCommentCheck::registerMatchers (MatchFinder *Finder) {
33
54
Finder->addMatcher (
34
55
callExpr (unless (cxxOperatorCallExpr ()),
35
- // NewCallback's arguments relate to the pointed function, don't
36
- // check them against NewCallback's parameter names.
56
+ // NewCallback's arguments relate to the pointed function,
57
+ // don't check them against NewCallback's parameter names.
37
58
// FIXME: Make this configurable.
38
59
unless (hasDeclaration (functionDecl (
39
60
hasAnyName (" NewCallback" , " NewPermanentCallback" )))))
@@ -126,8 +147,8 @@ static bool isLikelyTypo(llvm::ArrayRef<ParmVarDecl *> Params,
126
147
127
148
const unsigned Threshold = 2 ;
128
149
// Other parameters must be an edit distance at least Threshold more away
129
- // from this parameter. This gives us greater confidence that this is a typo
130
- // of this parameter and not one with a similar name.
150
+ // from this parameter. This gives us greater confidence that this is a
151
+ // typo of this parameter and not one with a similar name.
131
152
unsigned OtherED = ArgNameLower.edit_distance (II->getName ().lower (),
132
153
/* AllowReplacements=*/ true ,
133
154
ThisED + Threshold);
@@ -180,8 +201,8 @@ static const CXXMethodDecl *findMockedMethod(const CXXMethodDecl *Method) {
180
201
}
181
202
return nullptr ;
182
203
}
183
- if (const auto *Next = dyn_cast_or_null<CXXMethodDecl>(
184
- Method->getNextDeclInContext ())) {
204
+ if (const auto *Next =
205
+ dyn_cast_or_null<CXXMethodDecl>( Method->getNextDeclInContext ())) {
185
206
if (looksLikeExpectMethod (Next) && areMockAndExpectMethods (Method, Next))
186
207
return Method;
187
208
}
@@ -206,6 +227,21 @@ static const FunctionDecl *resolveMocks(const FunctionDecl *Func) {
206
227
return Func;
207
228
}
208
229
230
+ // Given the argument type and the options determine if we should
231
+ // be adding an argument comment.
232
+ bool ArgumentCommentCheck::shouldAddComment (const Expr *Arg) const {
233
+ if (Arg->getExprLoc ().isMacroID ())
234
+ return false ;
235
+ Arg = Arg->IgnoreImpCasts ();
236
+ return (CommentBoolLiterals && isa<CXXBoolLiteralExpr>(Arg)) ||
237
+ (CommentIntegerLiterals && isa<IntegerLiteral>(Arg)) ||
238
+ (CommentFloatLiterals && isa<FloatingLiteral>(Arg)) ||
239
+ (CommentUserDefinedLiterals && isa<UserDefinedLiteral>(Arg)) ||
240
+ (CommentCharacterLiterals && isa<CharacterLiteral>(Arg)) ||
241
+ (CommentStringLiterals && isa<StringLiteral>(Arg)) ||
242
+ (CommentNullPtrs && isa<CXXNullPtrLiteralExpr>(Arg));
243
+ }
244
+
209
245
void ArgumentCommentCheck::checkCallArgs (ASTContext *Ctx,
210
246
const FunctionDecl *OriginalCallee,
211
247
SourceLocation ArgBeginLoc,
@@ -219,7 +255,7 @@ void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
219
255
if (NumArgs == 0 )
220
256
return ;
221
257
222
- auto makeFileCharRange = [Ctx](SourceLocation Begin, SourceLocation End) {
258
+ auto MakeFileCharRange = [Ctx](SourceLocation Begin, SourceLocation End) {
223
259
return Lexer::makeFileCharRange (CharSourceRange::getCharRange (Begin, End),
224
260
Ctx->getSourceManager (),
225
261
Ctx->getLangOpts ());
@@ -242,15 +278,15 @@ void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
242
278
}
243
279
244
280
CharSourceRange BeforeArgument =
245
- makeFileCharRange (ArgBeginLoc, Args[I]->getBeginLoc ());
281
+ MakeFileCharRange (ArgBeginLoc, Args[I]->getBeginLoc ());
246
282
ArgBeginLoc = Args[I]->getEndLoc ();
247
283
248
284
std::vector<std::pair<SourceLocation, StringRef>> Comments;
249
285
if (BeforeArgument.isValid ()) {
250
286
Comments = getCommentsInRange (Ctx, BeforeArgument);
251
287
} else {
252
288
// Fall back to parsing back from the start of the argument.
253
- CharSourceRange ArgsRange = makeFileCharRange (
289
+ CharSourceRange ArgsRange = MakeFileCharRange (
254
290
Args[I]->getBeginLoc (), Args[NumArgs - 1 ]->getEndLoc ());
255
291
Comments = getCommentsBeforeLoc (Ctx, ArgsRange.getBegin ());
256
292
}
@@ -277,8 +313,19 @@ void ArgumentCommentCheck::checkCallArgs(ASTContext *Ctx,
277
313
}
278
314
}
279
315
}
316
+
317
+ // If the argument comments are missing for literals add them.
318
+ if (Comments.empty () && shouldAddComment (Args[I])) {
319
+ std::string ArgComment =
320
+ (llvm::Twine (" /*" ) + II->getName () + " =*/" ).str ();
321
+ DiagnosticBuilder Diag =
322
+ diag (Args[I]->getBeginLoc (),
323
+ " argument comment missing for literal argument %0" )
324
+ << II
325
+ << FixItHint::CreateInsertion (Args[I]->getBeginLoc (), ArgComment);
326
+ }
280
327
}
281
- }
328
+ } // namespace bugprone
282
329
283
330
void ArgumentCommentCheck::check (const MatchFinder::MatchResult &Result) {
284
331
const auto *E = Result.Nodes .getNodeAs <Expr>(" expr" );
0 commit comments