[cfe-dev] Best place for semantic checks

Ted Kremenek kremenek at apple.com
Tue Jul 8 13:19:45 PDT 2008


On Jul 8, 2008, at 11:55 AM, Martin Doucha wrote:

> Hi,
> I want to write semantic checker for newbie mistakes/undefined  
> behavior
> using Clang. Where should I put the code - into Sema module or into a
> new ASTConsumer module crammed between Sema and other ASTConsumers?
>
> Regards,
> Martin

Hi Martin,

You have three options.  Put the logic in Sema, create a new  
ASTConsumer, or use the AnalysisConsumer interface, which was designed  
explicitly for running different kinds of static analysis checks.  If  
you want your checks committed back to Clang, probably the best place  
is to use the new AnalysisConsumer interface (so that it hooks in  
nicely with the other static analysis checks), but it's entirely up to  
you.  Note that the AnalysisConsumer interface is designed to be us

If you use the new AnalysisConsumer interface, you will need to make a  
few small changes to AnalysisConsumer.h, AnalysisConsumer.cpp, and a  
small place in clang.cpp to hook up your checks to the driver.   
AnalysisConsumer calls the dead store checker, the memory leak  
checker, and so on.  The actual logic for your checks should go into a  
separate .cpp file, either in the Driver or in the Analysis library,  
with a header file included by AnalysisConsumer.cpp to actually invoke  
the logic of your checks.

Eventually, this interface will be further simplified, hopefully  
obviating the need to modify AnalysisConsumer.h, AnalysisConsumer.cpp,  
and clang.cpp.

Using the AnalysisConsumer interface (or your own ASTConsumer) uses a  
different code path than code generation, so using that interface  
means the checks won't be performed when code is compiled using  
Clang.  You can use scan-build/ccc-analyzer, however, to invoke your  
checker over an entire code base by modifying the clang command line  
invoked by ccc-analyzer.

If your checks prove to be both effective and very quick, this logic  
could be migrated to Sema.  I only suggest hooking it into  
AnalysisConsumer to start with because the logic is easier to work  
with than Sema (Sema is doing a lot of things), you get to harness the  
scan-build checker harness, and adding a new driver option is a snap.

More specifically, you need to modify the following to use the  
AnalysisConsumer interface:

--------------------

Driver/AnalysisConsumer.h:

Add a new value to the enum Analyses:

   enum Analyses {
   CFGDump,
   CFGView,
   WarnDeadStores,
   WarnUninitVals,
   DisplayLiveVariables,
   CheckerCFRef,
   CheckerSimple,
   MyChecker  // <--------------------------
};

--------------------

Driver/AnalysisConsumer.cpp:

1) Add a static "Action" function that calls your checker using the  
appropriate arguments.

static void ActionMyChecker(AnalysisManager& mgr) {
    // Call the checker using arguments provided by queries to  
AnalysisManager.
    ...
}


2) Add a case in CreateAnalysisConsumer for your Analysis using the  
enum value you added to Driver/AnalysisConsumer.h:

ASTConsumer* clang::CreateAnalysisConsumer(...) {

   ...

   for ( ; Beg != End ; ++Beg)
     switch (*Beg) {
       case WarnDeadStores:
         C->addCodeAction(&ActionDeadStores);
         break;

       case WarnUninitVals:
         C->addCodeAction(&ActionUninitVals);
         break;

       // ADD A CASE HERE
       case MyChecker:
       C->addCodeAction(&ActionMyChecker);
       break;

--------------------

Driver/Clang.cpp:

Add your command line argument to "Analyses"

static llvm::cl::list<Analyses>
AnalysisList(llvm::cl::desc("Available Source Code Analyses:"),
llvm::cl::values(
clEnumValN(CFGDump, "cfg-dump", "Display Control-Flow Graphs"),
clEnumValN(CFGView, "cfg-view", "View Control-Flow Graphs using  
GraphViz"),
clEnumValN(DisplayLiveVariables, "dump-live-variables",
            "Print results of live variable analysis"),
clEnumValN(WarnDeadStores, "warn-dead-stores",
            "Flag warnings of stores to dead variables"),
clEnumValN(WarnUninitVals, "warn-uninit-values",
            "Flag warnings of uses of unitialized variables"),
clEnumValN(CheckerSimple, "checker-simple",
            "Perform simple path-sensitive checks."),
clEnumValN(CheckerCFRef, "checker-cfref",
            "Run the [Core] Foundation reference count checker"),
clEnumValnN(MyChecker, "my-checker",     //    
<------------------------------------------
            "My Custom Checker"),
clEnumValEnd));


- Ted



More information about the cfe-dev mailing list