OverrideResolver factored out. Modality fixed for vals

This commit is contained in:
Andrey Breslav
2011-09-22 17:51:49 +04:00
parent e0548d54db
commit 2b7f892c4a
5 changed files with 239 additions and 168 deletions
@@ -68,7 +68,7 @@ public class BodyResolver {
public void resolveBehaviorDeclarationBodies() {
bindOverrides();
// bindOverrides();
resolveDelegationSpecifierLists();
resolveClassAnnotations();
@@ -81,159 +81,9 @@ public class BodyResolver {
checkIfPrimaryConstructorIsNecessary();
checkOverrides();
// checkOverrides();
}
private void bindOverrides() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
bindOverridesInAClass(entry.getValue());
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
bindOverridesInAClass(entry.getValue());
}
}
private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) {
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
if (overridden != null) {
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
}
}
}
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
PropertyDescriptor overridden = findPropertyOverridableBy(propertyDescriptor, supertype);
if (overridden != null) {
propertyDescriptor.addOverriddenDescriptor(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(context.getSemanticServices().getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) {
return functionDescriptor;
}
}
return null;
}
@Nullable
private PropertyDescriptor findPropertyOverridableBy(@NotNull PropertyDescriptor declaredProperty, @NotNull JetType supertype) {
PropertyDescriptor property = (PropertyDescriptor) supertype.getMemberScope().getVariable(declaredProperty.getName());
if (property == null) {
return null;
}
if (isOverridableBy(property, declaredProperty)) {
return property;
}
return null;
}
private boolean isOverridableBy(@NotNull PropertyDescriptor property, @NotNull PropertyDescriptor overrideCandidate) {
boolean var = property.isVar();
if (var && !overrideCandidate.isVar()) return false;
JetType propertyType = property.getReturnType();
JetType overrideType = overrideCandidate.getReturnType();
JetTypeChecker typeChecker = context.getSemanticServices().getTypeChecker();
if (var) {
return typeChecker.equalTypes(propertyType, overrideType);
}
else {
return typeChecker.isSubtypeOf(overrideType, propertyType);
}
}
private void checkOverrides() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey());
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey());
}
}
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
checkOverrideForFunction(declaredFunction);
}
if (classDescriptor.getModality() == Modality.ABSTRACT) {
return;
}
Set<FunctionDescriptor> allOverriddenFunctions = Sets.newHashSet();
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
for (DeclarationDescriptor descriptor : allDescriptors) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (functionDescriptor.getModality() != Modality.ABSTRACT) {
for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
allOverriddenFunctions.add(overriddenDescriptor.getOriginal());
}
}
}
}
boolean foundError = false;
PsiElement nameIdentifier = null;
if (klass instanceof JetClass) {
nameIdentifier = ((JetClass) klass).getNameIdentifier();
}
else if (klass instanceof JetObjectDeclaration) {
nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier();
}
for (DeclarationDescriptor descriptor : allDescriptors) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) {
DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration();
if (declarationDescriptor != classDescriptor) {
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" +
// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName());
context.getTrace().report(ABSTRACT_METHOD_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor, declarationDescriptor));
foundError = true;
}
}
}
}
}
private void checkOverrideForFunction(FunctionDescriptor declaredFunction) {
JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction);
assert function != null;
JetModifierList modifierList = function.getModifierList();
ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null;
boolean hasOverrideModifier = overrideNode != null;
boolean foundError = false;
for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) {
if (overridden != null) {
if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) {
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden");
context.getTrace().report(OVERRIDING_FINAL_FUNCTION.on(overrideNode, overridden, overridden.getContainingDeclaration()));
foundError = true;
}
}
}
if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) {
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing");
context.getTrace().report(NOTHING_TO_OVERRIDE.on(function, overrideNode, declaredFunction));
}
PsiElement nameIdentifier = function.getNameIdentifier();
if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) {
FunctionDescriptor overriddenFunction = declaredFunction.getOverriddenDescriptors().iterator().next();
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(),
// "Method '" + declaredFunction.getName() + "' overrides method '" + overriddenFunction.getName() + "' in class " +
// overriddenFunction.getContainingDeclaration().getName() + " and needs 'override' modifier");
context.getTrace().report(VIRTUAL_METHOD_HIDDEN.on(function, nameIdentifier, declaredFunction, overriddenFunction, overriddenFunction.getContainingDeclaration()));
}
}
private void checkIfPrimaryConstructorIsNecessary() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
@@ -188,16 +188,8 @@ public class ClassDescriptorResolver {
returnType = ErrorUtils.createErrorType("No type, no body");
}
}
Modality defaultModality;
if (containingDescriptor instanceof ClassDescriptor) {
boolean isTrait = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT;
boolean isDefinitelyAbstract = isTrait && function.getBodyExpression() == null;
Modality basicModality = isTrait ? Modality.OPEN : Modality.FINAL;
defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : basicModality;
}
else {
defaultModality = Modality.FINAL;
}
boolean hasBody = function.getBodyExpression() != null;
Modality defaultModality = getDefaultModality(containingDescriptor, hasBody);
Modality modality = resolveModalityFromModifiers(function.getModifierList(), defaultModality);
functionDescriptor.initialize(
@@ -211,6 +203,20 @@ public class ClassDescriptorResolver {
return functionDescriptor;
}
private Modality getDefaultModality(DeclarationDescriptor containingDescriptor, boolean isBodyPresent) {
Modality defaultModality;
if (containingDescriptor instanceof ClassDescriptor) {
boolean isTrait = ((ClassDescriptor) containingDescriptor).getKind() == ClassKind.TRAIT;
boolean isDefinitelyAbstract = isTrait && !isBodyPresent;
Modality basicModality = isTrait ? Modality.OPEN : Modality.FINAL;
defaultModality = isDefinitelyAbstract ? Modality.ABSTRACT : basicModality;
}
else {
defaultModality = Modality.FINAL;
}
return defaultModality;
}
@NotNull
private List<ValueParameterDescriptor> resolveValueParameters(FunctionDescriptor functionDescriptor, WritableScope parameterScope, List<JetParameter> valueParameters) {
List<ValueParameterDescriptor> result = new ArrayList<ValueParameterDescriptor>();
@@ -448,7 +454,6 @@ public class ClassDescriptorResolver {
@NotNull
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
JetScope scopeWithTypeParameters;
List<TypeParameterDescriptor> typeParameterDescriptors;
List<JetTypeParameter> typeParameters = property.getTypeParameters();
@@ -474,10 +479,22 @@ public class ClassDescriptorResolver {
JetType type = getVariableType(scopeWithTypeParameters, property, true);
boolean hasBody = property.getInitializer() != null;
if (!hasBody) {
JetPropertyAccessor getter = property.getGetter();
if (getter != null && getter.getBodyExpression() != null) {
hasBody = true;
}
JetPropertyAccessor setter = property.getSetter();
if (!hasBody && setter != null && setter.getBodyExpression() != null) {
hasBody = true;
}
}
Modality defaultModality = getDefaultModality(containingDeclaration, hasBody);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
containingDeclaration,
annotationResolver.resolveAnnotations(scope, modifierList),
resolveModalityFromModifiers(modifierList), // TODO : default modifiers differ in different contexts
resolveModalityFromModifiers(modifierList, defaultModality),
isVar,
receiverType,
JetPsiUtil.safeName(property.getName()),
@@ -0,0 +1,185 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
/**
* @author abreslav
*/
public class OverrideResolver {
private final TopDownAnalysisContext context;
public OverrideResolver(@NotNull TopDownAnalysisContext context) {
this.context = context;
}
public void process() {
bindOverrides();
checkOverrides();
}
private void bindOverrides() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
bindOverridesInAClass(entry.getValue());
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
bindOverridesInAClass(entry.getValue());
}
}
private void bindOverridesInAClass(MutableClassDescriptor classDescriptor) {
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
FunctionDescriptor overridden = findFunctionOverridableBy(declaredFunction, supertype);
if (overridden != null) {
((FunctionDescriptorImpl) declaredFunction).addOverriddenFunction(overridden);
}
}
}
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
PropertyDescriptor overridden = findPropertyOverridableBy(propertyDescriptor, supertype);
if (overridden != null) {
propertyDescriptor.addOverriddenDescriptor(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(context.getSemanticServices().getTypeChecker(), functionDescriptor, declaredFunction).isSuccess()) {
return functionDescriptor;
}
}
return null;
}
@Nullable
private PropertyDescriptor findPropertyOverridableBy(@NotNull PropertyDescriptor declaredProperty, @NotNull JetType supertype) {
PropertyDescriptor property = (PropertyDescriptor) supertype.getMemberScope().getVariable(declaredProperty.getName());
if (property == null) {
return null;
}
if (isOverridableBy(property, declaredProperty)) {
return property;
}
return null;
}
private boolean isOverridableBy(@NotNull PropertyDescriptor property, @NotNull PropertyDescriptor overrideCandidate) {
boolean var = property.isVar();
if (var && !overrideCandidate.isVar()) return false;
JetType propertyType = property.getReturnType();
JetType overrideType = overrideCandidate.getReturnType();
JetTypeChecker typeChecker = context.getSemanticServices().getTypeChecker();
if (var) {
return typeChecker.equalTypes(propertyType, overrideType);
}
else {
return typeChecker.isSubtypeOf(overrideType, propertyType);
}
}
private void checkOverrides() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey());
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
checkOverridesInAClass(entry.getValue(), entry.getKey());
}
}
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
for (FunctionDescriptor declaredFunction : classDescriptor.getFunctions()) {
checkOverrideForFunction(declaredFunction);
}
if (classDescriptor.getModality() == Modality.ABSTRACT) {
return;
}
Set<FunctionDescriptor> allOverriddenFunctions = Sets.newHashSet();
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
for (DeclarationDescriptor descriptor : allDescriptors) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (functionDescriptor.getModality() != Modality.ABSTRACT) {
for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
allOverriddenFunctions.add(overriddenDescriptor.getOriginal());
}
}
}
}
boolean foundError = false;
PsiElement nameIdentifier = null;
if (klass instanceof JetClass) {
nameIdentifier = ((JetClass) klass).getNameIdentifier();
}
else if (klass instanceof JetObjectDeclaration) {
nameIdentifier = ((JetObjectDeclaration) klass).getNameIdentifier();
}
for (DeclarationDescriptor descriptor : allDescriptors) {
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (functionDescriptor.getModality() == Modality.ABSTRACT && !allOverriddenFunctions.contains(functionDescriptor.getOriginal()) && !foundError && nameIdentifier != null) {
DeclarationDescriptor declarationDescriptor = functionDescriptor.getContainingDeclaration();
if (declarationDescriptor != classDescriptor) {
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(), "Class '" + klass.getName() + "' must be declared abstract or implement abstract method '" +
// functionDescriptor.getName() + "' declared in " + declarationDescriptor.getName());
context.getTrace().report(ABSTRACT_METHOD_NOT_IMPLEMENTED.on(nameIdentifier, klass, functionDescriptor, declarationDescriptor));
foundError = true;
}
}
}
}
}
private void checkOverrideForFunction(FunctionDescriptor declaredFunction) {
JetFunction function = (JetFunction) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredFunction);
assert function != null;
JetModifierList modifierList = function.getModifierList();
ASTNode overrideNode = modifierList != null ? modifierList.getModifierNode(JetTokens.OVERRIDE_KEYWORD) : null;
boolean hasOverrideModifier = overrideNode != null;
boolean foundError = false;
for (FunctionDescriptor overridden : declaredFunction.getOverriddenDescriptors()) {
if (overridden != null) {
if (hasOverrideModifier && !overridden.getModality().isOpen() && !foundError) {
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + overridden.getName() + " in " + overridden.getContainingDeclaration().getName() + " is final and cannot be overridden");
context.getTrace().report(OVERRIDING_FINAL_FUNCTION.on(overrideNode, overridden, overridden.getContainingDeclaration()));
foundError = true;
}
}
}
if (hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() == 0) {
// context.getTrace().getErrorHandler().genericError(overrideNode, "Method " + declaredFunction.getName() + " overrides nothing");
context.getTrace().report(NOTHING_TO_OVERRIDE.on(function, overrideNode, declaredFunction));
}
PsiElement nameIdentifier = function.getNameIdentifier();
if (!hasOverrideModifier && declaredFunction.getOverriddenDescriptors().size() > 0 && nameIdentifier != null) {
FunctionDescriptor overriddenFunction = declaredFunction.getOverriddenDescriptors().iterator().next();
// context.getTrace().getErrorHandler().genericError(nameIdentifier.getNode(),
// "Method '" + declaredFunction.getName() + "' overrides method '" + overriddenFunction.getName() + "' in class " +
// overriddenFunction.getContainingDeclaration().getName() + " and needs 'override' modifier");
context.getTrace().report(VIRTUAL_METHOD_HIDDEN.on(function, nameIdentifier, declaredFunction, overriddenFunction, overriddenFunction.getContainingDeclaration()));
}
}
}
@@ -65,6 +65,7 @@ public class TopDownAnalyzer {
TopDownAnalysisContext context = new TopDownAnalysisContext(semanticServices, trace);
new TypeHierarchyResolver(context).process(outerScope, owner, declarations);
new DeclarationResolver(context).process();
new OverrideResolver(context).process();
new BodyResolver(context).resolveBehaviorDeclarationBodies();
}
@@ -77,6 +78,12 @@ public class TopDownAnalyzer {
context.getNamespaceDescriptors().put(namespace, standardLibraryNamespace);
new TypeHierarchyResolver(context).process(outerScope, standardLibraryNamespace, namespace.getDeclarations());
new DeclarationResolver(context).process();
OverrideResolver overrideResolver = new OverrideResolver(context) {
@Override
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
}
};
overrideResolver.process();
BodyResolver bodyResolver = new BodyResolver(context) {
@Override
protected void checkProperty(JetProperty property, PropertyDescriptor propertyDescriptor, @Nullable ClassDescriptor classDescriptor) {
@@ -85,10 +92,6 @@ public class TopDownAnalyzer {
@Override
protected void checkFunction(JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
}
@Override
protected void checkOverridesInAClass(MutableClassDescriptor classDescriptor, JetClassOrObject klass) {
}
};
bodyResolver.resolveBehaviorDeclarationBodies();
}
@@ -172,6 +172,7 @@ public class DescriptorRenderer {
@Override
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
renderModality(descriptor.getModality(), builder);
String typeString = renderPropertyPrefixAndComputeTypeString(
builder, descriptor.getTypeParameters(),
descriptor.getReceiver(),
@@ -182,6 +183,21 @@ public class DescriptorRenderer {
return null;
}
private void renderModality(Modality modality, StringBuilder builder) {
switch (modality) {
case FINAL:
builder.append("final");
break;
case OPEN:
builder.append("open");
break;
case ABSTRACT:
builder.append("abstract");
break;
}
builder.append(" ");
}
@Override
public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) {
builder.append(renderKeyword("fun")).append(" ");