123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118(* 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.
*)openCommonmoduleE=Entity_codemoduleG=Graph_codemoduleError=Error_code(*****************************************************************************)(* Prelude *)(*****************************************************************************)(*
* current checks:
* - Deadcode
* - UndefinedDefOfDecl
* - UnusedExport
*)(*****************************************************************************)(* Helpers *)(*****************************************************************************)(* todo: generalize and mv in file_type.ml? *)letis_header_filefile=let(_d,_b,e)=Common2.dbe_of_filenamefileine="h"(*****************************************************************************)(* Checker *)(*****************************************************************************)letcheck_imperativeg=letpred=G.mk_eff_use_predging|>G.iter_nodes(funn->G.nodeinfo_optng|>Common.do_option(funinfo->letps=prednin(* todo: filter nodes that are in boilerplate code *)ifps=[]then(matchnwith|s,E.Functionwhens=$="main"||s=~"^main__.*"->()|_->Error.warning_locinfo.G.pos(Error.Deadcoden););(* todo: factorize with graph_code_clang, put in database_code? *)letn_def_opt=matchnwith|s,E.Prototype->Some(s,E.Function)|s,E.GlobalExtern->Some(s,E.Global)|_->Noneinn_def_opt|>Common.do_option(funn_def->letn_decl=ninifnot(G.has_noden_defg)then(* actually in C we can have things that looks like GlobalExtern
* e.g. Syscall sysnop; but are actually Prototype, so we must look
* for E.Function in that case
*)if(G.has_node(fstn_def,E.Function)g)then()elseError.warning_locinfo.G.pos(Error.UndefinedDefOfDecln_decl));letn_decl_opt=matchnwith|s,E.Function->Some(s,E.Prototype)|s,E.Global->Some(s,E.GlobalExtern)|_->Noneinn_decl_opt|>Common.do_option(funn_decl->letn_def=ninif(G.has_noden_declg)thenbeginletfile_def=G.file_of_noden_defginletfile_decl=G.file_of_noden_declginletinfo_decl=G.nodeinfon_declginletusers_outside=ps|>List.filter(funn->tryletfile_user=G.file_of_nodenginfile_user<>file_defwithNot_found->true)inifusers_outside=[]&&ps<>[]&&is_header_filefile_declthenError.warning_locinfo_decl.G.pos(Error.UnusedExport(n_decl,file_def));(* for clang I usually add a Use edge between the def and the decl
* so the decl would not have been marked as dead without this:
*)ifps=[]thenError.warning_locinfo_decl.G.pos(Error.Deadcoden_decl);end);))letcheckg=Common.save_excursionError.g_errors[](fun()->check_imperativeg;!Error.g_errors|>List.rev)