Skip to content

Commit

Permalink
[clang] Sorting the fields in structs and classes. Was needed in the …
Browse files Browse the repository at this point in the history
…backend and forgotten.

Summary:
@public
Sorting the fields in structs and classes. Was needed in the backend and forgotten.
Fixes the github issue facebook#90.

Test Plan: Added a new test that shows that we now get a spec for the example from the github issue.
  • Loading branch information
dulmarod committed Jun 23, 2015
1 parent 843e600 commit 510fc4e
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 3 deletions.
6 changes: 5 additions & 1 deletion infer/src/clang/cFrontend_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ struct
then Format.fprintf else Format.ifprintf in
pp Format.std_formatter fmt


let print_tenv tenv =
Sil.tenv_iter (fun typname typ ->
match typname with
Expand Down Expand Up @@ -292,6 +291,11 @@ struct
| _, _, _ -> false in
append_no_duplicates field_eq list1 list2

let sort_fields fields =
let compare (name1, _, _) (name2, _, _) =
Ident.fieldname_compare name1 name2 in
list_sort compare fields

let rec collect_list_tuples l (a, a1, b, c, d) =
match l with
| [] -> (a, a1, b, c, d)
Expand Down
2 changes: 2 additions & 0 deletions infer/src/clang/cFrontend_utils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ sig

val append_no_duplicated_pvars : (Sil.exp * Sil.typ) list -> (Sil.exp * Sil.typ) list -> (Sil.exp * Sil.typ) list

val sort_fields : (Ident.fieldname * Sil.typ * Sil.item_annotation) list -> (Ident.fieldname * Sil.typ * Sil.item_annotation) list

val collect_list_tuples : ('a list * 'b list * 'c list * 'd list * 'e list) list ->
'a list * 'b list * 'c list * 'd list * 'e list -> 'a list * 'b list * 'c list * 'd list * 'e list

Expand Down
1 change: 1 addition & 0 deletions infer/src/clang/cTrans.ml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ struct
let item_annot = Sil.item_annotation_empty in
fname, typ, item_annot in
let fields = list_map mk_field_from_captured_var captured_vars in
let fields = CFrontend_utils.General_utils.sort_fields fields in
Printing.log_out "Block %s field:\n" block_name;
list_iter (fun (fn, ft, _) ->
Printing.log_out "-----> field: '%s'\n" (Ident.fieldname_to_string fn)) fields;
Expand Down
1 change: 1 addition & 0 deletions infer/src/clang/cTypes_decl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ and get_declaration_type tenv namespace decl_info n opt_type decl_list decl_cont
let non_static_fields = if CTrans_models.is_objc_memory_model_controlled n then
append_no_duplicates_fields [Sil.objc_ref_counter_field] non_static_fields
else non_static_fields in
let non_static_fields = CFrontend_utils.General_utils.sort_fields non_static_fields in
let static_fields = [] in (* Warning for the moment we do not treat static field. *)
let typ = (match opt_type with
| `Type s -> qual_type_to_sil_type_no_expansions tenv (Ast_expressions.create_qual_type s)
Expand Down
1 change: 1 addition & 0 deletions infer/src/clang/objcCategory_decl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ let process_category tenv name class_name decl_list =
match Sil.tenv_lookup tenv class_tn_name with
| Some Sil.Tstruct (intf_fields, _, _, _, superclass, intf_methods, annotation) ->
let new_fields = General_utils.append_no_duplicates_fields fields intf_fields in
let new_fields = CFrontend_utils.General_utils.sort_fields new_fields in
let new_methods = General_utils.append_no_duplicates_methods methods intf_methods in
let class_type_info =
Sil.Tstruct (
Expand Down
2 changes: 2 additions & 0 deletions infer/src/clang/objcInterface_decl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ let add_class_to_tenv tenv class_name decl_list obj_c_interface_decl_info =
let fields = append_no_duplicates_fields fields fields_sc in
(* We add the special hidden counter_field for implementing reference counting *)
let fields = append_no_duplicates_fields [Sil.objc_ref_counter_field] fields in
let fields = CFrontend_utils.General_utils.sort_fields fields in
Printing.log_out "Class %s field:\n" class_name;
list_iter (fun (fn, ft, _) ->
Printing.log_out "-----> field: '%s'\n" (Ident.fieldname_to_string fn)) fields;
Expand Down Expand Up @@ -152,6 +153,7 @@ let add_missing_fields tenv class_name decl_list idi =
" ---> Extra non-static field: '%s'\n" (Ident.fieldname_to_string fn))
extra_fields;
let new_fields = append_no_duplicates_fields extra_fields intf_fields in
let new_fields = CFrontend_utils.General_utils.sort_fields new_fields in
let class_type_info =
Sil.Tstruct (
new_fields, [], Sil.Class, Some mang_name, superclass, methods, annotation
Expand Down
2 changes: 2 additions & 0 deletions infer/tests/codetoanalyze/c/errors/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ all:
make -C null_dereference
make -C resource_leaks
make -C memory_leaks
make -C lists

clean:
make -C arithmetic clean
Expand All @@ -16,4 +17,5 @@ clean:
make -C null_dereference clean
make -C resource_leaks clean
make -C memory_leaks
make -C lists

12 changes: 12 additions & 0 deletions infer/tests/codetoanalyze/c/errors/lists/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

SOURCES = $(shell ls *.c)
OBJECTS = $(SOURCES:.c=.o)

all: clean $(OBJECTS)
echo $(OBJECTS)

.c.o:
${CC} -c $<

clean:
rm -rf $(OBJECTS)
22 changes: 22 additions & 0 deletions infer/tests/codetoanalyze/c/errors/lists/lists.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2015 - Facebook.
* All rights reserved.
*/
struct l2 {
int b;
struct l2 *a;
};

int add2(struct l2 *l) {
int r = 0;
for (; l; l = l->a) {
r += l->b;
}
return r;
}

/* Divide by zero error shows that we get a spec for add2 */
int main() {
int res = add2(0);
return 5/res;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
digraph iCFG {
14 [label="14: InitListExp \n *&e.ssn:int =12 [line 37]\n *&e.salary:float =3000.500000 [line 37]\n *&e.doj.date:int =12 [line 37]\n *&e.doj.month:int =12 [line 37]\n *&e.doj.year:int =2010 [line 37]\n " shape="box"]
14 [label="14: InitListExp \n *&e.doj.date:int =12 [line 37]\n *&e.doj.month:int =3000.500000 [line 37]\n *&e.doj.year:int =12 [line 37]\n *&e.salary:float =12 [line 37]\n *&e.ssn:int =2010 [line 37]\n " shape="box"]


14 -> 13 ;
Expand Down
2 changes: 1 addition & 1 deletion infer/tests/codetoanalyze/objc/frontend/block/block.dot
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ digraph iCFG {


19 -> 18 ;
18 [label="18: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block___objc_anonymous_block_main1______2______3); [line 21]\n n$22=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block___objc_anonymous_block_main1______2______3 ):class __objc_anonymous_block___objc_anonymous_block_main1______2______3 *) [line 21]\n *&__objc_anonymous_block___objc_anonymous_block_main1______2______3:class __objc_anonymous_block___objc_anonymous_block_main1______2______3 =n$22 [line 21]\n n$23=*&x:int [line 21]\n n$24=*&bla:int [line 21]\n *n$22.x:int =n$23 [line 21]\n *n$22.bla:int =n$24 [line 21]\n n$16=*&x:int [line 21]\n n$17=*&bla:int [line 21]\n *&addblock2:_fn_ (*)=(_fun___objc_anonymous_block___objc_anonymous_block_main1______2______3,n$16,n$17) [line 21]\n REMOVE_TEMPS(n$22,n$23,n$24,n$16,n$17); [line 21]\n " shape="box"]
18 [label="18: BinaryOperatorStmt: Assign \n DECLARE_LOCALS(&__objc_anonymous_block___objc_anonymous_block_main1______2______3); [line 21]\n n$22=_fun___objc_alloc_no_fail(sizeof(class __objc_anonymous_block___objc_anonymous_block_main1______2______3 ):class __objc_anonymous_block___objc_anonymous_block_main1______2______3 *) [line 21]\n *&__objc_anonymous_block___objc_anonymous_block_main1______2______3:class __objc_anonymous_block___objc_anonymous_block_main1______2______3 =n$22 [line 21]\n n$23=*&x:int [line 21]\n n$24=*&bla:int [line 21]\n *n$22.bla:int =n$23 [line 21]\n *n$22.x:int =n$24 [line 21]\n n$16=*&x:int [line 21]\n n$17=*&bla:int [line 21]\n *&addblock2:_fn_ (*)=(_fun___objc_anonymous_block___objc_anonymous_block_main1______2______3,n$16,n$17) [line 21]\n REMOVE_TEMPS(n$22,n$23,n$24,n$16,n$17); [line 21]\n " shape="box"]


18 -> 14 ;
Expand Down
48 changes: 48 additions & 0 deletions infer/tests/endtoend/c/ListsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2013- Facebook.
* All rights reserved.
*/

package endtoend.c;

import static org.hamcrest.MatcherAssert.assertThat;
import static utils.matchers.ResultContainsExactly.containsExactly;

import org.junit.BeforeClass;
import org.junit.Test;

import java.io.IOException;

import utils.InferException;
import utils.InferResults;

public class ListsTest {

public static final String SOURCE_FILE = "lists/lists.c";

public static final String DIVIDE_BY_ZERO = "DIVIDE_BY_ZERO";

private static InferResults inferResults;

@BeforeClass
public static void runInfer() throws InterruptedException, IOException {
inferResults = InferResults.loadCInferResults(DivideByZeroTest.class, SOURCE_FILE);
}

@Test
public void whenInferRunsOnDivideByZeroThenDivideByZeroIsFound()
throws InterruptedException, IOException, InferException {
String[] procedures = {"main"};
assertThat(
"Results should contain divide by zero error",
inferResults,
containsExactly(
DIVIDE_BY_ZERO,
SOURCE_FILE,
procedures
)
);
}


}

0 comments on commit 510fc4e

Please sign in to comment.