forked from OSchip/llvm-project
[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:
parent
388de9dfcd
commit
398b4ed87d
|
@ -1148,6 +1148,11 @@ namespace {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isFollowedByFallThroughComment(LastStmt)) {
|
||||||
|
++AnnotatedCnt;
|
||||||
|
continue; // Fallthrough comment, good.
|
||||||
|
}
|
||||||
|
|
||||||
++UnannotatedCnt;
|
++UnannotatedCnt;
|
||||||
}
|
}
|
||||||
return !!UnannotatedCnt;
|
return !!UnannotatedCnt;
|
||||||
|
@ -1208,10 +1213,41 @@ namespace {
|
||||||
return nullptr;
|
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;
|
bool FoundSwitchStatements;
|
||||||
AttrStmts FallthroughStmts;
|
AttrStmts FallthroughStmts;
|
||||||
Sema &S;
|
Sema &S;
|
||||||
llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
|
llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
|
||||||
|
llvm::Regex FallthroughRegex;
|
||||||
};
|
};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue