Skip to content

Commit

Permalink
Add query to check if specific files are typechecked
Browse files Browse the repository at this point in the history
Summary:
Follow up to this diff: D49757461

Will take in a list of pyre files relative to the configuration and return if they are typechecked or not.

Will be used for a diff time job to check if changed files have type coverage

Reviewed By: connernilsen

Differential Revision: D50089721

fbshipit-source-id: f2a2e25a3ecb4579f01a2d9e4a18813668638b90
  • Loading branch information
Maggie Moss authored and facebook-github-bot committed Oct 9, 2023
1 parent 16cec0d commit a09c488
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 15 deletions.
38 changes: 23 additions & 15 deletions source/server/locationBasedLookupProcessor.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,41 @@ type types_by_location = ((Location.t * Type.t) list, error_reason) Result.t

type coverage_by_location = (LocationBasedLookup.coverage_for_path, error_reason) Result.t

let get_lookup ~build_system ~type_environment path =
let generate_lookup_for_existent_path { ModulePath.qualifier; _ } =
let timer = Timer.start () in
let lookup = LocationBasedLookup.create_of_module type_environment qualifier in
Log.log
~section:`Performance
"locationBasedLookupProcessor: create_of_module: %d"
(Timer.stop_in_ms timer);
Result.Ok lookup
in
let generate_lookup_for_nonexistent_path error_reason = Result.Error error_reason in
type module_path = (Ast.ModulePath.t, error_reason) Result.t

let get_module_path ~type_environment ~build_system path =
let full_path =
let { Configuration.Analysis.local_root = root; _ } =
TypeEnvironment.ReadOnly.controls type_environment |> EnvironmentControls.configuration
in
PyrePath.create_relative ~root ~relative:path |> SourcePath.create
in
match BuildSystem.lookup_artifact build_system full_path with
| [] -> generate_lookup_for_nonexistent_path FileNotFound
| [] -> Result.Error FileNotFound
| analysis_path :: _ -> (
(* If a source path corresponds to multiple artifacts, randomly pick an artifact and compute
results for it. *)
let module_tracker = TypeEnvironment.ReadOnly.module_tracker type_environment in
match ModuleTracker.ReadOnly.lookup_path module_tracker analysis_path with
| ModuleTracker.PathLookup.Found module_path -> generate_lookup_for_existent_path module_path
| ModuleTracker.PathLookup.ShadowedBy _ -> generate_lookup_for_nonexistent_path StubShadowing
| ModuleTracker.PathLookup.NotFound -> generate_lookup_for_nonexistent_path FileNotFound)
| ModuleTracker.PathLookup.Found module_path -> Result.Ok module_path
| ModuleTracker.PathLookup.ShadowedBy _ -> Result.Error StubShadowing
| ModuleTracker.PathLookup.NotFound -> Result.Error FileNotFound)


let get_lookup ~build_system ~type_environment path =
let module_path = get_module_path ~type_environment ~build_system path in
let generate_lookup_for_existent_path { ModulePath.qualifier; _ } =
let timer = Timer.start () in
let lookup = LocationBasedLookup.create_of_module type_environment qualifier in
Log.log
~section:`Performance
"locationBasedLookupProcessor: create_of_module: %d"
(Timer.stop_in_ms timer);
Result.Ok lookup
in
match module_path with
| Result.Ok path -> generate_lookup_for_existent_path path
| Result.Error error_reason -> Result.Error error_reason


let find_all_resolved_types_for_path ~type_environment ~build_system path =
Expand Down
8 changes: 8 additions & 0 deletions source/server/locationBasedLookupProcessor.mli
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type types_by_location = ((Location.t * Type.t) list, error_reason) Result.t

type coverage_by_location = (LocationBasedLookup.coverage_for_path, error_reason) Result.t

type module_path = (Ast.ModulePath.t, error_reason) Result.t

val find_all_resolved_types_for_path
: type_environment:TypeEnvironment.ReadOnly.t ->
build_system:BuildSystem.t ->
Expand All @@ -34,3 +36,9 @@ val get_lookup
type_environment:TypeEnvironment.ReadOnly.t ->
string ->
(LocationBasedLookup.coverage_data_lookup, error_reason) result

val get_module_path
: type_environment:TypeEnvironment.ReadOnly.t ->
build_system:BuildSystem.t ->
string ->
module_path
20 changes: 20 additions & 0 deletions source/server/query.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ module Request = struct
| SaveServerState of PyrePath.t
| Superclasses of Reference.t list
| Type of Expression.t
| IsTypechecked of string list
| TypesInFiles of string list
| ValidateTaintModels of {
path: string option;
Expand Down Expand Up @@ -136,6 +137,12 @@ module Response = struct
}
[@@deriving equal]

type typechecked = {
path: string;
is_typechecked: bool;
}
[@@deriving equal, to_yojson]

let range_to_yojson { start; end_ } =
`Assoc ["start", position_to_yojson start; "end", position_to_yojson end_]

Expand Down Expand Up @@ -174,6 +181,7 @@ module Response = struct
| Success of string
| Superclasses of superclasses_mapping list
| Type of Type.t
| IsTypechecked of typechecked list
| TypesByPath of types_at_path list
[@@deriving equal]

Expand Down Expand Up @@ -272,6 +280,7 @@ module Response = struct
in
`List (List.map class_to_superclasses_mapping ~f:mapping_to_yojson)
| Type annotation -> `Assoc ["type", Type.to_yojson annotation]
| IsTypechecked paths -> `List (List.map paths ~f:typechecked_to_yojson)
| TypesByPath paths_to_annotations ->
`List (List.map paths_to_annotations ~f:types_at_path_to_yojson)
end
Expand Down Expand Up @@ -419,6 +428,7 @@ let rec parse_request_exn query =
| "superclasses", names -> Superclasses (List.map ~f:reference names)
| "type", [argument] -> Type (expression argument)
| "types", paths -> Request.TypesInFiles (List.map ~f:string paths)
| "is_typechecked", paths -> Request.IsTypechecked (List.map ~f:string paths)
| "validate_taint_models", arguments -> parse_validate_taint_models arguments
| _ -> raise (InvalidQuery "unexpected query"))
| Ok _ -> raise (InvalidQuery "unexpected query")
Expand Down Expand Up @@ -980,6 +990,16 @@ let rec process_request_exn ~type_environment ~build_system request =
| Type expression ->
let annotation = Resolution.resolve_expression_to_type resolution expression in
Single (Type annotation)
| IsTypechecked paths ->
let get_is_typechecked path =
match
LocationBasedLookupProcessor.get_module_path ~build_system ~type_environment path
with
| Result.Ok { Ast.ModulePath.is_external; _ } ->
{ Base.path; is_typechecked = not is_external }
| Result.Error _ -> { Base.path; is_typechecked = false }
in
Single (Base.IsTypechecked (List.map paths ~f:get_is_typechecked))
| TypesInFiles paths ->
let find_resolved_types path =
match
Expand Down
8 changes: 8 additions & 0 deletions source/server/query.mli
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module Request : sig
| SaveServerState of PyrePath.t
| Superclasses of Reference.t list
| Type of Expression.t
| IsTypechecked of string list
| TypesInFiles of string list
| ValidateTaintModels of {
path: string option;
Expand Down Expand Up @@ -128,6 +129,12 @@ module Response : sig
}
[@@deriving equal, to_yojson]

type typechecked = {
path: string;
is_typechecked: bool;
}
[@@deriving equal, to_yojson]

type global_leak_errors = {
global_leaks: Analysis.AnalysisError.Instantiated.t list;
query_errors: string list;
Expand Down Expand Up @@ -158,6 +165,7 @@ module Response : sig
| Success of string
| Superclasses of superclasses_mapping list
| Type of Type.t
| IsTypechecked of typechecked list
| TypesByPath of types_at_path list
[@@deriving equal, to_yojson]
end
Expand Down
12 changes: 12 additions & 0 deletions source/server/test/queryTest.ml
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,18 @@ let test_handle_query_basic context =
~query:"modules_of_path('/non_existent_file.py')"
(Single (Base.FoundModules []))
>>= fun () ->
let custom_source_root =
OUnit2.bracket_tmpdir context |> PyrePath.create_absolute ~follow_symbolic_links:true
in
let handle = "my_test_file.py" in
let path = PyrePath.append custom_source_root ~element:handle |> PyrePath.absolute in
assert_type_query_response
~custom_source_root
~handle
~source:""
~query:(Format.sprintf "is_typechecked('%s')" path)
(Single (Base.IsTypechecked [{ Base.path; is_typechecked = true }]))
>>= fun () ->
let temporary_directory = OUnit2.bracket_tmpdir context in
assert_type_query_response
~source:""
Expand Down

0 comments on commit a09c488

Please sign in to comment.