[cfe-commits] Patch to do static analysis with range sets
Ted Kremenek
kremenek at apple.com
Thu Feb 5 17:27:33 PST 2009
On Feb 1, 2009, at 12:06 AM, Ben Laurie wrote:
> Not complete - no self-tests and full of diagnostics, but I'd love to
> get comments about the approach. Also hints on implementing tests (Ted
> told me in IM, but I forgot), and how to preserve/add more debugging
> stuff in an approved way, since I find that this stuff hurts my head
> without it...
BTW, thanks again for tackling this.
To answer your inquiry, tests go in the test directory 'test' under
the 'clang' directory. We put analysis tests in test/Analysis. The
test suite can be run doing "make test" from the 'clang directory.
Tests are best explained via example. Here is the top fragment of
test file test/Analysis/uninit-vals.c:
// RUN: clang -analyze -warn-uninit-values -verify %s
int f1() {
int x;
return x; // expected-warning {{use of uninitialized variable}}
}
int f2(int x) {
int y;
int z = x + y; // expected-warning {{use of uninitialized
variable}}
return z;
}
The top line of a test will be the "RUN" line, which shows the line
you pass to clang. '%s' gets substituted by the test harness for the
name of the current source file.
Notice the '-verify' flag to clang. It is used by clang to cross
check it's own diagnostics. Essentially it puts clang in a mode where
it collects all of its diagnostics and checks see if there are any
expected errors or warnings that showed up or didn't show up. The
test indicates the expected warnings/errors using special comments on
the line where the diagnostic would be emitted. There are four kinds
of annotations:
expected-warning{{A SUBSET OF THE TEXT YOU EXPECT}}
expected-error{{...}}
expected-note{{...}}
no-warning
Clang divides diagnostics into errors (e.g., could not parse a file,
stopping), warnings, and notes. Warnings are basically any type
checking warnings, but also (in this mode) include diagnostics from
the analyzer. no-warning means that you expected no warning to appear
on that line. no-warning is somewhat cosmetic; the test will fail if
there are *any* warnings that you didn't explicitly expect.
For debugs, we assert liberally. Typically we do assertions like the
following:
assert(condition && "Some descriptive text that explains at a high
level what the assertion means.").
Sometimes we leave off the descriptive text if it is obvious, but it
usually explains the assertion and is useful for people filing bugs.
Assertions are completely disabled in a Release-Asserts build, but
appear in Debug and Release builds.
Some other important information can be found in the LLVM Programmers'
Manual, particularly under "Helpful and Useful APIs":
http://llvm.org/docs/ProgrammersManual.html#apis
We don't compile LLVM or Clang with C++ exceptions or RTTI, but we
use some "home spun" RTTI (which works via some template magic) to
implement concepts similar to variants in functional languages.
Basically, we use the cast<>() and dyn_cast<>() template functions to
down type-safe downcasts. The former basically asserts that the
downcast always work (the assertion goes away in Release-Asserts
build) and dyn_cast<>() will return NULL if the cast fails. Classes
need to be specifically wired to use the LLVM-casting mechanism by
implementing a "classof" static method. The AST nodes in Clang, and
many of the objects in the static analyzer (e.g., SVals), use this
mechanism. If you are interested in using or adopting it, looking at
subclasses of Stmt or SVal would be a great place to look for
inspiration.
Ted
More information about the cfe-commits
mailing list