C/C++ KAST examplesC/C++ KAST examplesThe following examples describe common C/C++ KAST expressions. Overparenthesized expression// ParensExpr / Expr:: { ParensExpr/Expr:: } ParensExpr 1 int f(int i) { 2 return ((i+1)) /2; 3 } 4 5 int g(int n) { 6 return ((i+1)) /2; 7 } Note: Use the "sequence of 0 or more children" modifier ({}) to match a chain of child AST nodes.
Find all static functions// FuncDeclarator [ isStatic() ] 1 //finds this function 2 static void f() { 3 /*code*/ 4 } 5 6 // and this one 7 static void h() { 8 /*code*/ 9 } 10 11 class C { 12 public: 13 // find this function as well 14 static void m() { 15 /*code*/ 16 } 17 }; Find all definitions of static functions// FuncDeclarator [ isStatic() ] [ isDefinition() ] 1 //finds this function 2 static void f() { 3 /*code*/ 4 } 5 6 // and this one 7 static void h() { 8 /*code*/ 9 } 10 11 class C { 12 public: 13 // find this function as well 14 static void m() { 15 /*code*/ 16 } 17 }; Find all definitions of functions whose return type is a pointer// PtrDeclarator [ isFunction() ] [ isDefinition() ] [ @Spec = KTC_POINTEROPERATOR_POINTER ] 1 // finds this 2 void *foo() { 3 4 /*code*/ 5 } 6 7 // and this 8 FILE *xfo(const char *name) { 9 10 /*code*/ 11 } // no match - returns reference, not pointer 12 13 int &getir(unsigned key) { 14 15 /*code*/ 16 } 17 18 // no match 19 int boo() { 20 21 /*code*/ 22 } Find all functions whose return type is not a pointer// FuncDeclarator [ not parent::PtrDeclarator | parent::PtrDeclarator [ @Spec != KTC_POINTEROPERATOR_POINTER ] ] 1 // no match - returns pointer 2 void *foo() { 3 4 /*code*/ 5 } 6 // no match - returns pointer 7 FILE *xfo(const char *name) { 8 9 /*code*/ 10 } 11 12 // finds this - returns reference, not a pointer 13 int &getir(unsigned key) { 14 15 /*code*/ 16 } 17 18 // and this 19 int boo() { 20 21 /*code*/ 22 } Note: Use the not operator to negate the result of a predicate.
Find definitions of all non-member functions that use void in return typeThis refers to functions such as void functions and functions returning pointer to void. // FuncDef [ DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ] ] 1 // finds this function 2 void printMe() { } // and this one 3 inline void *getAddress() { } // no match - not void 4 int getCount() { } // no match - not void 5 static FILE *openFile() { } Note: Use the "any element" modifier ([*]) to check if a sequence of AST nodes contains a node of specified type.
Note: This pattern is applicable to definitions of non-member functions, but not for definitions of class methods. To catch method definitions that use void in their return types, modify this pattern replacing "FuncDef" with "MemberFunc".
Find all void functions// FuncDeclarator [ parent::DeclOrStmt / DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ] ] 1 // find this function 2 void f() { } // and this one static 3 void g() { } // no match - return type is not void 4 inline int h() { 5 6 return 0; 7 } // no match - return type is a pointer to void 8 9 void *j() { 10 11 return NULL; 12 } Find all static member functions// FuncDeclarator [ isClassMember() ] [ isStatic() ] 1 class C { 2 public: 3 4 // finds this function 5 static void m() { 6 /*code*/ 7 } 8 }; 9 // but not this one - not a member 10 static void f() { } Find all anonymous enums// EnumType [ Name::Null ] 1 // finds this enum 2 typedef enum { 3 4 VALUE_0, 5 VALUE_1 6 } anonymousEnum; 7 8 // but not this one 9 enum aEnum{ 10 11 INT_VALUE_0 = 0, 12 INT_VALUE_1 = 1 13 }; Note: Use Null to indicate a missing child of an AST node.
Find all anonymous unions// ClassType [ @Tag = KTC_CLASSTAG_UNION ] [ Name::Null ] 1 struct S { 2 // finds this union 3 union { 4 short s; 5 int i; 6 long l; 7 } 8 n; 9 }; // no match - named union 10 union U { 11 12 int i; 13 void *p; 14 }; Find non-template functions// FuncDeclarator [ not isTemplate() ] [ not getParent().isTemplate() ] [ not getParent().getParent().isSpecialization() ] 1 // no match - template function 2 template<> 3 void f() { } 4 template<> 5 class C { 6 public: 7 8 // no match - member of template class 9 void m() { 10 // ... 11 } 12 }; 13 class D { 14 public: 15 16 // finds this member function 17 void n1() { 18 } 19 // no match - member template 20 template<> 21 void n2() { 22 /*code*/ 23 } 24 }; 25 // finds this function 26 void g() { 27 28 /*code*/ 29 } Find all assignment expressions// BinaryExpr [ getOperationCode() = KTC_OPCODE_ASSIGN ] 1 void f() { 2 char *p; 3 // ... 4 p = "boo!"; 5 } Cast expression as lvalue// BinaryExpr [ getOperationCode() = KTC_OPCODE_ASSIGN ] / Left::CastExpr 1 void f() { 2 int *p; 3 // ... 4 (char *) p = "boo!"; 5 } Find functions that are syntactically declared within a namespace// FuncDeclarator [ ancestor::NamespaceDecl ] 1 namespace my { 2 // finds this 3 void f(); 4 } 5 namespace their { 6 // and finds these two functions 7 int f1(int), f2(int, int); 8 } Find functions that are syntactically declared not within a namespace// FuncDeclarator [ not ancestor::NamespaceDecl ] 1 // finds this 2 void f(); 3 namespace xn { 4 5 // no match - within a namespace 6 void f(); 7 } Find functions that are syntactically declared in an anonymous namespace// FuncDeclarator [ ancestor::NamespaceDecl [ @Id =] ] 1 namespace { 2 // finds this 3 void f(); 4 } 5 namespace my { 6 // no match - namespace has name 7 void f(); 8 } 9 // no match - on the global level 10 void f(); Find declarations of all non-static variables that are not part of any namespace ("global" variables)// NameDeclarator [ isVariable() ] [ isGlobal() ] [ not isStatic() ] 1 namespace n { 2 // no match - variable in namespace; 3 int a; 4 } // no match - static variable static 5 6 int b; // no match - not a variable 7 void f(); // finds this variable 8 extern int c; Find all classes whose name does not start with uppercase letter//ClassType [ isDefinition() ][ not getName().starts-from-capital() ] 1 class A { }; 2 // finds this class 3 class b { }; 4 struct C { 5 6 // and this union 7 union x { 8 }; 9 }; Find all non-public member variables whose name does not start from "m_"// NameDeclarator [ isClassMember() ] [ isVariable() ] [ not isPublic() ] [ not getName().starts-with('m_') ] 1 class C { 2 public: 3 4 // no match - public member 5 static int count; 6 protected: 7 8 // no match - starts with "m_" 9 char *m_data; 10 // finds this member variable 11 int length; 12 }; Find all destructor declarations// MemberDecl / Declarators[*]::AnyDeclarator [ isDestructor() ] 1 class C { 2 ~C(); 3 }; 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 [ isDestructor() ] 1 class C { 2 ~C() {} 3 }; Note: Use the isDestructor() predicate to check if an AST node declares a destructor.
Find classes with non-virtual destructor// ClassType [ MemberDecls[*]::MemberDecl / Declarators[*]::AnyDeclarator [ isDestructor() ] [ not isVirtual() ] ] // ClassType [ MemberDecls[*]::MemberFunc [ isDestructor() ] [ not isVirtual() ] ] 1 //Find classes with non-virtual destructor 2 // this class matches 3 class A { 4 public: 5 ~A(); 6 }; 7 // this one matches too 8 class B { 9 public: 10 ~B() {} 11 }; 12 // this class doesn't match - its destructor is virtual 13 class C { 14 public: 15 virtual ~C() {} 16 }; Find cases where a boolean value is incremented or decremented// UnaryExpr [ getOperationCode() = KTC_OPCODE_PREINC | getOperationCode() = KTC_OPCODE_POSTINC | getOperationCode() = KTC_OPCODE_PREDEC | getOperationCode() = KTC_OPCODE_POSTDEC ] [ Expr.isBoolean() ] 1 int main() { 2 bool bFlag = true; 3 // matches all of the following expressions 4 bFlag++; 5 bFlag--; 6 --bFlag; 7 ++bFlag; 8 return 0; 9 } Find labels followed by a "}" (empty labeled statements)// LabeledStmt [ Stmt::Null ] 1 int main(int argc, char** argv) { 2 if (argc < 3) { 3 return 1; 4 myLabel: /* empty labeled statement will be matched here */ 5 } 6 return 0; 7 } Find 'typedef's that do not define anything// Decl [ DeclSpecs[*]::StorageClass [ @Spec = KTC_STORAGECLASS_TYPEDEF ] ] [ not Declarators[0]:: { AnyDeclarator / Declarator:: } NameDeclarator ] /* 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// BitFieldDeclarator [ Bits::LiteralExpr.getIntValue() = 1 ] [ isSigned() ] 1 struct MT { 2 int ii: 1; 3 signed int si: 1; 4 }; 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] 1 void foo(int c) { 2 switch (c) { 3 case 1: bar(); /* constant is used for a selector */ 4 break; 5 default: baz(); 6 } 7 } 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 1 void foo(boolean b) { 2 if (b) { 3 /* code */ 4 } 5 } Find IF statements with THEN branch containing at least one executable statement// IfStmt [ Then::CompoundStmt / Stmts[*]::ExprStmt | Then::ExprStmt ] 1 void foo(boolean b) { 2 if (b) { // match this one 3 printf("IfStatement"); 4 } 5 if (b) { // match this one 6 printf("IfStatement: Then"); 7 } 8 else { 9 printf("IfStatement: Else"); 10 } 11 if (b) { // do not match this one 12 /* no code */ 13 } 14 } Find IF statements with no ELSE branch// IfStmt [ Else::Null ] 1 void foo(boolean b) { 2 if (b) { // find this one 3 /* code */ 4 } 5 if (b) { // do not match this one 6 /* code */ 7 } else { 8 /* code */ 9 } 10 } Find binary "+" expressions// BinaryExpr [ getOperationCode() = KTC_OPCODE_ADD ] 1 void foo(booleanint a, int b) { 2 int c = a + b; // match this one 3 c = ++b; // do not match 4 c = a / b; // do not match 5 } Find calls to "gets"// CallExpr / Func::IdExpr / Name::Name [ @Id = 'gets' ] 1 int main() { 2 3 char string [256]; 4 printf ("Insert your full address: "); 5 gets (string); 6 printf ("Your address is: %s\n",string); 7 return 0; 8 } Find functions that return "void"// FuncDeclarator [ parent::* [ DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ] ] ] 1 static void foo() { 2 /* code */ 3 } 4 5 void foo2() { } Find functions that return "void" or "char"// FuncDeclarator [ $ret_type := getReturnType().getTypeName() ] [ $ret_type = 'void' | $ret_type = 'char' ] 1 static char foo1() { 2 } 3 void foo2() { } 4 int foo3() { } Find inline void functions// FuncDeclarator [ parent::* [ DeclSpecs[*]::BuiltinType [ @Spec = KTC_BUILTINTYPE_VOID ] ] ] [ isInline() ] 1 inline void foo() { // will match 2 } 3 static void foo1() { // will not match 4 } 5 inline char foo2() { // will not match 6 } 7 void foo3() { // will not match 8 } Find functions whose declarations use formal parameter with names and without//FuncDeclarator [ Params[*]::Decl [ Declarators[*]:: { AnyDeclarator / Declarator:: } NameDeclarator ] ] [ Params[*]::Decl [ not Declarators[*]:: { AnyDeclarator / Declarator:: } NameDeclarator ] ] 1 void f(); // will not match 2 void fu(int, const char *); // will not match 3 void fn(int id, const char *name); // will not match 4 void fx1(int id, const char *); // will match 5 void fx2(int, const char *name); // will match Every non-empty clause in a switch statement shall be terminated with a break statement// LabeledStmt [ Label::CaseLabel | Label::CaseRangeLabel | Label::DefaultLabel ] [ not parent::LabeledStmt [ Label::CaseLabel | Label::CaseRangeLabel | Label::DefaultLabel ] ] [ Stmt::CompoundStmt [ not descendant::BreakStmt ] [ not descendant::ThrowExpr ] [ not descendant::ReturnStmt ] | Stmt::LabeledStmt [ not Stmt::Null ] [ not descendant::BreakStmt ] [ not descendant::ThrowExpr ] [ not descendant::ReturnStmt ] | Stmt::* [ name() != 'CompoundStmt' ] [ name() != 'BreakStmt' ] [ name() != 'ReturnStmt' ] [ name() != 'LabeledStmt' ] [ not descendant::ThrowExpr ] | Stmt::Null ] [ next-sibling:: { * [ name() != 'BreakStmt' ] [ name() != 'ReturnStmt' ] [ not descendant::ThrowExpr ] / next-sibling:: } LabeledStmt [ Label::CaseLabel | Label::CaseRangeLabel | Label::DefaultLabel ] | next-sibling:: { * [ name() != 'BreakStmt' ] [ name() != 'ReturnStmt' ] [ not descendant::ThrowExpr ] / next-sibling:: } Null ] 1 void test193() 2 { 3 int x = 0; 4 switch (x) 5 { 6 case 0: 7 break; 8 9 case 1: 10 11 case 2: 12 break; 13 14 case 3: 15 4+5; // MATCHES 16 17 default: 18 // MATCHES 19 } 20 switch (x) 21 { 22 case 0: 23 break; 24 25 case 1: 26 27 case 2: 28 break; 29 30 case 4: 31 x = 0; 32 break; 33 34 default: 35 break; 36 } 37 int i=0; 38 switch(i) 39 { 40 case 0 : 41 i++; // MATCHES 42 43 case 1 : 44 i++; 45 break; 46 47 case 3 : 48 49 case 4 : 50 break; 51 52 case 5: 53 i++; // MATCHES 54 55 case 8:{ 56 i++; // MATCHES 57 } 58 59 case 9:{ 60 } // MATCHES 61 62 default:{ 63 } // MATCHES 64 } 65 } Floating point variables shall not be used as loop counters// ForStmt [ Init::ExprStmt [ descendant::IdExpr [ isFloatPoint() ] ] ] 1 void test197() 2 { 3 int y,i,x = 0; 4 float j,x1 = 0; 5 for (x = 0; x < y; x = y++); 6 for (x1 = 0; x < 15; x++); // MATCHES 7 for (x1 = 0; x < j; x++); // MATCHES 8 for (x1 = 0; x < j; x = j++); // MATCHES 9 for (x = 0; i < 15; i++); 10 } All letters contained in function and variable names will be composed entirely of lowercase letters// NameDeclarator [ isVariable() | isFunction() ] [ getName().matches('[A-Z]') ] 1 class C { 2 3 int f; 4 int g; 5 int H; // MATCHES 6 int MLK; // MATCHES 7 }; 8 9 struct sD{}; struct SDKJSDF{}; extern void xY; // MATCHES 10 void test051(); void teSt051(); // MATCHES 11 void teSt051() { // MATCHES 12 13 int abcd; 14 int ABXY; // MATCHES 15 int Abyy; // MATCHES 16 int aCCCC; // MATCHES 17 double z_Y_k; // MATCHES 18 } Finding unnecessary negative value testing for unsigned integers// BinaryExpr [ getOperationCode() = KTC_OPCODE_GE | getOperationCode() = KTC_OPCODE_LT ] [ Left.isUnsigned() ] [ Right.getIntValue() = 0 ] 1 void testUnsignedNegative() 2 { 3 unsigned int abc; 4 if (abc < 0); // MATCHES 5 while (abc >= 0); // MATCHES 6 } Any label referenced by a goto statement is declared in the same block, or in a block enclosing the goto statement// Label [ $lname := @Id ] [ parent:: { * [ name() != 'CompoundStmt' ] / parent:: } CompoundStmt [ $container := this() ] / ancestor::FuncBody / descendant::GotoStmt [ @Label = $lname ] [ not ancestor::CompoundStmt [ this() = $container ] ] ] 1 void test6_6_1() 2 { 3 4 int j = 0; 5 goto L1; 6 for (j = 0; j < 10; ++j) L1: // MATCHES 7 j; 8 } 9 10 void test6_6_1x() { 11 12 int j = 0; 13 goto L2; 14 for (j = 0; j < 10; ++j) 15 { 16 L2: 17 j; 18 } 19 } A wider integer type may not be assigned to a narrower integer type// BinaryExpr [ getOperationCode() = KTC_OPCODE_ASSIGN ] [ Left.getTypeSize() < Right.getTypeSize() ] 1 void testGetTypeSize() 2 { 3 4 long int a; 5 short int x; 6 x = a; // MATCHES 7 } An assignment operator shall be declared for classes that contain pointers to data items// NameDeclarator [ isPointer() ] [ $ptr_dcl := getParent() ] [ ancestor::ClassType [ getSemanticInfo() = $ptr_dcl ] [ not descendant::NameDeclarator [ isAssignmentOperator() ] ] ] 1 class Matrix { 2 Matrix() 3 Matrix & operator = (const Matrix & other) 4 Matrix (Matrix &other) 5 private: 6 int *p; 7 int x[]; 8 }; 9 10 class X { 11 X() 12 private: 13 int *p; // MATCHES 14 int x[]; 15 }; 16 17 class P { 18 P() 19 P (P &other) 20 private: 21 int *p; // MATCHES 22 int x[]; 23 }; A copy constructor shall be declared for classes that contain pointers to data items// NameDeclarator [ isPointer() ] [ $ptr_dcl := getParent() ] [ ancestor::ClassType [ getSemanticInfo() = $ptr_dcl ] [ not descendant::NameDeclarator [ isCopyConstructor() ] ] ] 1 class Matrix { 2 Matrix() 3 Matrix & operator = (const Matrix & other) 4 Matrix (Matrix &other) 5 private: 6 int *p; 7 int x[]; 8 }; 9 10 class X { 11 X() 12 private: 13 int *p; // MATCHES 14 int x[]; 15 }; 16 17 class Y { 18 Y() 19 Y & operator = (const Y & other) 20 private: 21 int *p; // MATCHES (2) 22 int x[]; 23 }; Builtin type "wchar_t" will not be used// BuiltinType [ @Spec = KTC_BUILTINTYPE_WCHAR_T ] 1 void test013() 2 { 3 wchar_t x; // MATCHES 4 char y; 5 int j; 6 wchar_t *f; // MATCHES 7 } A class, or structure will not be declared in the definition of its type// AnyDeclarator [ isClass() ] [ parent::Decl / DeclSpecs[*]::ClassType | parent::MemberDecl / DeclSpecs[*]::ClassType] 1 struct S 2 { } s; // MATCHES 3 struct D { }; 4 D d; 5 class C { } s; // MATCHES 6 class F { }; 7 F f; 8 class X { }; A class's virtual functions shall not be invoked from its destructor or any of its constructors// CallExpr [ isClassMember() ] [ isVirtual() ] [ ancestor::FuncBody / parent::* [ isConstructor() | isDestructor() ] ] 1 class base{ 2 public: 3 base(int, int); 4 ~base(); 5 void xyz(); 6 virtual void display() 7 int x = 5; 8 }; 9 10 base::base (int a, int b) { 11 display(); // MATCHES 12 xyz(); 13 } 14 base::~base() { 15 display(); // MATCHES 16 xyz(); 17 } 18 class derived : public base { 19 20 public: 21 void display() 22 int y = 0; 23 }; 24 25 void main() { 26 base *ptr = new derived(); 27 ptr->display(); 28 } An enum will not be declared in the definition of its type// AnyDeclarator [ isEnum() ] [ parent::Decl / DeclSpecs[*]::EnumType ] 1 enum 2 { 3 4 up, 5 down 6 } 7 direction; // MATCHES 8 enum i { in, out } i; // MATCHES 9 enum XYZ_direction { up, down }; 10 XYZ_direction direction; 11 class X { 12 13 enum 14 max_length = 100, 15 max_time = 73 16 }; All declarations at file scope should be static where possible// NameDeclarator [ not isStatic() ] [ isGlobal() ] 1 int x; // MATCHES 2 int y; // MATCHES 3 int z; // MATCHES 4 static int h; 5 const int n = 5; // const static by default when global 6 struct S{} static s; 7 class C{} c; // MATCHES 8 void test() // MATCHES 9 { 10 int a; 11 int b; 12 } Trivial forwarding functions should be inlined// FuncDef [ not isInline() ] [ FuncBody::FuncBody / Stmt::CompoundStmt [ Stmts[0]::ReturnStmt ] [ Stmts[1]::Null ] ] 1 int safe() // MATCHES { 2 return 0; 3 } 4 int getVal() // MATCHES { 5 return safe(); 6 } 7 inline int getValue() { 8 return safe(); 9 } 10 inline int abc() { 11 int x = 5; 12 x = 2; 13 x = 1; 14 x++; 15 return 0; 16 } 17 int cde() { 18 int x = 5; 19 x = 2; 20 x = 1; 21 x++; 22 return 0; 23 } A class must not overload the greater than operator function// FuncDeclarator [ isOpFunc() ] [ descendant::OpFunc [ getOperationCode() = KTC_OPCODE_GT ] ] 1 class Matrix 2 { 3 Matrix() 4 Matrix & operator> (const Matrix & other) 5 }; The volatile keyword shall not be used// CVQualifier [ @Spec = KTC_CVQUALIFIER_VOLATILE ] 1 void test205() 2 { 3 volatile int *x; 4 int y; 5 int j; 6 volatile int a,b,c; // MATCHES three times 7 } User-specified identifiers (internal and external) will not rely on significance of more than 10 characters// NameDeclarator [ getName().length() > 10 ] 1 extern int alskfdiwoueroiweuroiweurweoriuweoriuweroiwuero; // MATCHES 2 extern int kjkjkje01; 3 4 void test046() { 5 int xcljkfsdlkjfsdlkfjsdl43534534534534534534534 = 0; // MATCHES 6 xcljkfsdlkjfsdlkfjsdl43534534534sfdsflkjsdf = 5; 7 int abcddde = 5; 8 abcddde = 20; 9 int x; 10 x = 0; 11 int lkajsdflksjflksjfwiuwoe31, lkasdjkffls45515j; // MATCHES twice 12 } |