You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
4.4 KiB

(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module F = Format
type attributes_kind = ProcUndefined | ProcObjCAccessor | ProcDefined [@@deriving compare]
let equal_attributes_kind = [%compare.equal: attributes_kind]
let attributes_kind_to_int64 =
[(ProcUndefined, Int64.zero); (ProcObjCAccessor, Int64.one); (ProcDefined, Int64.of_int 2)]
let int64_of_attributes_kind a =
List.Assoc.find_exn ~equal:equal_attributes_kind attributes_kind_to_int64 a
let deserialize_attributes_kind =
let int64_to_attributes_kind = List.Assoc.inverse attributes_kind_to_int64 in
function[@warning "-8"]
| Sqlite3.Data.INT n -> List.Assoc.find_exn ~equal:Int64.equal int64_to_attributes_kind n
let proc_kind_of_attr (proc_attributes : ProcAttributes.t) =
if proc_attributes.is_defined then ProcDefined
else if Option.is_some proc_attributes.objc_accessor then ProcObjCAccessor
else ProcUndefined
let replace pname pname_blob akind source_file attributes proc_desc callees =
let pname_str = Typ.Procname.to_string pname in
let akind_int64 = int64_of_attributes_kind akind in
let proc_desc_blob = Procdesc.SQLite.serialize proc_desc in
let callees_blob = Typ.Procname.SQLiteList.serialize callees in
DBWriter.replace_attributes ~pname_str ~pname:pname_blob ~akind:akind_int64 ~source_file
~attributes ~proc_desc:proc_desc_blob ~callees:callees_blob
let find_more_defined_statement =
ResultsDatabase.register_statement
{|
SELECT attr_kind
FROM procedures
WHERE proc_name = :pname
AND attr_kind > :akind
|}
let should_try_to_update pname_blob akind =
ResultsDatabase.with_registered_statement find_more_defined_statement ~f:(fun db find_stmt ->
Sqlite3.bind find_stmt 1 (* :pname *) pname_blob
|> SqliteUtils.check_result_code db ~log:"replace bind pname" ;
Sqlite3.bind find_stmt 2 (* :akind *) (Sqlite3.Data.INT (int64_of_attributes_kind akind))
|> SqliteUtils.check_result_code db ~log:"replace bind attribute kind" ;
SqliteUtils.result_single_column_option ~finalize:false ~log:"Attributes.replace" db find_stmt
|> (* there is no entry with a strictly larger "definedness" for that proc name *)
Option.is_none )
let select_statement =
ResultsDatabase.register_statement "SELECT proc_attributes FROM procedures WHERE proc_name = :k"
let select_defined_statement =
ResultsDatabase.register_statement
"SELECT proc_attributes FROM procedures WHERE proc_name = :k AND attr_kind = %Ld"
(int64_of_attributes_kind ProcDefined)
let find ~defined pname_blob =
(if defined then select_defined_statement else select_statement)
|> ResultsDatabase.with_registered_statement ~f:(fun db select_stmt ->
Sqlite3.bind select_stmt 1 pname_blob
|> SqliteUtils.check_result_code db ~log:"find bind proc name" ;
SqliteUtils.result_single_column_option ~finalize:false ~log:"Attributes.find" db
select_stmt
|> Option.map ~f:ProcAttributes.SQLite.deserialize )
let load pname = Typ.Procname.SQLite.serialize pname |> find ~defined:false
let store ~proc_desc (attr : ProcAttributes.t) =
let pkind = proc_kind_of_attr attr in
let key = Typ.Procname.SQLite.serialize attr.proc_name in
if should_try_to_update key pkind then
replace attr.proc_name key pkind
(SourceFile.SQLite.serialize attr.loc.Location.file)
(ProcAttributes.SQLite.serialize attr)
proc_desc
(Option.map proc_desc ~f:Procdesc.get_static_callees |> Option.value ~default:[])
let load_defined pname = Typ.Procname.SQLite.serialize pname |> find ~defined:true
let find_file_capturing_procedure pname =
Option.map (load pname) ~f:(fun proc_attributes ->
let source_file = proc_attributes.ProcAttributes.translation_unit in
let origin =
(* Procedure coming from include files if it has different location than the file where it
was captured. *)
match SourceFile.compare source_file proc_attributes.ProcAttributes.loc.file <> 0 with
| true ->
`Include
| false ->
`Source
in
(source_file, origin) )
let pp_attributes_kind f = function
| ProcUndefined ->
F.pp_print_string f "<undefined>"
| ProcObjCAccessor ->
F.pp_print_string f "<ObjC accessor>"
| ProcDefined ->
F.pp_print_string f "<defined>"