C/C++ KAST examples
From current
Overparenthesized expression
// ParensExpr / Expr:: { ParensExpr/Expr:: } ParensExpr
int f(int i) {
}
- return ((i + 1)) / 2;
int g(int n) {
}
- return (((i - 1))) * 2;
Note: Use the "sequence of 0 or more children" modifier ({}) to match a chain of child AST nodes.
Find all static functions
// Declarator [ isFunction() ] [ isStatic() ]
// finds this function
static void f() {
}
- // ...
// and this one
static void h();
class C {
public:
};
- // finds this function as well
- static void m() {
- // ...
- }
Find all definitions of static functions
// Declarator [ isFunction() ] [ isStatic() ] [ isDefinition() ]
// finds this function
static void f() {
}
// but not this one - not definition
static void g();
Find all functions whose return type is a pointer
// FuncDef [ Declarator::Declarator [ Ptr::Ptr [ @Spec = KTC_POINTEROPERATOR_POINTER ] ] ]
// finds this
void *foo() {
}
- // ...
// and this
FILE *xfo(const char *name) {
}
- // ...
// no match - returns reference, not pointer
int &getir(unsigned key) {
}
- // ...
// no match
int boo() {
}
- // ...
Find all functions whose return type is not a pointer
// FuncDef [ Declarator::Declarator [ not Ptr::Ptr [ @Spec = KTC_POINTEROPERATOR_POINTER ] ] ]
// no match - returns pointer
void *foo() {
}
- // ...
// no match - returns pointer
FILE *xfo(const char *name) {
}
- // ...
// finds this - returns reference, not a pointer
int &getir(unsigned key) {
}
- // ...
// and this
int boo() {
}
- // ...
Note: Use the not operator to negate the result of a predicate.
Find all functions that use void in return type void functions
This refers to functions such as void functions and functions returning pointer to void.
// FuncDef [ DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ] ]
// finds this function
void printMe() {
}
// and this one
inline void *getAddress() {
}
// no match - not void
int getCount() {
}
// no match - not void
static FILE *openFile() {
}
Note: Use the "any element" modifier ([*]) to check if a sequence of AST nodes contains a node of specified type.
Find all void functions
// FuncDef [ DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ] ] [ Declarator::Declarator / Ptr::Null ]
// find this function
void f() {
}
// and this one
static void g() {
}
// no match - return type is not void
inline int h() {
}
- return 0;
// no match - return type is a pointer to void
void *j() {
}
- return NULL;
Find all static member functions
// Declarator [ isClassMember() ] [ isFunction() ] [ isStatic() ]
class C {
public:
};
- // finds this function
- static void m() {
- // ...
- }
// but not this one - not a member
static void f() {
}
Find all anonymous enums
// EnumType [ Name::Null ]
// finds this enum
typedef enum {
} anonymousEnum;
- VALUE_0,
- VALUE_1
// but not this one
enum aEnum{
};
- INT_VALUE_0 = 0,
- INT_VALUE_1 = 1
Note: Use Null to indicate a missing child of an AST node.
Find all anonymous unions
// ClassType [ @Tag = KTC_CLASSTAG_UNION ] [ Name::Null ]
struct S {
};
- // finds this union
- union {
- short s;
- int i;
- long l;
- } n;
// no match - named union
union U {
};
- int i;
- void *p;
Find non-template functions
// FuncDef [ not ancestor::TemplateDecl ] [ not ancestor::MemberTemplate ]
// no match - template function
template
void f() {
}
template
class C
public:
};
- // no match - member of template class
- void m() {
- // ...
- }
class D {
public:
};
- // finds this member function
- void n1() {
- }
- // no match - member template
- template
- void n2() {
- // ...
- }
// finds this function
void g() {
}
- // ...
Find all assignment expressions
// BinaryExpr [ Op::Op [ @Code = KTC_OPCODE_ASSIGN ] ]
void f() {
}
- char *p;
- // ...
- p = "boo!";
Cast expression as lvalue
// BinaryExpr [ Op::Op [ @Code = KTC_OPCODE_ASSIGN ] ] / Left::CastExpr
void f() {
}
- int *p;
- // ...
- (char *) p = "boo!";
Find functions that are declared in a namespace
// Decl [ ancestor::NamespaceDecl ] / InitDeclarators[*]::InitDeclarator [ Declarator::Declarator [ DirectDeclarator::FuncDeclarator ] ]
namespace my {
// finds this
void f();
}
namespace their {
// and finds these two functions
int f1(int), f2(int, int);
}
Find functions that are not part of any namespace
// Decl [ not ancestor::NamespaceDecl ] / InitDeclarators[*]::InitDeclarator [ Declarator::Declarator [ DirectDeclarator::FuncDeclarator ] ]
// finds this
void f();
namespace xn {
// no match - within a namespace
void f();
}
Find functions that are declared in an anonymous namespace
//Decl[ancestor::NamespaceDecl[@Id=’’]]/InitDeclarators[*]::InitDeclarator[Declarator::Declarator[DirectDeclarator::FuncDeclarator]]
namespace {
// finds this
void f();
}
namespace my {
// no match - namespace has name
void f();
}
// no match - on the global level
void f();
Find all non-static variables that are not part of any namespace ("global" variables)
//Decl[not ancestor::NamespaceDecl]/InitDeclarators[*]::InitDeclarator[isVariable()][not isStatic()]
namespace n {
}
- // no match - variable in namespace;
- int a;
// no match - static variable
static int b;
// no match - not a variable
void f();
// finds this variable
extern int c;
Find all classes whose name does not start with uppercase letter
//ClassType[isDefinition()]/Name::QualifiedName/Name::Name[not starts-from-capital(@Id)]
class A {
};
// finds this class
class b {
};
struct C {
};
- // and this union
- union x {
- };
Find all non-public member variables whose name does not start from "m_"
//Declarator[isClassMember()][not isPublic()][not getName().starts-with(’m_’)]
class C {
public:
protected:
- // no match - public member
- static int count;
};
- // no match - starts with "m_"
- char *m_data;
- // finds this member variable
- int length;
Find all destructor declarations
//MemberDecl/MemberDeclarators[*]::MemberDeclarator[isDestructor()]
class C {
};
- ~C();
Note: Use the isDestructor() predicate to check if an AST node declares a destructor.
Find all inline destructor definitions (destructors defined inside a class)
//MemberFunc/FuncDef::FuncDef/Declarator::Declarator[isDestructor()]
class C {
};
- ~C() {}
Note: Use the isDestructor() predicate to check if an AST node declares a destructor.
Find classes with non-virtual destructor
//ClassType/MemberDecls[*]::MemberDecl[MemberDeclarators[*]::MemberDeclarator[isDestructor()][not isVirtual()]] //ClassType/MemberDecls[*]::MemberFunc[FuncDef::FuncDef/Declarator::Declarator[isDestructor()][not isVirtual()]]
class A {
public:
};
- // finds this destructor
- ~A();
class B {
public:
};
- // finds this destructor
- ~B() {}
Find cases where a boolean value is incremented or decremented
// UnaryExpr [ Op::Op [ @Code = KTC_OPCODE_PREINC | @Code = KTC_OPCODE_POSTINC | @Code = KTC_OPCODE_PREDEC | @Code = KTC_OPCODE_POSTDEC ] ] [ Expr.getTypeName() = 'bool' ]
int main() {
}
- bool bFlag = true;
- // matches all of the following expressions
- bFlag++;
- bFlag--;
- --bFlag;
- ++bFlag;
- return 0;
Find labels followed by a "}" (empty labeled statements)
// LabeledStmt [ Stmt::Null ]
int main(int argc, char** argv) {
}
- if (argc < 3) {
- return 1;
- myLabel: /* empty labeled statement will be matched here */
- }
- return 0;
Find 'typedef's that do not define anything
// Decl [ DeclSpecs[*]::StorageClass [@Spec = KTC_STORAGECLASS_TYPEDEF] ] [InitDeclarators::NoInitDeclarator]
/* These two 'typedef' definitions do not define anything */
typedef unsigned int;
signed char typedef;
Usually these type definitions are either typographical or programming errors. Please note that 'typedef' is not a special keyword, but rather another declaration specifier and may be inserted at any point among other declaration specifiers. That is why it is important to look for ’typedef’ at in any position within declaration specifiers, not at the beginning only (although that is where it is usually put).
To match any node in the sequence of nodes of the same generic type ('DeclSpec'’ link in this case), use the '[*]' modifier as shown.
Find signed bit fields occupying only one bit
// MemberDecl [MemberDeclarators[*]::MemberDeclarator [Bits::LiteralExpr [@Value = 1]][Declarator::Declarator.isSignedInt()] ]
struct MT {
};
- int ii: 1;
- signed int si: 1;
Storing a sign requires one bit, so there are no bits left for the value itself. The pattern looks for member declarations. For uniformity reasons in C and C++, structure and union fields are called members (because in C++ structures and unions are special types of classes). The number of bits is attached to the member declarator. We check numeric attribute for equality to one and apply a built-in predicate 'isSignedInt()' to a declarator to find out if a declared member is a signed integer.
Again, the '[*]' modifier is used to match any of the structure or union members in the sequence.
Find switch selector that is constant
//CaseLable[Expr::LiteralExpr]
void foo(int c) {
}
- switch (c) {
- case 1: bar(); /* constant is used for a selector */
- break;
- default: baz();
- }
This checker finds occurrences where a constant is used, but it would be better to use the value of enumerated type.
Find all IF statements
//IfStmt
void foo(boolean b) {
}
- if (b) {
- /* code */
- }
Find IF statements with THEN branch containing at least one executable statement
//IfStmt/Then::CompoundStmt/Stmts[*]::ExprStmt
void foo(boolean b) {
- if (b) {
- printf("IfStatement"); // match this one
- }
- if (b) {
- printf("IfStatement: Then"); // match this one
}
- } else {
- printf("IfStatement: Else");
- }
- if (b) {
- /* code */ // do not match this one
- }
Find IF statements with no ELSE branch
//IfStmt[Else::Null]
void foo(boolean b) {
}
- if (b) { // find this one
- /* code */
- }
- if (b) { // do not match this one
- /* code */
- } else {
- /* code */
- }
Find binary "+" operations
//BinaryExpr/Op::Op[@Code=KTC_OPCODE_ADD]
void foo(booleanint a, int b) {
}
- int c = a + b; // match this one
- c = ++b; // do not match
- c = a / b; // do not match
Find calls to "gets"
//CallExpr/Func::IdExpr[Name::QualifiedName/Name::Name[@Id='gets']]
/* gets example */
#include
int main()
{
}
- char string [256];
- printf ("Insert your full address: ");
- gets (string);
- printf ("Your address is: %s\n",string);
- return 0;
Find function declarations that return "void" and have no modifiers
//FuncDef/DeclSpecs[0]::BuiltinType[@Spec=KTC_BUILTINTYPE_VOID] //FuncDef/DeclSpecs::BuiltinType[@Spec=KTC_BUILTINTYPE_VOID]
static void foo() { // will not match
}
- /* code */
void foo2() { // will match
}
Find function declarations that return "void"
//FuncDef/DeclSpecs[*]::BuiltinType[@Spec=KTC_BUILTINTYPE_VOID]
static void foo() {
}
- /* code */
void foo2() {
}
Find function declarations that return "void" or "char"
//FuncDef/DeclSpecs[*]::BuiltinType[@Spec=KTC_BUILTINTYPE_VOID | @Spec=KTC_BUILTINTYPE_CHAR]
static char foo1() {
}
void foo2() {
}
int foo3() {
}
Find inline function declarations that return "void"
//FuncDef[DeclSpecs[*]::BuiltinType[@Spec=KTC_BUILTINTYPE_VOID]][DeclSpecs[*]::FuncSpec[@Spec=KTC_FUNCSPECIFIER_INLINE]]@Spec=KTC_BUILTINTYPE_CHAR]
inline void foo() { // will match
}
static void foo1() { // will not match
}
inline char foo2() { // will not match
}
void foo3() { // will not match
}
Find functions whose declarations use formal parameter with names and without
//FuncDeclarator[Params[*]::Decl[InitDeclarators[*]::InitDeclarator[Declarator::Declarator[DirectDeclarator::DirectDeclarator]]]][Params[*]::Decl[not InitDeclarators[*]::InitDeclarator[Declarator::Declarator[DirectDeclarator::DirectDeclarator]]]]
// will not match
void f();
// will not match
void fu(int, const char *);
// will not match
void fn(int id, const char *name);
// will match
void fx1(int id, const char *);
// will match
void fx2(int, const char *name);
Every non-empty case clause in a switch statement shall be terminated with a break statement
// LabeledStmt [not descendant::BreakStmt] [not following-sibling[*]::BreakStmt]
void test193()
{
- int x = 0;
- switch (x)
- {
- case 0:
- break;
- case 1:
- case 2:
- break;
- case 3:
- 4+5; // MATCHES
- default:
- // MATCHES
- }
- switch (x)
- {
- case 0:
- break;
- case 1:
- case 2:
- break;
- case 4:
- x = 0;
- break;
- default:
- break;
- }
- int i=0;
- switch(i)
- {
- case 0 :
- i++; // MATCHES
- case 1 :
- i++;
- break;
- case 3 :
- case 4 :
- break;
- case 5:
- i++; // MATCHES
- case 8:{
- i++; // MATCHES
- }
- case 9:{
- } // MATCHES
- default:{
- } // MATCHES
- }
}
Floating point variables shall not be used as loop counters
// ForStmt [ Init::ExprStmt [ descendant::IdExpr [isFloatPoint()] ] ]
void test197()
{
- int y,i,x = 0;
- float j,x1 = 0;
}
- for (x = 0; x < y; x = y++);
- for (x1 = 0; x < 15; x++); // MATCHES
- for (x1 = 0; x < j; x++); // MATCHES
- for (x1 = 0; x < j; x = j++); // MATCHES
- for (x = 0; i < 15; i++);
All letters contained in function and variable names will be composed entirely of lowercase letters
// Declarator [isVariable() | isFunction()] [$name:=getName()] [$name.contains('A') | $name.contains('A') | $name.contains('B') | $name.contains('C') | $name.contains('D') | $name.contains('E') | $name.contains('F') | $name.contains('G') | $name.contains('H') | $name.contains('I') | $name.contains('J') | $name.contains('K') | $name.contains('L') | $name.contains('M') | $name.contains('N') | $name.contains('O') | $name.contains('P') | $name.contains('Q') | $name.contains('R') | $name.contains('S') | $name.contains('T') | $name.contains('U') | $name.contains('V') | $name.contains('W') | $name.contains('X') | $name.contains('Y') | $name.contains('Z') ]
class C
{
};
- int f;
- int g;
- int H; // MATCHES
- int MLK; // MATCHES
struct sD{};
struct SDKJSDF{};
extern void xY; // MATCHES
void test051();
void teSt051(); // MATCHES
void teSt051() // MATCHES
{
}
- int abcd;
- int ABXY; // MATCHES
- int Abyy; // MATCHES
- int aCCCC; // MATCHES
- double z_Y_k; // MATCHES
Finding unnecessary negative value testing for unsigned integers
// BinaryExpr [ Op::Op [@Code=KTC_OPCODE_GE | @Code=KTC_OPCODE_LE | @Code=KTC_OPCODE_LT] ] [Left.isUnsigned()] [Right.getIntValue() = 0]
void testUnsignedNegative()
{
- unsigned int abc;
- if (abc < 0); // MATCHES
- while (abc >= 0); // MATCHES
}
- if (abc <= 0); // MATCHES
Any label referenced by a goto statement shall be declared in the same block, or in a block enclosing the goto statement
// Label [$name:=@Id] [ancestor::CompoundStmt [$par:=parent::Node.name()] ] [ ancestor::FuncDef [descendant::GotoStmt [@Label=$name] [ancestor::CompoundStmt [parent::Node.name()!=$par] ] ] ]
void test6_6_1()
{
- int j = 0;
- goto L1;
L1: // MATCHES
- for (j = 0; j < 10; ++j)
- {
}
- j;
- }
void test6_6_1x()
{
- int j = 0;
- goto L2;
L2:
- for (j = 0; j < 10; ++j)
- {
- }
}
- j;
Any label referenced by a goto statement shall be declared in the same block, or in a block enclosing the goto statement
// InitDeclarator [isTypedef()] [$type:=getTypeName()] [$s:=getSemanticInfo()] [ancestor::TranslationUnit [descendant::InitDeclarator [isTypedef()] [getTypeName()=$type] [getSemanticInfo()!=$s] ] ]
void test5_3()
{
- {
- typedef unsigned char uint8_t;
- }
}
- {
- typedef signed char uint8_t; // MATCHES
- }
A wider integer type may not be assigned to a narrower integer type
// BinaryExpr [ Op::Op [@Code=KTC_OPCODE_ASSIGN] ] [ Left.getTypeSize() < Right.getTypeSize() ]
void testGetTypeSize()
{
- long int a;
- short int x;
}
- x = a; // MATCHES
An assignment operator shall be declared for classes that contain pointers to data items or nontrivial destructors
// MemberDeclarator [isPointer()] [ancestor::ClassType [ not descendant::MemberFunc [isAssignmentOperator()] ] ]
class Matrix
{
- Matrix()
- {
- }
- Matrix & operator = (const Matrix & other)
- {
- }
- Matrix (Matrix &other)
- {
- }
};
- private:
- int *p;
- int x[];
class X
{
- X()
- {
- }
};
- private:
- int *p; // MATCHES
- int x[];
class P
{
- P()
- {
- }
- P (P &other)
- {
- }
};
- private:
- int *p; // MATCHES
- int x[];
A copy constructor shall be declared for classes that contain pointers to data items or nontrivial destructors
// MemberDeclarator [isPointer()] [ancestor::ClassType [ not descendant::MemberFunc [isCopyConstructor()] ] ]
class Matrix
{
- Matrix()
- {
- }
- Matrix & operator = (const Matrix & other)
- {
- }
- Matrix (Matrix &other)
- {
- }
};
- private:
- int *p;
- int x[];
class X
{
- X()
- {
- }
};
- private:
- int *p; // MATCHES
- int x[];
class Y
{
- Y()
- {
- }
- Y & operator = (const Y & other)
- {
- }
};
- private:
- int *p; // MATCHES (2)
- int x[];
Multi-byte characters and wide string literals will not be used
// InitDeclarator [getTypeName()='wchar_t'] [isBuiltinType()]
void test013()
{
}
- wchar_t x; // MATCHES
- char y;
- int j;
- wchar_t f; // MATCHES
A class, or structure will not be declared in the definition of its type
// InitDeclarator [isClass()] [parent::Decl/DeclSpecs[*]::ClassType]
struct S
{
} s; // MATCHES
struct D
{
};
D d;
class C
{
} s; // MATCHES
class F
{
};
F f;
class X
{
};
A class's virtual functions shall not be invoked from its destructor or any of its constructors
// CallExpr [ Func::IdExpr [isClassMember()] [isVirtual()] ] [ ancestor::FuncDef [isConstructor() | isDestructor()] ]
class base
{
public:
};
- base(int, int);
- ~base();
- void xyz();
- virtual void display()
- {
- int x = 5;
- }
base::base (int a, int b)
{
}
- display(); // MATCHES
- xyz();
base::~base()
{
}
- display(); // MATCHES
- xyz();
class derived : public base
{
public:
};
- void display()
- {
- int y = 0;
- }
void main()
{
}
- base *ptr = new derived();
- ptr->display();
An enum will not be declared in the definition of its type
// InitDeclarator [isEnum()] [parent::Decl/DeclSpecs[*]::EnumType]
enum
{
} direction; // MATCHES
- up,
- down
enum i { in, out } i; // MATCHES
enum XYZ_direction
{
};
- up,
- down
XYZ_direction direction;
class X
{
};
- enum
- {
- max_length = 100,
- max_time = 73
- };
All declarations at file scope should be static where possible
// Declarator [not isStatic()] [isGlobal()]
int x; // MATCHES
int y; // MATCHES
int z; // MATCHES
static int h;
const int n = 5; // const static by default when global
struct S{} static s;
class C{} c; // MATCHES
void test() // MATCHES
{
}
- int a;
- int b;
Trivial forwarding functions should be inlined
// FuncDef [not isInline()] [FuncBody::FuncBody/Stmt::CompoundStmt/Stmts[2]::Null]
int safe() // MATCHES
{
}
- return 0;
int getVal() // MATCHES
{
}
- return safe();
inline int getValue()
{
}
- return safe();
inline int abc()
{
}
- int x = 5;
- x = 2;
- x = 1;
- x++;
- return 0;
int cde()
{
}
- int x = 5;
- x = 2;
- x = 1;
- x++;
- return 0;
A class must not overload the greater than operator function
// FuncDeclarator [isOpFunc()] [descendant::OpFunc [Op::Op [@Code=KTC_OPCODE_GT] ] ]
class Matrix
{
- Matrix()
- {
- }
};
- Matrix & operator> (const Matrix & other)
- {
- }
The volatile keyword shall not be used
// Declarator [isVolatile()]
void test205()
{
}
- volatile int x;
- int y;
- int j;
- volatile int a,b,c; // MATCHES three times
User-specified identifiers (internal and external) will not rely on significance of more than 10 characters
// DirectDeclarator [getName().length() > 10]
extern int alskfdiwoueroiweuroiweurweoriuweoriuweroiwuero; // MATCHES
extern int kjkjkje01;
void test046()
{
- int xcljkfsdlkjfsdlkfjsdl43534534534534534534534 = 0; // MATCHES
- xcljkfsdlkjfsdlkfjsdl43534534534sfdsflkjsdf = 5;
- int abcddde = 5;
- abcddde = 20;
- int x;
- x = 0;
}
- int lkajsdflksjflksjfwiuwoe31, lkasdjkffls45515j; // MATCHES twice
Documentation for custom C/C++ KAST checkers
Overview
How-to
Tutorials
- Tutorial 1 - Creating a C/C++ KAST checker
- Tutorial 2 - Creating a C/C++ KAST checker with built-in functions
- Tutorial 3 - Creating a C/C++ KAST checker with custom functions
- Creating and testing C/C++ KAST custom functions
Examples
- C/C++ KAST examples
Deployment
Reference


