[linters] Take into account the respondsToSelector block in the unavailable api check

Reviewed By: martinoluca

Differential Revision: D4455886

fbshipit-source-id: 58d4d96
master
Dulma Churchill 8 years ago committed by Facebook Github Bot
parent d84a6b854f
commit 269ea5ffe5

@ -208,7 +208,8 @@ DEFINE-CHECKER CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK = {
// DEFINE-CHECKER ctl_unavailable_api_in_supported_ios_sdk_error = {
// SET report_when =
// WHEN
// WITH-TRANSITION PointerToDecl decl_unavailable_in_supported_ios_sdk
// WITH-TRANSITION PointerToDecl
// (decl_unavailable_in_supported_ios_sdk AND NOT within_responds_to_selector_block)
// HOLDS-IN-NODE DeclRefExpr, ObjCMessageExpr;
//
// SET message =

@ -10,7 +10,7 @@
open! IStd
type if_context = {
in_responds_to_selector_block : string list;
within_responds_to_selector_block : string list;
}
type context = {

@ -104,7 +104,10 @@ let ctl_unavailable_api_in_supported_ios_sdk_error lctx an =
let open CTL in
let condition =
InNode(["DeclRefExpr"; "ObjCMessageExpr"],
EX (Some PointerToDecl, (Atomic ("decl_unavailable_in_supported_ios_sdk", [])))) in
EX (Some PointerToDecl, (
And
(Atomic ("decl_unavailable_in_supported_ios_sdk", []),
Not (Atomic ("within_responds_to_selector_block", [])))))) in
let issue_desc =
{ CIssue.name = "UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK";
severity = Exceptions.Kerror;

@ -41,8 +41,28 @@ let parse_ctl_file linters_files =
| None -> Logging.out "No linters found.\n");
In_channel.close inx) linters_files
let compute_if_context _ _ =
None (* to be extended *)
let rec get_responds_to_selector stmt =
let open Clang_ast_t in
match stmt with
| ObjCMessageExpr (_, [_; ObjCSelectorExpr (_, _, _, method_name)], _, mdi)
when String.equal mdi.Clang_ast_t.omei_selector "respondsToSelector:" ->
[method_name]
| BinaryOperator (_, [stmt1;stmt2], _, bo_info)
when PVariant.(=) bo_info.Clang_ast_t.boi_kind `LAnd ->
List.append (get_responds_to_selector stmt1) (get_responds_to_selector stmt2)
| ImplicitCastExpr (_, [stmt], _, _) ->
get_responds_to_selector stmt
| _ -> []
let compute_if_context (context:CLintersContext.context) stmt =
let prev_responds_to_selector =
match context.if_context with
| Some if_context -> if_context.within_responds_to_selector_block
| None -> [] in
let within_responds_to_selector_block =
List.append (get_responds_to_selector stmt) (prev_responds_to_selector) in
Some ({within_responds_to_selector_block} : CLintersContext.if_context)
let is_factory_method (context: CLintersContext.context) decl =
let interface_decl_opt =

@ -222,3 +222,14 @@ let decl_unavailable_in_supported_ios_sdk decl =
| Some available_attr_ios_sdk, Some iphoneos_target_sdk_version ->
Int.equal (Utils.compare_versions available_attr_ios_sdk iphoneos_target_sdk_version) 1
| _ -> false
let within_responds_to_selector_block (cxt:CLintersContext.context) decl =
let open Clang_ast_t in
match decl with
| ObjCMethodDecl (_, named_decl_info, _) ->
(match cxt.if_context with
| Some if_context ->
let in_selector_block = if_context.within_responds_to_selector_block in
List.mem ~equal:String.equal in_selector_block named_decl_info.Clang_ast_t.ni_name
| None -> false)
| _ -> false

@ -58,3 +58,5 @@ val pp_predicate : Format.formatter -> t -> unit
val decl_unavailable_in_supported_ios_sdk : Clang_ast_t.decl -> bool
val get_available_attr_ios_sdk : Clang_ast_t.decl -> string option
val within_responds_to_selector_block : CLintersContext.context -> Clang_ast_t.decl -> bool

@ -417,6 +417,8 @@ let rec eval_Atomic pred_name args an lcxt =
| "isa", _, Decl _ -> false
| "decl_unavailable_in_supported_ios_sdk", [], Decl decl ->
CPredicates.decl_unavailable_in_supported_ios_sdk decl
| "within_responds_to_selector_block", [], Decl decl ->
CPredicates.within_responds_to_selector_block lcxt decl
| "decl_unavailable_in_supported_ios_sdk", _, Stmt _ -> false
| _ -> failwith ("ERROR: Undefined Predicate or wrong set of arguments: " ^ pred_name)

@ -0,0 +1,76 @@
/*
* 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 <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);
@end
@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];
}
// 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_responds_to_selector_two_selectors:
(Unavailable_api_allowed_cases*)a {
if ([a respondsToSelector:@selector(m)] &&
[a respondsToSelector:@selector(n)]) {
[a m];
[a n];
}
}
@end

@ -1,2 +1,4 @@
codetoanalyze/objc/ioslinters/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases_with_responds_to_selector_in_else:, 52, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, []
codetoanalyze/objc/ioslinters/unavailable_api_allowed_cases.m, Unavailable_api_allowed_cases_without_responds_to_selector:, 45, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, []
codetoanalyze/objc/ioslinters/unavailable_api_in_supported_ios_sdk.m, OpenURLOptionsFromSourceApplication, 18, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, []
codetoanalyze/objc/ioslinters/unavailable_api_in_supported_ios_sdk.m, Unavailable_api_in_supported_ios_sdk_test:and:, 11, UNAVAILABLE_API_IN_SUPPORTED_IOS_SDK, []

Loading…
Cancel
Save