Summary: As per title Reviewed By: jvillard Differential Revision: D22019146 fbshipit-source-id: 3837993e5master
parent
4bbe5a064b
commit
23c1b4f960
@ -1,138 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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 L = Logging
|
|
||||||
|
|
||||||
(* Sources: Java Virtual Machine Specification
|
|
||||||
- Chapter 5. Loading, Linking and Initializing
|
|
||||||
- Chapter 6. The Java Virtual Machine Instruction Set
|
|
||||||
*)
|
|
||||||
|
|
||||||
(* TODO
|
|
||||||
- catch / throw with exception classes
|
|
||||||
*)
|
|
||||||
|
|
||||||
let do_call {InterproceduralAnalysis.analyze_dependency} callee loc init =
|
|
||||||
analyze_dependency callee
|
|
||||||
|> Option.fold ~init ~f:(fun acc (_, summary) ->
|
|
||||||
ClassLoadsDomain.integrate_summary callee loc acc summary )
|
|
||||||
|
|
||||||
|
|
||||||
(** fully load a class given the typename *)
|
|
||||||
let rec load_class ({InterproceduralAnalysis.tenv} as analysis_data) loc astate class_name =
|
|
||||||
(* don't bother if class is already loaded *)
|
|
||||||
if ClassLoadsDomain.mem_typename class_name astate then astate
|
|
||||||
else
|
|
||||||
(* load the class itself *)
|
|
||||||
let astate1 = ClassLoadsDomain.add_typename loc astate class_name in
|
|
||||||
(* load classes referenced by the class initializer *)
|
|
||||||
let astate2 =
|
|
||||||
let class_initializer = Procname.(Java (Java.get_class_initializer class_name)) in
|
|
||||||
(* NB may recurse if we are in class init but the shortcircuiting above makes it a no-op *)
|
|
||||||
do_call analysis_data class_initializer loc astate1
|
|
||||||
in
|
|
||||||
(* finally, recursively load all superclasses *)
|
|
||||||
Tenv.lookup tenv class_name
|
|
||||||
|> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Struct.supers)
|
|
||||||
|> List.fold ~init:astate2 ~f:(load_class analysis_data loc)
|
|
||||||
|
|
||||||
|
|
||||||
let load_type analysis_data loc (typ : Typ.t) astate =
|
|
||||||
match typ with
|
|
||||||
| {desc= Tstruct name} | {desc= Tptr ({desc= Tstruct name}, _)} ->
|
|
||||||
load_class analysis_data loc astate name
|
|
||||||
| _ ->
|
|
||||||
astate
|
|
||||||
|
|
||||||
|
|
||||||
let rec load_array analysis_data loc (typ : Typ.t) astate =
|
|
||||||
match typ with
|
|
||||||
| {desc= Tarray {elt}} ->
|
|
||||||
load_array analysis_data loc elt astate
|
|
||||||
| _ ->
|
|
||||||
load_type analysis_data loc typ astate
|
|
||||||
|
|
||||||
|
|
||||||
let rec add_loads_of_exp analysis_data loc (exp : Exp.t) astate =
|
|
||||||
match exp with
|
|
||||||
| Const (Cclass class_ident) ->
|
|
||||||
(* [X.class] expressions *)
|
|
||||||
let class_str = Ident.name_to_string class_ident |> JavaClassName.from_string in
|
|
||||||
let class_name = Typ.JavaClass class_str in
|
|
||||||
load_class analysis_data loc astate class_name
|
|
||||||
| Sizeof {typ= {desc= Tarray {elt}}} ->
|
|
||||||
(* anewarray / multinewarray *)
|
|
||||||
load_array analysis_data loc elt astate
|
|
||||||
| Cast (_, e) | UnOp (_, e, _) | Exn e ->
|
|
||||||
(* NB Cast is only used for primitive types *)
|
|
||||||
add_loads_of_exp analysis_data loc e astate
|
|
||||||
| BinOp (_, e1, e2) ->
|
|
||||||
add_loads_of_exp analysis_data loc e1 astate |> add_loads_of_exp analysis_data loc e2
|
|
||||||
| Lfield (e, _, typ') ->
|
|
||||||
(* getfield / getstatic / putfield / putstatic *)
|
|
||||||
load_type analysis_data loc typ' astate |> add_loads_of_exp analysis_data loc e
|
|
||||||
| Var _ | Const _ | Closure _ | Sizeof _ | Lindex _ | Lvar _ ->
|
|
||||||
astate
|
|
||||||
|
|
||||||
|
|
||||||
let exec_call analysis_data callee args loc astate =
|
|
||||||
match args with
|
|
||||||
| [_; (Exp.Sizeof {typ}, _)] when Procname.equal callee BuiltinDecl.__instanceof ->
|
|
||||||
(* this matches downcasts/instanceof and exception handlers *)
|
|
||||||
load_type analysis_data loc typ astate
|
|
||||||
| _ ->
|
|
||||||
(* invokeinterface / invokespecial / invokestatic / invokevirtual / new *)
|
|
||||||
List.fold args ~init:astate ~f:(fun acc (exp, _) ->
|
|
||||||
add_loads_of_exp analysis_data loc exp acc )
|
|
||||||
|> do_call analysis_data callee loc
|
|
||||||
|
|
||||||
|
|
||||||
let exec_instr analysis_data astate _ (instr : Sil.instr) =
|
|
||||||
match instr with
|
|
||||||
| Call (_, Const (Cfun callee), args, loc, _) ->
|
|
||||||
exec_call analysis_data callee args loc astate
|
|
||||||
| Load {e= exp; loc} | Prune (exp, loc, _, _) ->
|
|
||||||
(* NB the java frontend seems to always translate complex guards into a sequence of
|
|
||||||
instructions plus a prune on logical vars only. So the below is only for completeness. *)
|
|
||||||
add_loads_of_exp analysis_data loc exp astate
|
|
||||||
| Store {e1; e2; loc} ->
|
|
||||||
add_loads_of_exp analysis_data loc e1 astate |> add_loads_of_exp analysis_data loc e2
|
|
||||||
| _ ->
|
|
||||||
astate
|
|
||||||
|
|
||||||
|
|
||||||
let report_loads {InterproceduralAnalysis.proc_desc; err_log} astate =
|
|
||||||
let report_load ({ClassLoadsDomain.Event.loc; elem} as event) =
|
|
||||||
if String.is_prefix ~prefix:"java." elem then ()
|
|
||||||
else
|
|
||||||
let ltr = ClassLoadsDomain.Event.make_loc_trace event in
|
|
||||||
let msg = Format.asprintf "Class %s loaded" elem in
|
|
||||||
Reporting.log_issue proc_desc err_log ~loc ~ltr ClassLoads IssueType.class_load msg
|
|
||||||
in
|
|
||||||
let pname = Procdesc.get_proc_name proc_desc in
|
|
||||||
Procname.get_class_name pname
|
|
||||||
|> Option.iter ~f:(fun clazz ->
|
|
||||||
let method_strname = Procname.get_method pname in
|
|
||||||
let fullname = clazz ^ "." ^ method_strname in
|
|
||||||
if String.Set.mem Config.class_loads_roots fullname then
|
|
||||||
ClassLoadsDomain.iter report_load astate )
|
|
||||||
|
|
||||||
|
|
||||||
let analyze_procedure ({InterproceduralAnalysis.proc_desc} as analysis_data) =
|
|
||||||
let proc_name = Procdesc.get_proc_name proc_desc in
|
|
||||||
L.debug Analysis Verbose "CL: ANALYZING %a@." Procname.pp proc_name ;
|
|
||||||
let loc = Procdesc.get_loc proc_desc in
|
|
||||||
(* load the method's class *)
|
|
||||||
let init =
|
|
||||||
Procname.get_class_type_name proc_name
|
|
||||||
|> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class analysis_data loc)
|
|
||||||
in
|
|
||||||
let post = Procdesc.fold_instrs proc_desc ~init ~f:(exec_instr analysis_data) in
|
|
||||||
report_loads analysis_data post ;
|
|
||||||
L.debug Analysis Verbose "CL: FINISHED ANALYZING %a@." Procname.pp proc_name ;
|
|
||||||
Some post
|
|
@ -1,11 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
val analyze_procedure :
|
|
||||||
ClassLoadsDomain.summary InterproceduralAnalysis.t -> ClassLoadsDomain.summary option
|
|
@ -1,56 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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
|
|
||||||
module L = Logging
|
|
||||||
|
|
||||||
module ClassLoad = struct
|
|
||||||
include String
|
|
||||||
|
|
||||||
let describe = pp
|
|
||||||
end
|
|
||||||
|
|
||||||
module Event =
|
|
||||||
ExplicitTrace.MakeTraceElemModuloLocation (ClassLoad) (ExplicitTrace.DefaultCallPrinter)
|
|
||||||
include Event.FiniteSet
|
|
||||||
|
|
||||||
let add ({Event.trace} as x) astate =
|
|
||||||
match find_opt x astate with
|
|
||||||
| None ->
|
|
||||||
add x astate
|
|
||||||
| Some ({Event.trace= trace'} as x') ->
|
|
||||||
if Int.( <= ) (List.length trace') (List.length trace) then astate
|
|
||||||
else remove x' astate |> add x
|
|
||||||
|
|
||||||
|
|
||||||
let union xs ys = fold add xs ys
|
|
||||||
|
|
||||||
let add_string loc astate clazz =
|
|
||||||
L.debug Analysis Verbose "CL: LOADING class %s@." clazz ;
|
|
||||||
let new_event = Event.make clazz loc in
|
|
||||||
add new_event astate
|
|
||||||
|
|
||||||
|
|
||||||
let mem_typename name astate =
|
|
||||||
let str_name = Typ.Name.name name in
|
|
||||||
(* comparison of elements is only over the string component so fake the rest *)
|
|
||||||
let fake_event = Event.make str_name Location.dummy in
|
|
||||||
mem fake_event astate
|
|
||||||
|
|
||||||
|
|
||||||
let add_typename loc astate name = Typ.Name.name name |> add_string loc astate
|
|
||||||
|
|
||||||
let integrate_summary callee_pname loc astate callee_summary =
|
|
||||||
L.debug Analysis Verbose "CL: ADDING SUMMARY OF %a@." Procname.pp callee_pname ;
|
|
||||||
let callsite = CallSite.make callee_pname loc in
|
|
||||||
let summary = with_callsite callee_summary callsite in
|
|
||||||
union astate summary
|
|
||||||
|
|
||||||
|
|
||||||
type summary = t
|
|
||||||
|
|
||||||
let pp_summary = pp
|
|
@ -1,26 +0,0 @@
|
|||||||
(*
|
|
||||||
* 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
|
|
||||||
|
|
||||||
module ClassLoad : ExplicitTrace.Element with type t = string
|
|
||||||
|
|
||||||
module Event : ExplicitTrace.TraceElem with type elem_t = ClassLoad.t
|
|
||||||
|
|
||||||
include AbstractDomain.WithBottom
|
|
||||||
|
|
||||||
type summary = t
|
|
||||||
|
|
||||||
val pp_summary : F.formatter -> summary -> unit
|
|
||||||
|
|
||||||
val mem_typename : Typ.Name.t -> t -> bool
|
|
||||||
|
|
||||||
val add_typename : Location.t -> t -> Typ.Name.t -> t
|
|
||||||
|
|
||||||
val integrate_summary : Procname.t -> Location.t -> t -> summary -> t
|
|
||||||
|
|
||||||
val iter : (Event.t -> unit) -> t -> unit
|
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Arrays {
|
|
||||||
static ArraysB[] arrayB = new ArraysB[10];
|
|
||||||
|
|
||||||
static ArraysC[] arrayC = ArraysD.arrayC;
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
|
||||||
ArraysA[] arrayA = new ArraysA[10];
|
|
||||||
|
|
||||||
System.out.println(ArraysF.foo()[0]);
|
|
||||||
|
|
||||||
ArraysG[][] arrayG = new ArraysG[10][10];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArraysA {}
|
|
||||||
|
|
||||||
class ArraysB {}
|
|
||||||
|
|
||||||
class ArraysC {}
|
|
||||||
|
|
||||||
class ArraysD {
|
|
||||||
static ArraysC[] arrayC = new ArraysC[10];
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArraysE {}
|
|
||||||
|
|
||||||
class ArraysF {
|
|
||||||
static ArraysE[] foo() {
|
|
||||||
return new ArraysE[10];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArraysG {}
|
|
@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Basic {
|
|
||||||
public static void main(String args[]) {
|
|
||||||
new BasicObj();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BasicObj {}
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Casts {
|
|
||||||
// there is no way to test this dynamically, as to avoid an exception
|
|
||||||
// we must first create a CastsC object. So this is more for documenting.
|
|
||||||
public static void main(String args[]) {
|
|
||||||
CastsA.downcast(new CastsC());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CastsA {
|
|
||||||
static CastsC downcast(CastsB c) {
|
|
||||||
return (CastsC) c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean checkclass(CastsD d) {
|
|
||||||
return d instanceof CastsE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CastsB {}
|
|
||||||
|
|
||||||
class CastsC extends CastsB {}
|
|
||||||
|
|
||||||
class CastsD {}
|
|
||||||
|
|
||||||
class CastsE extends CastsD {}
|
|
@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Catch {
|
|
||||||
public static void main(String args[]) {
|
|
||||||
try {
|
|
||||||
foo();
|
|
||||||
} catch (CatchA a) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void foo() throws CatchA {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CatchA extends Exception {
|
|
||||||
static final long serialVersionUID = 0L;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Const {
|
|
||||||
public static void main(String args[]) {
|
|
||||||
synchronized (ConstA.class) {
|
|
||||||
}
|
|
||||||
|
|
||||||
java.lang.Class<ConstB> b = ConstB.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConstA {}
|
|
||||||
|
|
||||||
class ConstB {}
|
|
@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Fields {
|
|
||||||
FieldsA a;
|
|
||||||
|
|
||||||
Fields() {
|
|
||||||
a = new FieldsA();
|
|
||||||
}
|
|
||||||
|
|
||||||
void foo() {
|
|
||||||
System.out.println(a.b.c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
|
||||||
Fields f = new Fields();
|
|
||||||
f.foo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FieldsA {
|
|
||||||
FieldsA() {
|
|
||||||
b = new FieldsB();
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldsB b;
|
|
||||||
}
|
|
||||||
|
|
||||||
class FieldsB {
|
|
||||||
FieldsB() {
|
|
||||||
c = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldsCNoLoad c;
|
|
||||||
}
|
|
||||||
|
|
||||||
class FieldsCNoLoad {}
|
|
@ -1,70 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
# Convention: each Java file must have a single [main] method in the eponymous public class
|
|
||||||
# This is the root for class loads analysis, and the one executed in the JVM to log loads.
|
|
||||||
# There is no .exp file committed, the loads are generated by JVM during testing.
|
|
||||||
|
|
||||||
TESTS_DIR = ../../..
|
|
||||||
|
|
||||||
INFERPRINT_OPTIONS = --issues-tests
|
|
||||||
|
|
||||||
SOURCES = $(wildcard *.java)
|
|
||||||
LOADS = $(patsubst %.java,%.loads,$(SOURCES))
|
|
||||||
OBJECTS = $(patsubst %.java,%.class,$(SOURCES))
|
|
||||||
CLASS_LOADS_OPT = $(patsubst %.java,--class-loads-roots %.main,$(SOURCES))
|
|
||||||
INFER_OPTIONS = --class-loads-only $(CLASS_LOADS_OPT) --debug-exceptions
|
|
||||||
CLEAN_EXTRA = *.class *.loads loads.exp loads.exp.test
|
|
||||||
|
|
||||||
include $(TESTS_DIR)/java.make
|
|
||||||
|
|
||||||
INFER_OUT ?= infer-out$(TEST_SUFFIX)
|
|
||||||
|
|
||||||
include $(TESTS_DIR)/base.make
|
|
||||||
|
|
||||||
.PHONY: clean
|
|
||||||
clean:
|
|
||||||
$(REMOVE_DIR) codetoanalyze com issues.exp.test$(TEST_SUFFIX) $(CLEAN_EXTRA)
|
|
||||||
ifneq ($(INFER_OUT),.)
|
|
||||||
$(REMOVE_DIR) $(INFER_OUT)
|
|
||||||
endif
|
|
||||||
|
|
||||||
PROJECT_ROOT ?= $(TESTS_DIR)
|
|
||||||
|
|
||||||
|
|
||||||
issues.exp.test$(TEST_SUFFIX): $(INFER_OUT)/report.json $(INFER_BIN)
|
|
||||||
$(QUIET)$(INFER_BIN) report -q --results-dir $(<D) \
|
|
||||||
$(INFERPRINT_OPTIONS) $@
|
|
||||||
|
|
||||||
infer-out/report.json: $(JAVA_DEPS) $(SOURCES) $(MAKEFILE_LIST)
|
|
||||||
$(QUIET)$(call silent_on_success,Testing infer/java in $(TEST_REL_DIR),\
|
|
||||||
$(INFER_BIN) --project-root $(PROJECT_ROOT) \
|
|
||||||
$(INFER_OPTIONS) -- \
|
|
||||||
$(JAVAC) -cp $(CLASSPATH) $(SOURCES))
|
|
||||||
|
|
||||||
%.loads: %.class
|
|
||||||
ifeq ($(JDK11_ENABLED),yes)
|
|
||||||
$(QUIET)java -verbose:class $* | grep "\[info\]\[class,load\]" | cut -f2 -d' ' | grep -vE "^(java|sun|jdk|opened:)" > $@
|
|
||||||
else
|
|
||||||
$(QUIET)java -verbose:class $* | grep "^\[Loaded" | cut -f2 -d' ' | grep -vE "^(java|sun)" > $@
|
|
||||||
endif
|
|
||||||
|
|
||||||
# infer compiles as well as analyses; dependency ensures class files are generated
|
|
||||||
$(OBJECTS): issues.exp.test$(TEST_SUFFIX)
|
|
||||||
|
|
||||||
loads.exp: $(LOADS)
|
|
||||||
$(QUIET)for F in $(LOADS) ; do sed -e "s#^#$(TEST_REL_DIR)/$${F%.*}.java, #" $$F ; done | sort > loads.exp
|
|
||||||
|
|
||||||
loads.exp.test: issues.exp.test$(TEST_SUFFIX)
|
|
||||||
$(QUIET)cat $< | sed 's/^\([^,]*\),.*[,\[]\([^,]*\)\]$$/\1, \2/' | sort > $@
|
|
||||||
|
|
||||||
.PHONY: test
|
|
||||||
test: loads.exp loads.exp.test
|
|
||||||
$(QUIET)cd $(TESTS_DIR) && \
|
|
||||||
$(call check_no_diff,$(TEST_REL_DIR)/loads.exp,$(TEST_REL_DIR)/loads.exp.test)
|
|
||||||
|
|
||||||
.PHONY: replace
|
|
||||||
replace:
|
|
||||||
@:
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Prune {
|
|
||||||
public static void main(String args[]) {
|
|
||||||
if (PruneA.f == 0) {
|
|
||||||
System.out.println(PruneB.g < 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PruneA {
|
|
||||||
static int f;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PruneB {
|
|
||||||
static int g;
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Static {
|
|
||||||
// this loads StaticA
|
|
||||||
static StaticA s = new StaticA();
|
|
||||||
|
|
||||||
public static void main(String args[]) {
|
|
||||||
// this loads StaticD
|
|
||||||
System.out.println(StaticD.static_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StaticA {
|
|
||||||
// this loads StaticB
|
|
||||||
static StaticB b = new StaticB();
|
|
||||||
}
|
|
||||||
|
|
||||||
class StaticB {
|
|
||||||
// no load here
|
|
||||||
static StaticCNoLoad c = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StaticCNoLoad {}
|
|
||||||
|
|
||||||
class StaticD {
|
|
||||||
static int static_data = 5;
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Super {
|
|
||||||
public static void main(String args[]) {
|
|
||||||
// this loads SuperB and SuperA
|
|
||||||
System.out.println(SuperB.static_data);
|
|
||||||
|
|
||||||
// this loads SuperC and SuperD
|
|
||||||
SuperD.foo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SuperA {}
|
|
||||||
|
|
||||||
class SuperB extends SuperA {
|
|
||||||
static int static_data = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SuperC {}
|
|
||||||
|
|
||||||
class SuperD extends SuperC {
|
|
||||||
public static void foo() {}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Unique {
|
|
||||||
public static void main(String args[]) {
|
|
||||||
// two loads for the same class with distinct locations and traces should be merged into one
|
|
||||||
UniqueObj u = new UniqueObj();
|
|
||||||
u.foo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UniqueObj {
|
|
||||||
void foo() {}
|
|
||||||
}
|
|
Loading…
Reference in new issue