Mark dynamic calls in for's, delegated properties and multi-declarations

This commit is contained in:
Andrey Breslav
2014-11-26 20:16:28 +03:00
parent 4adf74b46f
commit fac53de40c
2 changed files with 70 additions and 12 deletions
@@ -37,6 +37,7 @@ import org.jetbrains.jet.lang.diagnostics.rendering.AbstractDiagnosticWithParame
import org.jetbrains.jet.lang.diagnostics.rendering.DefaultErrorMessages;
import org.jetbrains.jet.lang.diagnostics.rendering.DiagnosticFactoryToRendererMap;
import org.jetbrains.jet.lang.diagnostics.rendering.DiagnosticRenderer;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
@@ -128,14 +129,14 @@ public class CheckerTestUtil {
}
@Override
public void reportDynamicCall(@NotNull JetReferenceExpression expression) {
public void reportDynamicCall(@NotNull JetElement element) {
if (markDynamicCalls) {
newDiagnostic(expression, DebugInfoDiagnosticFactory.DYNAMIC);
newDiagnostic(element, DebugInfoDiagnosticFactory.DYNAMIC);
}
}
private void newDiagnostic(JetReferenceExpression expression, DebugInfoDiagnosticFactory factory) {
debugAnnotations.add(new DebugInfoDiagnostic(expression, factory));
private void newDiagnostic(JetElement element, DebugInfoDiagnosticFactory factory) {
debugAnnotations.add(new DebugInfoDiagnostic(element, factory));
}
});
// this code is used in tests and in internal action 'copy current file as diagnostic test'
@@ -523,8 +524,8 @@ public class CheckerTestUtil {
}
public static class DebugInfoDiagnostic extends AbstractDiagnosticForTests {
public DebugInfoDiagnostic(@NotNull JetExpression reference, @NotNull DebugInfoDiagnosticFactory factory) {
super(reference, factory);
public DebugInfoDiagnostic(@NotNull JetElement element, @NotNull DebugInfoDiagnosticFactory factory) {
super(element, factory);
}
}
@@ -23,17 +23,22 @@ import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory;
import org.jetbrains.jet.lang.diagnostics.Errors;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.calls.tasks.TasksPackage;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.Collection;
import java.util.Map;
@@ -42,8 +47,9 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lexer.JetTokens.*;
public class DebugInfoUtil {
private static final TokenSet MAY_BE_UNRESOLVED = TokenSet.create(IN_KEYWORD, NOT_IN);
private static final TokenSet EXCLUDED = TokenSet.create(
COLON, AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS, OROR, ANDAND, EQ, EQEQEQ, EXCLEQEQEQ, ELVIS, EXCLEXCL, IN_KEYWORD, NOT_IN);
COLON, AS_KEYWORD, AS_SAFE, IS_KEYWORD, NOT_IS, OROR, ANDAND, EQ, EQEQEQ, EXCLEQEQEQ, ELVIS, EXCLEXCL);
public abstract static class DebugInfoReporter {
@@ -57,7 +63,7 @@ public class DebugInfoUtil {
public abstract void reportUnresolvedWithTarget(@NotNull JetReferenceExpression expression, @NotNull String target);
public void reportDynamicCall(@NotNull JetReferenceExpression expression) { }
public void reportDynamicCall(@NotNull JetElement element) { }
}
public static void markDebugAnnotations(
@@ -89,17 +95,51 @@ public class DebugInfoUtil {
root.acceptChildren(new JetTreeVisitorVoid() {
@Override
public void visitForExpression(@NotNull JetForExpression expression) {
JetExpression range = expression.getLoopRange();
if (reportIfDynamicCall(range, range, LOOP_RANGE_ITERATOR_RESOLVED_CALL) ||
reportIfDynamicCall(range, range, LOOP_RANGE_HAS_NEXT_RESOLVED_CALL) ||
reportIfDynamicCall(range, range, LOOP_RANGE_NEXT_RESOLVED_CALL)) {
// for side-effect of the condition only
}
super.visitForExpression(expression);
}
@Override
public void visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration) {
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
reportIfDynamicCall(entry, entry, COMPONENT_RESOLVED_CALL);
}
super.visitMultiDeclaration(multiDeclaration);
}
@Override
public void visitProperty(@NotNull JetProperty property) {
VariableDescriptor descriptor = bindingContext.get(VARIABLE, property);
if (descriptor instanceof PropertyDescriptor && property.getDelegate() != null) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (reportIfDynamicCall(property.getDelegate(), propertyDescriptor.getGetter(), DELEGATED_PROPERTY_RESOLVED_CALL)
|| reportIfDynamicCall(property.getDelegate(), propertyDescriptor.getSetter(), DELEGATED_PROPERTY_RESOLVED_CALL)
|| reportIfDynamicCall(property.getDelegate(), propertyDescriptor, DELEGATED_PROPERTY_PD_RESOLVED_CALL)) {
// for side-effect of the condition only
}
}
super.visitProperty(property);
}
@Override
public void visitReferenceExpression(@NotNull JetReferenceExpression expression) {
super.visitReferenceExpression(expression);
if (!BindingContextUtils.isExpressionWithValidReference(expression, bindingContext)){
return;
}
IElementType referencedNameElementType = null;
if (expression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) expression;
IElementType elementType = expression.getNode().getElementType();
if (elementType == JetNodeTypes.OPERATION_REFERENCE) {
IElementType referencedNameElementType = nameExpression.getReferencedNameElementType();
referencedNameElementType = nameExpression.getReferencedNameElementType();
if (EXCLUDED.contains(referencedNameElementType)) {
return;
}
@@ -117,9 +157,7 @@ public class DebugInfoUtil {
if (declarationDescriptor != null) {
target = declarationDescriptor.toString();
if (TasksPackage.isDynamic(declarationDescriptor)) {
debugInfoReporter.reportDynamicCall(expression);
}
reportIfDynamic(expression, declarationDescriptor, debugInfoReporter);
}
if (target == null) {
PsiElement labelTarget = bindingContext.get(LABEL_TARGET, expression);
@@ -141,6 +179,10 @@ public class DebugInfoUtil {
}
}
if (MAY_BE_UNRESOLVED.contains(referencedNameElementType)) {
return;
}
boolean resolved = target != null;
boolean markedWithError = markedWithErrorElements.containsKey(expression);
if (expression instanceof JetArrayAccessExpression &&
@@ -165,7 +207,22 @@ public class DebugInfoUtil {
debugInfoReporter.reportMissingUnresolved(expression);
}
}
private <E extends JetElement, K, D extends CallableDescriptor> boolean reportIfDynamicCall(E element, K key, WritableSlice<K, ResolvedCall<D>> slice) {
ResolvedCall<D> resolvedCall = bindingContext.get(slice, key);
if (resolvedCall != null) {
return reportIfDynamic(element, resolvedCall.getResultingDescriptor(), debugInfoReporter);
}
return false;
}
});
}
private static boolean reportIfDynamic(JetElement element, DeclarationDescriptor declarationDescriptor, DebugInfoReporter debugInfoReporter) {
if (TasksPackage.isDynamic(declarationDescriptor)) {
debugInfoReporter.reportDynamicCall(element);
return true;
}
return false;
}
}