From c6a29e5e8aa2fcd422c28499de5e3ba97b27666f Mon Sep 17 00:00:00 2001 From: Dino Distefano Date: Tue, 9 May 2017 10:41:54 -0700 Subject: [PATCH] Adding more builtin type to parser Reviewed By: dulmarod Differential Revision: D5027944 fbshipit-source-id: 050c44c --- infer/src/clang/cPredicates.ml | 30 +---- infer/src/clang/ctl_parser_types.ml | 123 ++++++++++++++++++ infer/src/clang/types_lexer.mll | 12 ++ infer/src/clang/types_parser.mly | 83 +++++++++--- .../objc/linters-for-test-only/issues.exp | 23 ++++ .../linters-for-test-only/linters_example.al | 32 +++++ .../objc/linters-for-test-only/subclassing.m | 33 ++++- 7 files changed, 295 insertions(+), 41 deletions(-) diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index 8fba90657..717a67120 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -346,28 +346,6 @@ let decl_unavailable_in_supported_ios_sdk (cxt : CLintersContext.context) an = | _ -> false -(* Temporary, partial equality function. Cover only what's covered - by the types_parser. It needs to be replaced by a real - comparison function for Clang_ast_t.c_type *) -let tmp_c_type_equal t1 t2 = - let open Clang_ast_t in - match t1, t2 with - | BuiltinType(_ , `Char_U), BuiltinType(_ , `Char_U) - | BuiltinType(_, `Char16), BuiltinType(_, `Char16) - | BuiltinType(_, `Char32), BuiltinType(_, `Char32) - | BuiltinType(_, `WChar_U), BuiltinType(_, `WChar_U) - | BuiltinType(_, `Bool), BuiltinType(_, `Bool) - | BuiltinType(_, `Short), BuiltinType(_, `Short) - | BuiltinType(_, `Int), BuiltinType(_, `Int) - | BuiltinType(_, `Long), BuiltinType(_, `Long) - | BuiltinType(_, `Float), BuiltinType(_, `Float) - | BuiltinType(_, `Double), BuiltinType(_, `Double) - | BuiltinType(_, `Void), BuiltinType(_, `Void) -> true - | BuiltinType(_, _), BuiltinType(_, _) -> false - | _, _ -> failwith ("[ERROR]: Cannot compare types. Cannot continue...") - - - (* Check whether a type_ptr and a string denote the same type *) let type_ptr_equal_type type_ptr type_str = let pos_str lexbuf = @@ -375,8 +353,8 @@ let type_ptr_equal_type type_ptr type_str = pos.pos_fname ^ ":" ^ (string_of_int pos.pos_lnum) ^ ":" ^ (string_of_int (pos.pos_cnum - pos.pos_bol + 1)) in let lexbuf = Lexing.from_string type_str in - let c_type = try - (Types_parser.ctype_specifier token lexbuf) + let abs_ctype = try + (Types_parser.ctype_specifier_seq token lexbuf) with | Ctl_parser_types.ALParsingException s -> raise (Ctl_parser_types.ALParsingException @@ -386,7 +364,9 @@ let type_ptr_equal_type type_ptr type_str = raise (Ctl_parser_types.ALParsingException ("SYNTAX ERROR at " ^ (pos_str lexbuf))) in match CAst_utils.get_type type_ptr with - | Some c_type' -> tmp_c_type_equal c_type c_type' + | Some c_type' -> + let name = Clang_ast_extend.type_ptr_to_string type_ptr in + Ctl_parser_types.tmp_c_type_equal ~name_c_type:name c_type' abs_ctype | _ -> Logging.out "Couldn't find type....\n"; false diff --git a/infer/src/clang/ctl_parser_types.ml b/infer/src/clang/ctl_parser_types.ml index fbb988830..b5a128824 100644 --- a/infer/src/clang/ctl_parser_types.ml +++ b/infer/src/clang/ctl_parser_types.ml @@ -26,3 +26,126 @@ let severity_const = "severity" let mode_const = "mode" exception ALParsingException of string + + +(* Data structures for type parser. + Correspondence with clang types inferred from + StringRef BuiltinType::getName in + https://clang.llvm.org/doxygen/Type_8cpp_source.html +*) +type builtin_kind = + | Void (* void *) + | Bool (* bool *) + | Char_U (* char *) + | UChar (* unsigned char *) + | WChar_U (* wchar_t *) + | Char16 (* char16_t *) + | Char32 (* char32_t *) + | UShort (* unsigned short *) + | UInt (* unsigned int *) + | ULong (* unsigned long *) + | ULongLong (* unsigned long long *) + | Int128 (* __int128 *) + | UInt128 (* unsigned __int128 *) + | SChar (* signed char *) + | Short (* short *) + | Int (* int *) + | Long (* long *) + | LongLong (* long long *) + | Half (* half of __fp16 *) + | Float (* float *) + | Double (* double *) + | LongDouble (* long double *) + | Float128 (* __float128 *) + | NullPtr (* nullptr_t *) + | ObjCId (* id *) + | ObjCClass (* Class *) + | ObjCSel (* SEL *) +(* | OCLSampler | OCLEvent | OCLClkEvent | OCLQueue | OCLNDRange + | OCLReserveID | Dependent | Overload | BoundMember | PseudoObject + | UnknownAny | BuiltinFn | ARCUnbridgedCast | OMPArraySection *) + +let builtin_kind_to_string t = + match t with + | Char_U -> "char" + | Char16 -> "char16_t" + | Char32 -> "char32_t" + | WChar_U -> "wchar_t" + | Bool -> "bool" + | Short -> "short" + | Int -> "int" + | Long -> "long" + | Float -> "float" + | Double -> "double" + | Void -> "void" + | SChar -> "signed char"; + | LongLong -> "long long"; + | UChar -> "unsigned char"; + | UShort -> "unsigned short"; + | UInt -> "unsigned int"; + | ULong -> "unsigned long"; + | ULongLong -> "unsigned long long"; + | LongDouble -> "long double"; + | Int128 -> "__int128" + | Float128 -> "__float128" + | UInt128 -> "unsigned __int128" + | Half -> "half" + | NullPtr -> "nullptr_t" + | ObjCId -> "id" + | ObjCClass -> "Class" + | ObjCSel -> "SEL" + + +type abs_ctype = + | BuiltIn of builtin_kind + +let abs_ctype_to_string t = + match t with + | BuiltIn t' -> "BuiltIn (" ^ (builtin_kind_to_string t') ^ ")" + +(* Temporary, partial equality function. Cover only what's covered + by the types_parser. It needs to be replaced by a real + comparison function for Clang_ast_t.c_type *) +let tmp_c_type_equal ?name_c_type c_type abs_ctype = + let open Clang_ast_t in + match c_type, abs_ctype with + | BuiltinType (_ , `Char_U), BuiltIn (Char_U) + | BuiltinType (_ , `Char_S), BuiltIn (Char_U) + | BuiltinType (_, `Char16), BuiltIn (Char16) + | BuiltinType (_, `Char32), BuiltIn (Char32) + | BuiltinType (_, `WChar_U), BuiltIn (WChar_U) + | BuiltinType (_, `WChar_S), BuiltIn (WChar_U) + | BuiltinType (_, `Bool), BuiltIn (Bool) + | BuiltinType (_, `Short), BuiltIn (Short) + | BuiltinType (_, `Int), BuiltIn (Int) + | BuiltinType (_, `Long), BuiltIn (Long) + | BuiltinType (_, `Float), BuiltIn (Float) + | BuiltinType (_, `Double), BuiltIn (Double) + | BuiltinType (_, `Void), BuiltIn (Void) + | BuiltinType (_, `SChar), BuiltIn (SChar) + | BuiltinType (_, `LongLong), BuiltIn (LongLong) + | BuiltinType (_, `UChar), BuiltIn (UChar) + | BuiltinType (_, `UShort), BuiltIn (UShort) + | BuiltinType (_, `UInt), BuiltIn (UInt) + | BuiltinType (_, `ULong), BuiltIn (ULong) + | BuiltinType (_, `ULongLong), BuiltIn (ULongLong) + | BuiltinType (_, `LongDouble), BuiltIn (LongDouble) + | BuiltinType (_, `Int128), BuiltIn (Int128) + | BuiltinType (_, `UInt128), BuiltIn (UInt128) + | BuiltinType (_, `Float128), BuiltIn (Float128) + | BuiltinType (_, `NullPtr), BuiltIn (NullPtr) + | BuiltinType (_, `ObjCId), BuiltIn (ObjCId) + | BuiltinType (_, `ObjCClass), BuiltIn (ObjCClass) + | BuiltinType (_, `ObjCSel), BuiltIn (ObjCSel) + | BuiltinType (_, `Half), BuiltIn (Half) -> true + | _, _ -> + let name = (match name_c_type with + | None -> "" + | Some n -> n) in + Logging.out + "[WARNING:] Type Comparison failed... \ + This might indicate that the types are different or the specified type \ + is internally represented in a different way and therefore not recognized. \ + Type compared: c_type = `%s` abs_ctype =`%s`\n" + name (abs_ctype_to_string abs_ctype); + false diff --git a/infer/src/clang/types_lexer.mll b/infer/src/clang/types_lexer.mll index 299555f37..d10a365d3 100644 --- a/infer/src/clang/types_lexer.mll +++ b/infer/src/clang/types_lexer.mll @@ -42,4 +42,16 @@ rule token = parse | "float" { FLOAT } | "double" { DOUBLE } | "void" { VOID } + | "signed" { SIGNED } + | "unsigned" { UNSIGNED } + | "__int128" { INT128 } + | "__float128" { FLOAT128 } + | "__wchar_t" { UNDUNDWCHAR_T } + | "half" { HALF } + | "__fp16" { UNDUNDFP16 } + | "nullptr_t" { NULLPTR } + | "id" { OBJCID } + | "Class" { OBJCCLASS } + | "SEL" { OBJCSEL } | _ { raise (SyntaxError ("Unexpected char: '" ^ (Lexing.lexeme lexbuf) ^"'")) } + | eof { EOF } diff --git a/infer/src/clang/types_parser.mly b/infer/src/clang/types_parser.mly index 6fe69700f..3817ffe65 100644 --- a/infer/src/clang/types_parser.mly +++ b/infer/src/clang/types_parser.mly @@ -8,9 +8,25 @@ */ %{ + open Ctl_parser_types + +(* See StringRef BuiltinType::getName in + https://clang.llvm.org/doxygen/Type_8cpp_source.html *) + let tokens_to_abs_types l = + match l with + | [t] -> BuiltIn t + | [Int; Char_U] -> BuiltIn SChar + | [Long; Long] -> BuiltIn LongLong + | [UInt; Char_U] -> BuiltIn UChar + | [UInt; Short] -> BuiltIn UShort + | [UInt; Int] -> BuiltIn UInt + | [UInt; Long] -> BuiltIn ULong + | [UInt; Long; Long] -> BuiltIn ULongLong + | [Long; Double] -> BuiltIn LongDouble + | [UInt; Int128] -> BuiltIn UInt128 + | _ -> raise (Ctl_parser_types.ALParsingException + ("ERROR: syntax error on types")) - let dummy_ptr = { Clang_ast_t.ti_pointer = 0; - Clang_ast_t.ti_desugared_type = None } %} @@ -18,6 +34,7 @@ %token CHAR16_T %token CHAR32_T %token WCHAR_T +%token UNDUNDWCHAR_T %token BOOL %token SHORT %token INT @@ -25,25 +42,61 @@ %token FLOAT %token DOUBLE %token VOID +%token SIGNED +%token UNSIGNED +%token INT128 +%token FLOAT128 +%token HALF +%token UNDUNDFP16 +%token NULLPTR +%token OBJCID +%token OBJCCLASS +%token OBJCSEL +%token EOF + -%start ctype_specifier +%start ctype_specifier_seq %% -ctype_specifier: +ctype_specifier_seq: + | trailing_type_specifier_seq EOF + { let atyp = tokens_to_abs_types $1 in + Logging.out "\tParsed `%s`\n" (Ctl_parser_types.abs_ctype_to_string atyp); + atyp + } + +trailing_type_specifier: | simple_type_specifier { $1 } + +trailing_type_specifier_seq: + | trailing_type_specifier { [$1] } + | simple_type_specifier trailing_type_specifier_seq { $1 :: $2 } + + simple_type_specifier: - | CHAR { Clang_ast_t.BuiltinType(dummy_ptr, `Char_U) } - | CHAR16_T { Clang_ast_t.BuiltinType(dummy_ptr, `Char16) } - | CHAR32_T { Clang_ast_t.BuiltinType(dummy_ptr, `Char32) } - | WCHAR_T { Clang_ast_t.BuiltinType(dummy_ptr, `WChar_U) } - | BOOL { Clang_ast_t.BuiltinType(dummy_ptr, `Bool) } - | SHORT { Clang_ast_t.BuiltinType(dummy_ptr, `Short) } - | INT { Clang_ast_t.BuiltinType(dummy_ptr, `Int) } - | LONG { Clang_ast_t.BuiltinType(dummy_ptr, `Long) } - | FLOAT { Clang_ast_t.BuiltinType(dummy_ptr, `Float) } - | DOUBLE { Clang_ast_t.BuiltinType(dummy_ptr, `Double) } - | VOID { Clang_ast_t.BuiltinType(dummy_ptr, `Void) } + | CHAR { Char_U } + | CHAR16_T { Char16 } + | CHAR32_T { Char32 } + | WCHAR_T { WChar_U } + | UNDUNDWCHAR_T { WChar_U } + | BOOL { Bool } + | SHORT { Short } + | INT { Int } + | LONG { Long } + | FLOAT { Float } + | DOUBLE { Double } + | VOID { Void } + | SIGNED { Int } + | UNSIGNED { UInt } + | INT128 { Int128 } + | FLOAT128 { Float128 } + | HALF { Half } + | UNDUNDFP16 { Half } + | NULLPTR { NullPtr } + | OBJCID { ObjCId } + | OBJCCLASS { ObjCClass } + | OBJCSEL { ObjCSel } ; %% diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp index 178254674..8dfcdbf4f 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -1,6 +1,10 @@ +codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 13, TEST_BUILTIN_TYPE, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 13, TEST_RETURN_METHOD, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 19, TEST_BUILTIN_TYPE, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 19, TEST_RETURN_METHOD, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 28, TEST_BUILTIN_TYPE, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 28, TEST_RETURN_METHOD, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 34, TEST_BUILTIN_TYPE, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 34, TEST_RETURN_METHOD, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 35, TEST_ALL_METHODS, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, B_bar, 36, MACRO_TEST1, [] @@ -22,3 +26,22 @@ codetoanalyze/objc/linters-for-test-only/subclassing.m, Linters_dummy_method, 53 codetoanalyze/objc/linters-for-test-only/subclassing.m, Linters_dummy_method, 53, IMPORTED_MACRO_SUBCLASS, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, Linters_dummy_method, 53, LOCAL_MACRO_SUBCLASS, [] codetoanalyze/objc/linters-for-test-only/subclassing.m, Linters_dummy_method, 53, SUBCLASSING_TEST_EXAMPLE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m1, 67, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m10, 76, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m11, 77, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m12, 78, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m13, 79, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m14, 80, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m15, 81, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m15, 81, TEST_RETURN_METHOD, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m16, 82, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m17, 83, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m2, 68, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m20, 85, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m21, 86, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m22, 87, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m3, 69, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m4, 70, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m7, 73, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m8, 74, TEST_BUILTIN_TYPE, [] +codetoanalyze/objc/linters-for-test-only/subclassing.m, TestType_m9, 75, TEST_BUILTIN_TYPE, [] diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al b/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al index 0d3d950eb..aa979a00c 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/linters_example.al @@ -97,3 +97,35 @@ DEFINE-CHECKER TEST_RETURN_METHOD = { SET message = "Method return int"; }; + +DEFINE-CHECKER TEST_BUILTIN_TYPE = { + + SET report_when = + WHEN + method_return_type("void") + OR method_return_type("bool") + OR method_return_type("char") + OR method_return_type("unsigned char") + OR method_return_type("wchar_t") + OR method_return_type("unsigned short") + OR method_return_type("unsigned int") + OR method_return_type("unsigned long") + OR method_return_type("unsigned long long") + OR method_return_type("__int128") + OR method_return_type("unsigned __int128") + OR method_return_type("signed char") + OR method_return_type("short") + OR method_return_type("int") + OR method_return_type("long") + OR method_return_type("long long") + OR method_return_type("float") + OR method_return_type("double") + OR method_return_type("long double") + OR method_return_type("id") + OR method_return_type("Class") + OR method_return_type("SEL") + HOLDS-IN-NODE ObjCMethodDecl; + + SET message = "Method return....."; + +}; diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/subclassing.m b/infer/tests/codetoanalyze/objc/linters-for-test-only/subclassing.m index 39f0b42c8..450f4e53e 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/subclassing.m +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/subclassing.m @@ -33,7 +33,7 @@ - (int)bar { A* a = [[A alloc] init]; - [a foo:5]; // Error: report MACRO_TEST1, MACRO_TEST2, MACRO_TEST3 + return [a foo:5]; // Error: report MACRO_TEST1, MACRO_TEST2, MACRO_TEST3 } @end @@ -61,3 +61,34 @@ @implementation F @end + +@interface TestType : NSObject + +- (void)m1; +- (bool)m2; +- (char)m3; +- (unsigned char)m4; +//- (wchar_t) m5; +//- (char16_t) m6; +- (unsigned short)m7; +- (unsigned int)m8; +- (unsigned long)m9; +- (unsigned long long)m10; +- (__int128)m11; +- (unsigned __int128)m12; +- (signed char)m13; +- (short)m14; +- (int)m15; +- (long)m16; +- (long long)m17; +//- (half) m18; +- (float)m20; +- (double)m21; +- (long double)m22; +//- (__float128) m23; +//- (nullptr_t) m24; +//- (id) m25; +//- (Class) m26; +//- (SEL) m27; + +@end