[linters] Adding a new predicate for in an ObjC class that is subclass of some class

Reviewed By: ddino

Differential Revision: D6284441

fbshipit-source-id: bcdd389
master
Dulma Churchill 7 years ago committed by Facebook Github Bot
parent a57a6078bc
commit 18782be7c9

@ -568,3 +568,30 @@ let has_block_attribute decl =
let is_implicit_decl decl =
let decl_info = Clang_ast_proj.get_decl_tuple decl in
decl_info.Clang_ast_t.di_is_implicit
let get_superclass_curr_class_objc_from_decl (decl: Clang_ast_t.decl) =
match decl with
| ObjCInterfaceDecl (_, _, _, _, otdi) ->
otdi.otdi_super
| ObjCImplementationDecl (_, ni, _, _, oi) -> (
match
oi.Clang_ast_t.oidi_class_interface
|> Option.map ~f:(fun dr -> dr.Clang_ast_t.dr_decl_pointer)
|> Option.value_map ~f:get_decl ~default:None
with
| Some ObjCInterfaceDecl (_, _, _, _, otdi) ->
otdi.otdi_super
| _ ->
Logging.die InternalError
"Expected that ObjCImplementationDecl always has a pointer to it's interface, but wasn't the case with %s"
ni.Clang_ast_t.ni_name )
| ObjCCategoryDecl (_, _, _, _, ocdi) ->
ocdi.odi_class_interface
| ObjCCategoryImplDecl (_, _, _, _, ocidi) ->
ocidi.ocidi_class_interface
| decl ->
Logging.die InternalError
"Expected to be called only with ObjCInterfaceDecl, ObjCImplementationDecl, ObjCCategoryDecl or ObjCCategoryImplDecl, but got %s"
(Clang_ast_proj.get_decl_kind_string decl)

@ -155,3 +155,5 @@ val is_std_vector : Clang_ast_t.qual_type -> bool
val has_block_attribute : Clang_ast_t.decl -> bool
val is_implicit_decl : Clang_ast_t.decl -> bool
val get_superclass_curr_class_objc_from_decl : Clang_ast_t.decl -> Clang_ast_t.decl_ref option

@ -262,41 +262,25 @@ let get_method_name_from_clang tenv ms_opt =
let get_superclass_curr_class_objc context =
let open Clang_ast_t in
let super_of_decl_ref_opt decl_ref =
match
decl_ref |> Option.value_map ~f:(fun dr -> dr.dr_name) ~default:None
|> Option.map ~f:CAst_utils.get_qualified_name
with
| Some name ->
name
| None ->
assert false
in
let retreive_super_name ptr =
match CAst_utils.get_decl ptr with
| Some ObjCInterfaceDecl (_, _, _, _, otdi) ->
super_of_decl_ref_opt otdi.otdi_super
| Some ObjCImplementationDecl (_, _, _, _, oi) -> (
match
oi.Clang_ast_t.oidi_class_interface |> Option.map ~f:(fun dr -> dr.dr_decl_pointer)
|> Option.value_map ~f:CAst_utils.get_decl ~default:None
with
| Some ObjCInterfaceDecl (_, _, _, _, otdi) ->
super_of_decl_ref_opt otdi.otdi_super
| _ ->
assert false )
| Some ObjCCategoryDecl (_, _, _, _, ocdi) ->
super_of_decl_ref_opt ocdi.odi_class_interface
| Some ObjCCategoryImplDecl (_, _, _, _, ocidi) ->
super_of_decl_ref_opt ocidi.ocidi_class_interface
| _ ->
assert false
let decl_ref =
match CContext.get_curr_class context with
| CContext.ContextClsDeclPtr ptr -> (
match CAst_utils.get_decl ptr with
| Some decl ->
CAst_utils.get_superclass_curr_class_objc_from_decl decl
| None ->
Logging.die InternalError
"Expected that the current class ptr in the context is a valid pointer to class decl, but didn't find declaration, ptr is %d "
ptr )
| CContext.ContextNoCls ->
Logging.die InternalError
"This should only be called in the context of a class, but got CContext.ContextNoCls"
in
match CContext.get_curr_class context with
| CContext.ContextClsDeclPtr ptr ->
Typ.Name.Objc.from_qual_name (retreive_super_name ptr)
| CContext.ContextNoCls ->
assert false
match decl_ref |> Option.value_map ~f:(fun dr -> dr.dr_name) ~default:None with
| Some name ->
Typ.Name.Objc.from_qual_name (CAst_utils.get_qualified_name name)
| None ->
Logging.die InternalError "Expected to always find a superclass, but found none"
(* Gets the class name from a method signature found by clang, if search is successful *)

@ -457,6 +457,30 @@ let is_in_block context =
match context.CLintersContext.current_method with Some BlockDecl _ -> true | _ -> false
let rec is_subclass_of decl name =
match CAst_utils.get_superclass_curr_class_objc_from_decl decl with
| Some super_ref
-> (
let ndi = match super_ref.Clang_ast_t.dr_name with Some ni -> ni | _ -> assert false in
if ALVar.compare_str_with_alexp ndi.ni_name name then true
else
match CAst_utils.get_decl_opt_with_decl_ref (Some super_ref) with
| Some decl ->
is_subclass_of decl name
| None ->
false )
| None ->
false
let is_in_objc_subclass_of context name =
match context.CLintersContext.current_objc_class with
| Some cls ->
is_subclass_of cls name
| None ->
false
let captures_cxx_references an = List.length (captured_variables_cxx_ref an) > 0
let is_binop_with_kind an alexp_kind =

@ -68,6 +68,10 @@ val is_objc_constructor : CLintersContext.context -> bool
val is_objc_dealloc : CLintersContext.context -> bool
val is_in_objc_subclass_of : CLintersContext.context -> ALVar.alexp -> bool
val is_subclass_of : Clang_ast_t.decl -> ALVar.alexp -> bool
val captures_cxx_references : Ctl_parser_types.ast_node -> bool
val is_binop_with_kind : Ctl_parser_types.ast_node -> ALVar.alexp -> bool

@ -1038,6 +1038,8 @@ let rec eval_Atomic _pred_name args an lcxt =
CPredicates.is_objc_dealloc lcxt
| "is_objc_extension", [], _ ->
CPredicates.is_objc_extension lcxt
| "is_in_objc_subclass_of", [name], _ ->
CPredicates.is_in_objc_subclass_of lcxt name
| "is_objc_interface_named", [name], an ->
CPredicates.is_objc_interface_named an name
| "is_property_pointer_type", [], an ->

@ -0,0 +1,41 @@
/*
* 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 <Foundation/NSObject.h>
@interface HappySadView : NSObject
@end
@implementation HappySadView
- (void)makeBadAction {
[self copy];
}
- (void)foo {
}
@end
@interface SubClassTestClass : NSObject
@end
@interface HappySadView2 : SubClassTestClass
@end
@implementation HappySadView2
- (void)makeBadAction {
[self copy];
}
- (void)foo {
}
@end

@ -6,6 +6,11 @@ codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 27,
codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, function, 27, TEST_VAR_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, objc_block_1, 21, TEST_VAR_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/InContextOfMethodsTest.m, objc_block_2, 21, TEST_IN_BLOCK_CONTEXT, []
codetoanalyze/objc/linters-for-test-only/InSubclassExample.m, HappySadView2_foo, 38, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/InSubclassExample.m, HappySadView2_makeBadAction, 34, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/InSubclassExample.m, HappySadView2_makeBadAction, 35, IN_SUBCLASS_TEST, []
codetoanalyze/objc/linters-for-test-only/InSubclassExample.m, HappySadView_foo, 20, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/InSubclassExample.m, HappySadView_makeBadAction, 16, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/PrivateAPIChecker.m, TestView_methodd, 16, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/PrivateAPIChecker.m, TestView_methoddd, 20, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/PrivateAPIChecker.m, TestView_methoddd, 21, TEST_SELECTOR, []

@ -423,3 +423,10 @@ DEFINE-CHECKER TEST_PARAMETER_SEL_TYPE = {
SET message = "Method has parameter of type SEL";
};
DEFINE-CHECKER IN_SUBCLASS_TEST = {
SET report_when =
WHEN is_in_objc_subclass_of("SubClassTestClass")
HOLDS-IN-NODE ObjCMessageExpr;
SET message = "Found a message call in a class that is not subclass of A.";
};

Loading…
Cancel
Save