
This commit heavily refactors and simplifies the small and trivial checker `apiModeling.llvm.ReturnValue`, which is responsible for modeling the peculiar coding convention that in the LLVM/Clang codebase certain Error() methods always return true. Changes included in this commit: - The call description mode is now specified explicitly (this is not the most significant change, but it was the original reason for touching this checker). - Previously the code provided support for modeling functions that always return `false`; but there was no need for that, so this commit hardcodes that the return value is `true`. - The overcomplicated constraint/state handling logic was simplified. - The separate `checkEndFunction` callback was removed to simplify the code. Admittedly this means that the note tag for the "<method> returns false, breaking the convention" case is placed on the method call instead of the `return` statement; but that case will _never_ appear in practice, so this difference is mostly academical. - The text of the note tags was clarified. - The descriptions in the header comment and Checkers.td were clarified. - Some minor cleanup was applied in the associated test file. This change is very close to NFC because it only affects a hidden `apiModeling.llvm` checker that's only relevant during the analysis of the LLVM/Clang codebase, and even there it doesn't affect the normal behavior of the checker.
92 lines
2.4 KiB
C++
92 lines
2.4 KiB
C++
// RUN: %clang_analyze_cc1 \
|
|
// RUN: -analyzer-checker=core,apiModeling.llvm.ReturnValue \
|
|
// RUN: -analyzer-output=text -verify %s
|
|
|
|
struct Foo { int Field; };
|
|
bool problem();
|
|
void doSomething();
|
|
|
|
// Test the normal case when the implementation of MCAsmParser::Error() (one of
|
|
// the methods modeled by this checker) is opaque.
|
|
namespace test_normal {
|
|
struct MCAsmParser {
|
|
static bool Error();
|
|
};
|
|
|
|
bool parseFoo(Foo &F) {
|
|
if (problem()) {
|
|
// expected-note@-1 {{Assuming the condition is false}}
|
|
// expected-note@-2 {{Taking false branch}}
|
|
return MCAsmParser::Error();
|
|
}
|
|
|
|
F.Field = 0;
|
|
// expected-note@-1 {{The value 0 is assigned to 'F.Field'}}
|
|
return false;
|
|
}
|
|
|
|
bool parseFile() {
|
|
Foo F;
|
|
if (parseFoo(F)) {
|
|
// expected-note@-1 {{Calling 'parseFoo'}}
|
|
// expected-note@-2 {{Returning from 'parseFoo'}}
|
|
// expected-note@-3 {{Taking false branch}}
|
|
return true;
|
|
}
|
|
|
|
// The following expression would produce the false positive report
|
|
// "The left operand of '==' is a garbage value"
|
|
// without the modeling done by apiModeling.llvm.ReturnValue:
|
|
if (F.Field == 0) {
|
|
// expected-note@-1 {{Field 'Field' is equal to 0}}
|
|
// expected-note@-2 {{Taking true branch}}
|
|
doSomething();
|
|
}
|
|
|
|
// Trigger a zero division to get path notes:
|
|
(void)(1 / F.Field);
|
|
// expected-warning@-1 {{Division by zero}}
|
|
// expected-note@-2 {{Division by zero}}
|
|
return false;
|
|
}
|
|
} // namespace test_normal
|
|
|
|
|
|
// Sanity check for the highly unlikely case where the implementation of the
|
|
// method breaks the convention.
|
|
namespace test_break {
|
|
struct MCAsmParser {
|
|
static bool Error() {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
bool parseFoo(Foo &F) {
|
|
if (problem()) {
|
|
// expected-note@-1 {{Assuming the condition is false}}
|
|
// expected-note@-2 {{Taking false branch}}
|
|
return !MCAsmParser::Error();
|
|
}
|
|
|
|
F.Field = 0;
|
|
// expected-note@-1 {{The value 0 is assigned to 'F.Field'}}
|
|
return MCAsmParser::Error();
|
|
// expected-note@-1 {{'MCAsmParser::Error' returned false, breaking the convention that it always returns true}}
|
|
}
|
|
|
|
bool parseFile() {
|
|
Foo F;
|
|
if (parseFoo(F)) {
|
|
// expected-note@-1 {{Calling 'parseFoo'}}
|
|
// expected-note@-2 {{Returning from 'parseFoo'}}
|
|
// expected-note@-3 {{Taking false branch}}
|
|
return true;
|
|
}
|
|
|
|
(void)(1 / F.Field);
|
|
// expected-warning@-1 {{Division by zero}}
|
|
// expected-note@-2 {{Division by zero}}
|
|
return false;
|
|
}
|
|
} // namespace test_break
|