diff --git a/Makefile b/Makefile index 83f576389..23a0aebff 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ ifneq ($(XCODE_SELECT),no) BUILD_SYSTEMS_TESTS += xcodebuild_no_xcpretty DIRECT_TESTS += \ objc_frontend objc_errors objc_linters objc_ioslints \ - objcpp_frontend objcpp_linters objc_linters-for-test-only \ + objcpp_frontend objcpp_linters objc_linters-for-test-only objcpp_linters-for-test-only \ objc_linters-def-folder ifneq ($(XCPRETTY),no) BUILD_SYSTEMS_TESTS += xcodebuild diff --git a/infer/src/clang/ctl_parser_types.ml b/infer/src/clang/ctl_parser_types.ml index 82cea8d34..3b530fff3 100644 --- a/infer/src/clang/ctl_parser_types.ml +++ b/infer/src/clang/ctl_parser_types.ml @@ -186,6 +186,7 @@ let builtin_kind_to_string t = type abs_ctype = | BuiltIn of builtin_kind | Pointer of abs_ctype + | Reference of abs_ctype | TypeName of ALVar.alexp | ObjCGenProt of abs_ctype * abs_ctype @@ -201,6 +202,8 @@ let rec abs_ctype_to_string t = -> "BuiltIn (" ^ builtin_kind_to_string t' ^ ")" | Pointer t' -> "Pointer (" ^ abs_ctype_to_string t' ^ ")" + | Reference t' + -> "Reference (" ^ abs_ctype_to_string t' ^ ")" | TypeName ae -> "TypeName (" ^ ALVar.alexp_to_string ae ^ ")" | ObjCGenProt (b, p) @@ -311,6 +314,8 @@ and c_type_equal c_type abs_ctype = -> builtin_equal bi abi | PointerType _, Pointer _ | ObjCObjectPointerType _, Pointer _ -> pointer_type_equal c_type abs_ctype + | LValueReferenceType (_, qt), Reference abs_typ | RValueReferenceType (_, qt), Reference abs_typ + -> check_type_ptr qt.qt_type_ptr abs_typ | ObjCObjectPointerType (_, qt), ObjCGenProt _ -> check_type_ptr qt.qt_type_ptr abs_ctype | ObjCObjectType _, ObjCGenProt _ diff --git a/infer/src/clang/ctl_parser_types.mli b/infer/src/clang/ctl_parser_types.mli index a738fd9b1..0be827544 100644 --- a/infer/src/clang/ctl_parser_types.mli +++ b/infer/src/clang/ctl_parser_types.mli @@ -62,6 +62,7 @@ type builtin_kind = type abs_ctype = | BuiltIn of builtin_kind | Pointer of abs_ctype + | Reference of abs_ctype | TypeName of ALVar.alexp | ObjCGenProt of abs_ctype * abs_ctype diff --git a/infer/src/clang/types_lexer.mll b/infer/src/clang/types_lexer.mll index c04bdd4f0..ee1389cbb 100644 --- a/infer/src/clang/types_lexer.mll +++ b/infer/src/clang/types_lexer.mll @@ -56,6 +56,7 @@ rule token = parse | "Class" { OBJCCLASS } | "SEL" { OBJCSEL } | "*" { STAR } + | "&" { AMPERSAND } | "REGEXP" { REGEXP } | "(" { LEFT_PAREN } | ")" { RIGHT_PAREN } diff --git a/infer/src/clang/types_parser.mly b/infer/src/clang/types_parser.mly index 4888bcd04..aee10cc85 100644 --- a/infer/src/clang/types_parser.mly +++ b/infer/src/clang/types_parser.mly @@ -57,6 +57,7 @@ %token OBJCCLASS %token OBJCSEL %token STAR +%token AMPERSAND %token EOF %token REGEXP %token LEFT_PAREN @@ -81,6 +82,7 @@ ctype_specifier_seq: | protocol_or_generics_type_spec { $1 } | noptr_type_spec { $1 } | ptr_type_spec { $1 } +| reference_type_spec { $1 } | type_name { $1 } ; @@ -91,6 +93,10 @@ ptr_type_spec: | protocol_or_generics_type_spec STAR { Pointer $1 } ; +reference_type_spec: +| type_name AMPERSAND { Reference $1 } +; + protocol_or_generics_type_spec: | type_name_or_objid LEFT_ANGLE ctype_specifier_seq RIGHT_ANGLE { let tname = $1 in diff --git a/infer/tests/codetoanalyze/objcpp/linters-for-test-only/Makefile b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/Makefile new file mode 100644 index 000000000..6c23afc49 --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/Makefile @@ -0,0 +1,21 @@ +# Copyright (c) 2016 - present Facebook, Inc. +# All rights reserved. +# +# This source code is licensed under the BSD style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. + +TESTS_DIR = ../../.. + +ANALYZER = linters +CLANG_OPTIONS = -x objective-c++ -std=c++11 -fobjc-arc -c +INFER_OPTIONS = --cxx --linters-def-file linters_example.al --project-root $(TESTS_DIR) --no-keep-going +INFERPRINT_OPTIONS = --issues-tests + +SOURCES = \ + $(wildcard *.m) \ + $(wildcard */*.m) \ + $(wildcard *.mm) \ + $(wildcard *.c) \ + +include $(TESTS_DIR)/clang.make diff --git a/infer/tests/codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm new file mode 100644 index 000000000..3428362f9 --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +#import + +#import +#import + +template +class MyClassTemplated {}; + +typedef MyClassTemplated<> MyClass; + +@interface ReferenceTest : NSObject +// bug ++ (instancetype)newWithConstAction:(const MyClass&)action; + +// bug ++ (instancetype)newWithActionRef:(MyClass&)action; + +// bug ++ (instancetype)newWithAction:(MyClass)action; + +// no bug ++ (instancetype)newWithTypedAction:(MyClassTemplated)typedAction; + +@end + +@implementation ReferenceTest +// bug ++ (instancetype)newWithConstAction:(const MyClass&)action { + return nil; +} +// bug ++ (instancetype)newWithActionRef:(MyClass&)action { + return nil; +} +// bug ++ (instancetype)newWithAction:(MyClass&)action { + return nil; +} + +// This should not produce an error ++ (instancetype)newWithTypedAction:(MyClassTemplated)typedAction { + return nil; +} + +@end diff --git a/infer/tests/codetoanalyze/objcpp/linters-for-test-only/issues.exp b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/issues.exp new file mode 100644 index 000000000..2e4933c3c --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/issues.exp @@ -0,0 +1,6 @@ +codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm, ReferenceTest_newWithAction:, 27, TEST_REFERENCE, [] +codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm, ReferenceTest_newWithAction:, 44, TEST_REFERENCE, [] +codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm, ReferenceTest_newWithActionRef:, 24, TEST_REFERENCE, [] +codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm, ReferenceTest_newWithActionRef:, 40, TEST_REFERENCE, [] +codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm, ReferenceTest_newWithConstAction:, 21, TEST_REFERENCE, [] +codetoanalyze/objcpp/linters-for-test-only/ReferenceTest.mm, ReferenceTest_newWithConstAction:, 36, TEST_REFERENCE, [] diff --git a/infer/tests/codetoanalyze/objcpp/linters-for-test-only/linters_example.al b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/linters_example.al new file mode 100644 index 000000000..382cde0f7 --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/linters-for-test-only/linters_example.al @@ -0,0 +1,9 @@ +DEFINE-CHECKER TEST_REFERENCE = { + SET report_when = + WHEN method_return_type("instancetype") + AND HOLDS-NEXT WITH-TRANSITION Parameters + (has_type("MyClass") OR has_type("MyClass &")) + AND declaration_has_name(REGEXP("^new.*:$")) + HOLDS-IN-NODE ObjCMethodDecl; + SET message = "Found reference in parameter of method new"; +};