Skip to content
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4256428
Added basic test cases for changed variable names.
TimOrtel Mar 17, 2022
27dd10f
Rename detection works for simple cases
TimOrtel Mar 18, 2022
6bc0fca
Rename detection for method parameters, too
TimOrtel Apr 3, 2022
ca6670b
Renaming of method params should work now.
TimOrtel Apr 5, 2022
c1e165c
Renaming of results does work for the log files.
TimOrtel Apr 18, 2022
d589278
Added multiple incremental runs test
TimOrtel Apr 19, 2022
9eb3f87
Renamed local vars are now also shown in g2html.
TimOrtel Apr 20, 2022
d652715
Added incremental aware print statements and replaced traditional pri…
TimOrtel May 3, 2022
08da3fb
Renamed variable names are now displayed with their new name in g2html
TimOrtel May 4, 2022
3a11fb9
Cleanup print statements and added some docu.
TimOrtel May 9, 2022
26d0702
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel May 9, 2022
b7fac89
Renamed context to rename_mapping
TimOrtel May 9, 2022
abf871b
Replaced rename mapping lists with Hashtbls for increased performance
TimOrtel May 9, 2022
4745a3f
cleanup print statements and code.
TimOrtel May 14, 2022
7d702f7
Merge upstream master
TimOrtel May 14, 2022
c645c68
cherry picked context -> rename mapping
TimOrtel May 14, 2022
aed7a3a
Replaced rename mapping lists with Hashtbls for increased performance
TimOrtel May 9, 2022
9e95ddb
Old locals are now renamed to the new local names.
TimOrtel May 14, 2022
7e89ec2
Fixed duplicate id tests
TimOrtel May 16, 2022
0c6b9c4
Moved multiple incremental run tests to subdirectory.
TimOrtel Jun 8, 2022
d5979f1
Merge Branch Without Rename Mapping
TimOrtel Jun 10, 2022
37e5703
Merged upstream master
TimOrtel Jun 10, 2022
3b60fb7
Removed unused currentFunctionName global state.
TimOrtel Jun 15, 2022
fd691c5
Removed nothing test case
TimOrtel Jun 15, 2022
686a3da
Added include assert to tests. Removed useless test.c
TimOrtel Jun 15, 2022
0a0ee34
Replaced tupletostring with fancy syntax.
TimOrtel Jun 15, 2022
8b28e89
Hashtbl.add is now replaced by Hashtbl.replace in many places.
TimOrtel Jun 15, 2022
77bd926
List optimization.
TimOrtel Jun 15, 2022
7371dc9
method_rename_assumptions now uses varinfo map instead of string hash…
TimOrtel Jun 20, 2022
7b320c9
Removed RenameMapping.
TimOrtel Jun 20, 2022
40281fe
Added documentation to tests in 04-var-rename
TimOrtel Jun 21, 2022
60468d4
Add comment to test-incremental-multiple.sh
TimOrtel Jun 15, 2022
9c8e226
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel Jun 22, 2022
a9d297c
Removed syntactic noise introduced by addition and removal of RenameM…
TimOrtel Jun 22, 2022
31283c9
Removed diffs directory in tests/incremental/04-var-rename
TimOrtel Jun 22, 2022
b3487ba
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel Jul 4, 2022
a3f48fa
function parameter names are now also updated. Cleanup code.
TimOrtel Jul 5, 2022
6fe1202
eqF now uses empty rename mapping for header comparison.
TimOrtel Jul 5, 2022
8b5fbd9
Merge remote-tracking branch 'upstream/master' into dev-local-var-rename
TimOrtel Jul 6, 2022
fd3f228
CFG comparison now verifies locals again.
TimOrtel Jul 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions scripts/test-incremental-multiple.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
test=$1

base=./tests/incremental
source=$base/${test}_1.c
conf=$base/$test.json
patch1=$base/${test}_1.patch
patch2=$base/${test}_2.patch

args="--enable dbg.debug --enable printstats -v"

cat $source

./goblint --conf $conf $args --enable incremental.save $source &> $base/$test.before.log --html

patch -p0 -b <$patch1

cat $source

./goblint --conf $conf $args --enable incremental.load --enable incremental.save $source &> $base/$test.after.incr1.log --html

patch -p0 <$patch2

cat $source

./goblint --conf $conf $args --enable incremental.load --enable incremental.save --set save_run $base/$test-incrementalrun $source &> $base/$test.after.incr2.log --html


#./goblint --conf $conf $args --enable incremental.only-rename --set save_run $base/$test-originalrun $source &> $base/$test.after.scratch.log --html
#./goblint --conf $conf --enable solverdiffs --compare_runs $base/$test-originalrun $base/$test-incrementalrun $source --html

patch -p0 -b -R <$patch2
patch -p0 -b -R <$patch1
# rm -r $base/$test-originalrun $base/$test-incrementalrun
rm -r $base/$test-incrementalrun

cat $source
2 changes: 1 addition & 1 deletion src/cdomains/baseDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ struct
let printXml f r =
let e = XmlUtil.escape in
BatPrintf.fprintf f "<value>\n<map>\n<key>\n%s\n</key>\n%a<key>\n%s\n</key>\n%a<key>\n%s\n</key>\n%a\n<key>\n%s\n</key>\n%a</map>\n</value>\n"
(e @@ CPA.name ()) CPA.printXml r.cpa
(e @@ (CPA.name ())) CPA.printXml r.cpa
(e @@ PartDeps.name ()) PartDeps.printXml r.deps
(e @@ WeakUpdates.name ()) WeakUpdates.printXml r.weak
(e @@ PrivD.name ()) PrivD.printXml r.priv
Expand Down
1 change: 1 addition & 0 deletions src/framework/analyses.ml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ struct
(* Not using Node.location here to have updated locations in incremental analysis.
See: https://github.com/goblint/analyzer/issues/290#issuecomment-881258091. *)
let loc = UpdateCil.getLoc n in

BatPrintf.fprintf f "<call id=\"%s\" file=\"%s\" line=\"%d\" order=\"%d\" column=\"%d\">\n" (Node.show_id n) loc.file loc.line loc.byte loc.column;
BatPrintf.fprintf f "%a</call>\n" Range.printXml v
in
Expand Down
16 changes: 8 additions & 8 deletions src/framework/node.ml
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,21 @@ let name () = "node"
(** Pretty node plainly with entire stmt. *)
let pretty_plain () = function
| Statement s -> text "Statement " ++ dn_stmt () s
| Function f -> text "Function " ++ text f.svar.vname
| FunctionEntry f -> text "FunctionEntry " ++ text f.svar.vname
| Function f -> text "Function " ++ text (f.svar.vname)
| FunctionEntry f -> text "FunctionEntry " ++ text (f.svar.vname)

(* TODO: remove this? *)
(** Pretty node plainly with stmt location. *)
let pretty_plain_short () = function
| Statement s -> text "Statement @ " ++ CilType.Location.pretty () (Cilfacade.get_stmtLoc s)
| Function f -> text "Function " ++ text f.svar.vname
| FunctionEntry f -> text "FunctionEntry " ++ text f.svar.vname
| Function f -> text "Function " ++ text (f.svar.vname)
| FunctionEntry f -> text "FunctionEntry " ++ text (f.svar.vname)

(** Pretty node for solver variable tracing with short stmt. *)
let pretty_trace () = function
| Statement stmt -> dprintf "node %d \"%a\"" stmt.sid Cilfacade.stmt_pretty_short stmt
| Function fd -> dprintf "call of %s" fd.svar.vname
| FunctionEntry fd -> dprintf "entry state of %s" fd.svar.vname
| Function fd -> dprintf "call of %s" (fd.svar.vname)
| FunctionEntry fd -> dprintf "entry state of %s" (fd.svar.vname)

(** Output functions for Printable interface *)
let pretty () x = pretty_trace () x
Expand All @@ -56,8 +56,8 @@ let show_id = function
(** Show node label for CFG. *)
let show_cfg = function
| Statement stmt -> string_of_int stmt.sid (* doesn't use this but defaults to no label and uses ID from show_id instead *)
| Function fd -> "return of " ^ fd.svar.vname ^ "()"
| FunctionEntry fd -> fd.svar.vname ^ "()"
| Function fd -> "return of " ^ (fd.svar.vname) ^ "()"
| FunctionEntry fd -> (fd.svar.vname) ^ "()"


let location (node: t) =
Expand Down
270 changes: 181 additions & 89 deletions src/incremental/compareAST.ml

Large diffs are not rendered by default.

28 changes: 16 additions & 12 deletions src/incremental/compareCFG.ml
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
open MyCFG
open Queue
open Cil
open CilMaps
include CompareAST

let eq_node (x, fun1) (y, fun2) =
let empty_rename_mapping: rename_mapping = (StringMap.empty, VarinfoMap.empty) in
match x,y with
| Statement s1, Statement s2 -> eq_stmt ~cfg_comp:true (s1, fun1) (s2, fun2)
| Function f1, Function f2 -> eq_varinfo f1.svar f2.svar
| FunctionEntry f1, FunctionEntry f2 -> eq_varinfo f1.svar f2.svar
| Statement s1, Statement s2 -> eq_stmt ~cfg_comp:true (s1, fun1) (s2, fun2) empty_rename_mapping
| Function f1, Function f2 -> eq_varinfo f1.svar f2.svar empty_rename_mapping
| FunctionEntry f1, FunctionEntry f2 -> eq_varinfo f1.svar f2.svar empty_rename_mapping
| _ -> false

(* TODO: compare ASMs properly instead of simply always assuming that they are not the same *)
let eq_edge x y = match x, y with
| Assign (lv1, rv1), Assign (lv2, rv2) -> eq_lval lv1 lv2 && eq_exp rv1 rv2
| Proc (None,f1,ars1), Proc (None,f2,ars2) -> eq_exp f1 f2 && GobList.equal eq_exp ars1 ars2
let eq_edge x y =
let empty_rename_mapping: rename_mapping = (StringMap.empty, VarinfoMap.empty) in
match x, y with
| Assign (lv1, rv1), Assign (lv2, rv2) -> eq_lval lv1 lv2 empty_rename_mapping && eq_exp rv1 rv2 empty_rename_mapping
| Proc (None,f1,ars1), Proc (None,f2,ars2) -> eq_exp f1 f2 empty_rename_mapping && GobList.equal (eq_exp2 empty_rename_mapping) ars1 ars2
| Proc (Some r1,f1,ars1), Proc (Some r2,f2,ars2) ->
eq_lval r1 r2 && eq_exp f1 f2 && GobList.equal eq_exp ars1 ars2
| Entry f1, Entry f2 -> eq_varinfo f1.svar f2.svar
| Ret (None,fd1), Ret (None,fd2) -> eq_varinfo fd1.svar fd2.svar
| Ret (Some r1,fd1), Ret (Some r2,fd2) -> eq_exp r1 r2 && eq_varinfo fd1.svar fd2.svar
| Test (p1,b1), Test (p2,b2) -> eq_exp p1 p2 && b1 = b2
eq_lval r1 r2 empty_rename_mapping && eq_exp f1 f2 empty_rename_mapping && GobList.equal (eq_exp2 empty_rename_mapping) ars1 ars2
| Entry f1, Entry f2 -> eq_varinfo f1.svar f2.svar empty_rename_mapping
| Ret (None,fd1), Ret (None,fd2) -> eq_varinfo fd1.svar fd2.svar empty_rename_mapping
| Ret (Some r1,fd1), Ret (Some r2,fd2) -> eq_exp r1 r2 empty_rename_mapping && eq_varinfo fd1.svar fd2.svar empty_rename_mapping
| Test (p1,b1), Test (p2,b2) -> eq_exp p1 p2 empty_rename_mapping && b1 = b2
| ASM _, ASM _ -> false
| Skip, Skip -> true
| VDecl v1, VDecl v2 -> eq_varinfo v1 v2
| VDecl v1, VDecl v2 -> eq_varinfo v1 v2 empty_rename_mapping
| _ -> false

(* The order of the edges in the list is relevant. Therefore compare them one to one without sorting first *)
Expand Down
86 changes: 75 additions & 11 deletions src/incremental/compareCIL.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
open Cil
open MyCFG
open CilMaps
include CompareAST
include CompareCFG

Expand Down Expand Up @@ -36,18 +37,45 @@ let should_reanalyze (fdec: Cil.fundec) =
(* If some CFGs of the two functions to be compared are provided, a fine-grained CFG comparison is done that also determines which
* nodes of the function changed. If on the other hand no CFGs are provided, the "old" AST comparison on the CIL.file is
* used for functions. Then no information is collected regarding which parts/nodes of the function changed. *)
let eqF (a: Cil.fundec) (b: Cil.fundec) (cfgs : (cfg * (cfg * cfg)) option) =
let unchangedHeader = eq_varinfo a.svar b.svar && GobList.equal eq_varinfo a.sformals b.sformals in
let eqF (a: Cil.fundec) (b: Cil.fundec) (cfgs : (cfg * (cfg * cfg)) option) (global_rename_mapping: method_rename_assumptions) =
let local_rename_map: (string, string) Hashtbl.t = Hashtbl.create (List.length a.slocals) in

if (List.length a.slocals) = (List.length b.slocals) then
List.combine a.slocals b.slocals |>
List.map (fun x -> match x with (a, b) -> (a.vname, b.vname)) |>
List.iter (fun pair -> match pair with (a, b) -> Hashtbl.replace local_rename_map a b);


(* Compares the two varinfo lists, returning as a first element, if the size of the two lists are equal,
* and as a second a rename_mapping, holding the rename assumptions *)
let rec rename_mapping_aware_compare (alocals: varinfo list) (blocals: varinfo list) (rename_mapping: string StringMap.t) = match alocals, blocals with
| [], [] -> true, rename_mapping
| origLocal :: als, nowLocal :: bls ->
let new_mapping = StringMap.add origLocal.vname nowLocal.vname rename_mapping in

(*TODO: maybe optimize this with eq_varinfo*)
rename_mapping_aware_compare als bls new_mapping
| _, _ -> false, rename_mapping
in

let headerSizeEqual, headerRenameMapping = rename_mapping_aware_compare a.sformals b.sformals (StringMap.empty) in
let actHeaderRenameMapping = (headerRenameMapping, global_rename_mapping) in

let unchangedHeader = eq_varinfo a.svar b.svar actHeaderRenameMapping && GobList.equal (eq_varinfo2 actHeaderRenameMapping) a.sformals b.sformals in
let identical, diffOpt =
if should_reanalyze a then
false, None
else
let sameDef = unchangedHeader && GobList.equal eq_varinfo a.slocals b.slocals in
(* Here the local variables are checked to be equal *)
let sizeEqual, local_rename = rename_mapping_aware_compare a.slocals b.slocals headerRenameMapping in
let rename_mapping: rename_mapping = (local_rename, global_rename_mapping) in

let sameDef = unchangedHeader && sizeEqual in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The renaming-aware comparison is used when comparing the parameters and local variables of a function. When using the cfg comparison, the body is however compared with an empty rename mapping. I think this is inconsistent. In most cases this does not directly cause a problem, because it is usually hidden by cil creating unique variable names within a function or a merge error in case of undeclared variables (when one only renames the declaration).
An example where this causes a problem, is whenever an unused formal parameter or local variable is renamed (without any other changes). The function headers of the two versions will be equivalent (due to the existence of a valid rename mapping) and no change will be detected in the functions body (because the renamed variable never appears). The function is considered unchanged, is not reanalyzed, and so the output still contains the old version of the renamed variable name instead of the updated one.
I see two options how to solve this:

  1. the basic approach: support rename detection only for the ast comparison, but make sure it does not break the cfg comparison. This would require to use an empty rename map also during the header comparison of functions. When the cfg comparison is turned on, the construction of the rename map could even be skipped completely.
  2. the nicer approach: support rename detection of variables within functions for the cfg comparison also. As far as I can tell, this would require to hand-through the constructed rename mapping to phase 1 of the cfg comparison and eq_node and eq_edge subsequently. In updateCil.ml the old names of the formal parameters and local variables would need to be overwritten with the new names for the partially changed functions (in reset_changed_function) to obtain a correct output.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the second approach is a nice idea. If I still find the time to do it, I will definitely implement it. However, because implementing the second approach comes with a lot of extra work in testing and verifying I implemented the first version for now.

Copy link
Member

@stilscher stilscher Jul 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created issue #777 for implementing the second approach later.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, your implementation for the first approach does still not work correctly. The comparison of the local variables is still done with the rename-aware comparison even if the cfg comparison is activated. This leads to renamed and unused local variables in a partially changed function not being shown with the updated name in the output. As an example you can take a look at

#include<assert.h>

int main () {
  int a = 3;
  int b; // rename to d
  int c;
  c = a + 2; // change to a + 3
  assert(a == 3);
  return 0;
}

In the incremental run, the old name b will still be used in the output.

Copy link
Member

@stilscher stilscher Jul 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually think, that implementing approach 2 would not be much more work. But I think it is ok, to postpone it and implement it in a new PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, the locals are now checked again for cfg runs.

if not sameDef then
(false, None)
else
match cfgs with
| None -> eq_block (a.sbody, a) (b.sbody, b), None
| None -> eq_block (a.sbody, a) (b.sbody, b) rename_mapping, None
| Some (cfgOld, (cfgNew, cfgNewBack)) ->
let module CfgOld : MyCFG.CfgForward = struct let next = cfgOld end in
let module CfgNew : MyCFG.CfgBidir = struct let prev = cfgNewBack let next = cfgNew end in
Expand All @@ -57,17 +85,44 @@ let eqF (a: Cil.fundec) (b: Cil.fundec) (cfgs : (cfg * (cfg * cfg)) option) =
in
identical, unchangedHeader, diffOpt

let eq_glob (a: global) (b: global) (cfgs : (cfg * (cfg * cfg)) option) = match a, b with
| GFun (f,_), GFun (g,_) -> eqF f g cfgs
| GVar (x, init_x, _), GVar (y, init_y, _) -> eq_varinfo x y, false, None (* ignore the init_info - a changed init of a global will lead to a different start state *)
| GVarDecl (x, _), GVarDecl (y, _) -> eq_varinfo x y, false, None
let eq_glob (a: global) (b: global) (cfgs : (cfg * (cfg * cfg)) option) (global_rename_mapping: method_rename_assumptions) = match a, b with
| GFun (f,_), GFun (g,_) ->
let identical, unchangedHeader, diffOpt = eqF f g cfgs global_rename_mapping in

identical, unchangedHeader, diffOpt
| GVar (x, init_x, _), GVar (y, init_y, _) -> eq_varinfo x y (StringMap.empty, VarinfoMap.empty), false, None (* ignore the init_info - a changed init of a global will lead to a different start state *)
| GVarDecl (x, _), GVarDecl (y, _) -> eq_varinfo x y (StringMap.empty, VarinfoMap.empty), false, None
| _ -> ignore @@ Pretty.printf "Not comparable: %a and %a\n" Cil.d_global a Cil.d_global b; false, false, None

let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) =
let cfgs = if GobConfig.get_string "incremental.compare" = "cfg"
then Some (CfgTools.getCFG oldAST |> fst, CfgTools.getCFG newAST)
else None in

let generate_global_rename_mapping map global =
try
let ident = identifier_of_global global in
let old_global = GlobalMap.find ident map in

match old_global, global with
| GFun(f, _), GFun (g, _) ->
let renamed_params: string StringMap.t = if (List.length f.sformals) = (List.length g.sformals) then
let mappings = List.combine f.sformals g.sformals |>
List.filter (fun (original, now) -> not (original.vname = now.vname)) |>
List.map (fun (original, now) -> (original.vname, now.vname)) |>
List.to_seq
in

StringMap.add_seq mappings StringMap.empty
else StringMap.empty in

if not (f.svar.vname = g.svar.vname) || (StringMap.cardinal renamed_params) > 0 then
Some (f.svar, {original_method_name=f.svar.vname; new_method_name=g.svar.vname; parameter_renames=renamed_params})
else None
| _, _ -> None
with Not_found -> None
in

let addGlobal map global =
try
let gid = identifier_of_global global in
Expand All @@ -79,14 +134,15 @@ let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) =
with
Not_found -> map
in

let changes = empty_change_info () in
global_typ_acc := [];
let checkUnchanged map global =
let findChanges map global global_rename_mapping =
try
let ident = identifier_of_global global in
let old_global = GlobalMap.find ident map in
(* Do a (recursive) equal comparison ignoring location information *)
let identical, unchangedHeader, diff = eq old_global global cfgs in
let identical, unchangedHeader, diff = eq old_global global cfgs global_rename_mapping in
if identical
then changes.unchanged <- {current = global; old = old_global} :: changes.unchanged
else changes.changed <- {current = global; old = old_global; unchangedHeader; diff} :: changes.changed
Expand All @@ -100,10 +156,18 @@ let compareCilFiles ?(eq=eq_glob) (oldAST: file) (newAST: file) =
(* Store a map from functionNames in the old file to the function definition*)
let oldMap = Cil.foldGlobals oldAST addGlobal GlobalMap.empty in
let newMap = Cil.foldGlobals newAST addGlobal GlobalMap.empty in

let global_rename_mapping: method_rename_assumptions = Cil.foldGlobals newAST (fun (current_global_rename_mapping: method_rename_assumption VarinfoMap.t) global ->
match generate_global_rename_mapping oldMap global with
| Some (funVar, rename_mapping) -> VarinfoMap.add funVar rename_mapping current_global_rename_mapping
| None -> current_global_rename_mapping
) VarinfoMap.empty
in

(* For each function in the new file, check whether a function with the same name
already existed in the old version, and whether it is the same function. *)
Cil.iterGlobals newAST
(fun glob -> checkUnchanged oldMap glob);
(fun glob -> findChanges oldMap glob global_rename_mapping);

(* We check whether functions have been added or removed *)
Cil.iterGlobals newAST (fun glob -> if not (checkExists oldMap glob) then changes.added <- (glob::changes.added));
Expand Down
2 changes: 1 addition & 1 deletion src/incremental/updateCil.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ let update_ids (old_file: file) (ids: max_ids) (new_file: file) (changes: change
in
let reset_fun (f: fundec) (old_f: fundec) =
f.svar.vid <- old_f.svar.vid;
List.iter2 (fun l o_l -> l.vid <- o_l.vid) f.slocals old_f.slocals;
List.iter2 (fun l o_l -> l.vid <- o_l.vid; o_l.vname <- l.vname) f.slocals old_f.slocals;
List.iter2 (fun lo o_f -> lo.vid <- o_f.vid) f.sformals old_f.sformals;
List.iter2 (fun s o_s -> s.sid <- o_s.sid) f.sallstmts old_f.sallstmts;
List.iter (fun s -> store_node_location (Statement s) (Cilfacade.get_stmtLoc s)) f.sallstmts;
Expand Down
11 changes: 11 additions & 0 deletions src/util/cilMaps.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
open Cil

module VarinfoOrdered = struct
type t = varinfo

(*x.svar.uid cannot be used, as they may overlap between old and now AST*)
let compare (x: varinfo) (y: varinfo) = String.compare x.vname y.vname
end


module VarinfoMap = Map.Make(VarinfoOrdered)
1 change: 1 addition & 0 deletions src/util/cilType.ml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ struct
let show = show
end
)

let pp fmt x = Format.fprintf fmt "%s" x.vname (* for deriving show *)
end

Expand Down
2 changes: 1 addition & 1 deletion src/util/server.ml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ let reparse (s: t) =

(* Only called when the file has not been reparsed, so we can skip the expensive CFG comparison. *)
let virtual_changes file =
let eq (glob: Cil.global) _ _ = match glob with
let eq (glob: Cil.global) _ _ _ = match glob with
| GFun (fdec, _) -> not (CompareCIL.should_reanalyze fdec), false, None
| _ -> true, false, None
in
Expand Down
4 changes: 4 additions & 0 deletions tests/incremental/04-var-rename/01-unused_rename.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int main() {
int a = 0;
return 0;
}
3 changes: 3 additions & 0 deletions tests/incremental/04-var-rename/01-unused_rename.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{

}
8 changes: 8 additions & 0 deletions tests/incremental/04-var-rename/01-unused_rename.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
--- tests/incremental/04-var-rename/01-unused_rename.c
+++ tests/incremental/04-var-rename/01-unused_rename.c
@@ -1,4 +1,4 @@
int main() {
- int a = 0;
+ int b = 0;
return 0;
}
3 changes: 3 additions & 0 deletions tests/incremental/04-var-rename/01-unused_rename.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
local variable a is renamed to b.
a/b is not used.
No semantic changes.
11 changes: 11 additions & 0 deletions tests/incremental/04-var-rename/02-rename_and_shuffle.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include<stdio.h>

//a is renamed to c, but the usage of a is replaced by b
int main() {
int a = 0;
int b = 1;

printf("Print %d", a);

return 0;
}
3 changes: 3 additions & 0 deletions tests/incremental/04-var-rename/02-rename_and_shuffle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{

}
15 changes: 15 additions & 0 deletions tests/incremental/04-var-rename/02-rename_and_shuffle.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--- tests/incremental/04-var-rename/02-rename_and_shuffle.c
+++ tests/incremental/04-var-rename/02-rename_and_shuffle.c
@@ -2,10 +2,10 @@

//a is renamed to c, but the usage of a is replaced by b
int main() {
- int a = 0;
+ int c = 0;
int b = 1;

- printf("Print %d", a);
+ printf("Print %d", b);

return 0;
}
2 changes: 2 additions & 0 deletions tests/incremental/04-var-rename/02-rename_and_shuffle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a is renamed to c, but the usage of a is replaced by b.
Semantic changes.
11 changes: 11 additions & 0 deletions tests/incremental/04-var-rename/03-rename_with_usage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include<stdio.h>

//a is renamed to c, but its usages stay the same
int main() {
int a = 0;
int b = 1;

printf("Print %d", a);

return 0;
}
3 changes: 3 additions & 0 deletions tests/incremental/04-var-rename/03-rename_with_usage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{

}
Loading