JET-94 Support enum classes

This commit is contained in:
Andrey Breslav
2011-06-14 22:06:56 +04:00
parent 400e939c21
commit e4e5c7b0dc
17 changed files with 157 additions and 43 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.AnalyzingUtils;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import javax.swing.*;
@@ -37,6 +38,7 @@ import java.util.Set;
public class JetLineMarkerProvider implements LineMarkerProvider {
public static final Icon OVERRIDING_FUNCTION = IconLoader.getIcon("/general/overridingMethod.png");
public static final Icon ICON_FOR_OBJECT = Icons.ANONYMOUS_CLASS_ICON;
@Override
public LineMarkerInfo getLineMarkerInfo(PsiElement element) {
@@ -47,7 +49,14 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
if (element instanceof JetClass) {
JetClass jetClass = (JetClass) element;
return new LineMarkerInfo<JetClass>(jetClass, jetClass.getTextOffset(), Icons.CLASS_ICON, Pass.UPDATE_ALL,
Icon icon = jetClass.hasModifier(JetTokens.ENUM_KEYWORD) ? Icons.ENUM_ICON : Icons.CLASS_ICON;
if (jetClass instanceof JetEnumEntry) {
JetEnumEntry enumEntry = (JetEnumEntry) jetClass;
if (enumEntry.getPrimaryConstructorParameterList() == null) {
icon = ICON_FOR_OBJECT;
}
}
return new LineMarkerInfo<JetClass>(jetClass, jetClass.getTextOffset(), icon, Pass.UPDATE_ALL,
new Function<JetClass, String>() {
@Override
public String fun(JetClass jetClass) {
@@ -44,6 +44,6 @@ public abstract class DeclarationDescriptorImpl extends AnnotatedImpl implements
@Override
public String toString() {
return DescriptorRenderer.TEXT_FOR_DEBUG.render(this) + "[" + getClass().getCanonicalName() + "@" + System.identityHashCode(this) + "]";
return DescriptorRenderer.TEXT_FOR_DEBUG.render(this) + "[" + getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + "]";
}
}
@@ -482,7 +482,9 @@ public class JetParsing extends AbstractJetParsing {
private void parseEnumEntry() {
assert _at(IDENTIFIER);
PsiBuilder.Marker nameAsDeclaration = mark();
advance(); // IDENTIFIER
nameAsDeclaration.done(OBJECT_DECLARATION_NAME);
parseTypeParameterList(TokenSet.create(COLON, LPAR, SEMICOLON, LBRACE));
@@ -79,6 +79,11 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj
return getPrimaryConstructorParameterList() != null;
}
@Override
public JetObjectDeclarationName getNameAsDeclaration() {
return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME);
}
public List<JetProperty> getProperties() {
JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY);
if (body == null) return Collections.emptyList();
@@ -25,4 +25,10 @@ public interface JetClassOrObject {
@Nullable
String getName();
@Nullable
JetModifierList getModifierList();
@Nullable
JetObjectDeclarationName getNameAsDeclaration();
}
@@ -1,7 +1,14 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
import java.util.Collections;
import java.util.List;
/**
* @author max
@@ -11,6 +18,34 @@ public class JetEnumEntry extends JetClass {
super(node);
}
@Override
public String getName() {
JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
return nameAsDeclaration == null ? "<Anonymous>" : nameAsDeclaration.getName();
}
@Override
public PsiElement getNameIdentifier() {
JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
return nameAsDeclaration == null ? null : nameAsDeclaration.getNameIdentifier();
}
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
JetObjectDeclarationName nameAsDeclaration = getNameAsDeclaration();
return nameAsDeclaration == null ? null : nameAsDeclaration.setName(name);
}
@NotNull
@Override
public List<JetDelegationSpecifier> getDelegationSpecifiers() {
JetInitializerList initializerList = (JetInitializerList) findChildByType(JetNodeTypes.INITIALIZER_LIST);
if (initializerList == null) {
return Collections.emptyList();
}
return initializerList.getInitializers();
}
@Override
public void accept(@NotNull JetVisitor visitor) {
visitor.visitEnumEntry(this);
@@ -94,7 +94,7 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
@Override
public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) {
safePut(primaryConstructorParameterDeclarationsToPropertyDescriptors, declaration, descriptor);
safePut(primaryConstructorParameterDeclarationsToPropertyDescriptors, declaration, (PropertyDescriptor) descriptor.getOriginal());
safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration);
}
@@ -431,7 +431,7 @@ public class ClassDescriptorResolver {
return variableDescriptor;
}
public PropertyDescriptor resolveObjectDeclarationAsPropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, JetObjectDeclaration objectDeclaration, @NotNull ClassDescriptor classDescriptor) {
public PropertyDescriptor resolveObjectDeclarationAsPropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, JetClassOrObject objectDeclaration, @NotNull ClassDescriptor classDescriptor) {
JetModifierList modifierList = objectDeclaration.getModifierList();
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
containingDeclaration,
@@ -168,20 +168,51 @@ public class TopDownAnalyzer {
@Override
public void visitClass(JetClass klass) {
MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope);
if (klass.hasModifier(JetTokens.ENUM_KEYWORD)) {
MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(trace, mutableClassDescriptor, outerScope);
classObjectDescriptor.setName("class-object-for-" + klass.getName());
classObjectDescriptor.createTypeConstructor();
createPrimaryConstructor(classObjectDescriptor);
mutableClassDescriptor.setClassObjectDescriptor(classObjectDescriptor);
}
visitClassOrObject(
klass,
(Map) classes,
owner,
outerScope,
new MutableClassDescriptor(trace, owner, outerScope));
mutableClassDescriptor);
owner.addClassifierDescriptor(mutableClassDescriptor);
}
@Override
public void visitObjectDeclaration(JetObjectDeclaration declaration) {
createClassDescriptorForObject(declaration);
createClassDescriptorForObject(declaration, owner);
}
private MutableClassDescriptor createClassDescriptorForObject(@NotNull JetObjectDeclaration declaration) {
@Override
public void visitEnumEntry(JetEnumEntry enumEntry) {
MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) owner).getClassObjectDescriptor();
assert classObjectDescriptor != null : enumEntry.getParent().getText();
if (enumEntry.getPrimaryConstructorParameterList() == null) {
MutableClassDescriptor classDescriptor = createClassDescriptorForObject(enumEntry, classObjectDescriptor);
objects.remove(enumEntry);
classes.put(enumEntry, classDescriptor);
}
else {
MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, classObjectDescriptor, outerScope);
visitClassOrObject(
enumEntry,
(Map) classes,
classObjectDescriptor,
outerScope,
mutableClassDescriptor);
classObjectDescriptor.addClassifierDescriptor(mutableClassDescriptor);
}
}
private MutableClassDescriptor createClassDescriptorForObject(@NotNull JetClassOrObject declaration, @NotNull NamespaceLike owner) {
MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(trace, owner, outerScope) {
@Override
public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
@@ -189,21 +220,21 @@ public class TopDownAnalyzer {
}
};
visitClassOrObject(declaration, (Map) objects, owner, outerScope, mutableClassDescriptor);
createPrimaryConstructor(mutableClassDescriptor);
trace.recordDeclarationResolution((PsiElement) declaration, mutableClassDescriptor);
return mutableClassDescriptor;
}
private void createPrimaryConstructor(MutableClassDescriptor mutableClassDescriptor) {
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(mutableClassDescriptor, Collections.<Annotation>emptyList(), true);
constructorDescriptor.initialize(Collections.<ValueParameterDescriptor>emptyList());
// TODO : make the constructor private?
mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
trace.recordDeclarationResolution(declaration, mutableClassDescriptor);
return mutableClassDescriptor;
}
private void visitClassOrObject(@NotNull JetClassOrObject declaration, Map<JetClassOrObject, MutableClassDescriptor> map, NamespaceLike owner, JetScope outerScope, MutableClassDescriptor mutableClassDescriptor) {
mutableClassDescriptor.setName(JetPsiUtil.safeName(declaration.getName()));
if (declaration instanceof JetClass) {
owner.addClassifierDescriptor(mutableClassDescriptor);
}
map.put(declaration, mutableClassDescriptor);
declaringScopes.put((JetDeclaration) declaration, outerScope);
@@ -225,7 +256,7 @@ public class TopDownAnalyzer {
public void visitClassObject(JetClassObject classObject) {
JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
if (objectDeclaration != null) {
NamespaceLike.ClassObjectStatus status = owner.setClassObjectDescriptor(createClassDescriptorForObject(objectDeclaration));
NamespaceLike.ClassObjectStatus status = owner.setClassObjectDescriptor(createClassDescriptorForObject(objectDeclaration, owner));
switch (status) {
case DUPLICATE:
trace.getErrorHandler().genericError(classObject.getNode(), "Only one class object is allowed per class");
@@ -240,7 +271,6 @@ public class TopDownAnalyzer {
}
}
private void processImports(@NotNull JetNamespace namespace, @NotNull WriteThroughScope namespaceScope, @NotNull JetScope outerScope) {
List<JetImportDirective> importDirectives = namespace.getImportDirectives();
for (JetImportDirective importDirective : importDirectives) {
@@ -372,8 +402,6 @@ public class TopDownAnalyzer {
for (JetConstructor jetConstructor : jetClass.getSecondaryConstructors()) {
processSecondaryConstructor(classDescriptor, jetConstructor);
}
// TODO : Constructors
}
for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : objects.entrySet()) {
JetObjectDeclaration object = entry.getKey();
@@ -409,6 +437,16 @@ public class TopDownAnalyzer {
PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, declaration, objects.get(declaration));
namespaceLike.addPropertyDescriptor(propertyDescriptor);
}
@Override
public void visitEnumEntry(JetEnumEntry enumEntry) {
if (enumEntry.getPrimaryConstructorParameterList() == null) {
PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolveObjectDeclarationAsPropertyDescriptor(namespaceLike, enumEntry, classes.get(enumEntry));
MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) namespaceLike).getClassObjectDescriptor();
assert classObjectDescriptor != null;
classObjectDescriptor.addPropertyDescriptor(propertyDescriptor);
}
}
});
}
}
@@ -495,7 +533,7 @@ public class TopDownAnalyzer {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : classes.entrySet()) {
MutableClassDescriptor classDescriptor = entry.getValue();
JetClass jetClass = entry.getKey();
if (!jetClass.hasPrimaryConstructor()) {
if (classDescriptor.getUnsubstitutedPrimaryConstructor() == null) {
for (PropertyDescriptor propertyDescriptor : classDescriptor.getProperties()) {
if (trace.getBindingContext().hasBackingField(propertyDescriptor)) {
PsiElement nameIdentifier = jetClass.getNameIdentifier();
@@ -546,7 +584,7 @@ public class TopDownAnalyzer {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
if (jetClass.hasPrimaryConstructor()) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
typeInferrer.checkConstructorCall(scopeForConstructor, typeReference, call);
}
else {
@@ -253,14 +253,16 @@ public class DescriptorRenderer {
builder.append(renderKeyword(keyword)).append(" ");
renderName(descriptor, builder);
renderTypeParameters(descriptor.getTypeConstructor().getParameters(), builder);
Collection<? extends JetType> supertypes = descriptor.getTypeConstructor().getSupertypes();
if (!supertypes.isEmpty()) {
builder.append(" : ");
for (Iterator<? extends JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
JetType supertype = iterator.next();
builder.append(renderType(supertype));
if (iterator.hasNext()) {
builder.append(", ");
if (!descriptor.equals(JetStandardClasses.getNothing())) {
Collection<? extends JetType> supertypes = descriptor.getTypeConstructor().getSupertypes();
if (!supertypes.isEmpty()) {
builder.append(" : ");
for (Iterator<? extends JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
JetType supertype = iterator.next();
builder.append(renderType(supertype));
if (iterator.hasNext()) {
builder.append(", ");
}
}
}
}
@@ -11,4 +11,4 @@ class Y1 {
}
class Z : Y<error>()</error> {
}
}
+10 -5
View File
@@ -28,7 +28,8 @@ JetFile: Enums.jet
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('RED')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('RED')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -48,7 +49,8 @@ JetFile: Enums.jet
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('GREEN')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('GREEN')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -68,7 +70,8 @@ JetFile: Enums.jet
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('BLUE')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('BLUE')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -123,7 +126,8 @@ JetFile: Enums.jet
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('Nil')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('Nil')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -151,7 +155,8 @@ JetFile: Enums.jet
PsiElement(RPAR)(')')
PsiWhiteSpace('\n\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('Cons')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('Cons')
TYPE_PARAMETER_LIST
PsiElement(LT)('<')
TYPE_PARAMETER
@@ -135,12 +135,14 @@ JetFile: AnonymousObjects.jet
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('TOO_MANY_CLICKS')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('TOO_MANY_CLICKS')
PsiWhiteSpace('\n ')
TYPE_PARAMETER_LIST
<empty list>
ENUM_ENTRY
PsiElement(IDENTIFIER)('ONE_MORE_MESSAGE')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('ONE_MORE_MESSAGE')
PsiWhiteSpace('\n')
TYPE_PARAMETER_LIST
<empty list>
+6 -3
View File
@@ -54,7 +54,8 @@ JetFile: Color.jet
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('RED')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('RED')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -84,7 +85,8 @@ JetFile: Color.jet
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('GREEN')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('GREEN')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -114,7 +116,8 @@ JetFile: Color.jet
PsiElement(RPAR)(')')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('BLUE')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('BLUE')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -49,7 +49,8 @@ JetFile: List.jet
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('Nil')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('Nil')
PsiWhiteSpace(' ')
TYPE_PARAMETER_LIST
<empty list>
@@ -77,7 +78,8 @@ JetFile: List.jet
PsiElement(RPAR)(')')
PsiWhiteSpace('\n\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('Cons')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('Cons')
TYPE_PARAMETER_LIST
PsiElement(LT)('<')
TYPE_PARAMETER
@@ -218,19 +218,22 @@ JetFile: Comparison.jet
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('LS')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('LS')
TYPE_PARAMETER_LIST
<empty list>
PsiElement(SEMICOLON)(';')
PsiWhiteSpace(' ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('EQ')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('EQ')
TYPE_PARAMETER_LIST
<empty list>
PsiElement(SEMICOLON)(';')
PsiWhiteSpace(' ')
ENUM_ENTRY
PsiElement(IDENTIFIER)('GR')
OBJECT_DECLARATION_NAME
PsiElement(IDENTIFIER)('GR')
PsiWhiteSpace('\n')
TYPE_PARAMETER_LIST
<empty list>
@@ -7,6 +7,8 @@ class C(~x~x : Int, ~y~val y : Int) : Base(`x`x /*parameter*/), Base1 by new Bas
val z = `x`x // parameter
}
val foo = `$y`y
this() : this(1, 2) {
val z = x // inaccessible
val zz = `$y`y // property