[linters] Remove the linters UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK and REGISTERED_OBSERVER_BEING_DEALLOCATED

Summary: There is now a compilation check for UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK so this check is less useful. Also the check REGISTERED_OBSERVER_BEING_DEALLOCATED is useful only in an old version of iOS.

Reviewed By: ngorogiannis

Differential Revision: D22231851

fbshipit-source-id: 72151fef5
master
Dulma Churchill 5 years ago committed by Facebook GitHub Bot
parent fc6cd0cb28
commit 622f0fb6f2

@ -103,7 +103,6 @@ BUILD_SYSTEMS_TESTS += \
DIRECT_TESTS += \
objc_biabduction \
objc_frontend \
objc_ioslints \
objc_linters \
objc_linters-def-folder \
objc_linters-for-test-only \

@ -1,5 +0,0 @@
Objects register with a notification center to receive notifications. This check
warns you when an object is registered as observer of a NSNotificationCenter but
it is never unregistered. This is problematic as if the object is not
unregistered the notification center can still send notification even after the
object has been deallocated. In that case we would get a crash.

@ -1,20 +0,0 @@
This checks warns you when you are using an API (constant, method call, etc.)
that is only defined in a version higher than the version that you support. To
enable this check, pass to Infer the option
`--iphoneos-target-sdk-version version`. Calling an undefined API will lead to a
crash in the app. To fix this, you can choose a different API or use it inside
an if, as in:
```objectivec
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) {
font = [UIFont systemFontOfSize:size weight:0];
}
```
or
```objectivec
if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_9_0) {
font = [UIFont systemFontOfSize:size weight:0];
}
```

@ -69,65 +69,6 @@ DEFINE-CHECKER BAD_POINTER_COMPARISON = {
"Did you mean to use/compare against the unboxed value instead? Please either explicitly compare the NSNumber instance to nil, or use one of the NSNumber accessors before the comparison.";
};
DEFINE-CHECKER REGISTERED_OBSERVER_BEING_DEALLOCATED = {
LET exists_method_calling_addObserver =
call_method("addObserver:selector:name:object:") HOLDS-EVENTUALLY;
LET exists_method_calling_addObserverForName =
call_method("addObserverForName:object:queue:usingBlock:") HOLDS-EVENTUALLY;
LET add_observer =
exists_method_calling_addObserver OR exists_method_calling_addObserverForName;
LET eventually_addObserver =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(add_observer)
HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserver =
call_method("removeObserver:") HOLDS-EVENTUALLY;
LET exists_method_calling_removeObserverName =
call_method("removeObserver:name:object:") HOLDS-EVENTUALLY;
LET remove_observer =
exists_method_calling_removeObserver OR exists_method_calling_removeObserverName;
LET remove_observer_in_block =
IN-NODE BlockDecl WITH-TRANSITION Body
(remove_observer)
HOLDS-EVENTUALLY;
LET remove_observer1 =
remove_observer OR remove_observer_in_block;
LET remove_observer_in_method =
IN-NODE ObjCMethodDecl WITH-TRANSITION Body
(remove_observer1)
HOLDS-EVENTUALLY;
LET eventually_removeObserver =
IN-NODE ObjCImplementationDecl, ObjCProtocolDecl WITH-TRANSITION Any
(remove_observer_in_method OR
remove_observer_in_method HOLDS-IN-SOME-SUPERCLASS-OF ObjCImplementationDecl)
HOLDS-EVENTUALLY;
SET report_when =
WHEN
NOT (eventually_addObserver IMPLIES eventually_removeObserver) AND
NOT iphoneos_target_sdk_version_greater_or_equal("9.0") //this is not needed after iOS SDK 9.0
HOLDS-IN-NODE ObjCImplementationDecl, ObjCProtocolDecl;
SET message =
"Object self is registered in a notification center but not being removed before deallocation";
SET suggestion =
"Consider removing the object from the notification center before its deallocation.";
};
DEFINE-CHECKER STRONG_DELEGATE_WARNING = {
LET name_contains_delegate = declaration_has_name(REGEXP("[dD]elegate"));
@ -215,38 +156,6 @@ DEFINE-CHECKER CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK = {
SET mode = "ON";
};
// If the declaration has availability attributes, check that it's compatible with
// the iphoneos_target_sdk_version
DEFINE-CHECKER UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK = {
SET report_when =
WHEN HOLDS-NEXT WITH-TRANSITION PointerToDecl
(decl_unavailable_in_supported_ios_sdk() AND
NOT within_responds_to_selector_block())
HOLDS-IN-NODE DeclRefExpr, ObjCMessageExpr;
SET message =
"%decl_ref_or_selector_name% is not available in the required iOS SDK version %iphoneos_target_sdk_version% (only available from version %available_ios_sdk%)";
SET name = "Unavailable API In Supported iOS SDK";
SET suggestion = "This could cause a crash.";
SET severity = "ERROR";
};
DEFINE-CHECKER UNAVAILABLE_CLASS_IN_SUPPORTED_IOS_SDK = {
SET report_when =
WHEN ((class_unavailable_in_supported_ios_sdk()) AND
NOT within_available_class_block() AND
(call_class_method("alloc") OR
call_class_method("new")))
HOLDS-IN-NODE ObjCMessageExpr;
SET message =
"The receiver %receiver_method_call% of %name% is not available in the required iOS SDK version %iphoneos_target_sdk_version% (only available from version %class_available_ios_sdk%)";
SET name = "Unavailable API In Supported iOS SDK";
SET severity = "ERROR";
SET mode = "ON";
};
DEFINE-CHECKER POINTER_TO_INTEGRAL_IMPLICIT_CAST = {
SET report_when =

@ -174,14 +174,6 @@ CLANG LINTERS OPTIONS
Deactivates: Use the default linters for the analysis.
(Conversely: --default-linters)
--iphoneos-target-sdk-version string
Specify the target SDK version to use for iphoneos
--iphoneos-target-sdk-version-path-regex +string
To pass a specific target SDK version to use for iphoneos in a
particular path, with the format path:version (can be specified
multiple times)
--linter string
From the linters available, only run this one linter. (Useful
together with --linters-developer-mode)

@ -478,7 +478,6 @@ OPTIONS
PREMATURE_NIL_TERMINATION_ARGUMENT (enabled by default),
PURE_FUNCTION (enabled by default),
QUANDARY_TAINT_ERROR (enabled by default),
REGISTERED_OBSERVER_BEING_DEALLOCATED (enabled by default),
RESOURCE_LEAK (enabled by default),
RETAIN_CYCLE (enabled by default),
SHELL_INJECTION (enabled by default),
@ -495,7 +494,6 @@ OPTIONS
Symexec_memory_error (enabled by default),
THREAD_SAFETY_VIOLATION (enabled by default),
TOPL_ERROR (enabled by default),
UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK (enabled by default),
UNINITIALIZED_VALUE (enabled by default),
UNREACHABLE_CODE (enabled by default),
UNTRUSTED_BUFFER_ACCESS (disabled by default),
@ -664,14 +662,6 @@ OPTIONS
other checkers (Conversely: --no-inefficient-keyset-iterator-only)
See also infer-analyze(1).
--iphoneos-target-sdk-version string
Specify the target SDK version to use for iphoneos See also infer-capture(1).
--iphoneos-target-sdk-version-path-regex +string
To pass a specific target SDK version to use for iphoneos in a
particular path, with the format path:version (can be specified
multiple times) See also infer-capture(1).
--issues-tests file
Write a list of issues in a format suitable for tests to file
See also infer-report(1).
@ -1471,12 +1461,6 @@ INTERNAL OPTIONS
files. Not compatible with --reanalyze and --continue-analysis.
(Conversely: --no-incremental-analysis)
--iphoneos-target-sdk-version-path-regex-reset
Set --iphoneos-target-sdk-version-path-regex to the empty list.
--iphoneos-target-sdk-version-reset
Cancel the effect of --iphoneos-target-sdk-version.
--issues-tests-reset
Cancel the effect of --issues-tests.

@ -203,7 +203,6 @@ OPTIONS
PREMATURE_NIL_TERMINATION_ARGUMENT (enabled by default),
PURE_FUNCTION (enabled by default),
QUANDARY_TAINT_ERROR (enabled by default),
REGISTERED_OBSERVER_BEING_DEALLOCATED (enabled by default),
RESOURCE_LEAK (enabled by default),
RETAIN_CYCLE (enabled by default),
SHELL_INJECTION (enabled by default),
@ -220,7 +219,6 @@ OPTIONS
Symexec_memory_error (enabled by default),
THREAD_SAFETY_VIOLATION (enabled by default),
TOPL_ERROR (enabled by default),
UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK (enabled by default),
UNINITIALIZED_VALUE (enabled by default),
UNREACHABLE_CODE (enabled by default),
UNTRUSTED_BUFFER_ACCESS (disabled by default),

@ -478,7 +478,6 @@ OPTIONS
PREMATURE_NIL_TERMINATION_ARGUMENT (enabled by default),
PURE_FUNCTION (enabled by default),
QUANDARY_TAINT_ERROR (enabled by default),
REGISTERED_OBSERVER_BEING_DEALLOCATED (enabled by default),
RESOURCE_LEAK (enabled by default),
RETAIN_CYCLE (enabled by default),
SHELL_INJECTION (enabled by default),
@ -495,7 +494,6 @@ OPTIONS
Symexec_memory_error (enabled by default),
THREAD_SAFETY_VIOLATION (enabled by default),
TOPL_ERROR (enabled by default),
UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK (enabled by default),
UNINITIALIZED_VALUE (enabled by default),
UNREACHABLE_CODE (enabled by default),
UNTRUSTED_BUFFER_ACCESS (disabled by default),
@ -664,14 +662,6 @@ OPTIONS
other checkers (Conversely: --no-inefficient-keyset-iterator-only)
See also infer-analyze(1).
--iphoneos-target-sdk-version string
Specify the target SDK version to use for iphoneos See also infer-capture(1).
--iphoneos-target-sdk-version-path-regex +string
To pass a specific target SDK version to use for iphoneos in a
particular path, with the format path:version (can be specified
multiple times) See also infer-capture(1).
--issues-tests file
Write a list of issues in a format suitable for tests to file
See also infer-report(1).

@ -99,7 +99,7 @@ let stmt_single_checkers_list =
let stmt_checkers_list = List.map ~f:single_to_multi stmt_single_checkers_list
let evaluate_place_holder context ph an =
let evaluate_place_holder ph an =
match ph with
| "%ivar_name%" ->
MF.monospaced_to_string (ALUtils.ivar_name an)
@ -111,12 +111,6 @@ let evaluate_place_holder context ph an =
MF.monospaced_to_string (ALUtils.decl_ref_or_selector_name an)
| "%receiver_method_call%" ->
MF.monospaced_to_string (ALUtils.receiver_method_call an)
| "%iphoneos_target_sdk_version%" ->
MF.monospaced_to_string (ALUtils.iphoneos_target_sdk_version context an)
| "%available_ios_sdk%" ->
MF.monospaced_to_string (ALUtils.available_ios_sdk an)
| "%class_available_ios_sdk%" ->
MF.monospaced_to_string (ALUtils.class_available_ios_sdk an)
| "%type%" ->
MF.monospaced_to_string (Ctl_parser_types.ast_node_type an)
| "%class_name%" ->
@ -160,7 +154,7 @@ let rec expand_message_string context message an =
try
ignore (Str.search_forward re message 0) ;
let ms = Str.matched_string message in
let res = evaluate_place_holder context ms an in
let res = evaluate_place_holder ms an in
L.(debug Linters Medium) "@\nMatched string '%s'@\n" ms ;
let re_ms = Str.regexp_string ms in
let message' = Str.replace_first re_ms res message in

@ -56,39 +56,6 @@ let decl_ref_or_selector_name an =
(tag_name_of_node an)
let iphoneos_target_sdk_version context _ =
match CPredicates.iphoneos_target_sdk_version_by_path context with Some f -> f | None -> "0"
let available_ios_sdk an =
let open Ctl_parser_types in
match CTL.next_state_via_transition an CTLTypes.PointerToDecl with
| [Decl decl] -> (
match CPredicates.get_available_attr_ios_sdk (Decl decl) with
| Some version ->
version
| None ->
"" )
| _ ->
L.(die ExternalError)
"available_ios_sdk must be called with a DeclRefExpr or an ObjCMessageExpr, but got %s"
(tag_name_of_node an)
let class_available_ios_sdk an =
match CPredicates.receiver_method_call an with
| Some decl -> (
match CPredicates.get_available_attr_ios_sdk (Decl decl) with
| Some version ->
version
| None ->
"" )
| None ->
L.(die ExternalError)
"class_available_ios_sdk must be called with ObjCMessageExpr, but got %s"
(tag_name_of_node an)
let receiver_method_call an =
match CPredicates.receiver_method_call an with
| Some decl ->

@ -21,12 +21,6 @@ val cxx_ref_captured_in_block : Ctl_parser_types.ast_node -> string
val decl_ref_or_selector_name : Ctl_parser_types.ast_node -> string
val iphoneos_target_sdk_version : CLintersContext.context -> Ctl_parser_types.ast_node -> string
val available_ios_sdk : Ctl_parser_types.ast_node -> string
val class_available_ios_sdk : Ctl_parser_types.ast_node -> string
val receiver_method_call : Ctl_parser_types.ast_node -> string
val class_name : Ctl_parser_types.ast_node -> string

@ -41,8 +41,6 @@ val is_doc_url_keyword : keyword -> bool
val is_name_keyword : keyword -> bool
val str_match_forward : string -> Str.regexp -> bool
val compare_str_with_alexp : string -> alexp -> bool
module FormulaIdMap : Caml.Map.S with type key = formula_id

@ -548,10 +548,6 @@ let eval_Atomic pred_name_ args an lcxt =
assert false )
| "declaration_ref_name", [decl_name], an ->
CPredicates.declaration_ref_name an decl_name
| "decl_unavailable_in_supported_ios_sdk", [], an ->
CPredicates.decl_unavailable_in_supported_ios_sdk lcxt an
| "class_unavailable_in_supported_ios_sdk", [], an ->
CPredicates.class_unavailable_in_supported_ios_sdk lcxt an
| "has_cast_kind", [name], an ->
CPredicates.has_cast_kind an name
| "has_type", [typ], an ->
@ -710,8 +706,6 @@ let eval_Atomic pred_name_ args an lcxt =
CPredicates.is_receiver_super an
| "is_receiver_self", [], an ->
CPredicates.is_receiver_self an
| "iphoneos_target_sdk_version_greater_or_equal", [version], _ ->
CPredicates.iphoneos_target_sdk_version_greater_or_equal lcxt (ALVar.alexp_to_string version)
| "method_return_type", [typ], an ->
CPredicates.method_return_type an typ
| "within_responds_to_selector_block", [], an ->

@ -75,22 +75,6 @@ let declaration_name decl =
None
let get_available_attr_ios_sdk an =
match an with
| Ctl_parser_types.Decl decl ->
let decl_info = Clang_ast_proj.get_decl_tuple decl in
List.find_map decl_info.di_attributes ~f:(function
| `AvailabilityAttr (_attr_info, {Clang_ast_t.aai_platform= Some "ios"; aai_introduced}) ->
let get_opt_number = Option.value ~default:0 in
Some
(Printf.sprintf "%d.%d" aai_introduced.vt_major
(get_opt_number aai_introduced.vt_minor))
| _ ->
None )
| _ ->
None
let get_ivar_attributes ivar_decl =
let open Clang_ast_t in
match ivar_decl with
@ -1117,62 +1101,6 @@ let is_at_selector_with_name an re =
false
let iphoneos_target_sdk_version_by_path (cxt : CLintersContext.context) =
let source_file = cxt.translation_unit_context.source_file in
let regex_version_opt =
List.find Config.iphoneos_target_sdk_version_path_regex
~f:(fun (version_path_regex : Config.iphoneos_target_sdk_version_path_regex) ->
ALVar.str_match_forward (SourceFile.to_rel_path source_file) version_path_regex.path )
in
match regex_version_opt with
| Some version_by_regex ->
Some version_by_regex.version
| None (* no version by path specified, use default version *) ->
Config.iphoneos_target_sdk_version
let iphoneos_target_sdk_version_greater_or_equal (cxt : CLintersContext.context) version =
match iphoneos_target_sdk_version_by_path cxt with
| Some target_version ->
Utils.compare_versions target_version version >= 0
| None ->
false
let decl_unavailable_in_supported_ios_sdk (cxt : CLintersContext.context) an =
let config_iphoneos_target_sdk_version = iphoneos_target_sdk_version_by_path cxt in
let available_attr_ios_sdk_current_method =
match cxt.current_method with
| Some decl ->
get_available_attr_ios_sdk (Decl decl)
| None ->
None
in
let ios_version_guard =
match cxt.if_context with Some if_context -> if_context.ios_version_guard | None -> []
in
let allowed_os_versions =
Option.to_list config_iphoneos_target_sdk_version
@ ios_version_guard
@ Option.to_list available_attr_ios_sdk_current_method
in
let max_allowed_version = List.max_elt allowed_os_versions ~compare:Utils.compare_versions in
let available_attr_ios_sdk = get_available_attr_ios_sdk an in
match (available_attr_ios_sdk, max_allowed_version) with
| Some available_attr_ios_sdk, Some max_allowed_version ->
Utils.compare_versions available_attr_ios_sdk max_allowed_version > 0
| _ ->
false
let class_unavailable_in_supported_ios_sdk (cxt : CLintersContext.context) an =
match receiver_method_call an with
| Some decl ->
decl_unavailable_in_supported_ios_sdk cxt (Ctl_parser_types.Decl decl)
| None ->
false
(* Check whether a type_ptr and a string denote the same type *)
let type_ptr_equal_type type_ptr type_str =
let parse_type_string str =

@ -359,12 +359,6 @@ val is_class : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val pp_predicate : Format.formatter -> t -> unit
val decl_unavailable_in_supported_ios_sdk :
CLintersContext.context -> Ctl_parser_types.ast_node -> bool
val class_unavailable_in_supported_ios_sdk :
CLintersContext.context -> Ctl_parser_types.ast_node -> bool
val has_type : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val has_value : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
@ -373,8 +367,6 @@ val method_return_type : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val has_type_subprotocol_of : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val get_available_attr_ios_sdk : Ctl_parser_types.ast_node -> string option
val get_selector : Ctl_parser_types.ast_node -> string option
val within_responds_to_selector_block : CLintersContext.context -> Ctl_parser_types.ast_node -> bool
@ -429,10 +421,6 @@ val has_used_attribute : Ctl_parser_types.ast_node -> bool
val has_no_escape_attribute : Ctl_parser_types.ast_node -> bool
val iphoneos_target_sdk_version_by_path : CLintersContext.context -> string option
val iphoneos_target_sdk_version_greater_or_equal : CLintersContext.context -> string -> bool
val within_available_class_block : CLintersContext.context -> Ctl_parser_types.ast_node -> bool
val has_type_const_ptr_to_objc_class : Ctl_parser_types.ast_node -> bool

@ -1398,19 +1398,6 @@ and inclusive_cost =
CLOpt.mk_bool ~long:"inclusive-cost" ~default:true "Computes the inclusive cost"
and iphoneos_target_sdk_version =
CLOpt.mk_string_opt ~long:"iphoneos-target-sdk-version"
~in_help:InferCommand.[(Capture, manual_clang_linters)]
"Specify the target SDK version to use for iphoneos"
and iphoneos_target_sdk_version_path_regex =
CLOpt.mk_string_list ~long:"iphoneos-target-sdk-version-path-regex"
~in_help:InferCommand.[(Capture, manual_clang_linters)]
"To pass a specific target SDK version to use for iphoneos in a particular path, with the \
format path:version (can be specified multiple times)"
and issues_tests_fields =
CLOpt.mk_symbol_seq ~long:"issues-tests-fields"
~in_help:InferCommand.[(Report, manual_generic)]
@ -2564,22 +2551,6 @@ let command, parse_args_and_return_usage_exit =
let print_usage_exit () = parse_args_and_return_usage_exit 1
type iphoneos_target_sdk_version_path_regex = {path: Str.regexp; version: string}
let process_iphoneos_target_sdk_version_path_regex args =
let process_iphoneos_target_sdk_version_path_regex arg : iphoneos_target_sdk_version_path_regex =
match String.rsplit2 ~on:':' arg with
| Some (path, version) ->
{path= Str.regexp path; version}
| None ->
L.(die UserError)
"Incorrect format for the option iphoneos-target-sdk_version-path-regex. The correct \
format is path:version but got %s"
arg
in
List.map ~f:process_iphoneos_target_sdk_version_path_regex args
let process_linters_doc_url args =
let linters_doc_url arg =
match String.lsplit2 ~on:':' arg with
@ -2829,12 +2800,6 @@ and icfg_dotty_outfile = !icfg_dotty_outfile
and inclusive_cost = !inclusive_cost
and iphoneos_target_sdk_version = !iphoneos_target_sdk_version
and iphoneos_target_sdk_version_path_regex =
process_iphoneos_target_sdk_version_path_regex !iphoneos_target_sdk_version_path_regex
and issues_tests = !issues_tests
and issues_tests_fields = !issues_tests_fields

@ -148,8 +148,6 @@ val wrappers_dir : string
(** {2 Configuration values specified by command-line options} *)
type iphoneos_target_sdk_version_path_regex = {path: Str.regexp; version: string}
val abs_struct : int
val abs_val : int
@ -330,10 +328,6 @@ val inferconfig_file : string option
val inferconfig_dir : string option
val iphoneos_target_sdk_version : string option
val iphoneos_target_sdk_version_path_regex : iphoneos_target_sdk_version_path_regex list
val is_checker_enabled : Checker.t -> bool
val issues_tests : string option

@ -804,12 +804,6 @@ let quandary_taint_error =
~user_documentation:"Generic taint error when nothing else fits."
let _registered_observer_being_deallocated =
register ~id:"REGISTERED_OBSERVER_BEING_DEALLOCATED" Warning Linters
~user_documentation:
[%blob "../../documentation/issues/REGISTERED_OBSERVER_BEING_DEALLOCATED.md"]
let resource_leak =
register ~id:"RESOURCE_LEAK" Error Biabduction
~user_documentation:[%blob "../../documentation/issues/RESOURCE_LEAK.md"]
@ -822,7 +816,6 @@ let retain_cycle =
let skip_function = register_hidden ~enabled:false ~id:"SKIP_FUNCTION" Info Biabduction
let shell_injection =
register ~id:"SHELL_INJECTION" Error Quandary
~user_documentation:"Environment variable or file data flowing to shell."
@ -889,12 +882,6 @@ let complexity_increase ~kind ~is_on_ui_thread =
let topl_error = register ~id:"TOPL_ERROR" Error TOPL ~user_documentation:"Experimental."
let _unavailable_api_in_supported_ios_sdk =
register ~id:"UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK" Warning Linters
~user_documentation:[%blob "../../documentation/issues/UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK.md"]
let uninitialized_value =
register ~id:"UNINITIALIZED_VALUE" Error Uninit
~user_documentation:[%blob "../../documentation/issues/UNINITIALIZED_VALUE.md"]

@ -329,17 +329,6 @@ let suppress_stderr2 f2 x1 x2 =
protect ~f ~finally
let compare_versions v1 v2 =
let int_list_of_version v =
let lv = match String.split ~on:'.' v with [v] -> [v; "0"] | v -> v in
let int_of_string_or_zero v = try int_of_string v with Failure _ -> 0 in
List.map ~f:int_of_string_or_zero lv
in
let lv1 = int_list_of_version v1 in
let lv2 = int_list_of_version v2 in
[%compare: int list] lv1 lv2
let rec rmtree name =
match Unix.((lstat name).st_kind) with
| S_DIR ->

@ -99,11 +99,6 @@ val suppress_stderr2 : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c
(** wraps a function expecting 2 arguments in another that temporarily redirects stderr to /dev/null
for the duration of the function call *)
val compare_versions : string -> string -> int
(** [compare_versions v1 v2] returns 1 if v1 is newer than v2, -1 if v1 is older than v2 and 0 if
they are the same version. The versions are strings of the shape "n.m.t", the order is
lexicographic. *)
val rmtree : string -> unit
(** [rmtree path] removes [path] and, if [path] is a directory, recursively removes its contents *)

@ -1,22 +0,0 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
TESTS_DIR = ../../..
CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS) -fobjc-arc
INFER_OPTIONS = --no-capture --linters-only --no-filtering --debug-exceptions --project-root $(TESTS_DIR) \
--iphoneos-target-sdk-version 8.0 \
--iphoneos-target-sdk-version-path-regex "codetoanalyze/objc/ioslints/filter_out_unavailable_api\.m:10.0" \
--iphoneos-target-sdk-version-path-regex "codetoanalyze/objc/ioslints/RemoveObserverInGivenSDKTest\.m:9.0" \
INFERPRINT_OPTIONS = --issues-tests
SOURCES = \
$(wildcard *.m) \
$(wildcard */*.m) \
include $(TESTS_DIR)/clang.make
include $(TESTS_DIR)/objc.make

@ -1,23 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 RemoveObserverInGivenSDKTest2 : NSObject
@property(strong) NSNotificationCenter* nc;
@end
@implementation RemoveObserverInGivenSDKTest2
- (void)foo:(NSMutableDictionary*)dict {
self.nc = [NSNotificationCenter defaultCenter];
[self.nc addObserver:self selector:@selector(foo:) name:nil object:nil];
}
@end

@ -1,25 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
@interface Filter_out_unavailable_api : NSObject
- (void)n NS_AVAILABLE(10_12, 10_0);
@end
@implementation Filter_out_unavailable_api
- (void)n {
}
// no bug
- (void)with_responds_to_selector:(Filter_out_unavailable_api*)a {
[a n];
}
@end

@ -1,10 +0,0 @@
codetoanalyze/objc/ioslints/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases.m2, 144, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases.m3, 152, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases.uifont_without_respondstoselector, 127, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases.with_responds_to_selector_in_else, 80, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases.without_instances_responds_to_selector, 104, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases.without_responds_to_selector, 65, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_in_supported_ios_sdk.m, OpenURLOptionsFromSourceApplication, 69, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_in_supported_ios_sdk.m, Unavailable_api_in_supported_ios_sdk.unsupported_class, 35, UNAVAILABLE_CLASS_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_api_in_supported_ios_sdk.m, Unavailable_api_in_supported_ios_sdk.unsupported_class_with_attributes, 54, UNAVAILABLE_CLASS_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []
codetoanalyze/objc/ioslints/unavailable_property_ios.m, FNFPlayerLayer.initWithConfigs, 20, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, no_bucket, ERROR, []

@ -1,223 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <AVFoundation/AVPlayer.h>
#import <Foundation/NSDictionary.h>
#import <Photos/PHAssetResource.h>
#import <UIKit/UIImagePickerController.h>
#import <UIKit/UIKit.h>
@interface Unavailable_api_allowed_cases : NSObject
- (void)m NS_AVAILABLE(10_12, 10_0);
- (void)n NS_AVAILABLE(10_12, 10_0);
@property(nonatomic, strong) AVPlayer* player;
@end
#define CK_AT_LEAST_IOS9 (kCFCoreFoundationVersionNumber >= 1223.1)
#define AT_LEAST_IOS9 \
(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_9_0)
#ifndef kCFCoreFoundationVersionNumber_iOS_10_0
#define kCFCoreFoundationVersionNumber_iOS_10_0 1348
#endif
#ifndef kCFCoreFoundationVersionNumber_iOS_10_2
#define kCFCoreFoundationVersionNumber_iOS_10_2 1348.22
#endif
#define AT_LEAST_IOS10 \
(kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_10_0)
@implementation Unavailable_api_allowed_cases
- (void)m {
}
- (void)n {
}
// no bug
- (void)with_responds_to_selector:(Unavailable_api_allowed_cases*)a {
if ([a respondsToSelector:@selector(m)]) {
int x = 1;
[a m];
x = 3;
}
}
// no bug
- (void)with_responds_to_selector:(Unavailable_api_allowed_cases*)a
and:(BOOL)ok {
if ([a respondsToSelector:@selector(m)] && ok) {
[a m];
}
}
// bug
- (void)without_responds_to_selector:(Unavailable_api_allowed_cases*)a {
[a m];
}
// no bug
- (void)call_m:(Unavailable_api_allowed_cases*)a
API_AVAILABLE(ios(10), macosx(10.13)) {
int x = 1;
[a m];
x = 3;
}
// bug
- (void)with_responds_to_selector_in_else:(Unavailable_api_allowed_cases*)a {
if ([a respondsToSelector:@selector(m)]) {
} else {
[a m];
}
}
// no bug
- (void)with_responds_to_selector_nested_if:(Unavailable_api_allowed_cases*)a {
if ([a respondsToSelector:@selector(m)]) {
if ([a respondsToSelector:@selector(n)]) {
[a m];
[a n];
}
}
}
// no bug
- (void)with_instances_responds_to_selector {
if ([[UICollectionView class]
instancesRespondToSelector:@selector(setPrefetchingEnabled:)]) {
[[UICollectionView appearance] setPrefetchingEnabled:NO];
}
}
// bug
- (void)without_instances_responds_to_selector {
[[UICollectionView appearance] setPrefetchingEnabled:NO];
}
// no bug
- (void)with_responds_to_selector_two_selectors:
(Unavailable_api_allowed_cases*)a {
if ([a respondsToSelector:@selector(m)] &&
[a respondsToSelector:@selector(n)]) {
[a m];
[a n];
}
}
// no bug
- (void)uifont_with_respondstoselector:(CGFloat)size {
UIFont* font;
if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) {
font = [UIFont systemFontOfSize:size weight:0];
}
}
// bug
- (void)uifont_without_respondstoselector:(CGFloat)size {
UIFont* font = [UIFont systemFontOfSize:size weight:0];
}
// no bug
- (void)m1 {
NSDictionary* destinationPixelBufferAttributes;
if (kCFCoreFoundationVersionNumber >=
kCFCoreFoundationVersionNumber_iOS_9_0) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// bug
- (void)m2 {
NSDictionary* destinationPixelBufferAttributes;
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
// bug
- (void)m3:(BOOL)ok {
NSDictionary* destinationPixelBufferAttributes;
if (ok) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// no bug
- (void)m4:(BOOL)ok {
NSDictionary* destinationPixelBufferAttributes;
if (kCFCoreFoundationVersionNumber >=
kCFCoreFoundationVersionNumber_iOS_9_0 &&
ok) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// no bug
- (void)m5 {
NSDictionary* destinationPixelBufferAttributes;
if (kCFCoreFoundationVersionNumber >=
kCFCoreFoundationVersionNumber_iOS_9_0 &&
kCFCoreFoundationVersionNumber >=
kCFCoreFoundationVersionNumber_iOS_7_0) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// no bug
- (void)m6 {
NSDictionary* destinationPixelBufferAttributes;
if (AT_LEAST_IOS9) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// no bug
- (void)m7 {
NSDictionary* destinationPixelBufferAttributes;
if (CK_AT_LEAST_IOS9) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// no bug
- (void)m8 {
NSDictionary* destinationPixelBufferAttributes;
if (AT_LEAST_IOS10) {
destinationPixelBufferAttributes =
@{(NSString*)kCVPixelBufferOpenGLESTextureCacheCompatibilityKey : @YES};
}
}
// no bug
- (void)playInReverse {
if ([self.player respondsToSelector:@selector(playImmediatelyAtRate:)]) {
[self.player playImmediatelyAtRate:-1.0];
}
}
// no bug
- (PHAsset*)improper_ios_version_good:(NSDictionary*)info {
PHAsset* videoAsset = NULL;
if (@available(iOS 11, *)) { // not strictly correct version number, should be
// "11.0" We should handle this case anyway.
videoAsset = [info objectForKey:UIImagePickerControllerPHAsset];
}
return videoAsset;
}
@end

@ -1,71 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
NS_CLASS_AVAILABLE(10_12, 10_0)
@interface Unav_class : NSObject
- (void)m;
@end
@interface Unavailable_api_in_supported_ios_sdk : NSObject
@end
@implementation Unavailable_api_in_supported_ios_sdk
// no bug
- (void)test_no_bug:(int)n and:(NSData*)data {
if (@available(macOS 10.13, iOS 11.0, *)) {
NSDictionary* cacheData =
[NSKeyedUnarchiver unarchiveTopLevelObjectWithData:data error:nil];
}
}
// bug
- (void)unsupported_class {
AVPlayerLooper* looper =
[[AVPlayerLooper alloc] initWithPlayer:nil
templateItem:nil
timeRange:kCMTimeRangeInvalid];
if (!looper) {
NSLog(@"");
}
}
// no bug
- (void)unsupported_class_with_check {
if ([AVPlayerLooper class]) {
AVPlayerLooper* looper =
[[AVPlayerLooper alloc] initWithPlayer:nil
templateItem:nil
timeRange:kCMTimeRangeInvalid];
}
}
// bug
- (void)unsupported_class_with_attributes:(nonnull Unav_class*)c {
[Unav_class new];
}
// no bug
- (void)unsupported_class_with_attributes_with_check:(nonnull Unav_class*)c {
if ([Unav_class class]) {
[[Unav_class alloc] init];
}
}
@end
static NSDictionary* OpenURLOptionsFromSourceApplication(
NSString* sourceApplication) {
NSDictionary* options =
@{UIApplicationOpenURLOptionsSourceApplicationKey : sourceApplication};
return options;
}

@ -1,24 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <AVFoundation/AVFoundation.h>
@interface FNFPlayerLayer : CAEAGLLayer
- (instancetype)initWithConfigs:(FNFPlayerLayer*)configs;
@end
@implementation FNFPlayerLayer {
BOOL my_field;
}
- (instancetype)initWithConfigs:(FNFPlayerLayer*)configs {
my_field = configs.presentsWithTransaction;
return self;
}
@end

@ -44,9 +44,6 @@ codetoanalyze/objc/linters/nsnumber.m, bad2, 16, BAD_POINTER_COMPARISON, no_buck
codetoanalyze/objc/linters/nsnumber.m, bad3, 21, BAD_POINTER_COMPARISON, no_bucket, WARNING, []
codetoanalyze/objc/linters/nsnumber.m, bad4, 41, BAD_POINTER_COMPARISON, no_bucket, WARNING, []
codetoanalyze/objc/linters/optional.m, Bar.unsafeAction, 21, UNSAFE_CALL_TO_OPTIONAL_METHOD, no_bucket, ERROR, []
codetoanalyze/objc/linters/registered_observer/Person.m, Linters_dummy_method, 78, REGISTERED_OBSERVER_BEING_DEALLOCATED, no_bucket, WARNING, []
codetoanalyze/objc/linters/registered_observer/Person.m, Linters_dummy_method, 95, REGISTERED_OBSERVER_BEING_DEALLOCATED, no_bucket, WARNING, []
codetoanalyze/objc/linters/registered_observer/ViewController3.m, Linters_dummy_method, 12, REGISTERED_OBSERVER_BEING_DEALLOCATED, no_bucket, WARNING, []
codetoanalyze/objc/linters/strong_delegate.m, Linters_dummy_method, 13, STRONG_DELEGATE_WARNING, no_bucket, WARNING, []
codetoanalyze/objc/linters/strong_delegate.m, Linters_dummy_method, 17, STRONG_DELEGATE_WARNING, no_bucket, WARNING, []
codetoanalyze/objc/linters/strong_delegate.m, Linters_dummy_method, 19, STRONG_DELEGATE_WARNING, no_bucket, WARNING, []

@ -1,102 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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>
// OkPerson is the only class in the whole hierarchy that invokes removeObserver
@interface OkPerson : NSObject
@property(strong) NSNotificationCenter* nc;
@end
@implementation OkPerson
- (void)boo {
[self.nc removeObserver:self];
}
@end
// ---
@interface OkPerson2 : OkPerson
@end
@implementation OkPerson2
- (void)foo:(NSMutableDictionary*)dict {
self.nc = [NSNotificationCenter defaultCenter];
[self.nc addObserver:self selector:@selector(foo:) name:nil object:nil];
}
@end
// ---
@interface OkPerson3 : OkPerson2
@end
@implementation OkPerson3
- (void)foo:(NSMutableDictionary*)dict {
self.nc = [NSNotificationCenter defaultCenter];
[self.nc addObserver:self selector:@selector(foo:) name:nil object:nil];
}
@end
// ---
// No one in the whole hierarchy of BadPerson invokes removeObserver
@interface BadPerson : NSObject
@property(strong) NSNotificationCenter* nc;
@end
@implementation BadPerson
@end
// ---
@interface BadPerson2 : BadPerson
@property(strong) NSNotificationCenter* nc;
@end
@implementation BadPerson2
- (void)foo:(NSMutableDictionary*)dict {
self.nc = [NSNotificationCenter defaultCenter];
[self.nc addObserver:self selector:@selector(foo:) name:nil object:nil];
}
@end
// ---
@interface BadPerson3 : BadPerson2
@property(strong) NSNotificationCenter* nc;
@end
@implementation BadPerson3
- (void)fooRegister:(NSMutableDictionary*)dict {
self.nc = [NSNotificationCenter defaultCenter];
[self.nc addObserver:self selector:@selector(foo:) name:nil object:nil];
}
@end

@ -1,87 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 ViewController : NSObject
@end
@implementation ViewController
- (instancetype)init {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(fired)
name:@"some_notification"
object:nil];
return self;
}
- (void)fired {
NSLog(@"This codepath fired");
}
- (void)invalidate1 {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)invalidate2 {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:@"some_notification"
object:nil];
}
@end
int fooError() {
ViewController* vc = [[ViewController alloc] init];
ViewController* vc2;
vc2 = vc;
[vc fired];
return 0;
}
int fooOK1() {
ViewController* vc = [[ViewController alloc] init];
ViewController* vc2;
vc2 = vc;
[vc fired];
[vc invalidate1];
return 0;
}
int fooOK2() {
ViewController* vc = [[ViewController alloc] init];
ViewController* vc2;
vc2 = vc;
[vc fired];
[vc invalidate2];
return 0;
}
int barError() {
// ViewController* vc = [[ViewController alloc] init];
//[vc fired];
// vc = [[ViewController alloc] init];
return 0;
}
int barOK1() {
ViewController* vc = [[ViewController alloc] init];
[vc invalidate1];
vc = [[ViewController alloc] init];
[vc invalidate1];
return 0;
}
int barOK2() {
ViewController* vc = [[ViewController alloc] init];
[vc invalidate2];
vc = [[ViewController alloc] init];
[vc invalidate1];
return 0;
}

@ -1,29 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 ViewController : NSObject
@end
@implementation ViewController
- (instancetype)init {
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(fired)
name:@"some_notification"
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:@"some_notification"
object:nil];
}
@end

@ -1,23 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 ViewControllerError : NSObject
@end
@implementation ViewControllerError
- (instancetype)init {
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(fired)
name:@"some_notification"
object:nil];
}
return self;
}
@end

@ -1,45 +0,0 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 AA : NSObject
@property(strong) NSNotificationCenter* nc;
- (void)my_method:(double)d
block_param:(double (^)(double time))myblock
st:(int)numSteps;
@end
@implementation AA
- (void)foo {
[self.nc addObserver:self selector:@selector(foo:) name:nil object:nil];
}
- (void)my_method:(double)d
block_param:(double (^)(double time))myblock
st:(int)num {
for (int i = 1; i <= num; i++) {
if (myblock)
myblock(i * d * num);
}
}
- (void)boo {
[self my_method:5.3
block_param:^(double time) {
[self.nc removeObserver:self];
return time + 7.4;
}
st:30];
}
@end

@ -7,7 +7,7 @@ TESTS_DIR = ../../..
CLANG_OPTIONS = -c $(OBJC_CLANG_OPTIONS)
INFER_OPTIONS = --quandary-only --no-filtering --debug-exceptions --project-root $(TESTS_DIR) --iphoneos-target-sdk-version 8.0
INFER_OPTIONS = --quandary-only --no-filtering --debug-exceptions --project-root $(TESTS_DIR)
INFERPRINT_OPTIONS = --issues-tests
SOURCES = \

Loading…
Cancel
Save