[clang] compare file paths in a more principled way

Reviewed By: jeremydubreil

Differential Revision: D4083490

fbshipit-source-id: 82db8f4
master
Jules Villard 8 years ago committed by Facebook Github Bot
parent ec45b44dfd
commit f21db5dab5

@ -243,34 +243,6 @@ let version_string =
Unix.time *)
let initial_analysis_time = Unix.time ()
(* Splits a path into its parts. For example:
- (split "path/to/file") is [".", "path"; "to"; "file"]
- (split "/path/to/file") is ["/", "path"; "to"; "file"] *)
let split path =
let rec loop accu p =
match Filename.dirname p with
| d when d = p -> d :: accu
| d -> loop ((Filename.basename p) :: accu) d in
loop [] path
(* Recursively resolve symlinks until we get something that is not a link. Executables may be
(multiple levels of) symbolic links to the real binary directory, eg after `make install` or
packaging. *)
let real_path path =
let rec resolve p =
match Unix.readlink p with
| link when Filename.is_relative link ->
(* [p] is a relative symbolic link *)
resolve ((Filename.dirname p) // link)
| link ->
(* [p] is an absolute symbolic link *)
resolve link
| exception Unix.Unix_error(Unix.EINVAL, _, _) ->
(* [p] is not a symbolic link *)
p in
IList.fold_left
(fun resolved_path p -> resolve (resolved_path // p)) "" (split path)
(* Resolve symlinks to get to the real executable. The real executable is located in [bin_dir]
below, which allows us to find [lib_dir], [models_dir], etc., relative to it. *)
let real_exe_name =

@ -81,6 +81,11 @@ let source_file_to_abs_path fname =
| Relative path -> Filename.concat (project_root()) path
| Absolute path -> path
let inode_equal sf1 sf2 =
let stat1 = Unix.stat (source_file_to_abs_path sf1) in
let stat2 = Unix.stat (source_file_to_abs_path sf2) in
stat1.st_dev = stat2.st_dev && stat1.st_ino = stat2.st_ino
let source_file_to_rel_path fname =
match fname with
| Relative path -> path

@ -92,6 +92,9 @@ val source_file_compare : source_file -> source_file -> int
(** equality of source files *)
val source_file_equal : source_file -> source_file -> bool
(** equality of the files on disk *)
val inode_equal : source_file -> source_file -> bool
(** empty source file *)
val source_file_empty : source_file

@ -677,3 +677,27 @@ let rec create_path path =
| Unix.Unix_error (Unix.ENOENT, _, _) ->
create_path (Filename.dirname path);
create_dir path
let real_path path =
(* Splits a path into its parts. For example:
- (split "path/to/file") is [".", "path"; "to"; "file"]
- (split "/path/to/file") is ["/", "path"; "to"; "file"] *)
let split path =
let rec loop accu p =
match Filename.dirname p with
| d when d = p -> d :: accu
| d -> loop ((Filename.basename p) :: accu) d in
loop [] path in
let rec resolve p =
match Unix.readlink p with
| link when Filename.is_relative link ->
(* [p] is a relative symbolic link *)
resolve ((Filename.dirname p) // link)
| link ->
(* [p] is an absolute symbolic link *)
resolve link
| exception Unix.Unix_error(Unix.EINVAL, _, _) ->
(* [p] is not a symbolic link *)
p in
IList.fold_left
(fun resolved_path p -> resolve (resolved_path // p)) "" (split path)

@ -305,3 +305,8 @@ val create_dir : string -> unit
(** [create_path path] will create a directory at [path], creating all the parent directories if
non-existing *)
val create_path : string -> unit
(** Recursively resolve symlinks until we get something that is not a link. Executables may be
(multiple levels of) symbolic links to the real binary directory, eg after `make install` or
packaging. *)
val real_path : string -> string

@ -50,6 +50,7 @@ let init_global_state_for_capture_and_linters source_file => {
);
register_perf_stats_report source_file;
Config.curr_language := Config.Clang;
CLocation.curr_file := source_file;
DB.Results_dir.init source_file;
Clang_ast_main.reset_cache ();
CFrontend_config.reset_global_state ()

@ -441,9 +441,10 @@ struct
let decl_info = Clang_ast_proj.get_decl_tuple decl in
let file_opt = (fst decl_info.Clang_ast_t.di_source_range).Clang_ast_t.sl_file in
match file_opt with
| None -> false
| None ->
false
| Some file ->
DB.source_file_equal
DB.inode_equal
(CLocation.source_file_from_path file)
translation_unit_context.CFrontend_config.source_file

@ -31,7 +31,7 @@ let source_file_from_path path =
let choose_sloc_to_update_curr_file trans_unit_ctx sloc1 sloc2 =
match sloc2.Clang_ast_t.sl_file with
| Some f when DB.source_file_equal (source_file_from_path f)
| Some f when DB.inode_equal (source_file_from_path f)
trans_unit_ctx.CFrontend_config.source_file ->
sloc2
| _ -> sloc1
@ -62,7 +62,7 @@ let clang_to_sil_location trans_unit_ctx clang_loc procdesc_opt =
| Some f ->
let file_db = source_file_from_path f in
let nloc =
if (DB.source_file_equal file_db trans_unit_ctx.CFrontend_config.source_file) then
if (DB.inode_equal file_db trans_unit_ctx.CFrontend_config.source_file) then
!Config.nLOC
else -1 in
file_db, nloc
@ -72,11 +72,13 @@ let clang_to_sil_location trans_unit_ctx clang_loc procdesc_opt =
let file_in_project file =
match Config.project_root with
| Some root ->
let file_in_project = string_is_prefix root file in
let real_root = real_path root in
let real_file = real_path file in
let file_in_project = string_is_prefix real_root real_file in
let paths = Config.skip_translation_headers in
let file_should_be_skipped =
IList.exists
(fun path -> string_is_prefix (Filename.concat root path) file)
(fun path -> string_is_prefix (Filename.concat real_root path) real_file)
paths in
file_in_project && not (file_should_be_skipped)
| None -> false
@ -84,7 +86,8 @@ let file_in_project file =
let should_do_frontend_check trans_unit_ctx (loc_start, _) =
match loc_start.Clang_ast_t.sl_file with
| Some file ->
let equal_current_source file = DB.source_file_equal (source_file_from_path file)
let equal_current_source file =
DB.inode_equal (source_file_from_path file)
trans_unit_ctx.CFrontend_config.source_file in
equal_current_source file ||
(file_in_project file && not Config.testing_mode)
@ -104,7 +107,7 @@ let should_translate trans_unit_ctx (loc_start, loc_end) decl_trans_context ~tra
let path_pred path = pred (source_file_from_path path) in
map_path_of path_pred loc
in
let equal_current_source = DB.source_file_equal trans_unit_ctx.CFrontend_config.source_file
let equal_current_source = DB.inode_equal trans_unit_ctx.CFrontend_config.source_file
in
let file_in_project = map_path_of file_in_project loc_end
|| map_path_of file_in_project loc_start in

Loading…
Cancel
Save