[clang] detect switch fallthrough marked by a comment (PR43465)

The regex can be extended if needed, but this should probably handle
most of the cases.

Differential Revision: https://reviews.llvm.org/D73852
This commit is contained in:
Luboš Luňák 2020-02-02 20:13:41 +01:00
parent 388de9dfcd
commit 398b4ed87d
2 changed files with 56 additions and 0 deletions

View File

@ -1148,6 +1148,11 @@ namespace {
continue;
}
if (isFollowedByFallThroughComment(LastStmt)) {
++AnnotatedCnt;
continue; // Fallthrough comment, good.
}
++UnannotatedCnt;
}
return !!UnannotatedCnt;
@ -1208,10 +1213,41 @@ namespace {
return nullptr;
}
bool isFollowedByFallThroughComment(const Stmt *Statement) {
// Try to detect whether the fallthough is marked by a comment like
// /*FALLTHOUGH*/.
bool Invalid;
const char *SourceData = S.getSourceManager().getCharacterData(
Statement->getEndLoc(), &Invalid);
if (Invalid)
return false;
const char *LineStart = SourceData;
for (;;) {
LineStart = strchr(LineStart, '\n');
if (LineStart == nullptr)
return false;
++LineStart; // Start of next line.
const char *LineEnd = strchr(LineStart, '\n');
StringRef Line(LineStart,
LineEnd ? LineEnd - LineStart : strlen(LineStart));
if (LineStart == LineEnd ||
Line.find_first_not_of(" \t\r") == StringRef::npos)
continue; // Whitespace-only line.
if (!FallthroughRegex.isValid())
FallthroughRegex =
llvm::Regex("(/\\*[ \\t]*fall(s | |-)?thr(ough|u)\\.?[ \\t]*\\*/)"
"|(//[ \\t]*fall(s | |-)?thr(ough|u)\\.?[ \\t]*)",
llvm::Regex::IgnoreCase);
assert(FallthroughRegex.isValid());
return FallthroughRegex.match(Line);
}
}
bool FoundSwitchStatements;
AttrStmts FallthroughStmts;
Sema &S;
llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
llvm::Regex FallthroughRegex;
};
} // anonymous namespace

View File

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -std=c11 -verify -Wimplicit-fallthrough %s
int fallthrough_comment(int n) {
switch (n) {
case 0:
n++;
// FALLTHROUGH
case 1:
n++;
/*fall-through.*/
case 2:
n++;
case 3: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '__attribute__((fallthrough));' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
n++;
break;
}
return n;
}