First approximation of stateless

Reviewed By: jvillard

Differential Revision: D10141376

fbshipit-source-id: a1dbb4c21
master
Dino Distefano 6 years ago committed by Facebook Github Bot
parent c3f2fbc8c6
commit 08a26d4ba1

@ -499,6 +499,14 @@ let call_instance_method an mname =
false false
let adhere_to_protocol an =
match an with
| Ctl_parser_types.Decl (Clang_ast_t.ObjCInterfaceDecl (_, _, _, _, idi)) ->
not (List.is_empty idi.otdi_protocols)
| _ ->
false
let is_objc_extension lcxt = let is_objc_extension lcxt =
CGeneral_utils.is_objc_extension lcxt.CLintersContext.translation_unit_context CGeneral_utils.is_objc_extension lcxt.CLintersContext.translation_unit_context
@ -527,6 +535,26 @@ let is_qual_type_const an =
false false
let objc_class_has_only_one_constructor_method_named an re =
let open Clang_ast_t in
let is_class_method d =
match d with
| Clang_ast_t.ObjCMethodDecl (_, _, omdi) ->
not omdi.omdi_is_instance_method
| _ ->
false
in
match an with
| Ctl_parser_types.Decl (ObjCImplementationDecl (_, _, decls, _, _)) -> (
match List.filter decls ~f:(fun d -> is_class_method d) with
| [n] ->
is_objc_class_method_named (Ctl_parser_types.Decl n) re
| _ ->
false )
| _ ->
false
let has_init_list_const_expr an = let has_init_list_const_expr an =
let rec fold lexp = List.fold ~f:(fun acc e -> is_const_expr' e && acc) ~init:true lexp let rec fold lexp = List.fold ~f:(fun acc e -> is_const_expr' e && acc) ~init:true lexp
and is_const_expr' exp = and is_const_expr' exp =
@ -789,6 +817,26 @@ let is_in_cxx_destructor context name =
false false
let cxx_construct_expr_has_no_parameters an =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.CXXConstructExpr (_, [], _, _)) ->
true
| _ ->
false
let cxx_construct_expr_has_name an name =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.CXXConstructExpr (_, _, _, xcei)) -> (
match xcei.xcei_decl_ref.dr_name with
| Some ni ->
ALVar.compare_str_with_alexp ni.ni_name name
| _ ->
false )
| _ ->
false
let is_in_block context = let is_in_block context =
match context.CLintersContext.current_method with Some (BlockDecl _) -> true | _ -> false match context.CLintersContext.current_method with Some (BlockDecl _) -> true | _ -> false
@ -930,6 +978,16 @@ let is_receiver_super an =
false false
let is_receiver_self an =
match an with
| Ctl_parser_types.Stmt (Clang_ast_t.ObjCMessageExpr (_, fst_param :: _, _, _)) ->
CAst_utils.exists_eventually_st
(decl_ref_name ~kind:`ImplicitParam)
(ALVar.Const "self") fst_param
| _ ->
false
let captures_cxx_references an = List.length (captured_variables_cxx_ref an) > 0 let captures_cxx_references an = List.length (captured_variables_cxx_ref an) > 0
let is_binop_with_kind an alexp_kind = let is_binop_with_kind an alexp_kind =

@ -196,6 +196,9 @@ val is_objc_category_implementation_on_subclass_of :
* inherits from a class whose name matches the provided REGEXP * inherits from a class whose name matches the provided REGEXP
*) *)
val adhere_to_protocol : Ctl_parser_types.ast_node -> bool
(** true if an objC class adhere to a protocol *)
val is_objc_protocol_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val is_objc_protocol_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** (**
* Checks if the current node is an ObjCProtocolDecl node * Checks if the current node is an ObjCProtocolDecl node
@ -223,6 +226,11 @@ val is_objc_method_named : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val is_objc_constructor : CLintersContext.context -> bool val is_objc_constructor : CLintersContext.context -> bool
(** 'is_in_objc_constructor context' is true if the curent node is within an ObjC constructor *) (** 'is_in_objc_constructor context' is true if the curent node is within an ObjC constructor *)
val objc_class_has_only_one_constructor_method_named :
Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** true if an ObjC class has only one class method and is a constructor
whose name matches the provided REGEXP *)
val is_objc_dealloc : CLintersContext.context -> bool val is_objc_dealloc : CLintersContext.context -> bool
(** 'is_in_objc_dealloc context' is true if the curent node is within an ObjC dealloc method *) (** 'is_in_objc_dealloc context' is true if the curent node is within an ObjC dealloc method *)
@ -445,11 +453,20 @@ val is_receiver_super : Ctl_parser_types.ast_node -> bool
* Matches on [super myMethod]; * Matches on [super myMethod];
*) *)
val is_receiver_self : Ctl_parser_types.ast_node -> bool
(**
* Checks if the current node is an ObjCMessageExpr node and has a
* receiver which is equal to 'self'.
*)
val is_at_selector_with_name : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val is_at_selector_with_name : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** an is an expression @selector with whose name in the language of re *) (** an is an expression @selector with whose name in the language of re *)
val has_visibility_attribute : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val has_visibility_attribute : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val cxx_construct_expr_has_name : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
(** true if the node is a CXXConstruct with name matching the provided REGEXP *)
val has_used_attribute : Ctl_parser_types.ast_node -> bool val has_used_attribute : Ctl_parser_types.ast_node -> bool
val iphoneos_target_sdk_version_by_path : CLintersContext.context -> string option val iphoneos_target_sdk_version_by_path : CLintersContext.context -> string option
@ -472,3 +489,6 @@ val is_cxx_copy_constructor : Ctl_parser_types.ast_node -> bool
val is_init_expr_cxx11_constant : Ctl_parser_types.ast_node -> bool val is_init_expr_cxx11_constant : Ctl_parser_types.ast_node -> bool
(** true if the current node is classified as C++11 constant expression by the AST. It works only for VarDecl init expr *) (** true if the current node is classified as C++11 constant expression by the AST. It works only for VarDecl init expr *)
val cxx_construct_expr_has_no_parameters : Ctl_parser_types.ast_node -> bool
(** true if a construct expr has no subexpressions *)

@ -1014,6 +1014,8 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.is_global_var an CPredicates.is_global_var an
| "is_static_local_var", [], an -> | "is_static_local_var", [], an ->
CPredicates.is_static_local_var an CPredicates.is_static_local_var an
| "adhere_to_protocol", [], an ->
CPredicates.adhere_to_protocol an
| "is_in_block", [], _ -> | "is_in_block", [], _ ->
CPredicates.is_in_block lcxt CPredicates.is_in_block lcxt
| "is_in_cxx_constructor", [name], _ -> | "is_in_cxx_constructor", [name], _ ->
@ -1066,6 +1068,8 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.is_node an nodename CPredicates.is_node an nodename
| "is_objc_constructor", [], _ -> | "is_objc_constructor", [], _ ->
CPredicates.is_objc_constructor lcxt CPredicates.is_objc_constructor lcxt
| "objc_class_has_only_one_constructor_method_named", [name], an ->
CPredicates.objc_class_has_only_one_constructor_method_named an name
| "is_objc_dealloc", [], _ -> | "is_objc_dealloc", [], _ ->
CPredicates.is_objc_dealloc lcxt CPredicates.is_objc_dealloc lcxt
| "is_objc_extension", [], _ -> | "is_objc_extension", [], _ ->
@ -1126,6 +1130,8 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.is_receiver_class_named lcxt an name CPredicates.is_receiver_class_named lcxt an name
| "is_receiver_super", [], an -> | "is_receiver_super", [], an ->
CPredicates.is_receiver_super an CPredicates.is_receiver_super an
| "is_receiver_self", [], an ->
CPredicates.is_receiver_self an
| "iphoneos_target_sdk_version_greater_or_equal", [version], _ -> | "iphoneos_target_sdk_version_greater_or_equal", [version], _ ->
CPredicates.iphoneos_target_sdk_version_greater_or_equal lcxt (ALVar.alexp_to_string version) CPredicates.iphoneos_target_sdk_version_greater_or_equal lcxt (ALVar.alexp_to_string version)
| "method_return_type", [typ], an -> | "method_return_type", [typ], an ->
@ -1136,6 +1142,8 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.using_namespace an namespace CPredicates.using_namespace an namespace
| "is_at_selector_with_name", [name], an -> | "is_at_selector_with_name", [name], an ->
CPredicates.is_at_selector_with_name an name CPredicates.is_at_selector_with_name an name
| "cxx_construct_expr_has_name", [name], an ->
CPredicates.cxx_construct_expr_has_name an name
| "has_type_const_ptr_to_objc_class", [], an -> | "has_type_const_ptr_to_objc_class", [], an ->
CPredicates.has_type_const_ptr_to_objc_class an CPredicates.has_type_const_ptr_to_objc_class an
| "has_type_subprotocol_of", [protname], an -> | "has_type_subprotocol_of", [protname], an ->
@ -1152,6 +1160,8 @@ let rec eval_Atomic pred_name_ args an lcxt =
CPredicates.is_cxx_copy_constructor an CPredicates.is_cxx_copy_constructor an
| "is_init_expr_cxx11_constant", [], an -> | "is_init_expr_cxx11_constant", [], an ->
CPredicates.is_init_expr_cxx11_constant an CPredicates.is_init_expr_cxx11_constant an
| "cxx_construct_expr_has_no_parameters", [], an ->
CPredicates.cxx_construct_expr_has_no_parameters an
| _ -> | _ ->
L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name

@ -27,4 +27,6 @@ codetoanalyze/objcpp/linters-for-test-only/TestStructFieldChecks.mm, buttonCompo
codetoanalyze/objcpp/linters-for-test-only/TestStructFieldChecks.mm, buttonComponent, 33, TITLE_NOT_INITIALIZED, no_bucket, WARNING, [] codetoanalyze/objcpp/linters-for-test-only/TestStructFieldChecks.mm, buttonComponent, 33, TITLE_NOT_INITIALIZED, no_bucket, WARNING, []
codetoanalyze/objcpp/linters-for-test-only/TestStructFieldChecks.mm, buttonComponent, 37, TITLE_NOT_INITIALIZED, no_bucket, WARNING, [] codetoanalyze/objcpp/linters-for-test-only/TestStructFieldChecks.mm, buttonComponent, 37, TITLE_NOT_INITIALIZED, no_bucket, WARNING, []
codetoanalyze/objcpp/linters-for-test-only/hash_test.mm, std::hash_NSObject_*__operator(), 12, DISCOURAGED_HASH_METHOD_INVOCATION, no_bucket, WARNING, [] codetoanalyze/objcpp/linters-for-test-only/hash_test.mm, std::hash_NSObject_*__operator(), 12, DISCOURAGED_HASH_METHOD_INVOCATION, no_bucket, WARNING, []
codetoanalyze/objcpp/linters-for-test-only/stateless.m, Linters_dummy_method, 21, ADHERE_TO_PROTOCOL, no_bucket, WARNING, []
codetoanalyze/objcpp/linters-for-test-only/stateless.m, Linters_dummy_method, 24, ONLY_ONE_CLASS_METHOD, no_bucket, WARNING, []
codetoanalyze/objcpp/linters-for-test-only/static.m, objc_block_1, 18, OBJC_BLOCK_CAPTURING_VALUES, no_bucket, WARNING, [] codetoanalyze/objcpp/linters-for-test-only/static.m, objc_block_1, 18, OBJC_BLOCK_CAPTURING_VALUES, no_bucket, WARNING, []

@ -209,3 +209,27 @@ DEFINE-CHECKER OBJC_BLOCK_CAPTURING_VALUES = {
SET message = "ObjC Block capturing values"; SET message = "ObjC Block capturing values";
SET mode = "ON"; SET mode = "ON";
}; };
DEFINE-CHECKER ADHERE_TO_PROTOCOL = {
SET report_when =
WHEN
adhere_to_protocol()
HOLDS-IN-NODE ObjCInterfaceDecl;
SET message = "Found class adhering to protocol";
SET mode = "ON";
};
DEFINE-CHECKER ONLY_ONE_CLASS_METHOD = {
SET report_when =
WHEN
objc_class_has_only_one_constructor_method_named(REGEXP("newWith.+"))
HOLDS-IN-NODE ObjCImplementationDecl;
SET message = "Found class with only one class method";
SET mode = "ON";
};

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
@interface B : NSObject
@end
@implementation B
+ (void)newWithB {
}
+ (void)foo {
}
@end
@interface A<NSObject>
@end
@implementation A
- (int)foo {
return 0;
}
+ (int)newWithBA {
return 0;
}
@end
Loading…
Cancel
Save