Get better language information about functions/methods

Summary: @​public
First diff to give better language information in the frontend.
This information is necessary to understand when 'self' is objc keyword,
when 'this' is C++ keyword and when they are not.

Reviewed By: @ddino, @dulmarod

Differential Revision: D2489252
master
Andrzej Kotulski 9 years ago committed by facebook-github-bot-1
parent 5e41fc7a54
commit a045886eba

@ -74,6 +74,13 @@ let lang_from_string lang_string =
else assert false in
language := lang
let lang_to_string lang =
match lang with
| C -> "c"
| OBJC -> "objective-c"
| CPP -> "c++"
| OBJCPP -> "objective-c++"
let emtpy_name_category ="EMPTY_NAME_CATEGORY_FOR_"
let objc_object = "objc_object"

@ -29,6 +29,8 @@ type lang =
val lang_from_string : string -> unit
val lang_to_string : lang -> string
val language : lang ref
val ast_file : string option ref

@ -446,7 +446,7 @@ struct
let prefix = Ast_utils.get_qualifier_string field_qual_name in
Ident.create_fieldname (Mangled.mangled field_name prefix) 0
let mk_procname_from_function name function_decl_info_opt tp =
let mk_procname_from_function name function_decl_info_opt tp language =
let file =
match function_decl_info_opt with
| Some (decl_info, function_decl_info) ->
@ -458,7 +458,7 @@ struct
| _ -> "")
| None -> "" in
let type_string =
match !CFrontend_config.language with
match language with
| CFrontend_config.CPP
| CFrontend_config.OBJCPP -> Ast_utils.string_of_type_ptr tp
| _ -> "" in

@ -141,7 +141,7 @@ sig
val mk_procname_from_objc_method : string -> string -> Procname.objc_method_kind -> Procname.t
val mk_procname_from_function : string -> (Clang_ast_t.decl_info * Clang_ast_t.function_decl_info)
option -> Clang_ast_t.type_ptr -> Procname.t
option -> Clang_ast_t.type_ptr -> CFrontend_config.lang -> Procname.t
val mk_procname_from_cpp_method : string -> string -> Clang_ast_t.type_ptr -> Procname.t

@ -18,6 +18,7 @@ type method_signature = {
_loc : Clang_ast_t.source_range;
_is_instance : bool;
_is_generated : bool;
_language : CFrontend_config.lang;
}
let ms_get_name ms =
@ -41,7 +42,10 @@ let ms_is_instance ms =
let ms_is_generated ms =
ms._is_generated
let make_ms procname args ret_type attributes loc is_instance is_generated =
let ms_get_lang ms =
ms._language
let make_ms procname args ret_type attributes loc is_instance is_generated lang =
let meth_signature = {
_name = procname;
_args = args;
@ -49,7 +53,9 @@ let make_ms procname args ret_type attributes loc is_instance is_generated =
_attributes = attributes;
_loc = loc;
_is_instance = is_instance;
_is_generated = is_generated} in
_is_generated = is_generated;
_language = lang;
} in
meth_signature
let replace_name_ms ms name =

@ -25,9 +25,11 @@ val ms_get_loc : method_signature -> Clang_ast_t.source_range
val ms_is_instance : method_signature -> bool
val ms_get_lang : method_signature -> CFrontend_config.lang
val make_ms : Procname.t -> (string * Clang_ast_t.type_ptr * Clang_ast_t.stmt option) list ->
Clang_ast_t.type_ptr -> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> bool -> bool ->
method_signature
Clang_ast_t.type_ptr -> Clang_ast_t.attribute list -> Clang_ast_t.source_range -> bool ->
bool -> CFrontend_config.lang -> method_signature
val replace_name_ms : method_signature -> Procname.t -> method_signature

@ -28,14 +28,14 @@ type method_call_type =
| MCStatic
type function_method_decl_info =
| Func_decl_info of Clang_ast_t.function_decl_info * Clang_ast_t.type_ptr
| Func_decl_info of Clang_ast_t.function_decl_info * Clang_ast_t.type_ptr * CFrontend_config.lang
| Cpp_Meth_decl_info of Clang_ast_t.function_decl_info * string * Clang_ast_t.type_ptr
| ObjC_Meth_decl_info of Clang_ast_t.obj_c_method_decl_info * string
| Block_decl_info of Clang_ast_t.block_decl_info * Clang_ast_t.type_ptr
let is_instance_method function_method_decl_info is_instance =
match function_method_decl_info with
| Func_decl_info (function_decl_info, _) -> false
| Func_decl_info (function_decl_info, _, _) -> false
| Cpp_Meth_decl_info _ -> true
| ObjC_Meth_decl_info (method_decl_info, _) ->
method_decl_info.Clang_ast_t.omdi_is_instance_method
@ -55,11 +55,18 @@ let get_class_param function_method_decl_info =
let get_param_decls function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (function_decl_info, _)
| Func_decl_info (function_decl_info, _, _)
| Cpp_Meth_decl_info (function_decl_info, _, _) -> function_decl_info.Clang_ast_t.fdi_parameters
| ObjC_Meth_decl_info (method_decl_info, _) -> method_decl_info.Clang_ast_t.omdi_parameters
| Block_decl_info (block_decl_info, _) -> block_decl_info.Clang_ast_t.bdi_parameters
let get_language function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (_, _, language) -> language
| Cpp_Meth_decl_info _ -> CFrontend_config.CPP
| ObjC_Meth_decl_info _ -> CFrontend_config.OBJC
| Block_decl_info _ -> CFrontend_config.OBJC
let get_parameters function_method_decl_info =
let par_to_ms_par par =
match par with
@ -73,7 +80,7 @@ let get_parameters function_method_decl_info =
let get_return_type function_method_decl_info =
match function_method_decl_info with
| Func_decl_info (_, typ)
| Func_decl_info (_, typ, _)
| Cpp_Meth_decl_info (_, _, typ)
| Block_decl_info (_, typ) ->
Ast_expressions.create_type_ptr_with_just_pointer (CTypes.return_type_of_function_type typ)
@ -85,16 +92,19 @@ let build_method_signature decl_info procname function_method_decl_info is_insta
let is_instance_method = is_instance_method function_method_decl_info is_instance in
let parameters = get_parameters function_method_decl_info in
let attributes = decl_info.Clang_ast_t.di_attributes in
CMethod_signature.make_ms procname parameters tp attributes source_range is_instance_method is_generated
let lang = get_language function_method_decl_info in
CMethod_signature.make_ms procname parameters tp attributes source_range is_instance_method
is_generated lang
let method_signature_of_decl class_name_opt meth_decl block_data_opt =
let open Clang_ast_t in
match meth_decl, block_data_opt, class_name_opt with
| FunctionDecl (decl_info, name_info, tp, fdi), _, _ ->
let name = name_info.ni_name in
let func_decl = Func_decl_info (fdi, tp) in
let language = !CFrontend_config.language in
let func_decl = Func_decl_info (fdi, tp, language) in
let function_info = Some (decl_info, fdi) in
let procname = General_utils.mk_procname_from_function name function_info tp in
let procname = General_utils.mk_procname_from_function name function_info tp language in
let ms = build_method_signature decl_info procname func_decl false false false in
ms, fdi.Clang_ast_t.fdi_body, fdi.Clang_ast_t.fdi_parameters
| CXXMethodDecl (decl_info, name_info, tp, fdi), _, Some class_name ->
@ -173,8 +183,9 @@ let get_formal_parameters tenv ms =
match pl with
| [] -> []
| (name, raw_type, _):: pl' ->
let tp =
if (name = CFrontend_config.self && CMethod_signature.ms_is_instance ms) then
let is_objc_self = name = CFrontend_config.self &&
CMethod_signature.ms_get_lang ms = CFrontend_config.OBJC in
let tp = if is_objc_self && CMethod_signature.ms_is_instance ms then
(Ast_expressions.create_pointer_type raw_type)
else raw_type in
let typ = CTypes_decl.type_ptr_to_sil_type tenv tp in
@ -324,7 +335,7 @@ let create_procdesc_with_pointer context pointer class_name_opt name tp =
| Some class_name ->
General_utils.mk_procname_from_cpp_method class_name name tp
| None ->
General_utils.mk_procname_from_function name None tp in
General_utils.mk_procname_from_function name None tp !CFrontend_config.language in
create_external_procdesc context.cfg callee_name false None;
callee_name

@ -42,7 +42,7 @@ struct
let callee_pn = General_utils.mk_procname_from_objc_method class_name method_name method_kind in
let open CContext in
match CTrans_models.get_predefined_model_method_signature class_name method_name
General_utils.mk_procname_from_objc_method with
General_utils.mk_procname_from_objc_method CFrontend_config.OBJC with
| Some ms ->
ignore (CMethod_trans.create_local_procdesc context.cfg context.tenv ms [] [] is_instance);
CMethod_signature.ms_get_name ms, CMethod_trans.MCNoVirtual

@ -119,7 +119,7 @@ let is_assert_log sil_fe =
let is_objc_memory_model_controlled o =
Core_foundation_model.is_objc_memory_model_controlled o
let get_predefined_ms_method condition class_name method_name method_kind mk_procname
let get_predefined_ms_method condition class_name method_name method_kind mk_procname lang
arguments return_type attributes builtin =
if condition then
let procname =
@ -127,54 +127,57 @@ let get_predefined_ms_method condition class_name method_name method_kind mk_pro
| Some procname -> procname
| None -> mk_procname class_name method_name method_kind in
let ms = CMethod_signature.make_ms procname arguments return_type attributes
(Ast_expressions.dummy_source_range ()) false false in
(Ast_expressions.dummy_source_range ()) false false lang in
Some ms
else None
let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname =
let get_predefined_ms_stringWithUTF8String class_name method_name mk_procname lang =
let condition =
class_name = CFrontend_config.nsstring_cl
&& method_name = CFrontend_config.string_with_utf8_m in
let id_type = Ast_expressions.create_id_type in
get_predefined_ms_method condition class_name method_name Procname.Class_objc_method
mk_procname [("x", Ast_expressions.create_char_star_type, None)] id_type [] None
mk_procname lang [("x", Ast_expressions.create_char_star_type, None)] id_type [] None
let get_predefined_ms_retain_release class_name method_name mk_procname =
let get_predefined_ms_retain_release class_name method_name mk_procname lang =
let condition = is_retain_or_release method_name in
let return_type =
if is_retain_method method_name || is_autorelease_method method_name
then Ast_expressions.create_id_type else Ast_expressions.create_void_type in
get_predefined_ms_method condition CFrontend_config.nsobject_cl method_name Procname.Instance_objc_method
mk_procname [(CFrontend_config.self, class_name, None)] return_type [] (get_builtinname method_name)
let class_name = CFrontend_config.nsobject_cl in
let args = [(CFrontend_config.self, class_name, None)] in
get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method
mk_procname lang args return_type [] (get_builtinname method_name)
let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname =
let get_predefined_ms_autoreleasepool_init class_name method_name mk_procname lang =
let condition =
method_name = CFrontend_config.init
&& class_name = CFrontend_config.nsautorelease_pool_cl in
let class_type = Ast_expressions.create_class_type class_name in
get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method
mk_procname [(CFrontend_config.self, class_type, None)] Ast_expressions.create_void_type [] None
mk_procname lang [(CFrontend_config.self, class_type, None)]
Ast_expressions.create_void_type [] None
let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname =
let get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname lang =
let condition =
(method_name = CFrontend_config.release || method_name = CFrontend_config.drain)
&& class_name = CFrontend_config.nsautorelease_pool_cl in
let class_type = Ast_expressions.create_class_type class_name in
get_predefined_ms_method condition class_name method_name Procname.Instance_objc_method
mk_procname [(CFrontend_config.self, class_type, None)]
Ast_expressions.create_void_type [] (Some SymExec.ModelBuiltins.__objc_release_autorelease_pool)
mk_procname lang [(CFrontend_config.self, class_type, None)] Ast_expressions.create_void_type
[] (Some SymExec.ModelBuiltins.__objc_release_autorelease_pool)
let get_predefined_model_method_signature class_name method_name mk_procname =
match get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname with
let get_predefined_model_method_signature class_name method_name mk_procname lang =
match get_predefined_ms_nsautoreleasepool_release class_name method_name mk_procname lang with
| Some ms -> Some ms
| None ->
let class_type = Ast_expressions.create_class_type class_name in
match get_predefined_ms_retain_release class_type method_name mk_procname with
match get_predefined_ms_retain_release class_type method_name mk_procname lang with
| Some ms -> Some ms
| None ->
match get_predefined_ms_stringWithUTF8String class_name method_name mk_procname with
match get_predefined_ms_stringWithUTF8String class_name method_name mk_procname lang with
| Some ms -> Some ms
| None -> get_predefined_ms_autoreleasepool_init class_name method_name mk_procname
| None -> get_predefined_ms_autoreleasepool_init class_name method_name mk_procname lang
let dispatch_functions = [
("_dispatch_once", 1);

@ -27,6 +27,6 @@ val is_toll_free_bridging : Procname.t option -> bool
val get_predefined_model_method_signature : string -> string ->
(string -> string -> Procname.objc_method_kind -> Procname.t) ->
CMethod_signature.method_signature option
CFrontend_config.lang -> CMethod_signature.method_signature option
val is_dispatch_function_name : string -> (string * int) option

@ -0,0 +1,23 @@
/*
* Copyright (c) 2015 - 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.
*/
class A {
public:
int meth_with_self(int self, int b) {
return self + b;
}
};
int fun_with_self(int self) {
return self;
}
int test(A *a) {
return a->meth_with_self(1, 2) + fun_with_self(10);
}

@ -0,0 +1,35 @@
digraph iCFG {
9 [label="9: Return Stmt \n n$0=*&a:class A * [line 22]\n n$1=_fun_A_meth_with_self(n$0:class A ,1:int ,2:int ) [line 22]\n n$2=_fun_fun_with_self(10:int ) [line 22]\n *&return:int =(n$1 + n$2) [line 22]\n REMOVE_TEMPS(n$0,n$1,n$2); [line 22]\n NULLIFY(&a,false); [line 22]\n APPLY_ABSTRACTION; [line 22]\n " shape="box"]
9 -> 8 ;
8 [label="8: Exit test \n " color=yellow style=filled]
7 [label="7: Start test\nFormals: a:class A *\nLocals: \n DECLARE_LOCALS(&return); [line 21]\n " color=yellow style=filled]
7 -> 9 ;
6 [label="6: Return Stmt \n n$0=*&self:int [line 18]\n *&return:int =n$0 [line 18]\n REMOVE_TEMPS(n$0); [line 18]\n NULLIFY(&self,false); [line 18]\n APPLY_ABSTRACTION; [line 18]\n " shape="box"]
6 -> 5 ;
5 [label="5: Exit fun_with_self \n " color=yellow style=filled]
4 [label="4: Start fun_with_self\nFormals: self:int \nLocals: \n DECLARE_LOCALS(&return); [line 17]\n " color=yellow style=filled]
4 -> 6 ;
3 [label="3: Return Stmt \n n$0=*&self:int [line 13]\n n$1=*&b:int [line 13]\n *&return:int =(n$0 + n$1) [line 13]\n REMOVE_TEMPS(n$0,n$1); [line 13]\n NULLIFY(&b,false); [line 13]\n NULLIFY(&self,false); [line 13]\n APPLY_ABSTRACTION; [line 13]\n " shape="box"]
3 -> 2 ;
2 [label="2: Exit A_meth_with_self \n " color=yellow style=filled]
1 [label="1: Start A_meth_with_self\nFormals: this:class A self:int b:int \nLocals: \n DECLARE_LOCALS(&return); [line 12]\n NULLIFY(&this,false); [line 12]\n " color=yellow style=filled]
1 -> 3 ;
}

@ -0,0 +1,51 @@
/*
* Copyright (c) 2013 - 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.
*/
package frontend.cpp;
import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.DotFilesEqual.dotFileEqualTo;
import com.google.common.collect.ImmutableList;
import org.junit.Rule;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import utils.DebuggableTemporaryFolder;
import utils.InferException;
import utils.InferRunner;
public class SelfParameterTest {
@Rule
public DebuggableTemporaryFolder folder = new DebuggableTemporaryFolder();
@Test
public void whenCaptureRunCommaThenDotFilesAreTheSame()
throws InterruptedException, IOException, InferException {
String src =
"infer/tests/codetoanalyze/cpp/frontend/keywords/self_parameter.cpp";
String dotty =
"infer/tests/codetoanalyze/cpp/frontend/keywords/self_parameter.dot";
ImmutableList<String> inferCmd =
InferRunner.createCPPInferCommandFrontend(
folder,
src);
File newDotFile = InferRunner.runInferFrontend(inferCmd);
assertThat(
"In the capture of " + src +
" the dotty files should be the same.",
newDotFile, dotFileEqualTo(dotty));
}
}
Loading…
Cancel
Save