[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