Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions graph/java/engine/expression-resolution/overload.dl
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,41 @@ arg_value_type(call, pos, vt) :- java_expression(_, "ARGUMENT", _, _, _, _, call
arg_value_type(call, pos, vt) :- java_expression(_, "ARGUMENT", _, _, _, _, call, pos, _, _, name, _, _, _, "FIELD", _, _, _, _, _, _, _, _, _, arg),
expr_ultimate_type("client", arg, encl),
java_field(name, vt, _, _, _, _, _, _, encl, _, _, _, _, _), value_type_name(vt).
// An ARITHMETIC or COMPARISON expression argument: `new Elements(elements.size() - 1)`, `remove(--i)`, `put(k, a == b)`.
// Its operands may be untyped (a call into an unstaged library), but the operator fixes what kind of value it is:
// `-` `*` `/` `%` and the shifts make a number, a comparison or `&&` / `||` / `!` a boolean. `+` is left out (a String
// concatenation is a `+` too), and so are `&` `|` `^` (numeric or boolean by operand). "numeric" is a value type of its
// own because the width is not known: it is compatible with every numeric primitive and wrapper, never with String,
// boolean or a reference type. Without it the call kept `Elements(Element...)` beside `Elements(int)`, and every
// caller of the one was a caller of the other.
// java_expression (25): 1 kind 2 edgeRole 7 parentExpressionHash 8 position 14 operatorString
.decl numeric_op(o:symbol)
.decl numeric_unary_op(o:symbol)
.decl boolean_op(o:symbol)
.decl numeric_prim(p:symbol)
.decl prim_value(v:symbol)
numeric_op("-"). numeric_op("*"). numeric_op("/"). numeric_op("%"). numeric_op("<<"). numeric_op(">>"). numeric_op(">>>").
numeric_unary_op("-"). numeric_unary_op("+"). numeric_unary_op("++"). numeric_unary_op("--"). numeric_unary_op("~").
boolean_op("=="). boolean_op("!="). boolean_op("<"). boolean_op(">"). boolean_op("<="). boolean_op(">="). boolean_op("&&"). boolean_op("||").
arg_value_type(call, pos, "numeric") :- java_expression("BINARY_EXPRESSION", "ARGUMENT", _, _, _, _, call, pos, _, _, _, _, _, op, _, _, _, _, _, _, _, _, _, _, _),
numeric_op(op).
arg_value_type(call, pos, "numeric") :- java_expression("UNARY_EXPRESSION", "ARGUMENT", _, _, _, _, call, pos, _, _, _, _, _, op, _, _, _, _, _, _, _, _, _, _, _),
numeric_unary_op(op).
arg_value_type(call, pos, "boolean") :- java_expression("BINARY_EXPRESSION", "ARGUMENT", _, _, _, _, call, pos, _, _, _, _, _, op, _, _, _, _, _, _, _, _, _, _, _),
boolean_op(op).
arg_value_type(call, pos, "boolean") :- java_expression("UNARY_EXPRESSION", "ARGUMENT", _, _, _, _, call, pos, _, _, _, _, _, "!", _, _, _, _, _, _, _, _, _, _, _).
numeric_prim("int"). numeric_prim("long"). numeric_prim("float"). numeric_prim("double").
numeric_prim("short"). numeric_prim("byte"). numeric_prim("char").
value_compatible("numeric", b) :- value_prim(b, p), numeric_prim(p).
// A primitive value (a literal, a primitive variable, an arithmetic or comparison expression) never reaches a
// parameter typed as a CLIENT type: boxing makes a java.lang wrapper, which no project type is.
prim_value(v) :- value_prim(v, v), v != "String", v != "null".
prim_value("numeric").
value_mismatch(call, callee) :- expr_call_candidate(call, callee),
arg_value_type(call, pos, at), prim_value(at),
param_type_hash(callee, pos, pt), type_prov(pt, "client"),
!arg_is_target_typed(call, pos).

// Parameter value-type (parameterTypeName col 4 is the simple name: int / String / ...).
param_value_type(callee, pos, vt) :- java_method_parameter(_, pos, callee, _, vt, _, _, _, _, _, _, _, _), value_type_name(vt).
param_value_type(callee, pos, vt) :- lib_method_parameter(_, pos, callee, _, vt, _, _, _, _, _, _, _, _), value_type_name(vt).
Expand Down
33 changes: 32 additions & 1 deletion graph/java/engine/resolution/external-types.dl
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,24 @@ local_creation_init(local) :- java_expression("ANONYMOUS_CLASS_CREATION", "ROOT"
local_reassigned(local) :- java_local_variable(name, _, _, _, _, _, _, _, _, _, _, _, _, m, _, _, _, _, local),
java_expression(_, "ASSIGNMENT_TARGET", _, _, _, _, _, _, _, _, name, _, _, _, "LOCAL_VARIABLE", _, _, _, _, _, _, _, _, _, e),
expr_ultimate_method("client", e, m).
local_creation_pinned(local) :- local_creation_init(local), !local_reassigned(local).
local_creation_pinned(local) :- local_creation_init(local), !local_reassigned(local), !local_creation_external(local).
// ...but a creation of a type no staged IR declares pins nothing: `final StringBuilder sb = new StringBuilder()`
// with no JDK staged has no flow type at all, so `sb.toString()` was an unresolved site -- and every unresolved
// `toString` / `append` was a by-name caller of each client method of that name. The declared type is then the
// answer, exactly as for an initializer that is not a creation: an external receiver, a library boundary.
.decl creation_ref_external(ref:symbol)
creation_ref_external(ref) :- java_type_reference(kind, "OBJECT_CREATION_TYPE", _, _, _, _, _, "0", tn, _, _, _, _, _, _, _, _, ref),
ext_ref_kind(kind),
tn != "",
ref_file(ref, tn, fp),
!name_resolves_in_file(tn, fp),
!simple_name_declared(tn),
!ref_names_tvar(ref).
.decl local_creation_external(local:symbol)
local_creation_external(local) :-
java_expression("OBJECT_CREATION", "ROOT", "LOCAL_VAR_INITIALIZER", "LOCAL_VARIABLE", _, local, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, obj),
java_type_reference(_, "OBJECT_CREATION_TYPE", _, _, _, _, _, "0", _, _, _, _, _, _, _, obj, "EXPRESSION", ref),
creation_ref_external(ref).

expr_type("external", e, x) :- java_expression(_, _, _, _, _, _, _, _, _, _, name, _, _, _, "FIELD", _, _, _, _, _, _, _, _, _, e),
expr_ultimate_type("client", e, encl),
Expand Down Expand Up @@ -230,6 +247,20 @@ expr_call_candidate(call, m) :- call_site(call, name, recv),
external_target(call, label) :- call_site(call, name, recv),
expr_type("external", recv, x),
label = cat(x, cat(".", name)).
// (a') the receiver is a TYPE NAME no staged IR declares: a static call on the platform or a dependency,
// `Character.charCount(cp)`, `Objects.equals(a, b)`, `Collections.unmodifiableMap(m)`. A static call never
// dispatches, so no client method runs behind it. The parser writes the receiver as an identifier it read as a
// type (not ambiguous with a variable) with the qualified name its imports give; left unresolved, each one was a
// by-name caller of every client method called `equals`, `valueOf`, `max`, `get`.
.decl external_static_receiver(recv:symbol, q:symbol)
external_static_receiver(recv, q) :-
java_expression("IDENTIFIER_REFERENCE", "RECEIVER", _, _, _, _, _, _, _, _, n, _, _, _, "TYPE", "", _, q, "false", _, _, _, _, _, recv),
q != "", n != "",
!qualified_name_declared(q),
!simple_name_declared(n).
external_target(call, label) :- call_site(call, name, recv),
external_static_receiver(recv, q),
label = cat("external:", cat(q, cat(".", name))).
// The parser writes parameterCount as text, so the written arity is compared as text.
call_arity(call, pc) :- call_argc(call, n), pc = to_string(n).
call_arity(call, "0") :- call_site(call, _, _), !call_has_args(call).
Expand Down
4 changes: 3 additions & 1 deletion graph/test/java/expected/02-anonymous-sam.edges
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
ambiguous_anon anon_new AnonymousClasses#main(String[]) -> -
ambiguous_unknown method AnonymousClasses#main(String[]) -> -
ambiguous_unknown method AnonymousClasses$anon:Comparator#compare(String,String) -> -
ambiguous_unknown method AnonymousClasses$anon:Runnable#run() -> -
ambiguous_unknown method AnonymousClasses$anon:Thread#run() -> -
ambiguous_unknown new AnonymousClasses#main(String[]) -> -
boundary_lib method AnonymousClasses#main(String[]) -> external:java.util.List.of
boundary_lib method AnonymousClasses#main(String[]) -> external:java.util.List.sort
boundary_lib method AnonymousClasses$anon:Comparator#compare(String,String) -> external:String.length
boundary_lib method AnonymousClasses$anon:Comparator#compare(String,String) -> external:java.lang.Integer.compare
boundary_lib method AnonymousClasses$anon:Thread#run() -> external:Thread.getName
known_edge method AnonymousClasses#main(String[]) -> AnonymousClasses$anon:Runnable#run()
known_edge method AnonymousClasses#main(String[]) -> AnonymousClasses$anon:Thread#run()
4 changes: 3 additions & 1 deletion graph/test/java/expected/03-overloads-and-receivers.edges
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
ambiguous_anon anon_new testcases.engine.ComplexDispatch#<type-initializer>() -> -
ambiguous_unknown method testcases.engine.ComplexDispatch#jdkStatics(String,int,int) -> -
ambiguous_unknown new testcases.engine.ComplexDispatch#<type-initializer>() -> -
boundary_lib method testcases.engine.ComplexDispatch#boxingAndFields(String) -> external:java.util.Map.put
boundary_lib method testcases.engine.ComplexDispatch#jdkStatics(String,int,int) -> external:String.length
boundary_lib method testcases.engine.ComplexDispatch#jdkStatics(String,int,int) -> external:java.lang.Integer.parseInt
boundary_lib method testcases.engine.ComplexDispatch#jdkStatics(String,int,int) -> external:java.lang.Math.max
boundary_lib method testcases.engine.ComplexDispatch#jdkStatics(String,int,int) -> external:java.lang.String.valueOf
known_edge method testcases.engine.ComplexDispatch#internalOverloads(Throwable) -> testcases.engine.ComplexDispatch#emit(String)
known_edge method testcases.engine.ComplexDispatch#internalOverloads(Throwable) -> testcases.engine.ComplexDispatch#log(String)
known_edge method testcases.engine.ComplexDispatch#internalOverloads(Throwable) -> testcases.engine.ComplexDispatch#log(String,Throwable)
Expand Down
1 change: 1 addition & 0 deletions graph/test/java/expected/05-lambda-and-method-refs.edges
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ambiguous_unknown method Lam#viaForEach(String) -> -
ambiguous_unknown method Lam#viaParamList(List) -> -
ambiguous_unknown new Lam#<type-initializer>() -> -
ambiguous_unknown new Lam#main(String[]) -> -
boundary_lib method Lam#main(String[]) -> external:java.util.List.add
boundary_lib method Lam#main(String[]) -> external:java.util.Map.put
boundary_lib method Lam#viaForEach(String) -> external:java.util.Map.values
boundary_lib method Lam#viaMethodRef(List) -> external:java.util.List.forEach
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ambiguous_unknown method LibIfaceOverride#main(String[]) -> -
ambiguous_unknown new LibIfaceOverride#main(String[]) -> -
boundary_lib method LibIfaceOverride#main(String[]) -> external:java.util.List.add
boundary_lib method LibIfaceOverride#viaComparator(Comparator,String,String) -> external:java.util.Comparator.compare
boundary_lib method LibIfaceOverride#viaFunction(Function,String) -> external:java.util.function.Function.apply
boundary_lib method LibIfaceOverride#viaLibrarySort(List) -> external:java.util.List.sort
Expand Down
3 changes: 2 additions & 1 deletion graph/test/java/expected/13-type-qualified-statics.edges
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
ambiguous_unknown method TypeQualifiedStatics#main(String[]) -> -
ambiguous_unknown method TypeQualifiedStatics#viaLibraryType(String) -> -
boundary_lib method TypeQualifiedStatics#viaLibraryType(String) -> external:java.lang.Integer.parseInt
boundary_lib method TypeQualifiedStatics#viaLibraryType(String) -> external:java.lang.String.valueOf
known_edge method TypeQualifiedStatics#main(String[]) -> TypeQualifiedStatics#viaLibraryType(String)
known_edge method TypeQualifiedStatics#main(String[]) -> TypeQualifiedStatics#viaNestedType(String)
known_edge method TypeQualifiedStatics#main(String[]) -> TypeQualifiedStatics#viaOwnTypeName(String)
Expand Down
2 changes: 1 addition & 1 deletion graph/test/java/expected/14-lambda-param-callback.edges
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
ambiguous_unknown method LambdaParamCallback#main(String[]) -> -
ambiguous_unknown method LambdaParamCallback#viaMapValues(String) -> -
ambiguous_unknown method LambdaParamCallback#viaStream(List,String) -> -
ambiguous_unknown method LambdaParamCallback#viaTypedList(List,String) -> -
ambiguous_unknown new LambdaParamCallback#<type-initializer>() -> -
ambiguous_unknown new LambdaParamCallback#main(String[]) -> -
boundary_lib method LambdaParamCallback#main(String[]) -> external:java.util.List.add
boundary_lib method LambdaParamCallback#main(String[]) -> external:java.util.Map.put
boundary_lib method LambdaParamCallback#viaMapValues(String) -> external:java.util.Map.values
boundary_lib method LambdaParamCallback#viaStream(List,String) -> external:java.util.List.stream
Expand Down
2 changes: 2 additions & 0 deletions graph/test/java/expected/20-reflection-blind-spot.edges
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ boundary_lib method ReflectionSites#viaDynamicName(String) -> external:String.su
boundary_lib method ReflectionSites#viaDynamicName(String) -> external:java.lang.reflect.Method.invoke
boundary_lib method ReflectionSites#viaMethodInvoke(String) -> external:Class.getDeclaredConstructor
boundary_lib method ReflectionSites#viaMethodInvoke(String) -> external:Class.getMethod
boundary_lib method ReflectionSites#viaMethodInvoke(String) -> external:java.lang.Class.forName
boundary_lib method ReflectionSites#viaMethodInvoke(String) -> external:java.lang.reflect.Method.invoke
boundary_lib method ReflectionSites#viaNewInstance(String) -> external:java.lang.Class.forName
boundary_lib method ReflectionSites#viaNewInstance(String) -> external:java.lang.reflect.Constructor.newInstance
known_edge method ReflectionSites#main(String[]) -> ReflectionSites#viaDynamicName(String)
known_edge method ReflectionSites#main(String[]) -> ReflectionSites#viaMethodInvoke(String)
Expand Down
5 changes: 3 additions & 2 deletions graph/test/java/expected/33-compiler-lowering.edges
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
ambiguous_unknown method lowering.Lowering#explicitRequireNonNull(Sink) -> -
ambiguous_unknown method lowering.Lowering#tryWithResources(String) -> -
ambiguous_unknown new lowering.Lowering#tryWithResources(String) -> -
ambiguous_unknown new lowering.Lowering.Bag#<type-initializer>() -> -
boundary_lib method lowering.Lowering#boundRef(List,Sink) -> external:java.util.List.forEach
boundary_lib method lowering.Lowering#explicitIterator(Bag) -> external:java.util.Iterator.hasNext
boundary_lib method lowering.Lowering#explicitIterator(Bag) -> external:java.util.Iterator.next
boundary_lib method lowering.Lowering#explicitRequireNonNull(Sink) -> external:java.util.Objects.requireNonNull
boundary_lib method lowering.Lowering#explicitUnbox(Integer) -> external:Integer.intValue
boundary_lib method lowering.Lowering#plainLibraryCall(List) -> external:java.util.List.size
boundary_lib method lowering.Lowering#tryWithResources(String) -> external:java.io.StringReader.read
boundary_lib method lowering.Lowering#tryWithResources(String) -> external:java.lang.String.valueOf
boundary_lib method lowering.Lowering#use(String) -> external:String.trim
boundary_lib method lowering.Lowering.Bag#iterator() -> external:java.util.List.iterator
boundary_lib method lowering.Lowering.Bag#size() -> external:java.util.List.size
Expand Down
2 changes: 1 addition & 1 deletion graph/test/java/expected/48-local-scope-shadowing.edges
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ambiguous_unknown method probe.Shadow#catchParameter() -> -
ambiguous_unknown new probe.Shadow#catchParameter() -> -
boundary_lib method probe.Shadow#catchParameter() -> external:RuntimeException.getMessage
boundary_lib method probe.Shadow#catchParameter() -> external:java.lang.String.valueOf
boundary_lib method probe.Shadow#forHeader() -> external:String.isEmpty
known_edge method probe.Shadow#after() -> probe.LocalSide#fromLocal()
known_edge method probe.Shadow#catchParameter() -> probe.FieldSide#fromField()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ambiguous_unknown method probe.App#<type-initializer>() -> -
ambiguous_unknown method probe.App#callers() -> -
boundary_lib method probe.App#<type-initializer>() -> external:java.lang.Boolean.getBoolean
boundary_lib method probe.App#callOther(App,String) -> external:java.util.function.Function.apply
boundary_lib method probe.App#callers() -> external:java.lang.Boolean.getBoolean
boundary_lib method probe.App#callers() -> external:java.util.function.Function.apply
boundary_lib method probe.App#dispatch(String) -> external:java.util.function.Function.apply
boundary_lib method probe.App#getPath(String) -> external:String.split
Expand Down
1 change: 1 addition & 0 deletions graph/test/java/expected/61-var-local-type.edges
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ ambiguous_unknown method probe.VarLocals#lambdaUnknownInterface() -> -
ambiguous_unknown method probe.VarLocals#literalInline() -> -
boundary_lib method probe.VarLocals#declaredExternal(Object) -> external:java.text.Format.format
boundary_lib method probe.VarLocals#fromLiteralDeclared() -> external:String.length
boundary_lib method probe.VarLocals#fromUnknown() -> external:java.util.Collections.emptyList
boundary_lib method probe.VarLocals#lambdaLocal(Widget) -> external:java.util.function.Consumer.accept
boundary_lib method probe.VarLocals#varExternal(Object) -> external:java.text.Format.format
known_edge lambda_body probe.VarLocals#lambdaLocal(Widget) -> probe.Widget#paint()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
ambiguous_unknown method app.init.AppInit#onStartup(Set,ServletContext) -> -
ambiguous_unknown method app.rs.Size#valueOf(String) -> -
ambiguous_unknown new app.init.BootConfig#bootServlet() -> -
boundary_lib method app.init.AppInit#onStartup(Set,ServletContext) -> external:jakarta.servlet.ServletContext.addFilter
boundary_lib method app.init.AppInit#onStartup(Set,ServletContext) -> external:jakarta.servlet.ServletContext.addListener
boundary_lib method app.init.AppInit#onStartup(Set,ServletContext) -> external:jakarta.servlet.ServletContext.addServlet
boundary_lib method app.rs.Size#valueOf(String) -> external:java.lang.Integer.parseInt
callback_registered callback app.init.AppInit#onStartup(Set,ServletContext) -> app.init.InitFilter#doFilter(ServletRequest,ServletResponse,FilterChain)
known_edge method app.init.AppInit#wire(EventBus) -> app.init.EventBus#addListener(Class)
known_edge new app.beans.AppConfig#plain() -> app.beans.Plain#<init>()
Expand Down
2 changes: 1 addition & 1 deletion graph/test/java/expected/68-http-routes-and-sends.edges
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
ambiguous_unknown method app.rs.RsClients#<type-initializer>() -> -
ambiguous_unknown method app.rs.RsClients#order(String) -> -
ambiguous_unknown method app.rs.RsClients#orders() -> -
ambiguous_unknown new app.rs.RsClients#<type-initializer>() -> -
ambiguous_unknown new app.spring.OrderClient#<type-initializer>() -> -
ambiguous_unknown new app.web.WebCaller#<type-initializer>() -> -
boundary_lib method app.rs.RsClients#<type-initializer>() -> external:jakarta.ws.rs.client.ClientBuilder.newClient
boundary_lib method app.rs.RsClients#gadget(String) -> external:org.springframework.web.client.RestTemplate.getForObject
boundary_lib method app.rs.RsClients#item(String) -> external:org.springframework.web.client.RestTemplate.getForObject
boundary_lib method app.rs.RsClients#widget(String) -> external:org.springframework.web.client.RestTemplate.getForObject
Expand Down
Loading
Loading