Skip to content

Commit 6671f21

Browse files
vassilmladenovmeta-codesync[bot]
authored andcommitted
track ::class in the cross-package linter
Summary: Allow the cross-package linter to track class constants when the option `package_allow_classconst_violations` is set to true. The linter error message is ad-hoc for class constant accesses. Observe that for classconst violations the linter does not check that the target file has a PackageOverride, as no errors would have been reported anyway if the file was missing a PackageOverride due to `package_allow_classconst_violations=true`. Reviewed By: DavidSnider Differential Revision: D94235975 fbshipit-source-id: 19798ff8cdbeec3b4ce6346e7f57b5ee392f4834
1 parent ceb37dc commit 6671f21

21 files changed

+346
-60
lines changed

hphp/hack/src/lints/lints_codes.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,6 @@ module Codes = struct
122122
(* let deprecated_nullsafe_on_null = 5654 *)
123123

124124
let package_into_override = 5655
125+
126+
let crosspackage_classptr_reference = 5656
125127
end

hphp/hack/src/lints/lints_diagnostics.ml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,3 +382,47 @@ let package_into_override
382382
^ ") or gate this reference via a `package` check "
383383
^ "(if this portion of the function is meant to be gated by an environment check)."
384384
)
385+
386+
let crosspackage_classptr_reference
387+
pos current_package target_package_before_override =
388+
let current_package_name =
389+
Option.value_map current_package ~default:"<none>" ~f:snd
390+
in
391+
let target_package_before_override_name =
392+
Option.value target_package_before_override ~default:"<none>"
393+
in
394+
Lints.add
395+
Codes.crosspackage_classptr_reference
396+
Lint_error
397+
pos
398+
("This is a potential cross-boundary edge from package "
399+
^ current_package_name
400+
^ " into package "
401+
^ target_package_before_override_name
402+
^ ". If this value isn't used to load the class "
403+
^ "via new $cls(), $cls::meth(), etc, please change this to a `nameof` expression. "
404+
^ "Otherwise, move the callee into the caller's package via hg mv, "
405+
^ "use `__RequirePackage` (if the whole function should only be invoked from "
406+
^ target_package_before_override_name
407+
^ ") or gate this reference via a `package` check "
408+
^ "(if this portion of the function is meant to be gated by an environment check)."
409+
)
410+
411+
(* wrapper around crosspackage_classconst_reference and package_into_override *)
412+
let crosspackage_linter
413+
pos
414+
current_package
415+
target_package
416+
target_package_before_override
417+
classptr_reference_warning =
418+
if classptr_reference_warning then
419+
crosspackage_classptr_reference
420+
pos
421+
current_package
422+
target_package_before_override
423+
else
424+
package_into_override
425+
pos
426+
current_package
427+
target_package
428+
target_package_before_override

hphp/hack/src/typing/typing.ml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,11 +1350,12 @@ end = struct
13501350
name
13511351
in
13521352
List.iter access_linter_errors ~f:(fun (pos, w) ->
1353-
Lints_diagnostics.package_into_override
1353+
Lints_diagnostics.crosspackage_linter
13541354
pos
13551355
w.current_package
13561356
w.target_package
1357-
w.target_package_before_override);
1357+
w.target_package_before_override
1358+
w.classptr_reference_warning);
13581359
Option.iter
13591360
~f:(Typing_error_utils.add_typing_error ~env)
13601361
(Typing_error.multiple_opt (other_errs @ access_errs))
@@ -3644,13 +3645,13 @@ end = struct
36443645
| TVis.Package_access_error err ->
36453646
Typing_error_utils.add_typing_error ~env err
36463647
| TVis.Package_access_linter_error (pos, w) ->
3647-
Lints_diagnostics.package_into_override
3648+
Lints_diagnostics.crosspackage_linter
36483649
pos
36493650
w.current_package
36503651
w.target_package
36513652
w.target_package_before_override
3653+
w.classptr_reference_warning
36523654
| TVis.Package_access_ok -> ());
3653-
36543655
let ((env, ty_err_opt), ty) =
36553656
Phase.localize_no_subst env ~ignore_errors:true const.cd_type
36563657
in
@@ -5116,11 +5117,12 @@ end = struct
51165117
| TVis.Package_access_error err ->
51175118
Typing_error_utils.add_typing_error ~env err
51185119
| TVis.Package_access_linter_error (pos, w) ->
5119-
Lints_diagnostics.package_into_override
5120+
Lints_diagnostics.crosspackage_linter
51205121
pos
51215122
w.current_package
51225123
w.target_package
51235124
w.target_package_before_override
5125+
w.classptr_reference_warning
51245126
| TVis.Package_access_ok -> ())
51255127
| Decl_entry.DoesNotExist
51265128
| Decl_entry.NotYetAvailable ->
@@ -11717,7 +11719,7 @@ end = struct
1171711719
`No
1171811720
else if is_const then begin
1171911721
if Env.package_allow_classconst_violations env then
11720-
`No
11722+
`ClassPtrLinterOnly
1172111723
else
1172211724
`Yes Typing_error.Primary.Package.Class
1172311725
end else
@@ -11736,11 +11738,12 @@ end = struct
1173611738
id
1173711739
in
1173811740
List.iter access_linter_errs ~f:(fun (pos, w) ->
11739-
Lints_diagnostics.package_into_override
11741+
Lints_diagnostics.crosspackage_linter
1174011742
pos
1174111743
w.current_package
1174211744
w.target_package
11743-
w.target_package_before_override);
11745+
w.target_package_before_override
11746+
w.classptr_reference_warning);
1174411747
List.iter ~f:(Typing_error_utils.add_typing_error ~env) access_errs
1174511748
);
1174611749

hphp/hack/src/typing/typing_class.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,11 +656,12 @@ let check_consistent_enum_inclusion
656656
| Typing_visibility.Package_access_error err ->
657657
Typing_error_utils.add_typing_error ~env err
658658
| Typing_visibility.Package_access_linter_error (pos, w) ->
659-
Lints_diagnostics.package_into_override
659+
Lints_diagnostics.crosspackage_linter
660660
pos
661661
w.current_package
662662
w.target_package
663663
w.target_package_before_override
664+
w.classptr_reference_warning
664665
| Typing_visibility.Package_access_ok -> ());
665666
match (Cls.enum_type included_cls, Cls.enum_type dest_cls) with
666667
| (Some included_e, Some dest_e) ->

hphp/hack/src/typing/typing_packages.ml

Lines changed: 77 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ type package_warning_info = {
3636
current_package: Package.pos_id option;
3737
target_package: Package.pos_id option;
3838
target_package_before_override: string option;
39+
classptr_reference_warning: bool;
3940
}
4041

4142
type package_error_info = {
@@ -48,6 +49,7 @@ type package_error_info = {
4849

4950
type check_reason =
5051
[ `Yes of Typing_error.Primary.Package.target_symbol_spec
52+
| `ClassPtrLinterOnly
5153
| `No
5254
]
5355

@@ -91,6 +93,73 @@ let package_includes current_pkg target_pkg =
9193
false)
9294
| _ -> false
9395

96+
(* triggers a linter error if the edge introduces a new dependency from a file in a package
97+
* due to another file, ingoring package rules to a file with a packageoverride; used *)
98+
let can_access_ignoring_package_override
99+
~(env : Typing_env_types.env)
100+
~(current_package : Package.pos_id option)
101+
~(target_package : Package.pos_id option)
102+
~(target_file : Relative_path.t)
103+
~(classptr_reference_warning : bool) =
104+
let tcopt = Env.get_tcopt env in
105+
let target_package_before_override =
106+
Option.map
107+
(Package_info.get_package_for_file
108+
~support_multifile_tests:
109+
(TypecheckerOptions.package_support_multifile_tests tcopt)
110+
(TypecheckerOptions.package_info tcopt)
111+
(Relative_path.suffix target_file))
112+
~f:Package.get_package_name
113+
in
114+
let is_target_package_before_override_included =
115+
match (current_package, target_package_before_override) with
116+
| (Some (_, current_package_name), Some target_package_before_override_name)
117+
->
118+
let target_package_before_override =
119+
Env.get_package_by_name env target_package_before_override_name
120+
in
121+
package_includes
122+
(Env.get_package_by_name env current_package_name)
123+
target_package_before_override
124+
| _ -> true
125+
in
126+
let is_target_package_before_override_loaded =
127+
match target_package_before_override with
128+
| Some pkg_name -> Env.is_package_loaded env pkg_name
129+
| None -> true
130+
in
131+
let is_target_package_before_override_soft_required =
132+
match
133+
(Env.get_soft_package_requirement env, target_package_before_override)
134+
with
135+
| (Some soft_required_package_name, Some pkg_name) ->
136+
let soft_required_package =
137+
Env.get_package_by_name env (snd soft_required_package_name)
138+
in
139+
let target_package_before_override =
140+
Env.get_package_by_name env pkg_name
141+
in
142+
package_includes soft_required_package target_package_before_override
143+
| (Some _, None) -> true
144+
| _ -> false
145+
in
146+
if
147+
is_target_package_before_override_included
148+
|| is_target_package_before_override_loaded
149+
|| is_target_package_before_override_soft_required
150+
then
151+
`Yes
152+
else
153+
let warn_info =
154+
{
155+
current_package;
156+
target_package;
157+
target_package_before_override;
158+
classptr_reference_warning;
159+
}
160+
in
161+
`YesWarning warn_info
162+
94163
let can_access_by_package_rules
95164
~(env : Typing_env_types.env)
96165
~(target_package_membership : Aast_defs.package_membership option)
@@ -122,55 +191,18 @@ let can_access_by_package_rules
122191
in
123192
match get_package_violation env current_pkg target_pkg with
124193
| None ->
125-
(* There are no package errrors, but emit a warning if the edge introduces a new
126-
* dependency a file in a package due to package rules and a file with a packageoverride *)
194+
(* There are no package errrors, but emit a warning if the edge introduces a new dependency
195+
* from a file in a package due to package rules to a file with a packageoverride *)
127196
(match (current_package_membership, target_package_membership) with
128197
| ( Some (Aast_defs.PackageConfigAssignment _),
129198
Some (Aast_defs.PackageOverride _) )
130199
when package_includes current_pkg target_pkg ->
131-
let target_package_before_override =
132-
let tcopt = Env.get_tcopt env in
133-
Option.map
134-
(Package_info.get_package_for_file
135-
~support_multifile_tests:
136-
(TypecheckerOptions.package_support_multifile_tests tcopt)
137-
(TypecheckerOptions.package_info tcopt)
138-
(Relative_path.suffix target_file))
139-
~f:Package.get_package_name
140-
in
141-
let is_target_package_before_override_loaded =
142-
match target_package_before_override with
143-
| Some pkg_name -> Env.is_package_loaded env pkg_name
144-
| None -> true
145-
in
146-
let is_target_package_before_override_soft_required =
147-
match
148-
( Env.get_soft_package_requirement env,
149-
target_package_before_override )
150-
with
151-
| (Some soft_required_package_name, Some pkg_name) ->
152-
let soft_required_package =
153-
Env.get_package_by_name env (snd soft_required_package_name)
154-
in
155-
let target_package_before_override =
156-
Env.get_package_by_name env pkg_name
157-
in
158-
package_includes
159-
soft_required_package
160-
target_package_before_override
161-
| (Some _, None) -> true
162-
| _ -> false
163-
in
164-
if
165-
is_target_package_before_override_loaded
166-
|| is_target_package_before_override_soft_required
167-
then
168-
`Yes
169-
else
170-
let warn_info =
171-
{ current_package; target_package; target_package_before_override }
172-
in
173-
`YesWarning warn_info
200+
can_access_ignoring_package_override
201+
~env
202+
~current_package
203+
~target_package
204+
~target_file
205+
~classptr_reference_warning:false
174206
| _ -> `Yes)
175207
| Some pkg_relationship ->
176208
let err_info =

hphp/hack/src/typing/typing_packages.mli

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type package_warning_info = {
1010
current_package: Package.pos_id option;
1111
target_package: Package.pos_id option;
1212
target_package_before_override: string option;
13+
classptr_reference_warning: bool;
1314
}
1415

1516
type package_error_info = {
@@ -22,9 +23,23 @@ type package_error_info = {
2223

2324
type check_reason =
2425
[ `Yes of Typing_error.Primary.Package.target_symbol_spec
26+
| `ClassPtrLinterOnly
2527
| `No
2628
]
2729

30+
val get_package_profile :
31+
Typing_env_types.env ->
32+
Aast_defs.package_membership option ->
33+
Package.t option * Package.pos_id option * string
34+
35+
val can_access_ignoring_package_override :
36+
env:Typing_env_types.env ->
37+
current_package:Package.pos_id option ->
38+
target_package:Package.pos_id option ->
39+
target_file:Relative_path.t ->
40+
classptr_reference_warning:bool ->
41+
[ `Yes | `YesWarning of package_warning_info ]
42+
2843
(** Calculate the packages of the current and target symbols using their filenames.
2944
* The target symbol can be accessed if:
3045
* - current and target are in the same file

hphp/hack/src/typing/typing_type_integrity.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,12 @@ and check_type_integrity
288288
cid
289289
in
290290
List.iter linter_errs ~f:(fun (pos, w) ->
291-
Lints_diagnostics.package_into_override
291+
Lints_diagnostics.crosspackage_linter
292292
pos
293293
w.current_package
294294
w.target_package
295-
w.target_package_before_override);
295+
w.target_package_before_override
296+
w.classptr_reference_warning);
296297
List.iter errs ~f:(Typing_error_utils.add_typing_error ~env));
297298
let tparams = Cls.tparams class_info in
298299
check_targs_integrity ~in_signature (Cls.pos class_info) argl tparams
@@ -310,11 +311,12 @@ and check_type_integrity
310311
cid
311312
in
312313
List.iter linter_errs ~f:(fun (pos, w) ->
313-
Lints_diagnostics.package_into_override
314+
Lints_diagnostics.crosspackage_linter
314315
pos
315316
w.current_package
316317
w.target_package
317-
w.target_package_before_override);
318+
w.target_package_before_override
319+
w.classptr_reference_warning);
318320
List.iter errs ~f:(Typing_error_utils.add_typing_error ~env));
319321
check_targs_integrity ~in_signature typedef.td_pos argl typedef.td_tparams
320322
| Decl_entry.DoesNotExist

hphp/hack/src/typing/typing_visibility.ml

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ let check_package_access
159159
~use_pos
160160
~def_pos
161161
env
162-
target_package
162+
target_package_membership
163163
target_id =
164164
match should_check_package_boundary with
165165
| `No -> Package_access_ok
@@ -170,7 +170,7 @@ let check_package_access
170170
match
171171
Typing_packages.can_access_by_package_rules
172172
~env
173-
~target_package_membership:target_package
173+
~target_package_membership
174174
~target_pos:def_pos
175175
~target_id
176176
with
@@ -229,6 +229,23 @@ let check_package_access
229229
included_packages;
230230
}))
231231
end
232+
| `ClassPtrLinterOnly ->
233+
let current_package =
234+
Option.map ~f:(fun p -> p.name) (Typing_env.get_current_package env)
235+
in
236+
let (_, target_package, _) =
237+
Typing_packages.get_package_profile env target_package_membership
238+
in
239+
(match
240+
Typing_packages.can_access_ignoring_package_override
241+
~env
242+
~current_package
243+
~target_package
244+
~target_file:(Pos_or_decl.filename def_pos)
245+
~classptr_reference_warning:true
246+
with
247+
| `Yes -> Package_access_ok
248+
| `YesWarning w -> Package_access_linter_error (use_pos, w))
232249

233250
let is_visible_for_obj ~is_method ~is_receiver_interface env vis =
234251
let member_ty =

0 commit comments

Comments
 (0)