Add poc files
This commit is contained in:
parent
30da2412e3
commit
fa600b98f7
220 changed files with 45679 additions and 0 deletions
281
h_program-lang/errors_code.ml
Normal file
281
h_program-lang/errors_code.ml
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
(* Yoann Padioleau
|
||||
*
|
||||
* Copyright (C) 2014 Facebook
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* version 2.1 as published by the Free Software Foundation, with the
|
||||
* special exception on linking described in file license.txt.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
|
||||
* license.txt for more details.
|
||||
*)
|
||||
open Common
|
||||
|
||||
module E = Entity_code
|
||||
module PI = Parse_info
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Prelude *)
|
||||
(*****************************************************************************)
|
||||
(*
|
||||
* Centralize errors report functions (they did the same in c--).
|
||||
* Mostly a copy paste of error_php.ml
|
||||
*
|
||||
* history:
|
||||
* - was in check_module.ml
|
||||
* - was generalized for scheck php
|
||||
* - introduced ranking via int (but mess)
|
||||
* - introduced simplified ranking using intermediate rank type
|
||||
* - fully generalize when introduced graph_code_checker.ml
|
||||
* - added @Scheck annotation
|
||||
* - added some false positive deadcode detection
|
||||
*
|
||||
* todo:
|
||||
* - priority to errors, so dead code func more important than dead field
|
||||
* - factorize code with errors_cpp.ml, errors_php.ml, error_php.ml
|
||||
*)
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Globals *)
|
||||
(*****************************************************************************)
|
||||
(* see g_errors below *)
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Types *)
|
||||
(*****************************************************************************)
|
||||
|
||||
type error = {
|
||||
typ: error_kind;
|
||||
loc: Parse_info.token_location;
|
||||
sev: severity;
|
||||
}
|
||||
(* less: Advice | Noisy | Meticulous ? *)
|
||||
and severity = Fatal | Warning
|
||||
|
||||
and error_kind =
|
||||
(* entities *)
|
||||
(* done while building the graph:
|
||||
* - UndefinedEntity (UseOfUndefined)
|
||||
* - MultiDefinedEntity (DupeEntity)
|
||||
*)
|
||||
(* As done by my PHP global analysis checker.
|
||||
* Never done by compilers, and unusual for linters to do that.
|
||||
*
|
||||
* note: OCaml 4.01 now does that partially by locally checking if
|
||||
* an entity is unused and not exported (which does not require
|
||||
* global analysis)
|
||||
*)
|
||||
| Deadcode of entity
|
||||
| UndefinedDefOfDecl of entity
|
||||
(* really a special case of Deadcode decl *)
|
||||
| UnusedExport of entity (* tge decl*) * Common.filename (* file of def *)
|
||||
|
||||
(* call sites *)
|
||||
(* should be done by the compiler (ocaml does):
|
||||
* - TooManyArguments, NotEnoughArguments
|
||||
* - WrongKeywordArguments
|
||||
* - ...
|
||||
*)
|
||||
|
||||
(* variables *)
|
||||
(* also done by some compilers (ocaml does):
|
||||
* - UseOfUndefinedVariable
|
||||
* - UnusedVariable
|
||||
*)
|
||||
| UnusedVariable of string * Scope_code.scope
|
||||
|
||||
(* classes *)
|
||||
|
||||
(* files (include/import) *)
|
||||
|
||||
(* bail-out constructs *)
|
||||
(* a proper language should not have that *)
|
||||
|
||||
(* lint *)
|
||||
|
||||
(* other *)
|
||||
|
||||
(* todo: should be merged with Graph_code.entity or put in Database_code?*)
|
||||
and entity = (string * Entity_code.entity_kind)
|
||||
|
||||
|
||||
type rank =
|
||||
(* Too many FPs for now. Not applied even in strict mode. *)
|
||||
| Never
|
||||
(* Usually a few FPs or too many of them. Only applied in strict mode. *)
|
||||
| OnlyStrict
|
||||
| Less
|
||||
| Ok
|
||||
| Important
|
||||
| ReallyImportant
|
||||
|
||||
(* @xxx to acknowledge or explain false positives *)
|
||||
type annotation =
|
||||
| AtScheck of string
|
||||
|
||||
(* to detect false positives (we use the Hashtbl.find_all property) *)
|
||||
type identifier_index = (string, Parse_info.token_location) Hashtbl.t
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Pretty printers *)
|
||||
(*****************************************************************************)
|
||||
|
||||
let string_of_error_kind error_kind =
|
||||
match error_kind with
|
||||
| Deadcode (s, kind) ->
|
||||
spf "dead %s, %s" (Entity_code.string_of_entity_kind kind) s
|
||||
| UndefinedDefOfDecl (s, kind) ->
|
||||
spf "no def found for %s (%s)" s (Entity_code.string_of_entity_kind kind)
|
||||
| UnusedExport ((s, kind), file_def) ->
|
||||
spf "useless export of %s (%s) (consider forward decl in %s)"
|
||||
s (Entity_code.string_of_entity_kind kind) file_def
|
||||
|
||||
| UnusedVariable (name, scope) ->
|
||||
spf "Unused variable %s, scope = %s" name
|
||||
(Scope_code.string_of_scope scope)
|
||||
|
||||
(*
|
||||
let loc_of_node root n g =
|
||||
try
|
||||
let info = G.nodeinfo n g in
|
||||
let pos = info.G.pos in
|
||||
let file = Filename.concat root pos.PI.file in
|
||||
spf "%s:%d" file pos.PI.line
|
||||
with Not_found -> "NO LOCATION"
|
||||
*)
|
||||
|
||||
let string_of_error err =
|
||||
let pos = err.loc in
|
||||
spf "%s:%d: %s" pos.PI.file pos.PI.line (string_of_error_kind err.typ)
|
||||
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Main entry points *)
|
||||
(*****************************************************************************)
|
||||
|
||||
let g_errors = ref []
|
||||
|
||||
let fatal loc err =
|
||||
Common.push { loc = loc; typ = err; sev = Fatal } g_errors
|
||||
let warning loc err =
|
||||
Common.push { loc = loc; typ = err; sev = Warning } g_errors
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Ranking *)
|
||||
(*****************************************************************************)
|
||||
|
||||
let score_of_rank = function
|
||||
| Never -> 0
|
||||
| OnlyStrict -> 1
|
||||
| Less -> 2
|
||||
| Ok -> 3
|
||||
| Important -> 4
|
||||
| ReallyImportant -> 5
|
||||
|
||||
let rank_of_error err =
|
||||
match err.typ with
|
||||
| Deadcode (_s, kind) ->
|
||||
(match kind with
|
||||
| E.Function -> Ok
|
||||
(* or enable when use propagate_uses_of_defs_to_decl in graph_code *)
|
||||
| E.GlobalExtern | E.Prototype -> Less
|
||||
| _ -> Ok
|
||||
)
|
||||
(* probably defined in assembly code? *)
|
||||
| UndefinedDefOfDecl _ -> Important
|
||||
(* we want to simplify interfaces as much as possible! *)
|
||||
| UnusedExport _ -> ReallyImportant
|
||||
| UnusedVariable _ -> Less
|
||||
|
||||
|
||||
let score_of_error err =
|
||||
err +> rank_of_error +> score_of_rank
|
||||
|
||||
(*****************************************************************************)
|
||||
(* False positives *)
|
||||
(*****************************************************************************)
|
||||
|
||||
let adjust_errors xs =
|
||||
xs +> Common.exclude (fun err ->
|
||||
let file = err.loc.PI.file in
|
||||
|
||||
match err.typ with
|
||||
| Deadcode (s, kind) ->
|
||||
(match kind with
|
||||
| E.Dir | E.File -> true
|
||||
|
||||
(* kencc *)
|
||||
| E.Prototype when s = "SET" || s = "USED" -> true
|
||||
|
||||
(* FP in graph_code_clang for now *)
|
||||
| E.Type when s =~ "E__anon" -> true
|
||||
| E.Type when s =~ "U__anon" -> true
|
||||
| E.Type when s =~ "S__anon" -> true
|
||||
| E.Type when s =~ "E__" -> true
|
||||
| E.Type when s =~ "T__" -> true
|
||||
|
||||
(* FP in graph_code_c for now *)
|
||||
| E.Type when s =~ "U____anon" -> true
|
||||
|
||||
(* TODO: to remove, but too many for now *)
|
||||
| E.Constructor
|
||||
| E.Field
|
||||
-> true
|
||||
|
||||
(* hmm plan9 specific? being unused for one project does not mean
|
||||
* it's not used by another one.
|
||||
*)
|
||||
| _ when file =~ "^include/" -> true
|
||||
|
||||
| _ when file =~ "^EXTERNAL/" -> true
|
||||
|
||||
(* too many FP on dynamic lang like PHP *)
|
||||
| E.Method -> true
|
||||
|
||||
| _ -> false
|
||||
)
|
||||
|
||||
(* kencc *)
|
||||
| UndefinedDefOfDecl (("SET" | "USED"), _) -> true
|
||||
|
||||
| UndefinedDefOfDecl _ ->
|
||||
|
||||
(* hmm very plan9 specific *)
|
||||
file =~ "^include/" ||
|
||||
file = "kernel/lib/lib.h" ||
|
||||
file = "kernel/network/ip/ip.h" ||
|
||||
file =~ "kernel/conf/" ||
|
||||
false
|
||||
|
||||
| _ -> false
|
||||
)
|
||||
|
||||
(*****************************************************************************)
|
||||
(* Annotations *)
|
||||
(*****************************************************************************)
|
||||
|
||||
let annotation_of_line_opt s =
|
||||
if s =~ ".*@\\([A-Za-z_]+\\):[ ]?\\([^@]*\\)"
|
||||
then
|
||||
let (kind, explain) = Common.matched2 s in
|
||||
Some (match kind with
|
||||
| "Scheck" -> AtScheck explain
|
||||
| s -> failwith ("Bad annotation: " ^ s)
|
||||
)
|
||||
else None
|
||||
|
||||
(* The user can override the checks by adding special annotations
|
||||
* in the code at the same line than the code it related to.
|
||||
*)
|
||||
let annotation_at2 loc =
|
||||
let file = loc.PI.file in
|
||||
let line = max (loc.PI.line - 1) 1 in
|
||||
match Common2.cat_excerpts file [line] with
|
||||
| [s] -> annotation_of_line_opt s
|
||||
| _ -> failwith (spf "wrong line number %d in %s" line file)
|
||||
|
||||
let annotation_at a =
|
||||
Common.profile_code "Errors_code.annotation" (fun () -> annotation_at2 a)
|
||||
Loading…
Add table
Add a link
Reference in a new issue