Report more details about calling async code from sync method

This commit is contained in:
Alexey Andreev 2016-10-22 17:40:32 +03:00
parent 37d4c3349e
commit 9fd744f550

View File

@ -71,7 +71,7 @@ public class AsyncMethodFinder {
continue; continue;
} }
if (method.getAnnotations().get(Async.class.getName()) != null) { if (method.getAnnotations().get(Async.class.getName()) != null) {
add(method.getReference()); add(method.getReference(), new CallStack(method.getReference(), null));
} }
} }
} }
@ -83,7 +83,7 @@ public class AsyncMethodFinder {
continue; continue;
} }
if (hasMonitor(method)) { if (hasMonitor(method)) {
add(method.getReference()); add(method.getReference(), new CallStack(method.getReference(), null));
} }
} }
} }
@ -137,7 +137,7 @@ public class AsyncMethodFinder {
return false; return false;
} }
private void add(MethodReference methodRef) { private void add(MethodReference methodRef, CallStack stack) {
if (!asyncMethods.add(methodRef)) { if (!asyncMethods.add(methodRef)) {
return; return;
} }
@ -156,11 +156,33 @@ public class AsyncMethodFinder {
if (method.getAnnotations().get(Sync.class.getName()) != null if (method.getAnnotations().get(Sync.class.getName()) != null
|| method.getAnnotations().get(InjectedBy.class.getName()) != null) { || method.getAnnotations().get(InjectedBy.class.getName()) != null) {
diagnostics.error(new CallLocation(methodRef), "Method {{m0}} is claimed to be synchronous, " diagnostics.error(new CallLocation(methodRef), "Method {{m0}} is claimed to be synchronous, "
+ "but it is has invocations of asynchronous methods", methodRef); + "but it is has invocations of asynchronous methods:" + stack.toString(), methodRef);
return; return;
} }
for (CallSite callSite : node.getCallerCallSites()) { for (CallSite callSite : node.getCallerCallSites()) {
add(callSite.getCaller().getMethod()); MethodReference nextMethod = callSite.getCaller().getMethod();
add(nextMethod, new CallStack(nextMethod, stack));
}
}
private class CallStack {
MethodReference method;
CallStack next;
public CallStack(MethodReference method, CallStack next) {
this.method = method;
this.next = next;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
CallStack stack = this;
while (stack != null) {
sb.append("\n calling " + stack.method);
stack = stack.next;
}
return sb.toString();
} }
} }
@ -170,7 +192,7 @@ public class AsyncMethodFinder {
if (cls == null) { if (cls == null) {
return; return;
} }
for (MethodReference overridenMethod : findOverridenMethods(cls, methodRef)) { for (MethodReference overridenMethod : findOverriddenMethods(cls, methodRef)) {
addOverridenToFamily(overridenMethod); addOverridenToFamily(overridenMethod);
} }
} }
@ -193,7 +215,7 @@ public class AsyncMethodFinder {
if (cls == null) { if (cls == null) {
return false; return false;
} }
for (MethodReference overridenMethod : findOverridenMethods(cls, methodRef)) { for (MethodReference overridenMethod : findOverriddenMethods(cls, methodRef)) {
if (addToFamily(overridenMethod)) { if (addToFamily(overridenMethod)) {
return true; return true;
} }
@ -201,7 +223,7 @@ public class AsyncMethodFinder {
return false; return false;
} }
private Set<MethodReference> findOverridenMethods(ClassReader cls, MethodReference methodRef) { private Set<MethodReference> findOverriddenMethods(ClassReader cls, MethodReference methodRef) {
List<String> parents = new ArrayList<>(); List<String> parents = new ArrayList<>();
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
parents.add(cls.getParent()); parents.add(cls.getParent());
@ -211,12 +233,12 @@ public class AsyncMethodFinder {
Set<MethodReference> visited = new HashSet<>(); Set<MethodReference> visited = new HashSet<>();
Set<MethodReference> overriden = new HashSet<>(); Set<MethodReference> overriden = new HashSet<>();
for (String parent : parents) { for (String parent : parents) {
findOverridenMethods(new MethodReference(parent, methodRef.getDescriptor()), overriden, visited); findOverriddenMethods(new MethodReference(parent, methodRef.getDescriptor()), overriden, visited);
} }
return overriden; return overriden;
} }
private void findOverridenMethods(MethodReference methodRef, Set<MethodReference> result, private void findOverriddenMethods(MethodReference methodRef, Set<MethodReference> result,
Set<MethodReference> visited) { Set<MethodReference> visited) {
if (!visited.add(methodRef)) { if (!visited.add(methodRef)) {
return; return;
@ -235,10 +257,10 @@ public class AsyncMethodFinder {
} }
} else { } else {
if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) {
findOverridenMethods(new MethodReference(cls.getParent(), methodRef.getDescriptor()), result, visited); findOverriddenMethods(new MethodReference(cls.getParent(), methodRef.getDescriptor()), result, visited);
} }
for (String iface : cls.getInterfaces()) { for (String iface : cls.getInterfaces()) {
findOverridenMethods(new MethodReference(iface, methodRef.getDescriptor()), result, visited); findOverriddenMethods(new MethodReference(iface, methodRef.getDescriptor()), result, visited);
} }
} }
} }