[linters] Add new predicate has_type and check for implicit cast

Reviewed By: ddino

Differential Revision: D5025959

fbshipit-source-id: de7eb55
master
Dulma Churchill 8 years ago committed by Facebook Github Bot
parent 30b3075d11
commit c9670d215d

@ -159,7 +159,7 @@ DEFINE-CHECKER GLOBAL_VARIABLE_INITIALIZED_WITH_FUNCTION_OR_METHOD_CALL = {
is_objc_extension() AND is_global_var() AND (NOT is_const_var());
LET makes_an_expensive_call =
(is_node("CallExpr") AND NOT call_function_named("CGPointMake"))
(is_node("CallExpr") AND NOT call_function("CGPointMake"))
OR is_node("CXXTemporaryObjectExpr")
OR is_node("CXXMemberCallExpr")
OR is_node("CXXOperatorCallExpr")

@ -401,3 +401,45 @@ let name_of_decl_ref_opt (decl_ref_opt: Clang_ast_t.decl_ref option) =
| Some named_decl_info -> Some named_decl_info.ni_name
| _ -> None)
| _ -> None
let type_of_decl decl =
let open Clang_ast_t in
match decl with
| ObjCMethodDecl (_, _, obj_c_method_decl_info) ->
Some obj_c_method_decl_info.omdi_result_type.qt_type_ptr
| ObjCPropertyDecl (_, _, obj_c_property_decl_info) ->
Some obj_c_property_decl_info.opdi_qual_type.qt_type_ptr
| EnumDecl (_, _, _, type_ptr, _, _, _)
| RecordDecl (_, _, _, type_ptr, _, _, _)
| CXXRecordDecl(_, _, _, type_ptr, _, _, _, _)
| ClassTemplateSpecializationDecl(_, _, _, type_ptr, _, _, _, _, _)
| ClassTemplatePartialSpecializationDecl(_, _, _, type_ptr, _, _, _, _, _)
| TemplateTypeParmDecl (_, _, _, type_ptr)
| ObjCTypeParamDecl (_, _, _, type_ptr)
| TypeAliasDecl (_, _, _, type_ptr)
| TypedefDecl (_, _, _, type_ptr, _)
| UnresolvedUsingTypenameDecl (_, _, _, type_ptr) -> Some type_ptr
| BindingDecl (_, _, qual_type)
| FieldDecl (_, _, qual_type, _)
| ObjCAtDefsFieldDecl (_, _, qual_type, _)
| ObjCIvarDecl (_, _, qual_type, _, _)
| FunctionDecl (_, _, qual_type, _)
| CXXMethodDecl (_, _, qual_type, _, _)
| CXXConstructorDecl (_, _, qual_type, _, _)
| CXXConversionDecl (_, _, qual_type, _, _)
| CXXDestructorDecl (_, _, qual_type, _, _)
| MSPropertyDecl (_, _, qual_type)
| NonTypeTemplateParmDecl (_, _, qual_type)
| VarDecl (_, _, qual_type, _)
| DecompositionDecl (_, _, qual_type, _)
| ImplicitParamDecl (_, _, qual_type, _)
| OMPCapturedExprDecl (_, _, qual_type, _)
| ParmVarDecl (_, _, qual_type, _)
| VarTemplateSpecializationDecl (_, _, qual_type, _)
| VarTemplatePartialSpecializationDecl (_, _, qual_type, _)
| EnumConstantDecl (_, _, qual_type, _)
| IndirectFieldDecl (_, _, qual_type, _)
| OMPDeclareReductionDecl (_, _, qual_type)
| UnresolvedUsingValueDecl (_, _, qual_type) ->
Some qual_type.qt_type_ptr
| _ -> None

@ -139,3 +139,5 @@ val is_objc_factory_method : Clang_ast_t.decl -> Clang_ast_t.decl -> bool
val name_of_decl_ref_opt : Clang_ast_t.decl_ref option -> string option
val sil_annot_of_type : Clang_ast_t.qual_type -> Annot.Item.t
val type_of_decl : Clang_ast_t.decl -> Clang_ast_t.type_ptr option

@ -163,19 +163,29 @@ let is_const_expr_var an =
| Ctl_parser_types.Decl d -> CAst_utils.is_const_expr_var d
| _ -> false
let decl_ref_is_in names st =
let decl_ref_name ?kind name st =
match st with
| Clang_ast_t.DeclRefExpr (_, _, _, drti) ->
(match drti.drti_decl_ref with
| Some dr -> let ndi, _, _ = CAst_utils.get_info_from_decl_ref dr in
List.exists ~f:(compare_str_with_alexp ndi.ni_name) names
let has_right_name = compare_str_with_alexp ndi.ni_name name in
(match kind with
| Some decl_kind ->
has_right_name && PVariant.(=) dr.Clang_ast_t.dr_kind decl_kind
| None -> has_right_name)
| _ -> false)
| _ -> false
let call_function_named an names =
let declaration_ref_name ?kind an name =
match an with
| Ctl_parser_types.Stmt st ->
CAst_utils.exists_eventually_st decl_ref_is_in names st
decl_ref_name ?kind name st
| _ -> false
let call_function an name =
match an with
| Ctl_parser_types.Stmt st ->
CAst_utils.exists_eventually_st (decl_ref_name ~kind:`Function) name st
| _ -> false
let is_strong_property an =
@ -345,7 +355,6 @@ let decl_unavailable_in_supported_ios_sdk (cxt : CLintersContext.context) an =
(Utils.compare_versions available_attr_ios_sdk max_allowed_version) > 0
| _ -> false
(* Check whether a type_ptr and a string denote the same type *)
let type_ptr_equal_type type_ptr type_str =
let pos_str lexbuf =
@ -369,6 +378,19 @@ let type_ptr_equal_type type_ptr type_str =
Ctl_parser_types.tmp_c_type_equal ~name_c_type:name c_type' abs_ctype
| _ -> Logging.out "Couldn't find type....\n"; false
let has_type an _typ =
match an, _typ with
| Ctl_parser_types.Stmt stmt, ALVar.Const typ ->
(match Clang_ast_proj.get_expr_tuple stmt with
| Some (_, _, expr_info) ->
type_ptr_equal_type expr_info.ei_qual_type.qt_type_ptr typ
| _ -> false)
| Ctl_parser_types.Decl decl, ALVar.Const typ ->
(match CAst_utils.type_of_decl decl with
| Some type_ptr ->
type_ptr_equal_type type_ptr typ
| _ -> false)
| _ -> false
let method_return_type an _typ =
Logging.out "\n Executing method_return_type...";

@ -29,7 +29,7 @@ val is_syntactically_global_var : Ctl_parser_types.ast_node -> bool
val is_const_expr_var : Ctl_parser_types.ast_node -> bool
val call_function_named : Ctl_parser_types.ast_node -> ALVar.alexp list -> bool
val call_function : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val is_strong_property : Ctl_parser_types.ast_node -> bool
@ -60,6 +60,9 @@ val is_node : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val declaration_has_name : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val declaration_ref_name : ?kind:Clang_ast_t.decl_kind -> Ctl_parser_types.ast_node ->
ALVar.alexp -> bool
val is_class : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val pp_predicate : Format.formatter -> t -> unit
@ -67,6 +70,8 @@ val pp_predicate : Format.formatter -> t -> unit
val decl_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 method_return_type : Ctl_parser_types.ast_node -> ALVar.alexp -> bool
val get_available_attr_ios_sdk : Ctl_parser_types.ast_node -> string option

@ -597,45 +597,38 @@ let next_state_via_transition an trans =
let rec eval_Atomic _pred_name args an lcxt =
let pred_name = ALVar.formula_id_to_string _pred_name in
match pred_name, args, an with
| "call_class_method", [c; m], an -> CPredicates.call_class_method an c m
| "call_function", [m], an -> CPredicates.call_function an m
| "call_instance_method", [c; m], an -> CPredicates.call_instance_method an c m
| "call_method", [m], an -> CPredicates.call_method an m
| "call_class_method", [c; m], an ->
CPredicates.call_class_method an c m
| "call_instance_method", [c; m], an ->
CPredicates.call_instance_method an c m
| "is_objc_interface_named", [name], an ->
CPredicates.is_objc_interface_named an name
| "property_named", [word], an ->
CPredicates.property_named an word
| "is_objc_extension", [], _ -> CPredicates.is_objc_extension lcxt
| "is_global_var", [], an -> CPredicates.is_syntactically_global_var an
| "is_const_var", [], an -> CPredicates.is_const_expr_var an
| "call_function_named", args, an -> CPredicates.call_function_named an args
| "is_strong_property", [], an -> CPredicates.is_strong_property an
| "captures_cxx_references", [], _ -> CPredicates.captures_cxx_references an
| "context_in_synchronized_block", [], _ -> CPredicates.context_in_synchronized_block lcxt
| "declaration_has_name", [decl_name], an -> CPredicates.declaration_has_name an decl_name
| "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
| "has_type", [typ], an -> CPredicates.has_type an typ
| "isa", [classname], an -> CPredicates.isa an classname
| "is_assign_property", [], an -> CPredicates.is_assign_property an
| "is_property_pointer_type", [], an -> CPredicates.is_property_pointer_type an
| "context_in_synchronized_block", [], _ ->
CPredicates.context_in_synchronized_block lcxt
| "is_binop_with_kind", [kind], an -> CPredicates.is_binop_with_kind an kind
| "is_class", [cname], an -> CPredicates.is_class an cname
| "is_const_var", [], an -> CPredicates.is_const_expr_var an
| "is_global_var", [], an -> CPredicates.is_syntactically_global_var an
| "is_ivar_atomic", [], an -> CPredicates.is_ivar_atomic an
| "is_method_property_accessor_of_ivar", [], an ->
CPredicates.is_method_property_accessor_of_ivar an lcxt
| "is_node", [nodename], an -> CPredicates.is_node an nodename
| "is_objc_constructor", [], _ -> CPredicates.is_objc_constructor lcxt
| "is_objc_dealloc", [], _ -> CPredicates.is_objc_dealloc lcxt
| "captures_cxx_references", [], _ -> CPredicates.captures_cxx_references an
| "is_binop_with_kind", [kind], an ->
CPredicates.is_binop_with_kind an kind
| "is_unop_with_kind", [kind], an ->
CPredicates.is_unop_with_kind an kind
| "is_node", [nodename], an -> CPredicates.is_node an nodename
| "isa", [classname], an -> CPredicates.isa an classname
| "declaration_has_name", [decl_name], an ->
CPredicates.declaration_has_name an decl_name
| "is_class", [cname], an -> CPredicates.is_class an cname
| "decl_unavailable_in_supported_ios_sdk", [], an ->
CPredicates.decl_unavailable_in_supported_ios_sdk lcxt an
| "is_objc_extension", [], _ -> CPredicates.is_objc_extension lcxt
| "is_objc_interface_named", [name], an -> CPredicates.is_objc_interface_named an name
| "is_property_pointer_type", [], an -> CPredicates.is_property_pointer_type an
| "is_strong_property", [], an -> CPredicates.is_strong_property an
| "is_unop_with_kind", [kind], an -> CPredicates.is_unop_with_kind an kind
| "method_return_type", [typ], an -> CPredicates.method_return_type an typ
| "property_named", [word], an -> CPredicates.property_named an word
| "within_responds_to_selector_block", [], an ->
CPredicates.within_responds_to_selector_block lcxt an
| "method_return_type", [typ], an ->
CPredicates.method_return_type an typ
| _ -> failwith
("ERROR: Undefined Predicate or wrong set of arguments: '"
^ pred_name ^ "'")

@ -15,5 +15,6 @@ INFERPRINT_OPTIONS = --issues-tests
SOURCES = \
$(wildcard *.m) \
$(wildcard */*.m) \
$(wildcard *.c) \
include $(TESTS_DIR)/clang.make

@ -0,0 +1,12 @@
/*
* 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.
*/
int main() {
long n = 5000000000;
int c = n;
}

@ -1,3 +1,6 @@
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 10, TEST_VAR_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 11, TEST_IMPLICIT_CAST_CHECK, []
codetoanalyze/objc/linters-for-test-only/implicit_cast.c, main, 11, TEST_VAR_TYPE_CHECK, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 13, TEST_BUILTIN_TYPE, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 13, TEST_RETURN_METHOD, []
codetoanalyze/objc/linters-for-test-only/subclassing.m, A_foo:, 19, TEST_BUILTIN_TYPE, []

@ -127,5 +127,25 @@ DEFINE-CHECKER TEST_BUILTIN_TYPE = {
HOLDS-IN-NODE ObjCMethodDecl;
SET message = "Method return.....";
};
DEFINE-CHECKER TEST_IMPLICIT_CAST_CHECK = {
LET has_type_long_expr = has_type("long") HOLDS-EVENTUALLY;
SET report_when =
WHEN
has_type("int") AND has_type_long_expr
HOLDS-IN-NODE ImplicitCastExpr;
SET message = "An implicit case from long to int can cause a crash";
};
DEFINE-CHECKER TEST_VAR_TYPE_CHECK = {
SET report_when =
WHEN has_type("int") OR has_type("long")
HOLDS-IN-NODE VarDecl;
SET message = "Var has type int or long";
};

Loading…
Cancel
Save