From a9a9b4fe62d034bcc8692d14289386bd4024d021 Mon Sep 17 00:00:00 2001 From: Pascal Rigaux Date: Wed, 4 Dec 2002 21:26:53 +0000 Subject: add "unused variable" detection --- perl_checker.src/tree.ml | 69 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 20 deletions(-) (limited to 'perl_checker.src/tree.ml') diff --git a/perl_checker.src/tree.ml b/perl_checker.src/tree.ml index 3145215..ee1a4ce 100644 --- a/perl_checker.src/tree.ml +++ b/perl_checker.src/tree.ml @@ -31,8 +31,8 @@ type state = { } type vars = { - my_vars : (context * string) list list ; - our_vars : (context * string) list list ; + my_vars : ((context * string) * (pos * bool ref)) list list ; + our_vars : ((context * string) * (pos * bool ref)) list list ; locally_imported : ((context * string) * string) list ; required_vars : (context * string * string) list ; current_package : per_package ; @@ -251,23 +251,26 @@ let rec fold_tree f env e = | Anonymous_sub(e') | Ref(_, e') | Deref(_, e') - -> fold_tree f env e' + -> fold_tree f env e' | Diamond(e') - -> fold_tree_option f env e' + -> fold_tree_option f env e' + + | String(l, _) + -> List.fold_left (fun env (_, e) -> fold_tree f env e) env l | Sub_declaration(e1, _, e2) | Deref_with(_, _, e1, e2) - -> - let env = fold_tree f env e1 in - let env = fold_tree f env e2 in - env + -> + let env = fold_tree f env e1 in + let env = fold_tree f env e2 in + env | Use(_, l) | List l | Block l | Call_op(_, l, _) - -> List.fold_left (fold_tree f) env l + -> List.fold_left (fold_tree f) env l | Call(e', l) -> @@ -306,6 +309,10 @@ let get_global_info_from_package t = | Call(Deref(I_func, Ident (None, "require", pos)), [Ident _ as pkg]) -> let package = string_of_Ident pkg in if uses_external_package package then None else Some((package, pos) :: l) + | Call(Deref(I_func, Ident (None, "require", pos)), [Raw_string(pkg, _)]) + when not (String.contains pkg '/') && Filename.check_suffix pkg ".pm" -> + let package = Filename.chop_suffix pkg ".pm" in + if uses_external_package package then None else Some((package, pos) :: l) | _ -> None) ) required_packages t in { @@ -320,8 +327,14 @@ let get_global_info_from_package t = }, required_packages ) [] current_packages -let is_my_declared vars t = List.exists (List.exists ((=) t)) vars.my_vars -let is_our_declared vars t = List.exists (List.exists ((=) t)) vars.our_vars +let is_my_declared vars t = + List.exists (fun l -> + List.mem_assoc t l && (snd (List.assoc t l) := true ; true) + ) vars.my_vars +let is_our_declared vars t = + List.exists (fun l -> + List.mem_assoc t l && (snd (List.assoc t l) := true ; true) + ) vars.our_vars let is_var_declared vars (context, name) = List.mem_assoc (context, name) vars.locally_imported || List.mem_assoc (context, name) (get_imports vars.state vars.current_package) || @@ -403,18 +416,18 @@ let declare_My vars (mys, pos) = ) mys in let l_pre = List.hd vars.my_vars in List.iter (fun v -> - if List.exists ((=) v) l_pre then warn_with_pos pos (sprintf "redeclared variable %s" (variable2s v)) + if List.mem_assoc v l_pre then warn_with_pos pos (sprintf "redeclared variable %s" (variable2s v)) ) l_new ; - { vars with my_vars = (l_new @ l_pre) :: List.tl vars.my_vars } + { vars with my_vars = (List.map (fun v -> v, (pos, ref false)) l_new @ l_pre) :: List.tl vars.my_vars } let declare_Our vars (ours, pos) = match vars.our_vars with | [] -> vars (* we're at the toplevel, already declared in vars_declared *) | l_pre :: other -> List.iter (fun v -> - if List.exists ((=) v) l_pre then warn_with_pos pos (sprintf "redeclared variable %s" (variable2s v)) + if List.mem_assoc v l_pre then warn_with_pos pos (sprintf "redeclared variable %s" (variable2s v)) ) ours ; - { vars with our_vars = (ours @ l_pre) :: other } + { vars with our_vars = (List.map (fun v -> v, (pos, ref false)) ours @ l_pre) :: other } let declare_My_our vars (my_or_our, l, pos) = match my_or_our with @@ -423,18 +436,26 @@ let declare_My_our vars (my_or_our, l, pos) = | "our" -> declare_Our vars (l, pos) | _ -> internal_error "declare_My_our" +let check_unused_local_variables vars = + List.iter (fun ((_, s as v), (pos, used)) -> + if not !used && s.[0] != '_' then warn_with_pos pos (sprintf "unused variable %s" (variable2s v)) + ) (List.hd vars.my_vars) + + let check_variables vars t = let rec check_variables_ vars t = fold_tree check vars t and check vars = function | Block l -> let vars' = { vars with my_vars = [] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in - let _vars' = List.fold_left check_variables_ vars' l in + let vars' = List.fold_left check_variables_ vars' l in + check_unused_local_variables vars' ; Some vars - | Call(Deref(I_func, Ident(None, "sort", _)), (Anonymous_sub(Block f) :: l)) -> + | Call(Deref(I_func, Ident(None, "sort", pos)), (Anonymous_sub(Block f) :: l)) -> let vars = List.fold_left check_variables_ vars l in - let vars' = { vars with my_vars = [ I_scalar, "a" ; I_scalar, "b" ] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in - let _vars' = List.fold_left check_variables_ vars' f in + let vars' = { vars with my_vars = [ (I_scalar, "a"), (pos, ref true) ; (I_scalar, "b"), (pos, ref true) ] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in + let vars' = List.fold_left check_variables_ vars' f in + check_unused_local_variables vars' ; Some vars | Call_op("foreach my", [my; expr; Block block], _) -> @@ -444,10 +465,18 @@ let check_variables vars t = | Call_op(op, cond :: Block first_bl :: other, _) when op = "if" || op = "while" || op = "unless" || op = "until" -> let vars' = { vars with my_vars = [] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in let vars' = check_variables_ vars' cond in - let _vars' = List.fold_left check_variables_ vars' first_bl in + let vars' = List.fold_left check_variables_ vars' first_bl in + check_unused_local_variables vars' ; let vars = List.fold_left check_variables_ vars other in Some vars + | Sub_declaration(Ident(None, "AUTOLOAD", pos) as ident, _proto, Block l) -> + let vars = declare_Our vars ([ I_func, string_of_Ident ident ], pos) in + let vars' = { vars with my_vars = [ (I_scalar, "AUTOLOAD"), (pos, ref true) ] :: vars.my_vars ; our_vars = [] :: vars.our_vars } in + let vars' = List.fold_left check_variables_ vars' l in + check_unused_local_variables vars' ; + Some vars + | Sub_declaration(Ident(_, _, pos) as ident, _proto, body) -> let vars = declare_Our vars ([ I_func, string_of_Ident ident ], pos) in let vars = check_variables_ vars body in -- cgit v1.2.1