Permalink
Browse files

introduce scheck_heavy

  • Loading branch information...
1 parent a5fa1c6 commit 9efc1da8c395264d95201bc89313bc3136097f1a pad committed Dec 2, 2010
Showing with 284 additions and 42 deletions.
  1. +2 −0 .gitignore
  2. +14 −0 Makefile
  3. +41 −0 lang_php/analyze/checker/error_php.ml
  4. +3 −0 lang_php/analyze/checker/error_php.mli
  5. +11 −42 main_scheck.ml
  6. +213 −0 main_scheck_heavy.ml
View
@@ -253,3 +253,5 @@ external/ocamlbdb/libcamlbdb.a
/lang_csharp/parsing/parser_csharp.output
/pfff_test
/ocamldoc.out
+/pfff_db_heavy
+/scheck_heavy
View
@@ -32,6 +32,7 @@ PROGS+=pfff_test
ifeq ($(FEATURE_BDB), 1)
PROGS+=pfff_db_heavy
+PROGS+=scheck_heavy
endif
ifeq ($(FEATURE_VISUAL), 1)
@@ -400,6 +401,19 @@ clean::
rm -f scheck
#------------------------------------------------------------------------------
+# scheck_heavy targets
+#------------------------------------------------------------------------------
+
+scheck_heavy: $(LIBS) main_scheck_heavy.cmo
+ $(OCAMLC) $(CUSTOM) -o $@ $(SYSLIBS) $^
+
+scheck_heavy.opt: $(LIBS:.cma=.cmxa) $(LIBS2:.cma=.cmxa) $(OBJS2:.cmo=.cmx) main_scheck_heavy.cmx
+ $(OCAMLOPT) $(STATIC) -o $@ $(SYSLIBS:.cma=.cmxa) $^
+
+clean::
+ rm -f scheck_heavy
+
+#------------------------------------------------------------------------------
# ppp targets
#------------------------------------------------------------------------------
@@ -209,3 +209,44 @@ let warning err =
let report_all_errors () =
!_errors |> List.rev |> List.iter report_error
+
+
+(*****************************************************************************)
+(* Ranking bis *)
+(*****************************************************************************)
+
+(* ranking errors, inspired by Engler slides *)
+let rank_errors errs =
+ errs +> List.map (fun x ->
+ x,
+ match x with
+ | UnusedVariable (_, Scope_code.Local) -> 10
+ | CfgError (Controlflow_build_php.DeadCode (_, node_kind)) ->
+ (match node_kind with
+ | Controlflow_php.Break -> 3
+ | Controlflow_php.Return -> 3
+ | _ -> 15
+ )
+ | CfgError _ -> 11
+ | _ -> 0
+ ) +> Common.sort_by_val_highfirst +> Common.map fst
+
+
+let show_10_most_recurring_unused_variable_names () =
+
+ (* most recurring probably false positif *)
+ let hcount_str = Common.hash_with_default (fun() -> 0) in
+
+ !_errors +> List.iter (fun err ->
+ match err with
+ | UnusedVariable (dname, scope) ->
+ let s = Ast.dname dname in
+ hcount_str#update s (fun old -> old+1);
+ | _ -> ()
+ );
+ pr2 "top 10 most recurring unused variable names";
+ hcount_str#to_list +> Common.sort_by_val_highfirst +> Common.take_safe 10
+ +> List.iter (fun (s, cnt) ->
+ pr2 (spf " %s -> %d" s cnt)
+ );
+ ()
@@ -35,3 +35,6 @@ val warning: error -> unit
val report_error : error -> unit
val report_all_errors: unit -> unit
+val rank_errors: error list -> error list
+
+val show_10_most_recurring_unused_variable_names: unit -> unit
View
@@ -29,8 +29,8 @@ module S = Scope_code
*
* 'scheck' can also leverage more expensive global analysis to find more bugs.
* Doing so requires a PHP code database which is usually very expensive
- * to build (see pfff_db) and very large disk-wise. Fortunately one can
- * now build a light database (see pfff_db_light) and use this as a cache.
+ * to build (see pfff_db_heavy) and very large disk-wise. Fortunately one can
+ * now build a light database (see pfff_db) and use this as a cache.
*
* One could also use the heavy database but this requires to have
* the program linked with Berkeley DB, adding some dependencies to
@@ -51,12 +51,13 @@ module S = Scope_code
* - TODO leverage global analysis computed previously by pfff_db_light
* - TODO perform global analysis "lazily" by building db on-the-fly
* of the relevant included files (configurable via a -depth_limit flag)
- * - still? leverage global analysis computed by pfff_db
+ * - leverage global analysis computed by pfff_db_heavy, see
+ * main_scheck_heavy.ml
*
* current checks:
+ * - variable related (use of undeclared variable, unused variable, etc)
* - TODO use/def of entities (e.g. use of undefined class/function/constant
* a la checkModule)
- * - TODO variable related (use of undeclared variable, unused variable, etc)
* - TODO function call related (wrong number of arguments, bad keyword
* arguments, etc)
* - TODO class related (use of undefined member)
@@ -121,42 +122,6 @@ let layer_file = ref (None: filename option)
(* Helpers *)
(*****************************************************************************)
-(* ranking errors, inspired by Engler slides *)
-let rank_errors errs =
- errs +> List.map (fun x ->
- x,
- match x with
- | Error_php.UnusedVariable (_, S.Local) -> 10
- | Error_php.CfgError (Controlflow_build_php.DeadCode (_, node_kind)) ->
- (match node_kind with
- | Controlflow_php.Break -> 3
- | Controlflow_php.Return -> 3
- | _ -> 15
- )
- | Error_php.CfgError _ -> 11
- | _ -> 0
- ) +> Common.sort_by_val_highfirst +> Common.map fst
-
-
-let show_10_most_recurssing_unused_variable_names () =
-
- (* most recurring probably false positif *)
- let hcount_str = Common.hash_with_default (fun() -> 0) in
-
- !Error_php._errors +> List.iter (fun err ->
- match err with
- | Error_php.UnusedVariable (dname, scope) ->
- let s = Ast.dname dname in
- hcount_str#update s (fun old -> old+1);
- | _ -> ()
- );
- pr2 "top 10 most recurring unused variable names";
- hcount_str#to_list +> Common.sort_by_val_highfirst +> Common.take_safe 10
- +> List.iter (fun (s, cnt) ->
- pr2 (spf " %s -> %d" s cnt)
- );
- ()
-
(*****************************************************************************)
(* Wrappers *)
(*****************************************************************************)
@@ -187,10 +152,14 @@ let main_action xs =
);
let errs = !Error_php._errors +> List.rev in
- let errs = if !rank then rank_errors errs +> Common.take_safe 20 else errs in
+ let errs =
+ if !rank
+ then Error_php.rank_errors errs +> Common.take_safe 20
+ else errs
+ in
errs +> List.iter (fun err -> pr (Error_php.string_of_error err));
- show_10_most_recurssing_unused_variable_names ();
+ Error_php.show_10_most_recurring_unused_variable_names ();
pr2 (spf "total errors = %d" (List.length !Error_php._errors));
pr2 "";
View
@@ -0,0 +1,213 @@
+
+(*
+ * The author disclaims copyright to this source code. In place of
+ * a legal notice, here is a blessing:
+ *
+ * May you do good and not evil.
+ * May you find forgiveness for yourself and forgive others.
+ * May you share freely, never taking more than you give.
+ *)
+
+open Common
+
+open Ast_php
+
+module Ast = Ast_php
+module V = Visitor_php
+
+module S = Scope_code
+
+(*****************************************************************************)
+(* Purpose *)
+(*****************************************************************************)
+
+(* A lint-like checker for PHP using (expensive) global analysis.
+ * See also main_scheck.ml
+ *)
+
+(*****************************************************************************)
+(* Flags *)
+(*****************************************************************************)
+
+let verbose = ref false
+
+(* action mode *)
+let action = ref ""
+
+(* In strict mode, we are more aggressive regarding scope like in
+ * JsLint.
+ *
+ * is also in Error_php.ml
+ *)
+let strict_scope = ref false
+
+let rank = ref true
+
+let layer_file = ref (None: filename option)
+
+let metapath = ref "/tmp/pfff_db"
+
+(*****************************************************************************)
+(* Helpers *)
+(*****************************************************************************)
+
+(*****************************************************************************)
+(* Wrappers *)
+(*****************************************************************************)
+let pr2_dbg s =
+ if !verbose then Common.pr2 s
+
+(*****************************************************************************)
+(* Main action *)
+(*****************************************************************************)
+
+(* mostly a copy paste of main_scheck.ml but now use metapath
+ * and calls more check_xxx functions.
+ *)
+let main_action xs =
+
+ let files = Lib_parsing_php.find_php_files_of_dir_or_files xs in
+ let errors = ref [] in
+
+ Flag_parsing_php.show_parsing_error := false;
+ Flag_parsing_php.verbose_lexing := false;
+ files +> List.iter (fun file ->
+ try
+ pr2_dbg (spf "processing: %s" file);
+ raise Todo;
+ let find_entity = None in
+
+ Check_all_php.check_file ~find_entity file;
+ with exn ->
+ Common.push2 (spf "PB with %s, exn = %s" file
+ (Common.string_of_exn exn)) errors;
+ );
+
+ let errs = !Error_php._errors +> List.rev in
+ let errs =
+ if !rank
+ then Error_php.rank_errors errs +> Common.take_safe 20
+ else errs
+ in
+
+ errs +> List.iter (fun err -> pr (Error_php.string_of_error err));
+ Error_php.show_10_most_recurring_unused_variable_names ();
+ pr2 (spf "total errors = %d" (List.length !Error_php._errors));
+
+ pr2 "";
+ !errors +> List.iter pr2;
+ pr2 "";
+
+ !layer_file +> Common.do_option (fun file ->
+ (* a layer needs readable paths, hence the root *)
+ let root = Common.common_prefix_of_files_or_dirs xs in
+
+ Layer_checker_php.gen_layer ~root ~output:file !Error_php._errors
+
+ );
+ ()
+
+(*****************************************************************************)
+(* Extra actions *)
+(*****************************************************************************)
+
+(*---------------------------------------------------------------------------*)
+(* the command line flags *)
+(*---------------------------------------------------------------------------*)
+let scheck_extra_actions () = [
+]
+
+(*****************************************************************************)
+(* The options *)
+(*****************************************************************************)
+
+let all_actions () =
+ scheck_extra_actions()++
+ Test_parsing_php.actions()++
+ Test_analyze_php.actions()++
+ []
+
+let options () =
+ [
+ "-metapath", Arg.Set_string metapath,
+ "<dir> (default=" ^ !metapath ^ ")";
+ "-strict", Arg.Set strict_scope,
+ " emulate block scope instead of function scope";
+ "-no_scrict_scope", Arg.Clear strict_scope,
+ " use function scope (default)";
+ "-no_rank", Arg.Clear rank,
+ " ";
+ "-gen_layer", Arg.String (fun s -> layer_file := Some s),
+ " <file> save result in pfff layer file";
+
+ "-verbose", Arg.Set verbose,
+ " ";
+ ] ++
+ Flag_analyze_php.cmdline_flags_verbose () ++
+ Common.options_of_actions action (all_actions()) ++
+ Common.cmdline_flags_devel () ++
+ Common.cmdline_flags_verbose () ++
+ Common.cmdline_flags_other () ++
+ [
+ "-version", Arg.Unit (fun () ->
+ pr2 (spf "scheck version: %s" Config.version);
+ exit 0;
+ ),
+ " guess what";
+
+ (* this can not be factorized in Common *)
+ "-date", Arg.Unit (fun () ->
+ pr2 "version: $Date: 2010/04/25 00:44:57 $";
+ raise (Common.UnixExit 0)
+ ),
+ " guess what";
+ ] ++
+ []
+
+(*****************************************************************************)
+(* Main entry point *)
+(*****************************************************************************)
+
+let main () =
+
+ let usage_msg =
+ "Usage: " ^ Common.basename Sys.argv.(0) ^
+ " [options] <file or dir> " ^ "\n" ^ "Options are:"
+ in
+ (* does side effect on many global flags *)
+ let args = Common.parse_options (options()) usage_msg Sys.argv in
+
+ (* must be done after Arg.parse, because Common.profile is set by it *)
+ Common.profile_code "Main total" (fun () ->
+
+ (match args with
+
+ (* --------------------------------------------------------- *)
+ (* actions, useful to debug subpart *)
+ (* --------------------------------------------------------- *)
+ | xs when List.mem !action (Common.action_list (all_actions())) ->
+ Common.do_action !action xs (all_actions())
+
+ | _ when not (Common.null_string !action) ->
+ failwith ("unrecognized action or wrong params: " ^ !action)
+
+ (* --------------------------------------------------------- *)
+ (* main entry *)
+ (* --------------------------------------------------------- *)
+ | x::xs ->
+ main_action (x::xs)
+
+ (* --------------------------------------------------------- *)
+ (* empty entry *)
+ (* --------------------------------------------------------- *)
+ | [] ->
+ Common.usage usage_msg (options());
+ failwith "too few arguments"
+ )
+ )
+
+(*****************************************************************************)
+let _ =
+ Common.main_boilerplate (fun () ->
+ main ();
+ )

0 comments on commit 9efc1da

Please sign in to comment.