35
35
#include " llvm/Support/FormatVariadic.h"
36
36
#include " llvm/Support/Regex.h"
37
37
#include < tuple>
38
+ #include < utility>
38
39
#include < vector>
39
40
using namespace clang ;
40
41
using namespace tidy ;
@@ -321,11 +322,11 @@ void ClangTidyDiagnosticConsumer::finalizeLastError() {
321
322
322
323
static bool isNOLINTFound (StringRef NolintDirectiveText, StringRef CheckName,
323
324
StringRef Line, size_t *FoundNolintIndex = nullptr ,
324
- bool *SuppressionIsSpecific = nullptr ) {
325
+ StringRef *FoundNolintChecksStr = nullptr ) {
325
326
if (FoundNolintIndex)
326
327
*FoundNolintIndex = StringRef::npos;
327
- if (SuppressionIsSpecific )
328
- *SuppressionIsSpecific = false ;
328
+ if (FoundNolintChecksStr )
329
+ *FoundNolintChecksStr = StringRef () ;
329
330
330
331
size_t NolintIndex = Line.find (NolintDirectiveText);
331
332
if (NolintIndex == StringRef::npos)
@@ -345,18 +346,13 @@ static bool isNOLINTFound(StringRef NolintDirectiveText, StringRef CheckName,
345
346
if (BracketEndIndex != StringRef::npos) {
346
347
StringRef ChecksStr =
347
348
Line.substr (BracketIndex, BracketEndIndex - BracketIndex);
348
- // Allow disabling all the checks with "*".
349
- if (ChecksStr != " *" ) {
350
- // Allow specifying a few check names, delimited with comma.
351
- SmallVector<StringRef, 1 > Checks;
352
- ChecksStr.split (Checks, ' ,' , -1 , false );
353
- llvm::transform (Checks, Checks.begin (),
354
- [](StringRef S) { return S.trim (); });
355
- if (llvm::find (Checks, CheckName) == Checks.end ())
356
- return false ;
357
- if (SuppressionIsSpecific)
358
- *SuppressionIsSpecific = true ;
359
- }
349
+ if (FoundNolintChecksStr)
350
+ *FoundNolintChecksStr = ChecksStr;
351
+ // Allow specifying a few checks with a glob expression, ignoring
352
+ // negative globs (which would effectively disable the suppression).
353
+ GlobList Globs (ChecksStr, /* KeepNegativeGlobs=*/ false );
354
+ if (!Globs.contains (CheckName))
355
+ return false ;
360
356
}
361
357
}
362
358
@@ -388,28 +384,27 @@ static ClangTidyError createNolintError(const ClangTidyContext &Context,
388
384
return Error;
389
385
}
390
386
391
- static Optional<ClangTidyError>
392
- tallyNolintBegins ( const ClangTidyContext &Context, const SourceManager &SM,
393
- StringRef CheckName, SmallVector<StringRef> Lines,
394
- SourceLocation LinesLoc,
395
- SmallVector<SourceLocation> &SpecificNolintBegins,
396
- SmallVector<SourceLocation> &GlobalNolintBegins) {
397
- // Keep a running total of how many NOLINT(BEGIN...END) blocks are active .
387
+ static Optional<ClangTidyError> tallyNolintBegins (
388
+ const ClangTidyContext &Context, const SourceManager &SM,
389
+ StringRef CheckName, SmallVector<StringRef> Lines, SourceLocation LinesLoc ,
390
+ SmallVector<std::pair<SourceLocation, StringRef>> &NolintBegins) {
391
+ // Keep a running total of how many NOLINT(BEGIN...END) blocks are active, as
392
+ // well as the bracket expression (if any) that was used in the NOLINT
393
+ // expression .
398
394
size_t NolintIndex;
399
- bool SuppressionIsSpecific;
400
- auto List = [&]() -> SmallVector<SourceLocation> * {
401
- return SuppressionIsSpecific ? &SpecificNolintBegins : &GlobalNolintBegins;
402
- };
395
+ StringRef NolintChecksStr;
403
396
for (const auto &Line : Lines) {
404
397
if (isNOLINTFound (" NOLINTBEGIN" , CheckName, Line, &NolintIndex,
405
- &SuppressionIsSpecific )) {
398
+ &NolintChecksStr )) {
406
399
// Check if a new block is being started.
407
- List ()->emplace_back (LinesLoc.getLocWithOffset (NolintIndex));
400
+ NolintBegins.emplace_back (std::make_pair (
401
+ LinesLoc.getLocWithOffset (NolintIndex), NolintChecksStr));
408
402
} else if (isNOLINTFound (" NOLINTEND" , CheckName, Line, &NolintIndex,
409
- &SuppressionIsSpecific )) {
403
+ &NolintChecksStr )) {
410
404
// Check if the previous block is being closed.
411
- if (!List ()->empty ()) {
412
- List ()->pop_back ();
405
+ if (!NolintBegins.empty () &&
406
+ NolintBegins.back ().second == NolintChecksStr) {
407
+ NolintBegins.pop_back ();
413
408
} else {
414
409
// Trying to close a nonexistent block. Return a diagnostic about this
415
410
// misuse that can be displayed along with the original clang-tidy check
@@ -432,42 +427,33 @@ lineIsWithinNolintBegin(const ClangTidyContext &Context,
432
427
StringRef TextAfterDiag) {
433
428
Loc = SM.getExpansionRange (Loc).getBegin ();
434
429
SourceLocation FileStartLoc = SM.getLocForStartOfFile (SM.getFileID (Loc));
430
+ SmallVector<std::pair<SourceLocation, StringRef>> NolintBegins;
435
431
436
432
// Check if there's an open NOLINT(BEGIN...END) block on the previous lines.
437
433
SmallVector<StringRef> PrevLines;
438
434
TextBeforeDiag.split (PrevLines, ' \n ' );
439
- SmallVector<SourceLocation> SpecificNolintBegins;
440
- SmallVector<SourceLocation> GlobalNolintBegins;
441
- auto Error =
442
- tallyNolintBegins (Context, SM, CheckName, PrevLines, FileStartLoc,
443
- SpecificNolintBegins, GlobalNolintBegins);
435
+ auto Error = tallyNolintBegins (Context, SM, CheckName, PrevLines,
436
+ FileStartLoc, NolintBegins);
444
437
if (Error) {
445
438
SuppressionErrors.emplace_back (Error.getValue ());
446
- return false ;
447
439
}
448
- bool WithinNolintBegin =
449
- !SpecificNolintBegins.empty () || !GlobalNolintBegins.empty ();
440
+ bool WithinNolintBegin = !NolintBegins.empty ();
450
441
451
442
// Check that every block is terminated correctly on the following lines.
452
443
SmallVector<StringRef> FollowingLines;
453
444
TextAfterDiag.split (FollowingLines, ' \n ' );
454
445
Error = tallyNolintBegins (Context, SM, CheckName, FollowingLines, Loc,
455
- SpecificNolintBegins, GlobalNolintBegins );
446
+ NolintBegins );
456
447
if (Error) {
457
448
SuppressionErrors.emplace_back (Error.getValue ());
458
- return false ;
459
449
}
460
450
461
451
// The following blocks were never closed. Return diagnostics for each
462
452
// instance that can be displayed along with the original clang-tidy check
463
453
// that the user was attempting to suppress.
464
- for (const auto NolintBegin : SpecificNolintBegins) {
465
- auto Error = createNolintError (Context, SM, NolintBegin, true );
466
- SuppressionErrors.emplace_back (Error);
467
- }
468
- for (const auto NolintBegin : GlobalNolintBegins) {
469
- auto Error = createNolintError (Context, SM, NolintBegin, true );
470
- SuppressionErrors.emplace_back (Error);
454
+ for (const auto &NolintBegin : NolintBegins) {
455
+ SuppressionErrors.emplace_back (
456
+ createNolintError (Context, SM, NolintBegin.first , true ));
471
457
}
472
458
473
459
return WithinNolintBegin && SuppressionErrors.empty ();
0 commit comments