Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

pfff: better version of find_methods_return_$this using a CFG

Summary:
This uses the control flow graph abstraction in pfff to better check
if all branches return $this.

Test Plan:
$ ./find_methods_return_this 2 methods_return_this.php
Found a match in methods_return_this.php ok__simple
Found a match in methods_return_this.php ok__last_stmt
Found a match in methods_return_this.php ok__all_branches

which is better than the first version.

Reviewers: jeev, zoel, pieter

Reviewed By: pieter

CC: pieter, julienv, mathieubaudet, erling, platform-diffs@lists, andrewparoski

Differential Revision: https://phabricator.fb.com/D658549
  • Loading branch information...
commit fec335da7da9564bc258fda67f37c5bb3fedf891 1 parent f2aed4f
pad authored
View
1  .gitignore
@@ -433,3 +433,4 @@ web/old/codemap_client.ml
web/var/logs/access.log
web/var/logs/errors.log
web/var/logs/warnings.log
+/demos/find_methods_return_this
View
50 demos/find_methods_return_this.ml
@@ -31,4 +31,52 @@ let find_methods_return_this_version1 dir =
)
)
-let main = find_methods_return_this_version1 Sys.argv.(1)
+open Ast_php
+(* the control flow graph currently works on Ast_php, not Ast_php_simple *)
+module Ast = Ast_php
+module CFG = Controlflow_php
+
+let find_methods_return_this_version2 dir =
+ let files = Lib_parsing_php.find_php_files_of_dir_or_files [dir] in
+ files +> List.iter (fun file ->
+ let cst = Parse_php.parse_program file in
+ let classes = cst +> Common.map_filter (function
+ | ClassDef def -> Some def
+ | _ -> None
+ ) in
+ classes +> List.iter (fun def ->
+ def.c_body +> Ast.unbrace +> List.iter (fun class_stmt ->
+ match class_stmt with
+ | Method def ->
+ let cfg = Controlflow_build_php.cfg_of_func def in
+ let exit_nodei = CFG.find_exit cfg in
+ let pred = cfg#predecessors exit_nodei in
+ let has_only_return_this =
+ pred#tolist +> List.for_all (fun (nodei, _edge) ->
+ let node = cfg#nodes#assoc nodei in
+ match node.CFG.n with
+ | CFG.Return (Some(Lv(This _))) -> true
+ | CFG.Return _ -> false
+ (* when have empty else branch, implicit return void *)
+ | CFG.FalseNode -> false
+ | _ -> false
+
+ )
+ in
+ if has_only_return_this
+ then
+ pr2 (spf "Found a match in %s %s"
+ file (Ast_php.str_of_name def.f_name))
+ | _ -> ()
+ )
+ )
+ )
+
+let main =
+ let func =
+ match Sys.argv.(1) with
+ | "1" -> find_methods_return_this_version1
+ | "2" -> find_methods_return_this_version2
+ | _ -> failwith "usage: find_methods_return_this 1|2 <phpfile>"
+ in
+ func Sys.argv.(2)
View
9 lang_php/analyze/foundation/controlflow_php.ml
@@ -185,6 +185,15 @@ let short_string_of_node_kind nkind =
(* Accessors *)
(*****************************************************************************)
+let find_node f cfg =
+ cfg#nodes#tolist +> Common.find_some (fun (nodei, node) ->
+ if f node then Some nodei else None
+ )
+
+let find_exit cfg = find_node (fun node -> node.n = Exit) cfg
+let find_enter cfg = find_node (fun node -> node.n = Enter) cfg
+
+
(*s: controlflow_php accessors *)
let (first_node : flow -> Ograph_extended.nodei) = fun flow ->
raise Todo
View
4 lang_php/analyze/foundation/controlflow_php.mli
@@ -107,6 +107,10 @@ type edge = Direct
type flow = (node, edge) Ograph_extended.ograph_mutable
(*e: type flow *)
+val find_node: (node -> bool) -> flow -> Ograph_extended.nodei
+val find_enter: flow -> Ograph_extended.nodei
+val find_exit: flow -> Ograph_extended.nodei
+
(*s: controlflow helpers signatures *)
val first_node : flow -> Ograph_extended.nodei
val mk_node: node_kind -> node
Please sign in to comment.
Something went wrong with that request. Please try again.