JET-25 Support method overriding: overrides are bound together (and displayed in the editor)

This commit is contained in:
Andrey Breslav
2011-05-06 19:28:46 +04:00
parent 32f5e3c5b9
commit 392d3c340d
24 changed files with 550 additions and 100 deletions
+1
View File
@@ -27,5 +27,6 @@
<annotator language="jet" implementationClass="org.jetbrains.jet.lang.annotations.JetPsiChecker"/>
<documentationProvider implementation="org.jetbrains.jet.plugin.JetQuickDocumentationProvider"/>
<configurationType implementation="org.jetbrains.jet.run.JetRunConfigurationType"/>
<codeInsight.lineMarkerProvider language="jet" implementationClass="org.jetbrains.jet.lang.annotations.JetLineMarkerProvider"/>
</extensions>
</idea-plugin>
@@ -14,38 +14,38 @@ public class ErrorHandler {
public static final ErrorHandler DO_NOTHING = new ErrorHandler();
public static final ErrorHandler THROW_EXCEPTION = new ErrorHandler() {
@Override
public void unresolvedReference(JetReferenceExpression referenceExpression) {
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
throw new IllegalStateException("Unresolved reference: " + referenceExpression.getText());
}
@Override
public void genericError(@NotNull ASTNode node, String errorMessage) {
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
throw new IllegalStateException(errorMessage);
}
@Override
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
throw new IllegalStateException("Type mismatch: inferred type is " + actualType + " but " + expectedType + " was expected");
}
@Override
public void redeclaration(DeclarationDescriptor existingDescriptor, DeclarationDescriptor redeclaredDescriptor) {
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
throw new IllegalStateException("Redeclaration: " + existingDescriptor.getName());
}
};
public void unresolvedReference(JetReferenceExpression referenceExpression) {
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
}
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
}
public void redeclaration(DeclarationDescriptor existingDescriptor, DeclarationDescriptor redeclaredDescriptor) {
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
}
public void genericError(@NotNull ASTNode node, String errorMessage) {
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
}
public void genericWarning(ASTNode node, String message) {
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
}
}
@@ -0,0 +1,96 @@
package org.jetbrains.jet.lang;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import org.jetbrains.jet.lang.types.DeclarationDescriptor;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author abreslav
*/
public abstract class JetDiagnostic {
public static class UnresolvedReferenceError extends JetDiagnostic {
private final JetReferenceExpression referenceExpression;
public UnresolvedReferenceError(@NonNls JetReferenceExpression referenceExpression) {
this.referenceExpression = referenceExpression;
}
@Override
public void acceptHandler(@NonNls ErrorHandler handler) {
handler.unresolvedReference(referenceExpression);
}
}
public static class GenericError extends JetDiagnostic {
private final ASTNode node;
private final String message;
public GenericError(@NonNls ASTNode node, @NonNls String message) {
this.node = node;
this.message = message;
}
@Override
public void acceptHandler(@NonNls ErrorHandler handler) {
handler.genericError(node, message);
}
}
public static class TypeMismatchError extends JetDiagnostic {
private final JetExpression expression;
private final JetType expectedType;
private final JetType actualType;
public TypeMismatchError(@NonNls JetExpression expression, @NonNls JetType expectedType, @NonNls JetType actualType) {
this.expression = expression;
this.expectedType = expectedType;
this.actualType = actualType;
}
@Override
public void acceptHandler(@NonNls ErrorHandler handler) {
handler.typeMismatch(expression, expectedType, actualType);
}
}
public static class RedeclarationError extends JetDiagnostic {
private final DeclarationDescriptor existingDescriptor;
private final DeclarationDescriptor redeclaredDescriptor;
public RedeclarationError(@NonNls DeclarationDescriptor existingDescriptor, @NonNls DeclarationDescriptor redeclaredDescriptor) {
this.existingDescriptor = existingDescriptor;
this.redeclaredDescriptor = redeclaredDescriptor;
}
@Override
public void acceptHandler(@NonNls ErrorHandler handler) {
handler.redeclaration(existingDescriptor, redeclaredDescriptor);
}
}
public static class GenericWarning extends JetDiagnostic {
private final ASTNode node;
private final String message;
public GenericWarning(@NonNls ASTNode node, @NonNls String message) {
this.message = message;
this.node = node;
}
@Override
public void acceptHandler(@NonNls ErrorHandler handler) {
handler.genericWarning(node, message);
}
}
public abstract void acceptHandler(@NonNls ErrorHandler handler);
}
@@ -0,0 +1,107 @@
package org.jetbrains.jet.lang.annotations;
import com.google.common.collect.Lists;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.ide.util.DefaultPsiElementCellRenderer;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.IconLoader;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Function;
import com.intellij.util.PsiNavigateUtil;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetFunction;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public class JetLineMarkerProvider implements LineMarkerProvider {
public static final Icon OVERRIDING_FUNCTION = IconLoader.getIcon("/general/overridingMethod.png");
@Override
public LineMarkerInfo getLineMarkerInfo(PsiElement element) {
if (element instanceof JetFunction) {
JetFunction jetFunction = (JetFunction) element;
JetFile file = PsiTreeUtil.getParentOfType(element, JetFile.class);
assert file != null;
final BindingContext bindingContext = AnalyzingUtils.analyzeFile(file, ErrorHandler.DO_NOTHING);
FunctionDescriptor functionDescriptor = bindingContext.getFunctionDescriptor(jetFunction);
final Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenFunctions();
if (!overriddenFunctions.isEmpty()) {
return new LineMarkerInfo<JetFunction>(
jetFunction, jetFunction.getTextOffset(), OVERRIDING_FUNCTION, Pass.UPDATE_ALL,
new Function<JetFunction, String>() {
@Override
public String fun(JetFunction jetFunction) {
return overriddenFunctions.toString();
}
},
new GutterIconNavigationHandler<JetFunction>() {
@Override
public void navigate(MouseEvent event, JetFunction elt) {
final List<PsiElement> list = Lists.newArrayList();
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(overriddenFunction);
list.add(declarationPsiElement);
}
if (list.isEmpty()) {
String myEmptyText = "empty text";
if (myEmptyText != null) {
final JComponent renderer = HintUtil.createErrorLabel(myEmptyText);
final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(renderer, renderer).createPopup();
if (event != null) {
popup.show(new RelativePoint(event));
}
}
return;
}
if (list.size() == 1) {
PsiNavigateUtil.navigate(list.iterator().next());
}
else {
final JBPopup popup = NavigationUtil.getPsiElementPopup(PsiUtilBase.toPsiElementArray(list), new DefaultPsiElementCellRenderer() {
@Override
public String getElementText(PsiElement element) {
if (element instanceof JetFunction) {
JetFunction function = (JetFunction) element;
return bindingContext.getFunctionDescriptor(function).toString();
}
return super.getElementText(element);
}
}, "title");
if (event != null) {
popup.show(new RelativePoint(event));
}
}
}
}
);
}
}
return null;
}
@Override
public void collectSlowLineMarkers(List<PsiElement> elements, Collection<LineMarkerInfo> result) {
}
}
@@ -12,6 +12,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetDiagnostic;
import org.jetbrains.jet.lang.JetHighlighter;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
@@ -21,8 +22,8 @@ import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.PropertyDescriptor;
import org.jetbrains.jet.lang.types.VariableDescriptor;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* @author abreslav
@@ -36,47 +37,57 @@ public class JetPsiChecker implements Annotator {
JetFile file = (JetFile) element;
try {
final Collection<DeclarationDescriptor> redeclarations = new HashSet<DeclarationDescriptor>();
final BindingContext bindingContext = AnalyzingUtils.analyzeFile(file, new ErrorHandler() {
final BindingContext bindingContext = AnalyzingUtils.analyzeFile(file);
ErrorHandler errorHandler = new ErrorHandler() {
private final Set<DeclarationDescriptor> redeclarations = new HashSet<DeclarationDescriptor>();
@Override
public void unresolvedReference(JetReferenceExpression referenceExpression) {
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
PsiReference reference = referenceExpression.getReference();
if (reference instanceof MultiRangeReference) {
MultiRangeReference mrr = (MultiRangeReference) reference;
for (TextRange range : mrr.getRanges()) {
holder.createErrorAnnotation(range.shiftRight(referenceExpression.getTextOffset()), "Unresolved").setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
} else {
}
else {
holder.createErrorAnnotation(referenceExpression, "Unresolved").setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
}
@Override
public void typeMismatch(JetExpression expression, JetType expectedType, JetType actualType) {
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
holder.createErrorAnnotation(expression, "Type mismatch: inferred type is " + actualType + " but " + expectedType + " was expected");
}
@Override
public void redeclaration(DeclarationDescriptor existingDescriptor, DeclarationDescriptor redeclaredDescriptor) {
redeclarations.add(existingDescriptor);
redeclarations.add(redeclaredDescriptor);
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
markRedeclaration(existingDescriptor);
markRedeclaration(redeclaredDescriptor);
}
private void markRedeclaration(DeclarationDescriptor redeclaration) {
if (!redeclarations.add(redeclaration)) return;
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(redeclaration);
if (declarationPsiElement != null) {
holder.createErrorAnnotation(declarationPsiElement, "Redeclaration");
}
}
@Override
public void genericError(@NotNull ASTNode node, String errorMessage) {
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
holder.createErrorAnnotation(node, errorMessage);
}
@Override
public void genericWarning(ASTNode node, String message) {
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
holder.createWarningAnnotation(node, message);
}
});
for (DeclarationDescriptor redeclaration : redeclarations) {
PsiElement declarationPsiElement = bindingContext.getDeclarationPsiElement(redeclaration);
if (declarationPsiElement != null) {
holder.createErrorAnnotation(declarationPsiElement, "Redeclaration");
}
};
for (JetDiagnostic diagnostic : bindingContext.getDiagnostics()) {
diagnostic.acceptHandler(errorHandler);
}
highlightBackingFields(holder, file, bindingContext);
@@ -92,6 +103,7 @@ public class JetPsiChecker implements Annotator {
}
}
private void highlightBackingFields(final AnnotationHolder holder, JetFile file, final BindingContext bindingContext) {
file.acceptChildren(new JetVisitor() {
@Override
@@ -1,11 +1,17 @@
package org.jetbrains.jet.lang.resolve;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiErrorElement;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetDiagnostic;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.psi.JetFile;
@@ -18,6 +24,48 @@ import org.jetbrains.jet.lang.types.ModuleDescriptor;
* @author abreslav
*/
public class AnalyzingUtils {
private final static Key<CachedValue<BindingContext>> BINDING_CONTEXT = Key.create("BINDING_CONTEXT");
public static BindingContext analyzeFile(@NotNull final JetFile file) {
// TODO : Synchronization?
// TODO : Error handler may be ignored
CachedValue<BindingContext> bindingContextCachedValue = file.getUserData(BINDING_CONTEXT);
if (bindingContextCachedValue == null) {
bindingContextCachedValue = CachedValuesManager.getManager(file.getProject()).createCachedValue(new CachedValueProvider<BindingContext>() {
@Override
public Result<BindingContext> compute() {
JetNamespace rootNamespace = file.getRootNamespace();
BindingContext bindingContext = analyzeNamespace(rootNamespace, JetControlFlowDataTraceFactory.EMPTY);
return new Result<BindingContext>(bindingContext, PsiModificationTracker.MODIFICATION_COUNT);
}
}, false);
file.putUserData(BINDING_CONTEXT, bindingContextCachedValue);
}
return bindingContextCachedValue.getValue();
}
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace) {
return analyzeNamespace(namespace, JetControlFlowDataTraceFactory.EMPTY);
}
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
Project project = namespace.getProject();
BindingTraceContext bindingTraceContext = new BindingTraceContext();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, bindingTraceContext.getErrorHandler());
JavaSemanticServices javaSemanticServices = new JavaSemanticServices(project, semanticServices, bindingTraceContext);
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
WritableScope scope = semanticServices.createWritableScope(libraryScope, new ModuleDescriptor("<module>"));
// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("").getMemberScope());
// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("java.lang").getMemberScope());
scope.importScope(new JavaPackageScope("", null, javaSemanticServices));
scope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices));
new TopDownAnalyzer(semanticServices, bindingTraceContext, flowDataTraceFactory).process(scope, namespace);
return bindingTraceContext;
}
public static void checkForSyntacticErrors(@NotNull PsiElement root) {
root.acceptChildren(new PsiElementVisitor() {
@Override
@@ -32,30 +80,21 @@ public class AnalyzingUtils {
});
}
public static BindingContext analyzeFile(@NotNull JetFile file, @NotNull ErrorHandler errorHandler) {
JetNamespace rootNamespace = file.getRootNamespace();
return analyzeNamespace(rootNamespace, errorHandler, JetControlFlowDataTraceFactory.EMPTY);
}
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull ErrorHandler errorHandler) {
return analyzeNamespace(namespace, errorHandler, JetControlFlowDataTraceFactory.EMPTY);
BindingContext bindingContext = analyzeNamespace(namespace);
applyHandler(errorHandler, bindingContext);
return bindingContext;
}
public static BindingContext analyzeNamespace(@NotNull JetNamespace namespace, @NotNull ErrorHandler errorHandler, @NotNull JetControlFlowDataTraceFactory flowDataTraceFactory) {
Project project = namespace.getProject();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(project, errorHandler);
private static void applyHandler(@NotNull ErrorHandler errorHandler, @NotNull BindingContext bindingContext) {
for (JetDiagnostic jetDiagnostic : bindingContext.getDiagnostics()) {
jetDiagnostic.acceptHandler(errorHandler);
}
}
BindingTraceContext bindingTraceContext = new BindingTraceContext();
JavaSemanticServices javaSemanticServices = new JavaSemanticServices(project, semanticServices, bindingTraceContext);
JetScope libraryScope = semanticServices.getStandardLibrary().getLibraryScope();
WritableScope scope = semanticServices.createWritableScope(libraryScope, new ModuleDescriptor("<module>"));
// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("").getMemberScope());
// scope.importScope(javaSemanticServices.getDescriptorResolver().resolveNamespace("java.lang").getMemberScope());
scope.importScope(new JavaPackageScope("", null, javaSemanticServices));
scope.importScope(new JavaPackageScope("java.lang", null, javaSemanticServices));
new TopDownAnalyzer(semanticServices, bindingTraceContext, flowDataTraceFactory).process(scope, namespace);
return bindingTraceContext;
public static BindingContext analyzeFile(@NotNull JetFile file, @NotNull ErrorHandler errorHandler) {
BindingContext bindingContext = analyzeFile(file);
applyHandler(errorHandler, bindingContext);
return bindingContext;
}
}
@@ -2,9 +2,12 @@ package org.jetbrains.jet.lang.resolve;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.codegen.ClassCodegen;
import org.jetbrains.jet.lang.JetDiagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
import java.util.Collection;
/**
* @author abreslav
*/
@@ -38,4 +41,6 @@ public interface BindingContext {
boolean hasBackingField(PropertyDescriptor propertyDescriptor);
ConstructorDescriptor resolveSuperConstructor(JetDelegatorToSuperCall superCall, ClassCodegen classCodegen);
Collection<JetDiagnostic> getDiagnostics();
}
@@ -1,17 +1,18 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.ClassCodegen;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetDiagnostic;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
/**
* @author abreslav
@@ -30,10 +31,43 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
private final Set<JetElement> statements = new HashSet<JetElement>();
private final Set<PropertyDescriptor> backingFieldRequired = new HashSet<PropertyDescriptor>();
private Collection<JetDiagnostic> diagnostics = Lists.newArrayList();
private ErrorHandler errorHandler = new ErrorHandler() {
@Override
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
diagnostics.add(new JetDiagnostic.UnresolvedReferenceError(referenceExpression));
}
@Override
public void typeMismatch(@NotNull JetExpression expression, @NotNull JetType expectedType, @NotNull JetType actualType) {
diagnostics.add(new JetDiagnostic.TypeMismatchError(expression, expectedType, actualType));
}
@Override
public void redeclaration(@NotNull DeclarationDescriptor existingDescriptor, @NotNull DeclarationDescriptor redeclaredDescriptor) {
diagnostics.add(new JetDiagnostic.RedeclarationError(existingDescriptor, redeclaredDescriptor));
}
@Override
public void genericError(@NotNull ASTNode node, @NotNull String errorMessage) {
diagnostics.add(new JetDiagnostic.GenericError(node, errorMessage));
}
@Override
public void genericWarning(@NotNull ASTNode node, @NotNull String message) {
diagnostics.add(new JetDiagnostic.GenericWarning(node, message));
}
};
private JetScope toplevelScope;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public ErrorHandler getErrorHandler() {
return errorHandler;
}
@Override
public void recordExpressionType(@NotNull JetExpression expression, @NotNull JetType type) {
expressionTypes.put(expression, type);
@@ -250,4 +284,9 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
DeclarationDescriptor descriptor = resolveReferenceExpression(((JetUserType) typeElement).getReferenceExpression());
return descriptor instanceof ConstructorDescriptor ? (ConstructorDescriptor) descriptor : null;
}
@Override
public Collection<JetDiagnostic> getDiagnostics() {
return diagnostics;
}
}
@@ -14,13 +14,16 @@ import java.util.Set;
* @author abreslav
*/
public class MutableClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor {
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
private final WritableScope classHeaderScope;
private final WritableScope writableMemberScope;
private final Set<PropertyDescriptor> properties = Sets.newHashSet();
private ConstructorDescriptor primaryConstructor;
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
private final Set<FunctionDescriptor> functions = Sets.newHashSet();
private final Set<PropertyDescriptor> properties = Sets.newHashSet();
private final Set<MutableClassDescriptor> classes = Sets.newHashSet();
private TypeConstructor typeConstructor;
private final WritableScope classHeaderScope;
private final WritableScope writableMemberScope;
private JetScope unsubstitutedMemberScope;
public MutableClassDescriptor(@NotNull JetSemanticServices semanticServices, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) {
@@ -32,6 +35,12 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
properties.add(descriptor);
return null;
}
@Override
public Void visitFunctionDescriptor(FunctionDescriptor descriptor, WritableScope data) {
functions.add(descriptor);
return null;
}
});
this.unsubstitutedMemberScope = this.writableMemberScope;
}
@@ -42,6 +51,45 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
this.writableMemberScope = null;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void setPrimaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert this.primaryConstructor == null : "Primary constructor assigned twice " + this;
this.primaryConstructor = constructorDescriptor;
addConstructor(constructorDescriptor);
}
@Override
@Nullable
public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
return primaryConstructor;
}
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert constructorDescriptor.getContainingDeclaration() == this;
constructors.addFunction(constructorDescriptor);
}
public void addProperty(@NotNull PropertyDescriptor propertyDescriptor) {
properties.add(propertyDescriptor);
}
@NotNull
public Set<PropertyDescriptor> getProperties() {
return properties;
}
public void addFunction(@NotNull FunctionDescriptor functionDescriptor) {
functions.add(functionDescriptor);
}
@NotNull
public Set<FunctionDescriptor> getFunctions() {
return functions;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void setUnsubstitutedMemberScope(@NotNull JetScope unsubstitutedMemberScope) {
assert writableMemberScope == null;
this.unsubstitutedMemberScope = unsubstitutedMemberScope;
@@ -57,10 +105,6 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
this.typeConstructor = typeConstructor;
}
public Set<PropertyDescriptor> getProperties() {
return properties;
}
@NotNull
@Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
@@ -79,11 +123,6 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
return TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope);
}
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert constructorDescriptor.getContainingDeclaration() == this;
constructors.addFunction(constructorDescriptor);
}
@NotNull
@Override
public FunctionGroup getConstructors(List<TypeProjection> typeArguments) {
@@ -118,18 +157,6 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
return visitor.visitClassDescriptor(this, data);
}
public void setPrimaryConstructor(@NotNull ConstructorDescriptor constructorDescriptor) {
assert this.primaryConstructor == null : "Primary constructor assigned twice " + this;
this.primaryConstructor = constructorDescriptor;
addConstructor(constructorDescriptor);
}
@Override
@Nullable
public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
return primaryConstructor;
}
@Override
public boolean hasConstructors() {
return !constructors.isEmpty();
@@ -7,6 +7,7 @@ import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.JetControlFlowProcessor;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
@@ -314,6 +315,40 @@ public class TopDownAnalyzer {
resolveSecondaryConstructorBodies();
resolveFunctionBodies();
checkIfPrimaryConstructorIsNecessary();
bindOverrides();
}
private void bindOverrides() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
// JetClass jetClass = entry.getKey();
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
if (overridden != null) {
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
}
}
}
}
}
@Nullable
private FunctionDescriptor findFunctionOverridableBy(@NotNull FunctionDescriptor declaredFunction, @NotNull JetType supertype) {
FunctionGroup functionGroup = supertype.getMemberScope().getFunctionGroup(declaredFunction.getName());
for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) {
if (FunctionDescriptorUtil.isOverridableBy(semanticServices.getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) {
return functionDescriptor;
}
}
return null;
}
private void checkIfPrimaryConstructorIsNecessary() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey();
@@ -1,20 +1,19 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.types.FunctionDescriptorUtil;
import org.jetbrains.jet.lang.types.FunctionGroup;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public class WritableFunctionGroup implements FunctionGroup {
private final String name;
private List<FunctionDescriptor> functionDescriptors;
private Set<FunctionDescriptor> functionDescriptors;
public WritableFunctionGroup(String name) {
this.name = name;
@@ -38,9 +37,9 @@ public class WritableFunctionGroup implements FunctionGroup {
}
@NotNull
private List<FunctionDescriptor> getFunctionDescriptors() {
public Set<FunctionDescriptor> getFunctionDescriptors() {
if (functionDescriptors == null) {
functionDescriptors = new ArrayList<FunctionDescriptor>();
functionDescriptors = Sets.newLinkedHashSet();
}
return functionDescriptors;
}
@@ -48,7 +47,7 @@ public class WritableFunctionGroup implements FunctionGroup {
@NotNull
@Override
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
List<FunctionDescriptor> functionDescriptors = getFunctionDescriptors();
Set<FunctionDescriptor> functionDescriptors = getFunctionDescriptors();
if (functionDescriptors.isEmpty()) return OverloadResolutionResult.nameNotFound();
int typeArgCount = typeArguments.size();
@@ -68,7 +67,7 @@ public class WritableFunctionGroup implements FunctionGroup {
if (result.isEmpty()) {
assert !functionDescriptors.isEmpty();
if (functionDescriptors.size() == 1) {
return OverloadResolutionResult.singleFunctionArgumentMismatch(functionDescriptors.get(0));
return OverloadResolutionResult.singleFunctionArgumentMismatch(functionDescriptors.iterator().next());
}
}
if (result.size() == 1) {
@@ -1,9 +1,11 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -61,6 +63,17 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
return Collections.emptyList();
}
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
return null;
}
@Override
public void addOverriddenFunction(@NotNull FunctionDescriptor overriddenFunction) {
throw new UnsupportedOperationException("Constructors cannot override anything");
}
@Override
protected FunctionDescriptorImpl createSubstitutedCopy() {
return new ConstructorDescriptorImpl(
@@ -78,6 +78,12 @@ public class ErrorUtils {
public boolean isEmpty() {
return false;
}
@NotNull
@Override
public Set<FunctionDescriptor> getFunctionDescriptors() {
return Collections.singleton(createErrorFunction(0, Collections.<JetType>emptyList()));
}
};
private static final ClassDescriptorImpl ERROR_CLASS = new ClassDescriptorImpl(ERROR_MODULE, Collections.<Annotation>emptyList(), "<ERROR CLASS>");
@@ -3,11 +3,16 @@ package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public interface FunctionDescriptor extends DeclarationDescriptor {
@Override
@NotNull
DeclarationDescriptor getContainingDeclaration();
@NotNull
List<TypeParameterDescriptor> getTypeParameters();
@@ -20,10 +25,9 @@ public interface FunctionDescriptor extends DeclarationDescriptor {
@NotNull
FunctionDescriptor getOriginal();
@Override
@NotNull
DeclarationDescriptor getContainingDeclaration();
@Override
FunctionDescriptor substitute(TypeSubstitutor substitutor);
@NotNull
Set<? extends FunctionDescriptor> getOverriddenFunctions();
}
@@ -1,10 +1,12 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -12,10 +14,11 @@ import java.util.List;
public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements MutableFunctionDescriptor {
private List<TypeParameterDescriptor> typeParameters;
private List<ValueParameterDescriptor> unsubstitutedValueParameters;
private JetType unsubstitutedReturnType;
private final Set<FunctionDescriptor> overriddenFunctions = Sets.newHashSet();
private final FunctionDescriptor original;
public FunctionDescriptorImpl(
@@ -44,6 +47,16 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
return this;
}
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
return overriddenFunctions;
}
public void addOverriddenFunction(@NotNull FunctionDescriptor overriddenFunction) {
overriddenFunctions.add(overriddenFunction);
}
@Override
public void setUnsubstitutedReturnType(@NotNull JetType unsubstitutedReturnType) {
this.unsubstitutedReturnType = unsubstitutedReturnType;
@@ -156,8 +156,8 @@ public class FunctionDescriptorUtil {
this.message = message;
}
public boolean isError() {
return isError;
public boolean isSuccess() {
return !isError;
}
public String getMessage() {
@@ -166,7 +166,7 @@ public class FunctionDescriptorUtil {
}
@NotNull
public static OverrideCompatibilityInfo isOverridableWith(@NotNull JetTypeChecker typeChecker, @NotNull FunctionDescriptor superFunction, @NotNull FunctionDescriptor subFunction) {
public static OverrideCompatibilityInfo isOverridableBy(@NotNull JetTypeChecker typeChecker, @NotNull FunctionDescriptor superFunction, @NotNull FunctionDescriptor subFunction) {
if (!superFunction.getName().equals(subFunction.getName())) {
return OverrideCompatibilityInfo.nameMismatch();
}
@@ -3,7 +3,9 @@ package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -26,6 +28,12 @@ public interface FunctionGroup extends Named {
public boolean isEmpty() {
return true;
}
@NotNull
@Override
public Set<FunctionDescriptor> getFunctionDescriptors() {
return Collections.emptySet();
}
};
@@ -37,4 +45,7 @@ public interface FunctionGroup extends Named {
OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
boolean isEmpty();
@NotNull
Set<FunctionDescriptor> getFunctionDescriptors();
}
@@ -10,6 +10,8 @@ import java.util.*;
*/
public class JetTypeChecker {
public static final JetTypeChecker INSTANCE = new JetTypeChecker(null);
private final Map<TypeConstructor, Set<TypeConstructor>> conversionMap = new HashMap<TypeConstructor, Set<TypeConstructor>>();
private final JetStandardLibrary standardLibrary;
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
@@ -7,6 +8,7 @@ import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -14,6 +16,7 @@ import java.util.List;
public class LazySubstitutingFunctionGroup implements FunctionGroup {
private final TypeSubstitutor substitutor;
private final FunctionGroup functionGroup;
private Set<FunctionDescriptor> functionDescriptors;
public LazySubstitutingFunctionGroup(TypeSubstitutor substitutor, FunctionGroup functionGroup) {
this.substitutor = substitutor;
@@ -54,4 +57,16 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
public boolean isEmpty() {
return functionGroup.isEmpty();
}
@NotNull
@Override
public Set<FunctionDescriptor> getFunctionDescriptors() {
if (functionDescriptors == null) {
functionDescriptors = Sets.newHashSet();
for (FunctionDescriptor descriptor : functionGroup.getFunctionDescriptors()) {
functionDescriptors.add(descriptor.substitute(substitutor));
}
}
return functionDescriptors;
}
}
@@ -1,15 +1,18 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
*/
public class PropertyGetterDescriptor extends PropertyAccessorDescriptor implements MutableFunctionDescriptor {
private final Set<PropertyGetterDescriptor> overriddenGetters = Sets.newHashSet();
private JetType returnType;
public PropertyGetterDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List<Annotation> annotations, @Nullable JetType returnType, boolean hasBody) {
@@ -17,6 +20,16 @@ public class PropertyGetterDescriptor extends PropertyAccessorDescriptor impleme
this.returnType = returnType == null ? correspondingProperty.getOutType() : returnType;
}
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
return overriddenGetters;
}
public void addOverriddenFunction(@NotNull PropertyGetterDescriptor overriddenGetter) {
overriddenGetters.add(overriddenGetter);
}
@NotNull
@Override
public List<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
@@ -1,9 +1,11 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author abreslav
@@ -11,6 +13,7 @@ import java.util.List;
public class PropertySetterDescriptor extends PropertyAccessorDescriptor implements MutableFunctionDescriptor {
private MutableValueParameterDescriptor parameter;
private final Set<PropertySetterDescriptor> overriddenSetters = Sets.newHashSet();
public PropertySetterDescriptor(@NotNull PropertyDescriptor correspondingProperty, @NotNull List<Annotation> annotations, boolean hasBody) {
super(correspondingProperty, annotations, "set-" + correspondingProperty.getName(), hasBody);
@@ -25,6 +28,16 @@ public class PropertySetterDescriptor extends PropertyAccessorDescriptor impleme
parameter.setType(type);
}
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
return overriddenSetters;
}
public void setOverriddenFunction(@NotNull PropertySetterDescriptor overriddenSetter) {
overriddenSetters.add(overriddenSetter);
}
@NotNull
@Override
public List<ValueParameterDescriptor> getUnsubstitutedValueParameters() {
@@ -8,10 +8,9 @@ import junit.framework.Test;
import junit.framework.TestSuite;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetTestCaseBase;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.cfg.pseudocode.Instruction;
import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.cfg.pseudocode.JetPseudocodeTrace;
import org.jetbrains.jet.lang.cfg.pseudocode.Pseudocode;
import org.jetbrains.jet.lang.psi.JetElement;
import org.jetbrains.jet.lang.psi.JetFile;
@@ -62,7 +61,7 @@ public class JetControlFlowTest extends JetTestCaseBase {
};
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), ErrorHandler.DO_NOTHING, new JetControlFlowDataTraceFactory() {
AnalyzingUtils.analyzeNamespace(file.getRootNamespace(), new JetControlFlowDataTraceFactory() {
@NotNull
@Override
public JetPseudocodeTrace createTrace(JetElement element) {
@@ -4,6 +4,7 @@ import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.psi.*;
@@ -82,7 +83,7 @@ public class ExpectedResolveData {
final Set<PsiElement> unresolvedReferences = new HashSet<PsiElement>();
JetSemanticServices semanticServices = JetSemanticServices.createSemanticServices(file.getProject(), new ErrorHandler() {
@Override
public void unresolvedReference(JetReferenceExpression referenceExpression) {
public void unresolvedReference(@NotNull JetReferenceExpression referenceExpression) {
unresolvedReferences.add(referenceExpression);
}
});
@@ -136,8 +136,8 @@ public class JetOverridingTest extends LightDaemonAnalyzerTestCase {
private void assertOverridabilityRelation(String superFun, String subFun, boolean expectedIsError) {
FunctionDescriptor a = makeFunction(superFun);
FunctionDescriptor b = makeFunction(subFun);
FunctionDescriptorUtil.OverrideCompatibilityInfo overridableWith = FunctionDescriptorUtil.isOverridableWith(semanticServices.getTypeChecker(), a, b);
assertEquals(overridableWith.getMessage(), expectedIsError, overridableWith.isError());
FunctionDescriptorUtil.OverrideCompatibilityInfo overridableWith = FunctionDescriptorUtil.isOverridableBy(semanticServices.getTypeChecker(), a, b);
assertEquals(overridableWith.getMessage(), expectedIsError, !overridableWith.isSuccess());
}
private FunctionDescriptor makeFunction(String funDecl) {