From 8a40482fac2bf3af1509f85fc8991588fcd805ed Mon Sep 17 00:00:00 2001 From: Ryan Rhee Date: Thu, 11 Aug 2016 20:32:28 -0700 Subject: [PATCH] Detect when in CK Reviewed By: jvillard Differential Revision: D3693935 fbshipit-source-id: e381966 --- infer/src/clang/ComponentKit.ml | 50 ++++++++++++++++++++++ infer/src/clang/ComponentKit.mli | 15 +++++++ infer/src/clang/cFrontend_checkers_main.ml | 11 ++++- infer/src/clang/cFrontend_config.ml | 3 ++ infer/src/clang/cFrontend_config.mli | 3 ++ 5 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 infer/src/clang/ComponentKit.ml create mode 100644 infer/src/clang/ComponentKit.mli diff --git a/infer/src/clang/ComponentKit.ml b/infer/src/clang/ComponentKit.ml new file mode 100644 index 000000000..0de6a6a01 --- /dev/null +++ b/infer/src/clang/ComponentKit.ml @@ -0,0 +1,50 @@ +(* + * 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. + *) + +open CFrontend_utils +open !Utils + +(** Recursively go up the inheritance hierarchy of a given ObjCInterfaceDecl. + (Returns false on decls other than that one.) *) +let rec is_component_or_controller_if decl = + match decl with + | Clang_ast_t.ObjCInterfaceDecl (_, ndi, _, _, _)-> + let open CFrontend_config in + let whitelist = [ckcomponent_cl; ckcomponentcontroller_cl] in + let blacklist = [nsobject_cl; nsproxy_cl] in + let in_list some_list = IList.mem string_equal ndi.Clang_ast_t.ni_name some_list in + if in_list whitelist then + true + else if in_list blacklist then + false + else + (match Ast_utils.get_super_if (Some decl) with + | Some super_decl -> + is_component_or_controller_if super_decl + | None -> false) + | _ -> false + +(** True if it's an objc class impl that extends from CKComponent or + CKComponentController, false otherwise *) +let rec is_component_or_controller_descendant_impl decl = + match decl with + | Clang_ast_t.ObjCImplementationDecl _ -> + let super_if = Ast_utils.get_super_if (Some decl) in + Option.map_default is_component_or_controller_if false super_if + | Clang_ast_t.LinkageSpecDecl (_, decl_list, _) -> + contains_ck_impl decl_list + | _ -> false + +(** Returns true if the passed-in list of decls contains an + ObjCImplementationDecl of a descendant of CKComponent or + CKComponentController. + + Does not recurse into hierarchy. *) +and contains_ck_impl decl_list = + IList.exists is_component_or_controller_descendant_impl decl_list diff --git a/infer/src/clang/ComponentKit.mli b/infer/src/clang/ComponentKit.mli new file mode 100644 index 000000000..13944031a --- /dev/null +++ b/infer/src/clang/ComponentKit.mli @@ -0,0 +1,15 @@ +(* + * 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. + *) + +(** Returns true if the passed-in list of decls contains an + ObjCImplementationDecl of a descendant of CKComponent or + CKComponentController. + + Does not recurse into hierarchy. *) +val contains_ck_impl : Clang_ast_t.decl list -> bool diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index 271fe7623..f1d8aa99d 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -40,8 +40,17 @@ and do_frontend_checks_decl context cfg cg decl = | Some (decls, _) -> IList.iter (do_frontend_checks_decl context' cfg cg) decls | None -> () +let context_with_ck_set context decl_list = + let is_ck = context.CLintersContext.is_ck_translation_unit + || ComponentKit.contains_ck_impl decl_list in + if is_ck then + { context with CLintersContext.is_ck_translation_unit = true } + else + context + let do_frontend_checks cfg cg ast = match ast with | Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> - IList.iter (do_frontend_checks_decl CLintersContext.empty cfg cg) decl_list + let context = context_with_ck_set CLintersContext.empty decl_list in + IList.iter (do_frontend_checks_decl context cfg cg) decl_list | _ -> assert false (* NOTE: Assumes that an AST alsways starts with a TranslationUnitDecl *) diff --git a/infer/src/clang/cFrontend_config.ml b/infer/src/clang/cFrontend_config.ml index 0c6255e91..9863016b9 100644 --- a/infer/src/clang/cFrontend_config.ml +++ b/infer/src/clang/cFrontend_config.ml @@ -28,6 +28,8 @@ let cf_autorelease = "CFAutorelease" let cf_bridging_release = "CFBridgingRelease" let cf_bridging_retain = "CFBridgingRetain" let cf_non_null_alloc ="__cf_non_null_alloc" +let ckcomponent_cl = "CKComponent" +let ckcomponentcontroller_cl = "CKComponentController" let class_method = "class" let class_type = "Class" let copy = "copy" @@ -55,6 +57,7 @@ let next_object = "nextObject" let ns_make_collectable = "NSMakeCollectable" let nsarray_cl = "NSArray" let nsautorelease_pool_cl = "NSAutoreleasePool" +let nsproxy_cl = "NSProxy" let nsobject_cl = "NSObject" let nsstring_cl = "NSString" let objc_class = "objc_class" diff --git a/infer/src/clang/cFrontend_config.mli b/infer/src/clang/cFrontend_config.mli index f32b659b0..29b470c64 100644 --- a/infer/src/clang/cFrontend_config.mli +++ b/infer/src/clang/cFrontend_config.mli @@ -28,6 +28,8 @@ val cf_autorelease : string val cf_bridging_release : string val cf_bridging_retain : string val cf_non_null_alloc : string +val ckcomponent_cl : string +val ckcomponentcontroller_cl : string val class_method : string val class_type : string val copy : string @@ -55,6 +57,7 @@ val next_object : string val ns_make_collectable : string val nsarray_cl : string val nsautorelease_pool_cl : string +val nsproxy_cl : string val nsobject_cl : string val nsstring_cl : string val objc_class : string