# ubuntu
$ sudo apt install clang
# mac
$ brew install llvm
# download prebuilt clang libraries
$ wget https://github.com/xcalcc/labrador/releases/download/v0.1/clang-11.0.0.tar.xz
$ mkdir clang-prebuilt && cd clang-prebuilt
$ tar Jxf clang-11.0.0.tar.xz
# set CLANG_HOME
$ export CLANG_HOME=/path/to/clang/libraries
$ git clone https://github.com/xcalcc/labrador.git
xsca will be built in build directory, and its components will be installed to $XSCA_HOME
# set XSCA_HOME
$ export XSCA_HOME=/directory/which/contains/components
$ cd labrador
$ mkdir build && cd build
$ cmake -G Ninja ../src
$ ninja
$ ninja install
$ ./xsca -cc1 -emit-llvm test.c
Copy the whole example in src/rules directory to new ruleset name:
$ cd src/rules
$ cp -r example <NEW-RULESET-NAME>
rename files in .
Modify /CMakeLists.txt with correct library and source file name to build the library for new rule
Modify src/rules/CMakeLists.txt to include this new ruleset subdirectory
Modify src/CMakeLists.txt to add the new library to XSCA_LIBS
Modify src/xsca_link.cpp to add new extern and static variable to make sure the library is correct linked and static objects are initialized correctly. Define the new variable in example_checker.cpp. In xsca_link.cpp
extern int __NEW_RULESET_NAME__; // defined in rules/example/example_checker.cpp
static ATTRIBUTE_UNUSED int New_Ruleset_Name = __NEW_RULESET_NAME__;
In example_checker.cpp
int __NEW_RULESET_NAME__; // used in xsca_link.cpp
- A preprocessor(PP) rule
- An AST decl rule
- An AST stmt/expr rule
- An AST type rule
- For PP rule, follow check_pp_example.inc to implement the new rule. New rule class must inherit from
PPNullHandler
which implements all clang preprocess callbacks but do nothing. New rule needs to overwrite callbacks interfaces to do corresponding check. - For AST decl rule, follow check_decl_example.inc to inherit from
DeclNullHandler
. AST stmt/expr rule follows check_stmt_example.inc and inherit fromStmtNullHandler
. AST type rule follows check_type_example.inc and inherit fromTypeNullHandler
.
- Modify example_pp_rule.h with new namespace. Add new PP rule class and name to
ALL_PP_RULES
macro and include the new PP rule inc file. - Modify example_decl_rule.h with new namespace. Add new decl rule class and name to
ALL_DECL_RULES
macro and include the new decl rule inc file. - Modify example_stmt_rule.h with new namespace. Add new stmt rule class and name to
ALL_STMT_RULES
macro and include the new stmt rule inc file. - Modify example_type_rule.h with new namespace. Add new type rule class and name to
ALL_TYPE_RULES
macro and include the new type rule inc file.
- Modify example_checker.cpp with new namespace, using name, factory name.
XSCA oonly uses virtual functions in the interface with clang, include ASTConsumer
and PPCallbacks
. Inside XSCA, all checkers are composed by template without virtual function for performance consideration.
Each ruleset is implemented as a checker. The checker base class provides 2 virtual functions to return callbacks (ASTConsumer
and PPCallbacks
) to be invoked by clang Lexer and Sema.
CheckerManager
is a singleton to manage all Checker instances and CheckerFactory
instances. In XcalCheckerManager::Initialize()
, all checker are created by CheckerFactory
and added to clang's preprocess callbacks or AST consumers.
CheckerFactory
provides interface to create the Checker instance. It's created and added to CheckerManager by CheckerFactoryRegister.CheckerFactoryRegister
is a static object to create CheckerFactory instance and add to CheckerManager.
XcalChecker
is defined in include/xsca_checker.h. XcalCheckerManager, XcalCheckerFactory and XcalCheckerFactoryRegister is defined in include/xsca_checker_manager.h.
PPCallback
derives from clang::PPCallbacks
which will be invoked by clang Lexer. When interfaces in PPCallbacks
is called, the corresponding handler API will be invoked.
PPNullHandler
implements all clang::PPCallbacks
API but do nothing. This can be the default base class for all PP handlers.
PPListHandler
composes multiple PP handles as a list so that they can be invoked by PPCallbacks
one by one.
XcalPPCallback
is defined in include/pp_callback.h. PPNullHandler is defined in pp_null_handler.h. PPListHandler is defined in pp_list_handler.h
TypeVisitor
implements a general Visit(clang::Type *type)
method, which checks the type class and call individual Visit* method on given Type class. In iindividual Visit* method, corresponding handler method is called.
TypeNullHandler implements all Visit*
method for types but do nothing. This can be the default base class for all Type checkers.
TypeListHandler
composes multiple Type handlers as a list so that they can be invoked one by one.
XcalTypeVisitor
is defined in include/type_visiotor.h. TypeNullHandler
is defined in type_null_handler.h. TypeListHandler is defined in type_list_handler.h
Similar to TypeVisitor, TypeNullHandler, TypeListHandler. StmtVisitor
will visit the Stmt node ans all it's children.
XcalStmtVisitor
is defined in include/stmt_visiotor.h. StmtNullHandler
is defined in stmt_null_handler.h. StmtListHandler is defined in stmt_list_handler.h
Similar to TypeVisitor, TypeNullHandler, TypeListHandler. DeclVisitor
will visit the Decl node ans call TypeVisitor for TypeDecl and StmtVisitor for FunctionDecl.
XcalDeclVisitor
is defined in include/decl_visiotor.h. DeclNullHandler
is defined in decl_null_handler.h. DeclListHandler is defined in decl_list_handler.h
Interfaces in ASTConsumer
is called by clang Sema and corresponding method in DeclVisitor
is called so that all Handlers can be called.
For preprocess:
Clang Lex --> PPCallbacks --> PPHandler --> individual PP check
For AST:
Clang Sema --> ASTConsumer --> DeclVisitor --> DeclHandler --> individual Decl check
--> (FunctionDecl) StmtVisitor --> StmtHandler --> individual Stmt check
--> (TypeDecl) TypeVisitor --> TypeHandler --> individual Type check