From 0e4a7ebe90a1d9f4c0d5253fe7ca5cd169b6cc75 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Fri, 4 Nov 2011 20:58:31 +0300 Subject: [PATCH 1/8] isReified() for type parameters --- .../resolve/java/JavaDescriptorResolver.java | 1 + .../descriptors/TypeParameterDescriptor.java | 16 +++++++++++++--- .../lang/resolve/ClassDescriptorResolver.java | 2 ++ .../jet/lang/types/DescriptorSubstitutor.java | 1 + .../jet/lang/types/JetStandardClasses.java | 8 ++++---- .../jet/resolve/DescriptorRenderer.java | 3 +++ 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java index a66b089f62c..054734e2c5b 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/JavaDescriptorResolver.java @@ -189,6 +189,7 @@ public class JavaDescriptorResolver { TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification( owner, Collections.emptyList(), // TODO + false, Variance.INVARIANT, typeParameter.getName(), typeParameter.getIndex() diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java index b3c49e458c4..695686b10b0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/TypeParameterDescriptor.java @@ -21,10 +21,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement public static TypeParameterDescriptor createWithDefaultBound( @NotNull DeclarationDescriptor containingDeclaration, @NotNull List annotations, + boolean reified, @NotNull Variance variance, @NotNull String name, int index) { - TypeParameterDescriptor typeParameterDescriptor = createForFurtherModification(containingDeclaration, annotations, variance, name, index); + TypeParameterDescriptor typeParameterDescriptor = createForFurtherModification(containingDeclaration, annotations, reified, variance, name, index); typeParameterDescriptor.addUpperBound(JetStandardClasses.getDefaultBound()); return typeParameterDescriptor; } @@ -32,10 +33,11 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement public static TypeParameterDescriptor createForFurtherModification( @NotNull DeclarationDescriptor containingDeclaration, @NotNull List annotations, + boolean reified, @NotNull Variance variance, @NotNull String name, int index) { - return new TypeParameterDescriptor(containingDeclaration, annotations, variance, name, index); + return new TypeParameterDescriptor(containingDeclaration, annotations, reified, variance, name, index); } private final int index; @@ -47,9 +49,12 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement private final Set classObjectUpperBounds = Sets.newLinkedHashSet(); private JetType classObjectBoundsAsType; + private final boolean reified; + private TypeParameterDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @NotNull List annotations, + boolean reified, @NotNull Variance variance, @NotNull String name, int index) { @@ -57,6 +62,7 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement this.index = index; this.variance = variance; this.upperBounds = Sets.newLinkedHashSet(); + this.reified = reified; // TODO: Should we actually pass the annotations on to the type constructor? this.typeConstructor = new TypeConstructorImpl( this, @@ -67,6 +73,10 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement upperBounds); } + public boolean isReified() { + return reified; + } + public Variance getVariance() { return variance; } @@ -162,6 +172,6 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement @NotNull public TypeParameterDescriptor copy(@NotNull DeclarationDescriptor newOwner) { - return new TypeParameterDescriptor(newOwner, Lists.newArrayList(getAnnotations()), variance, getName(), index); + return new TypeParameterDescriptor(newOwner, Lists.newArrayList(getAnnotations()), reified, variance, getName(), index); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 112c798ab46..c5ded6ed64e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -50,6 +50,7 @@ public class ClassDescriptorResolver { TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification( descriptor, annotationResolver.createAnnotationStubs(typeParameter.getModifierList()), + true, typeParameter.getVariance(), JetPsiUtil.safeName(typeParameter.getName()), index @@ -313,6 +314,7 @@ public class ClassDescriptorResolver { TypeParameterDescriptor typeParameterDescriptor = TypeParameterDescriptor.createForFurtherModification( containingDescriptor, annotationResolver.createAnnotationStubs(typeParameter.getModifierList()), + true, typeParameter.getVariance(), JetPsiUtil.safeName(typeParameter.getName()), index diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java index 3d29ab80a1d..b31f101c402 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/DescriptorSubstitutor.java @@ -40,6 +40,7 @@ public class DescriptorSubstitutor { TypeParameterDescriptor substituted = TypeParameterDescriptor.createForFurtherModification( newContainingDeclaration, descriptor.getAnnotations(), + descriptor.isReified(), descriptor.getVariance(), descriptor.getName(), descriptor.getIndex()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index e637d05de72..c76c5c797ca 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -116,7 +116,7 @@ public class JetStandardClasses { parameters.add(TypeParameterDescriptor.createWithDefaultBound( classDescriptor, Collections.emptyList(), - Variance.OUT_VARIANCE, "T" + j, j)); + true, Variance.OUT_VARIANCE, "T" + j, j)); } TUPLE[i] = classDescriptor.initialize( true, @@ -159,7 +159,7 @@ public class JetStandardClasses { parameters.add(0, TypeParameterDescriptor.createWithDefaultBound( receiverFunction, Collections.emptyList(), - Variance.IN_VARIANCE, "T", 0)); + true, Variance.IN_VARIANCE, "T", 0)); RECEIVER_FUNCTION[i] = receiverFunction.initialize( false, parameters, @@ -174,12 +174,12 @@ public class JetStandardClasses { parameters.add(TypeParameterDescriptor.createWithDefaultBound( function, Collections.emptyList(), - Variance.IN_VARIANCE, "P" + j, j + 1)); + true, Variance.IN_VARIANCE, "P" + j, j + 1)); } parameters.add(TypeParameterDescriptor.createWithDefaultBound( function, Collections.emptyList(), - Variance.OUT_VARIANCE, "R", parameterCount + 1)); + true, Variance.OUT_VARIANCE, "R", parameterCount + 1)); return parameters; } diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index a9bddbb2c7a..b744988a594 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -311,6 +311,9 @@ public class DescriptorRenderer implements Renderer { } protected void renderTypeParameter(TypeParameterDescriptor descriptor, StringBuilder builder) { + if (!descriptor.isReified()) { + builder.append(renderKeyword("erased")).append(" "); + } renderName(descriptor, builder); if (!descriptor.getUpperBounds().isEmpty()) { JetType bound = descriptor.getUpperBounds().iterator().next(); From 8f15eea9c52fd1b20630ed09b5455effe9b55ad9 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 17:59:59 +0100 Subject: [PATCH 2/8] Kotlin implement members initial (not much works) --- .../org/jetbrains/jet/lang/psi/JetClass.java | 11 +- .../jetbrains/jet/lang/psi/JetClassBody.java | 8 ++ .../jet/lang/psi/JetClassOrObject.java | 3 + .../jet/lang/psi/JetObjectDeclaration.java | 7 +- .../jet/lang/resolve/OverrideResolver.java | 117 ++++++++-------- idea/src/META-INF/plugin.xml | 1 + .../codeInsight/DescriptorClassMember.java | 40 ++++++ .../codeInsight/ImplementMethodsHandler.java | 132 ++++++++++++++++++ .../jet/plugin/formatter/JetBlock.java | 11 +- .../formatter/JetFormattingModelBuilder.java | 21 ++- .../javaInterfaceMethod/foo/Impl.kt | 5 + .../javaInterfaceMethod/foo/Impl.kt.after | 8 ++ .../javaInterfaceMethod/foo/Intf.java | 5 + .../jet/checkers/JetPsiCheckerTest.java | 2 +- .../jet/plugin/JetLightProjectDescriptor.java | 33 +++++ .../{quickfix => }/PluginTestCaseBase.java | 5 +- .../codeInsight/OverrideImplementTest.java | 50 +++++++ .../jet/plugin/quickfix/JetQuickFixTest.java | 1 + stdlib/ktSrc/ModuleBuilder.kt | 3 +- 19 files changed, 390 insertions(+), 73 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java create mode 100644 idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java create mode 100644 idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt create mode 100644 idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt.after create mode 100644 idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Intf.java create mode 100644 idea/tests/org/jetbrains/jet/plugin/JetLightProjectDescriptor.java rename idea/tests/org/jetbrains/jet/plugin/{quickfix => }/PluginTestCaseBase.java (86%) create mode 100644 idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java index dc232e66306..c03bf3a471e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClass.java @@ -75,7 +75,7 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj @NotNull public List getAnonymousInitializers() { - JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); + JetClassBody body = getBody(); if (body == null) return Collections.emptyList(); return body.getAnonymousInitializers(); @@ -90,15 +90,20 @@ public class JetClass extends JetTypeParameterListOwner implements JetClassOrObj return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME); } + @Override + public JetClassBody getBody() { + return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); + } + @Nullable public JetClassObject getClassObject() { - JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); + JetClassBody body = getBody(); if (body == null) return null; return body.getClassObject(); } public List getProperties() { - JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); + JetClassBody body = getBody(); if (body == null) return Collections.emptyList(); return body.getProperties(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java index 5b4e67347f7..ea4768639d1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassBody.java @@ -1,10 +1,13 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; import java.util.List; @@ -48,4 +51,9 @@ public class JetClassBody extends JetElement { public JetClassObject getClassObject() { return (JetClassObject) findChildByType(JetNodeTypes.CLASS_OBJECT); } + + public PsiElement getRBrace() { + final ASTNode[] children = getNode().getChildren(TokenSet.create(JetTokens.RBRACE)); + return children.length == 1 ? children[0].getPsi() : null; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java index 07f0160cff6..efa701ec1ee 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java @@ -32,4 +32,7 @@ public interface JetClassOrObject extends PsiElement { @Nullable JetObjectDeclarationName getNameAsDeclaration(); + + @Nullable + JetClassBody getBody(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java index 27bea8777bd..7c3d58de4c8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetObjectDeclaration.java @@ -69,10 +69,15 @@ public class JetObjectDeclaration extends JetNamedDeclaration implements JetClas return true; } + @Override + public JetClassBody getBody() { + return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); + } + @Override @NotNull public List getDeclarations() { - JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); + JetClassBody body = getBody(); if (body == null) return Collections.emptyList(); return body.getDeclarations(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index 6f52c4737ce..ca2742311b7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -103,66 +103,10 @@ public class OverrideResolver { } // Check if everything that must be overridden, actually is - - // Everything from supertypes - Map implementedWithDelegationBy = Maps.newHashMap(); - Set inheritedFunctions = Sets.newLinkedHashSet(); - for (JetType supertype : classDescriptor.getSupertypes()) { - for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) { - if (descriptor instanceof CallableMemberDescriptor) { - CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor; - inheritedFunctions.add(memberDescriptor); - } - } - } - - // Only those actually inherited - Set filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions); - - // Group members with "the same" signature - Multimap factoredMembers = CommonSuppliers.newLinkedHashSetHashSetMultimap(); - for (CallableMemberDescriptor one : filteredMembers) { - if (factoredMembers.values().contains(one)) continue; - for (CallableMemberDescriptor another : filteredMembers) { -// if (one == another) continue; - factoredMembers.put(one, one); - if (OverridingUtil.isOverridableBy(one, another).isSuccess() - || OverridingUtil.isOverridableBy(another, one).isSuccess()) { - factoredMembers.put(one, another); - } - } - } - // More than one implementation or no implementations at all Set abstractNoImpl = Sets.newLinkedHashSet(); Set manyImpl = Sets.newLinkedHashSet(); - for (CallableMemberDescriptor key : factoredMembers.keySet()) { - Collection mutuallyOverridable = factoredMembers.get(key); - - int implementationCount = 0; - for (CallableMemberDescriptor member : mutuallyOverridable) { - if (member.getModality() != Modality.ABSTRACT) { - implementationCount++; - } - } - - if (implementationCount == 0) { - abstractNoImpl.addAll(mutuallyOverridable); - } - else if (implementationCount > 1) { - manyImpl.addAll(mutuallyOverridable); - } - } - - // Members actually present (declared) in the class - Set actuallyOverridden = Sets.newHashSet(implementedWithDelegationBy.keySet()); - for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) { - actuallyOverridden.addAll(member.getOverriddenDescriptors()); - } - - // Those to be overridden that are actually not - abstractNoImpl.removeAll(actuallyOverridden); - manyImpl.removeAll(actuallyOverridden); + collectMissingImplementations(classDescriptor, abstractNoImpl, manyImpl); PsiElement nameIdentifier = klass; if (klass instanceof JetClass) { @@ -216,6 +160,65 @@ public class OverrideResolver { // } } + public static void collectMissingImplementations(MutableClassDescriptor classDescriptor, Set abstractNoImpl, Set manyImpl) { + // Everything from supertypes + Map implementedWithDelegationBy = Maps.newHashMap(); + Set inheritedFunctions = Sets.newLinkedHashSet(); + for (JetType supertype : classDescriptor.getSupertypes()) { + for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) { + if (descriptor instanceof CallableMemberDescriptor) { + CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor; + inheritedFunctions.add(memberDescriptor); + } + } + } + + // Only those actually inherited + Set filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions); + + // Group members with "the same" signature + Multimap factoredMembers = CommonSuppliers.newLinkedHashSetHashSetMultimap(); + for (CallableMemberDescriptor one : filteredMembers) { + if (factoredMembers.values().contains(one)) continue; + for (CallableMemberDescriptor another : filteredMembers) { +// if (one == another) continue; + factoredMembers.put(one, one); + if (OverridingUtil.isOverridableBy(one, another).isSuccess() + || OverridingUtil.isOverridableBy(another, one).isSuccess()) { + factoredMembers.put(one, another); + } + } + } + + for (CallableMemberDescriptor key : factoredMembers.keySet()) { + Collection mutuallyOverridable = factoredMembers.get(key); + + int implementationCount = 0; + for (CallableMemberDescriptor member : mutuallyOverridable) { + if (member.getModality() != Modality.ABSTRACT) { + implementationCount++; + } + } + + if (implementationCount == 0) { + abstractNoImpl.addAll(mutuallyOverridable); + } + else if (implementationCount > 1) { + manyImpl.addAll(mutuallyOverridable); + } + } + + // Members actually present (declared) in the class + Set actuallyOverridden = Sets.newHashSet(implementedWithDelegationBy.keySet()); + for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) { + actuallyOverridden.addAll(member.getOverriddenDescriptors()); + } + + // Those to be overridden that are actually not + abstractNoImpl.removeAll(actuallyOverridden); + manyImpl.removeAll(actuallyOverridden); + } + private void checkOverride(CallableMemberDescriptor declared) { JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declared); if (member == null) { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 48949cbb3f0..c991281de46 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -54,5 +54,6 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java new file mode 100644 index 00000000000..fc89fba21aa --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java @@ -0,0 +1,40 @@ +package org.jetbrains.jet.plugin.codeInsight; + +import com.intellij.codeInsight.generation.ClassMember; +import com.intellij.codeInsight.generation.MemberChooserObject; +import com.intellij.ui.SimpleColoredComponent; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.resolve.DescriptorRenderer; + +import javax.swing.*; + +/** + * @author yole + */ +public class DescriptorClassMember implements ClassMember { + private final DeclarationDescriptor myDescriptor; + + public DescriptorClassMember(DeclarationDescriptor descriptor) { + myDescriptor = descriptor; + } + + @Override + public MemberChooserObject getParentNodeDelegate() { + final DeclarationDescriptor parent = myDescriptor.getContainingDeclaration(); + return new DescriptorClassMember(parent); + } + + @Override + public void renderTreeNode(SimpleColoredComponent component, JTree tree) { + component.append(getText()); + } + + @Override + public String getText() { + return DescriptorRenderer.TEXT.render(myDescriptor); + } + + public DeclarationDescriptor getDescriptor() { + return myDescriptor; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java new file mode 100644 index 00000000000..b72192455f0 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java @@ -0,0 +1,132 @@ +package org.jetbrains.jet.plugin.codeInsight; + +import com.google.common.collect.Sets; +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.ide.util.MemberChooser; +import com.intellij.lang.LanguageCodeInsightActionHandler; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.OverrideResolver; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * @author yole + */ +public class ImplementMethodsHandler implements LanguageCodeInsightActionHandler { + @Override + public boolean isValidFor(Editor editor, PsiFile file) { + if (!(file instanceof JetFile)) { + return false; + } + final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); + final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + return classOrObject != null; + } + + @Override + public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) { + final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); + final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + Set missingImplementations = collectMethodsToImplement(classOrObject); + if (missingImplementations.isEmpty()) { + HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found"); + return; + } + List members = membersFromDescriptors(missingImplementations); + final MemberChooser chooser = showOverrideImplementChooser(project, + members.toArray(new DescriptorClassMember[members.size()])); + if (chooser == null) { + return; + } + + final List selectedElements = chooser.getSelectedElements(); + if (selectedElements == null || selectedElements.isEmpty()) return; + + new WriteCommandAction(project, file) { + protected void run(final Result result) throws Throwable { + overrideOrImplementMethodsInRightPlace(project, editor, classOrObject, selectedElements); + } + }.execute(); + + } + + public static List membersFromDescriptors(Set missingImplementations) { + List members = new ArrayList(); + for (CallableMemberDescriptor memberDescriptor : missingImplementations) { + members.add(new DescriptorClassMember(memberDescriptor)); + } + return members; + } + + public static Set collectMethodsToImplement(JetClassOrObject classOrObject) { + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) classOrObject.getContainingFile()); + final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject); + Set missingImplementations = Sets.newLinkedHashSet(); + if (descriptor instanceof MutableClassDescriptor) { + OverrideResolver.collectMissingImplementations((MutableClassDescriptor) descriptor, + missingImplementations, missingImplementations); + } + return missingImplementations; + } + + public static void overrideOrImplementMethodsInRightPlace(Project project, Editor editor, JetClassOrObject classOrObject, List selectedElements) { + final JetClassBody body = classOrObject.getBody(); + if (body == null) { + return; + } + for (DescriptorClassMember selectedElement : selectedElements) { + final DeclarationDescriptor descriptor = selectedElement.getDescriptor(); + if (descriptor instanceof FunctionDescriptor) { + JetElement target = overrideFunction(project, (FunctionDescriptor) descriptor); + body.addBefore(target, body.getRBrace()); + } + } + } + + private static JetElement overrideFunction(Project project, FunctionDescriptor descriptor) { + StringBuilder bodyBuilder = new StringBuilder("override fun "); + bodyBuilder.append(descriptor.getName()); + bodyBuilder.append("("); + bodyBuilder.append(")"); + final JetType returnType = descriptor.getReturnType(); + bodyBuilder.append(": ").append(returnType.toString()); + bodyBuilder.append("{"); + if (returnType.isNullable()) { + bodyBuilder.append("return null"); + } + bodyBuilder.append("}"); + return JetPsiFactory.createFunction(project, bodyBuilder.toString()); + } + + private static MemberChooser showOverrideImplementChooser(Project project, + DescriptorClassMember[] members) { + final MemberChooser chooser = new MemberChooser(members, true, true, project); + chooser.setTitle("Implement Members"); + chooser.show(); + if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null; + return chooser; + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java index ff2ae3cadf1..ae847276ba7 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetBlock.java @@ -24,6 +24,7 @@ public class JetBlock implements ASTBlock { private Indent myIndent; private Wrap myWrap; private CodeStyleSettings mySettings; + private final SpacingBuilder mySpacingBuilder; private List mySubBlocks; private static final TokenSet CODE_BLOCKS = TokenSet.create( @@ -35,12 +36,14 @@ public class JetBlock implements ASTBlock { JetNodeTypes.THEN, JetNodeTypes.ELSE); - public JetBlock(ASTNode node, Alignment alignment, Indent indent, Wrap wrap, CodeStyleSettings settings) { + public JetBlock(ASTNode node, Alignment alignment, Indent indent, Wrap wrap, CodeStyleSettings settings, + SpacingBuilder spacingBuilder) { myNode = node; myAlignment = alignment; myIndent = indent; myWrap = wrap; mySettings = settings; + mySpacingBuilder = spacingBuilder; } @Override @@ -110,7 +113,7 @@ public class JetBlock implements ASTBlock { childIndent = Indent.getNormalIndent(); } - return new JetBlock(child, childAlignment, childIndent, wrap, mySettings); + return new JetBlock(child, childAlignment, childIndent, wrap, mySettings, mySpacingBuilder); } private static Indent indentIfNotBrace(ASTNode child) { @@ -120,8 +123,8 @@ public class JetBlock implements ASTBlock { } @Override - public Spacing getSpacing(Block block, Block block1) { - return null; + public Spacing getSpacing(Block child1, Block child2) { + return mySpacingBuilder.getSpacing(this, child1, child2); } @NotNull diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java index 852e8a05a30..04ef828bd79 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java @@ -1,15 +1,17 @@ package org.jetbrains.jet.plugin.formatter; -import com.intellij.formatting.FormattingModel; -import com.intellij.formatting.FormattingModelBuilder; -import com.intellij.formatting.FormattingModelProvider; -import com.intellij.formatting.Indent; +import com.intellij.formatting.*; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.CodeStyleSettings; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; + +import static org.jetbrains.jet.JetNodeTypes.*; +import static org.jetbrains.jet.lexer.JetTokens.*; /** * @author yole @@ -18,10 +20,19 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder { @NotNull @Override public FormattingModel createModel(PsiElement element, CodeStyleSettings settings) { - final JetBlock block = new JetBlock(element.getNode(), null, Indent.getNoneIndent(), null, settings); + final JetBlock block = new JetBlock(element.getNode(), null, Indent.getNoneIndent(), null, settings, + createSpacingBuilder(settings)); return FormattingModelProvider.createFormattingModelForPsiFile(element.getContainingFile(), block, settings); } + private static SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) { + return new SpacingBuilder(settings) + .beforeInside(BLOCK, FUN).spaceIf(settings.SPACE_BEFORE_METHOD_LBRACE) + .afterInside(LBRACE, BLOCK).lineBreakInCode() + .beforeInside(RBRACE, CLASS_BODY).lineBreakInCode() + .beforeInside(RBRACE, BLOCK).lineBreakInCode(); + } + @Override public TextRange getRangeAffectingIndent(PsiFile psiFile, int i, ASTNode astNode) { return null; diff --git a/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt b/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt new file mode 100644 index 00000000000..14c331bd84c --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt @@ -0,0 +1,5 @@ +import foo.Intf + +class Impl(): Intf { + +} diff --git a/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt.after b/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt.after new file mode 100644 index 00000000000..f0e3fb14e49 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Impl.kt.after @@ -0,0 +1,8 @@ +import foo.Intf + +class Impl(): Intf { + + override fun getFooBar(): String? { + return null + } +} diff --git a/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Intf.java b/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Intf.java new file mode 100644 index 00000000000..65891b1db74 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/javaInterfaceMethod/foo/Intf.java @@ -0,0 +1,5 @@ +package foo; + +interface Intf { + String getFooBar(); +} diff --git a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java index c99444a9fb9..2072055fa59 100644 --- a/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/checkers/JetPsiCheckerTest.java @@ -6,7 +6,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBuilder; -import org.jetbrains.jet.plugin.quickfix.PluginTestCaseBase; +import org.jetbrains.jet.plugin.PluginTestCaseBase; import java.io.File; diff --git a/idea/tests/org/jetbrains/jet/plugin/JetLightProjectDescriptor.java b/idea/tests/org/jetbrains/jet/plugin/JetLightProjectDescriptor.java new file mode 100644 index 00000000000..9fe80a43672 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/JetLightProjectDescriptor.java @@ -0,0 +1,33 @@ +package org.jetbrains.jet.plugin; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.module.StdModuleTypes; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ContentEntry; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.testFramework.LightProjectDescriptor; + +/** + * @author yole + */ +public class JetLightProjectDescriptor implements LightProjectDescriptor { + private JetLightProjectDescriptor() { + } + + public static final JetLightProjectDescriptor INSTANCE = new JetLightProjectDescriptor(); + + @Override + public ModuleType getModuleType() { + return StdModuleTypes.JAVA; + } + + @Override + public Sdk getSdk() { + return PluginTestCaseBase.jdkFromIdeaHome(); + } + + @Override + public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) { + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/PluginTestCaseBase.java b/idea/tests/org/jetbrains/jet/plugin/PluginTestCaseBase.java similarity index 86% rename from idea/tests/org/jetbrains/jet/plugin/quickfix/PluginTestCaseBase.java rename to idea/tests/org/jetbrains/jet/plugin/PluginTestCaseBase.java index 7a14d6e797c..5aaf520fc18 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/PluginTestCaseBase.java +++ b/idea/tests/org/jetbrains/jet/plugin/PluginTestCaseBase.java @@ -1,4 +1,4 @@ -package org.jetbrains.jet.plugin.quickfix; +package org.jetbrains.jet.plugin; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.impl.JavaSdkImpl; @@ -8,6 +8,9 @@ import org.jetbrains.jet.JetTestCaseBuilder; * @author yole */ public class PluginTestCaseBase { + private PluginTestCaseBase() { + } + public static String getTestDataPathBase() { return JetTestCaseBuilder.getHomeDirectory() + "/idea/testData"; } diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java new file mode 100644 index 00000000000..b7f6fc28298 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -0,0 +1,50 @@ +package org.jetbrains.jet.plugin.codeInsight; + +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; +import org.jetbrains.jet.lang.psi.JetClassOrObject; +import org.jetbrains.jet.plugin.JetLightProjectDescriptor; +import org.jetbrains.jet.plugin.PluginTestCaseBase; + +import java.util.Set; + +/** + * @author yole + */ +public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JetLightProjectDescriptor.INSTANCE; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/codeInsight/overrideImplement"); + } + + public void testJavaInterfaceMethod() { + myFixture.copyDirectoryToProject("javaInterfaceMethod", ""); + myFixture.configureFromTempProjectFile("foo/Impl.kt"); + final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset()); + final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + final Set descriptors = ImplementMethodsHandler.collectMethodsToImplement(classOrObject); + assertEquals(1, descriptors.size()); + new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) { + @Override + protected void run(Result result) throws Throwable { + ImplementMethodsHandler.overrideOrImplementMethodsInRightPlace(myFixture.getProject(), myFixture.getEditor(), classOrObject, + ImplementMethodsHandler.membersFromDescriptors(descriptors)); + } + }.execute(); + myFixture.checkResultByFile("javaInterfaceMethod/foo/Impl.kt.after"); + + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java index 2e0da1ea44c..7b8521fb419 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/JetQuickFixTest.java @@ -7,6 +7,7 @@ import junit.framework.Test; import junit.framework.TestSuite; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.JetTestCaseBuilder; +import org.jetbrains.jet.plugin.PluginTestCaseBase; import java.io.File; import java.io.FilenameFilter; diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index bee397cbb56..b15302eab63 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -66,4 +66,5 @@ class ModuleBuilder(val name: String): IModuleBuilder { override fun getModuleName(): String? = name override fun getJarName(): String? = _jarName -} \ No newline at end of file +} +} From 7714e850b9dd2314f1adca54635dfc23558bcfe7 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 18:10:11 +0100 Subject: [PATCH 3/8] handle parameters in implement members --- .../codeInsight/ImplementMethodsHandler.java | 20 ++++++++++++++----- .../formatter/JetFormattingModelBuilder.java | 2 ++ .../javaParameters/foo/Impl.kt | 5 +++++ .../javaParameters/foo/Impl.kt.after | 7 +++++++ .../javaParameters/foo/Intf.java | 5 +++++ .../codeInsight/OverrideImplementTest.java | 13 +++++++++--- 6 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt create mode 100644 idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt.after create mode 100644 idea/testData/codeInsight/overrideImplement/javaParameters/foo/Intf.java diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java index b72192455f0..fb1b8eb80d3 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java @@ -13,13 +13,11 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.OverrideResolver; +import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; @@ -105,9 +103,21 @@ public class ImplementMethodsHandler implements LanguageCodeInsightActionHandler StringBuilder bodyBuilder = new StringBuilder("override fun "); bodyBuilder.append(descriptor.getName()); bodyBuilder.append("("); + boolean first = true; + for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) { + if (!first) { + bodyBuilder.append(","); + } + first = false; + bodyBuilder.append(parameterDescriptor.getName()); + bodyBuilder.append(": "); + bodyBuilder.append(parameterDescriptor.getOutType().toString()); + } bodyBuilder.append(")"); final JetType returnType = descriptor.getReturnType(); - bodyBuilder.append(": ").append(returnType.toString()); + if (!returnType.equals(JetStandardLibrary.getJetStandardLibrary(project).getTuple0Type())) { + bodyBuilder.append(": ").append(returnType.toString()); + } bodyBuilder.append("{"); if (returnType.isNullable()) { bodyBuilder.append("return null"); diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java index 04ef828bd79..54cb3e97069 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java @@ -27,6 +27,8 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder { private static SpacingBuilder createSpacingBuilder(CodeStyleSettings settings) { return new SpacingBuilder(settings) + .before(COMMA).spaceIf(settings.SPACE_BEFORE_COMMA) + .after(COMMA).spaceIf(settings.SPACE_AFTER_COMMA) .beforeInside(BLOCK, FUN).spaceIf(settings.SPACE_BEFORE_METHOD_LBRACE) .afterInside(LBRACE, BLOCK).lineBreakInCode() .beforeInside(RBRACE, CLASS_BODY).lineBreakInCode() diff --git a/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt b/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt new file mode 100644 index 00000000000..14c331bd84c --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt @@ -0,0 +1,5 @@ +import foo.Intf + +class Impl(): Intf { + +} diff --git a/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt.after b/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt.after new file mode 100644 index 00000000000..a20e435f471 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Impl.kt.after @@ -0,0 +1,7 @@ +import foo.Intf + +class Impl(): Intf { + + override fun fooBar(i: Int, s: Array?, foo: Any?) { + } +} diff --git a/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Intf.java b/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Intf.java new file mode 100644 index 00000000000..04c1e8f6dfa --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/javaParameters/foo/Intf.java @@ -0,0 +1,5 @@ +package foo; + +interface Intf { + void fooBar(int i, String[] s, Object foo); +} diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java index b7f6fc28298..de80e8a49a6 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -31,7 +31,15 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { } public void testJavaInterfaceMethod() { - myFixture.copyDirectoryToProject("javaInterfaceMethod", ""); + doDirectoryTest(); + } + + public void testJavaParameters() { + doDirectoryTest(); + } + + private void doDirectoryTest() { + myFixture.copyDirectoryToProject(getTestName(true), ""); myFixture.configureFromTempProjectFile("foo/Impl.kt"); final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset()); final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); @@ -44,7 +52,6 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { ImplementMethodsHandler.membersFromDescriptors(descriptors)); } }.execute(); - myFixture.checkResultByFile("javaInterfaceMethod/foo/Impl.kt.after"); - + myFixture.checkResultByFile(getTestName(true) + "/foo/Impl.kt.after"); } } From b2990b74ef6f5b621037387fcbcd7dfdccec4bec Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 18:20:56 +0100 Subject: [PATCH 4/8] one more test; generate 'return' for primitive type return values --- .../plugin/codeInsight/ImplementMethodsHandler.java | 11 ++++++++++- .../codeInsight/overrideImplement/genericMethod.kt | 7 +++++++ .../overrideImplement/genericMethod.kt.after | 10 ++++++++++ .../plugin/codeInsight/OverrideImplementTest.java | 12 +++++++++++- 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 idea/testData/codeInsight/overrideImplement/genericMethod.kt create mode 100644 idea/testData/codeInsight/overrideImplement/genericMethod.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java index fb1b8eb80d3..921ff3a4938 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java @@ -115,13 +115,22 @@ public class ImplementMethodsHandler implements LanguageCodeInsightActionHandler } bodyBuilder.append(")"); final JetType returnType = descriptor.getReturnType(); - if (!returnType.equals(JetStandardLibrary.getJetStandardLibrary(project).getTuple0Type())) { + final JetStandardLibrary stdlib = JetStandardLibrary.getJetStandardLibrary(project); + if (!returnType.equals(stdlib.getTuple0Type())) { bodyBuilder.append(": ").append(returnType.toString()); } bodyBuilder.append("{"); if (returnType.isNullable()) { bodyBuilder.append("return null"); } + else if (returnType.equals(stdlib.getIntType()) || returnType.equals(stdlib.getLongType()) || + returnType.equals(stdlib.getShortType()) || returnType.equals(stdlib.getByteType()) || + returnType.equals(stdlib.getFloatType()) || returnType.equals(stdlib.getDoubleType())) { + bodyBuilder.append("return 0"); + } + else if (returnType.equals(stdlib.getBooleanType())) { + bodyBuilder.append("return false"); + } bodyBuilder.append("}"); return JetPsiFactory.createFunction(project, bodyBuilder.toString()); } diff --git a/idea/testData/codeInsight/overrideImplement/genericMethod.kt b/idea/testData/codeInsight/overrideImplement/genericMethod.kt new file mode 100644 index 00000000000..3c7e6d8de5b --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/genericMethod.kt @@ -0,0 +1,7 @@ +trait G { + fun foo(t : T) : T +} + +class GC() : G { + +} diff --git a/idea/testData/codeInsight/overrideImplement/genericMethod.kt.after b/idea/testData/codeInsight/overrideImplement/genericMethod.kt.after new file mode 100644 index 00000000000..f55e765fc4e --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/genericMethod.kt.after @@ -0,0 +1,10 @@ +trait G { + fun foo(t : T) : T +} + +class GC() : G { + + override fun foo(t: Int): Int { + return 0 + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java index de80e8a49a6..c821b510dd6 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -37,10 +37,21 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { public void testJavaParameters() { doDirectoryTest(); } + + public void testGenericMethod() { + myFixture.configureByFile("genericMethod.kt"); + doImplement(); + myFixture.checkResultByFile("genericMethod.kt.after"); + } private void doDirectoryTest() { myFixture.copyDirectoryToProject(getTestName(true), ""); myFixture.configureFromTempProjectFile("foo/Impl.kt"); + doImplement(); + myFixture.checkResultByFile(getTestName(true) + "/foo/Impl.kt.after"); + } + + private void doImplement() { final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset()); final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); final Set descriptors = ImplementMethodsHandler.collectMethodsToImplement(classOrObject); @@ -52,6 +63,5 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { ImplementMethodsHandler.membersFromDescriptors(descriptors)); } }.execute(); - myFixture.checkResultByFile(getTestName(true) + "/foo/Impl.kt.after"); } } From 7171fe8b028b301544bd1f7ef6bd2d78032aaa07 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 18:42:38 +0100 Subject: [PATCH 5/8] implement works for properties --- .../jetbrains/jet/lang/psi/JetPsiFactory.java | 2 +- .../codeInsight/ImplementMethodsHandler.java | 41 ++++++++++++++++--- .../formatter/JetFormattingModelBuilder.java | 1 + .../codeInsight/overrideImplement/property.kt | 7 ++++ .../overrideImplement/property.kt.after | 8 ++++ .../codeInsight/OverrideImplementTest.java | 12 +++++- 6 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 idea/testData/codeInsight/overrideImplement/property.kt create mode 100644 idea/testData/codeInsight/overrideImplement/property.kt.after diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java index ab9ad23aa7c..4c0dced694d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java @@ -54,7 +54,7 @@ public class JetPsiFactory { return createProperty(project, text); } - private static JetProperty createProperty(Project project, String text) { + public static JetProperty createProperty(Project project, String text) { return createDeclaration(project, text, JetProperty.class); } diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java index 921ff3a4938..7b03f6eef67 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java @@ -96,9 +96,32 @@ public class ImplementMethodsHandler implements LanguageCodeInsightActionHandler JetElement target = overrideFunction(project, (FunctionDescriptor) descriptor); body.addBefore(target, body.getRBrace()); } + else if (descriptor instanceof PropertyDescriptor) { + JetElement target = overrideProperty(project, (PropertyDescriptor) descriptor); + body.addBefore(target, body.getRBrace()); + } } } + private static JetElement overrideProperty(Project project, PropertyDescriptor descriptor) { + StringBuilder bodyBuilder = new StringBuilder("override "); + if (descriptor.isVar()) { + bodyBuilder.append("var "); + } + else { + bodyBuilder.append("val "); + } + bodyBuilder.append(descriptor.getName()).append(": ").append(descriptor.getOutType()); + String initializer = defaultInitializer(descriptor.getOutType(), JetStandardLibrary.getJetStandardLibrary(project)); + if (initializer != null) { + bodyBuilder.append("=").append(initializer); + } + else { + bodyBuilder.append("= ?"); + } + return JetPsiFactory.createProperty(project, bodyBuilder.toString()); + } + private static JetElement overrideFunction(Project project, FunctionDescriptor descriptor) { StringBuilder bodyBuilder = new StringBuilder("override fun "); bodyBuilder.append(descriptor.getName()); @@ -120,19 +143,27 @@ public class ImplementMethodsHandler implements LanguageCodeInsightActionHandler bodyBuilder.append(": ").append(returnType.toString()); } bodyBuilder.append("{"); + final String initializer = defaultInitializer(returnType, stdlib); + if (initializer != null) { + bodyBuilder.append("return " ).append(initializer); + } + bodyBuilder.append("}"); + return JetPsiFactory.createFunction(project, bodyBuilder.toString()); + } + + private static String defaultInitializer(JetType returnType, JetStandardLibrary stdlib) { if (returnType.isNullable()) { - bodyBuilder.append("return null"); + return "null"; } else if (returnType.equals(stdlib.getIntType()) || returnType.equals(stdlib.getLongType()) || returnType.equals(stdlib.getShortType()) || returnType.equals(stdlib.getByteType()) || returnType.equals(stdlib.getFloatType()) || returnType.equals(stdlib.getDoubleType())) { - bodyBuilder.append("return 0"); + return "0"; } else if (returnType.equals(stdlib.getBooleanType())) { - bodyBuilder.append("return false"); + return "false"; } - bodyBuilder.append("}"); - return JetPsiFactory.createFunction(project, bodyBuilder.toString()); + return null; } private static MemberChooser showOverrideImplementChooser(Project project, diff --git a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java index 54cb3e97069..e4a3f0d4901 100644 --- a/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java +++ b/idea/src/org/jetbrains/jet/plugin/formatter/JetFormattingModelBuilder.java @@ -29,6 +29,7 @@ public class JetFormattingModelBuilder implements FormattingModelBuilder { return new SpacingBuilder(settings) .before(COMMA).spaceIf(settings.SPACE_BEFORE_COMMA) .after(COMMA).spaceIf(settings.SPACE_AFTER_COMMA) + .around(EQ).spaceIf(settings.SPACE_AROUND_ASSIGNMENT_OPERATORS) .beforeInside(BLOCK, FUN).spaceIf(settings.SPACE_BEFORE_METHOD_LBRACE) .afterInside(LBRACE, BLOCK).lineBreakInCode() .beforeInside(RBRACE, CLASS_BODY).lineBreakInCode() diff --git a/idea/testData/codeInsight/overrideImplement/property.kt b/idea/testData/codeInsight/overrideImplement/property.kt new file mode 100644 index 00000000000..0f08af46b60 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/property.kt @@ -0,0 +1,7 @@ +trait T { + val v : Int +} + +class GC() : T { + +} diff --git a/idea/testData/codeInsight/overrideImplement/property.kt.after b/idea/testData/codeInsight/overrideImplement/property.kt.after new file mode 100644 index 00000000000..bfff67330db --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/property.kt.after @@ -0,0 +1,8 @@ +trait T { + val v : Int +} + +class GC() : T { + + override val v: Int = 0 +} diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java index c821b510dd6..b5d6d95016c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -39,9 +39,17 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { } public void testGenericMethod() { - myFixture.configureByFile("genericMethod.kt"); + doFileTest(); + } + + public void testProperty() { + doFileTest(); + } + + private void doFileTest() { + myFixture.configureByFile(getTestName(true) + ".kt"); doImplement(); - myFixture.checkResultByFile("genericMethod.kt.after"); + myFixture.checkResultByFile(getTestName(true) + ".kt.after"); } private void doDirectoryTest() { From fc4b810065844b4e19d5313b86773e17a1708da0 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 19:12:02 +0100 Subject: [PATCH 6/8] override methods initial --- .../jet/lang/resolve/OverrideResolver.java | 57 +++--- idea/src/META-INF/plugin.xml | 1 + .../codeInsight/ImplementMethodsHandler.java | 170 +--------------- .../OverrideImplementMethodsHandler.java | 183 ++++++++++++++++++ .../codeInsight/OverrideMethodsHandler.java | 24 +++ .../codeInsight/OverrideImplementTest.java | 6 +- stdlib/ktSrc/ModuleBuilder.kt | 8 +- 7 files changed, 254 insertions(+), 195 deletions(-) create mode 100644 idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java create mode 100644 idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index ca2742311b7..c59fd03c47e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -163,32 +163,7 @@ public class OverrideResolver { public static void collectMissingImplementations(MutableClassDescriptor classDescriptor, Set abstractNoImpl, Set manyImpl) { // Everything from supertypes Map implementedWithDelegationBy = Maps.newHashMap(); - Set inheritedFunctions = Sets.newLinkedHashSet(); - for (JetType supertype : classDescriptor.getSupertypes()) { - for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) { - if (descriptor instanceof CallableMemberDescriptor) { - CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor; - inheritedFunctions.add(memberDescriptor); - } - } - } - - // Only those actually inherited - Set filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions); - - // Group members with "the same" signature - Multimap factoredMembers = CommonSuppliers.newLinkedHashSetHashSetMultimap(); - for (CallableMemberDescriptor one : filteredMembers) { - if (factoredMembers.values().contains(one)) continue; - for (CallableMemberDescriptor another : filteredMembers) { -// if (one == another) continue; - factoredMembers.put(one, one); - if (OverridingUtil.isOverridableBy(one, another).isSuccess() - || OverridingUtil.isOverridableBy(another, one).isSuccess()) { - factoredMembers.put(one, another); - } - } - } + Multimap factoredMembers = collectSuperMethods(classDescriptor); for (CallableMemberDescriptor key : factoredMembers.keySet()) { Collection mutuallyOverridable = factoredMembers.get(key); @@ -219,6 +194,36 @@ public class OverrideResolver { manyImpl.removeAll(actuallyOverridden); } + public static Multimap collectSuperMethods(MutableClassDescriptor classDescriptor) { + Set inheritedFunctions = Sets.newLinkedHashSet(); + for (JetType supertype : classDescriptor.getSupertypes()) { + for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) { + if (descriptor instanceof CallableMemberDescriptor) { + CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor; + inheritedFunctions.add(memberDescriptor); + } + } + } + + // Only those actually inherited + Set filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions); + + // Group members with "the same" signature + Multimap factoredMembers = CommonSuppliers.newLinkedHashSetHashSetMultimap(); + for (CallableMemberDescriptor one : filteredMembers) { + if (factoredMembers.values().contains(one)) continue; + for (CallableMemberDescriptor another : filteredMembers) { +// if (one == another) continue; + factoredMembers.put(one, one); + if (OverridingUtil.isOverridableBy(one, another).isSuccess() + || OverridingUtil.isOverridableBy(another, one).isSuccess()) { + factoredMembers.put(one, another); + } + } + } + return factoredMembers; + } + private void checkOverride(CallableMemberDescriptor declared) { JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declared); if (member == null) { diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index c991281de46..a14c23ddbed 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -55,5 +55,6 @@ + diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java index 7b03f6eef67..abf648878ea 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java @@ -1,182 +1,22 @@ package org.jetbrains.jet.plugin.codeInsight; import com.google.common.collect.Sets; -import com.intellij.codeInsight.hint.HintManager; -import com.intellij.ide.util.MemberChooser; -import com.intellij.lang.LanguageCodeInsightActionHandler; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.OverrideResolver; -import org.jetbrains.jet.lang.types.JetStandardLibrary; -import org.jetbrains.jet.lang.types.JetType; -import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; -import java.util.ArrayList; -import java.util.List; import java.util.Set; /** * @author yole */ -public class ImplementMethodsHandler implements LanguageCodeInsightActionHandler { - @Override - public boolean isValidFor(Editor editor, PsiFile file) { - if (!(file instanceof JetFile)) { - return false; - } - final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); - final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); - return classOrObject != null; - } - - @Override - public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) { - final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); - final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); - Set missingImplementations = collectMethodsToImplement(classOrObject); - if (missingImplementations.isEmpty()) { - HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found"); - return; - } - List members = membersFromDescriptors(missingImplementations); - final MemberChooser chooser = showOverrideImplementChooser(project, - members.toArray(new DescriptorClassMember[members.size()])); - if (chooser == null) { - return; - } - - final List selectedElements = chooser.getSelectedElements(); - if (selectedElements == null || selectedElements.isEmpty()) return; - - new WriteCommandAction(project, file) { - protected void run(final Result result) throws Throwable { - overrideOrImplementMethodsInRightPlace(project, editor, classOrObject, selectedElements); - } - }.execute(); - - } - - public static List membersFromDescriptors(Set missingImplementations) { - List members = new ArrayList(); - for (CallableMemberDescriptor memberDescriptor : missingImplementations) { - members.add(new DescriptorClassMember(memberDescriptor)); - } - return members; - } - - public static Set collectMethodsToImplement(JetClassOrObject classOrObject) { - BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) classOrObject.getContainingFile()); - final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject); +public class ImplementMethodsHandler extends OverrideImplementMethodsHandler { + protected Set collectMethodsToGenerate(MutableClassDescriptor descriptor) { Set missingImplementations = Sets.newLinkedHashSet(); - if (descriptor instanceof MutableClassDescriptor) { - OverrideResolver.collectMissingImplementations((MutableClassDescriptor) descriptor, - missingImplementations, missingImplementations); - } + OverrideResolver.collectMissingImplementations(descriptor, missingImplementations, missingImplementations); return missingImplementations; } - public static void overrideOrImplementMethodsInRightPlace(Project project, Editor editor, JetClassOrObject classOrObject, List selectedElements) { - final JetClassBody body = classOrObject.getBody(); - if (body == null) { - return; - } - for (DescriptorClassMember selectedElement : selectedElements) { - final DeclarationDescriptor descriptor = selectedElement.getDescriptor(); - if (descriptor instanceof FunctionDescriptor) { - JetElement target = overrideFunction(project, (FunctionDescriptor) descriptor); - body.addBefore(target, body.getRBrace()); - } - else if (descriptor instanceof PropertyDescriptor) { - JetElement target = overrideProperty(project, (PropertyDescriptor) descriptor); - body.addBefore(target, body.getRBrace()); - } - } - } - - private static JetElement overrideProperty(Project project, PropertyDescriptor descriptor) { - StringBuilder bodyBuilder = new StringBuilder("override "); - if (descriptor.isVar()) { - bodyBuilder.append("var "); - } - else { - bodyBuilder.append("val "); - } - bodyBuilder.append(descriptor.getName()).append(": ").append(descriptor.getOutType()); - String initializer = defaultInitializer(descriptor.getOutType(), JetStandardLibrary.getJetStandardLibrary(project)); - if (initializer != null) { - bodyBuilder.append("=").append(initializer); - } - else { - bodyBuilder.append("= ?"); - } - return JetPsiFactory.createProperty(project, bodyBuilder.toString()); - } - - private static JetElement overrideFunction(Project project, FunctionDescriptor descriptor) { - StringBuilder bodyBuilder = new StringBuilder("override fun "); - bodyBuilder.append(descriptor.getName()); - bodyBuilder.append("("); - boolean first = true; - for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) { - if (!first) { - bodyBuilder.append(","); - } - first = false; - bodyBuilder.append(parameterDescriptor.getName()); - bodyBuilder.append(": "); - bodyBuilder.append(parameterDescriptor.getOutType().toString()); - } - bodyBuilder.append(")"); - final JetType returnType = descriptor.getReturnType(); - final JetStandardLibrary stdlib = JetStandardLibrary.getJetStandardLibrary(project); - if (!returnType.equals(stdlib.getTuple0Type())) { - bodyBuilder.append(": ").append(returnType.toString()); - } - bodyBuilder.append("{"); - final String initializer = defaultInitializer(returnType, stdlib); - if (initializer != null) { - bodyBuilder.append("return " ).append(initializer); - } - bodyBuilder.append("}"); - return JetPsiFactory.createFunction(project, bodyBuilder.toString()); - } - - private static String defaultInitializer(JetType returnType, JetStandardLibrary stdlib) { - if (returnType.isNullable()) { - return "null"; - } - else if (returnType.equals(stdlib.getIntType()) || returnType.equals(stdlib.getLongType()) || - returnType.equals(stdlib.getShortType()) || returnType.equals(stdlib.getByteType()) || - returnType.equals(stdlib.getFloatType()) || returnType.equals(stdlib.getDoubleType())) { - return "0"; - } - else if (returnType.equals(stdlib.getBooleanType())) { - return "false"; - } - return null; - } - - private static MemberChooser showOverrideImplementChooser(Project project, - DescriptorClassMember[] members) { - final MemberChooser chooser = new MemberChooser(members, true, true, project); - chooser.setTitle("Implement Members"); - chooser.show(); - if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null; - return chooser; - } - - @Override - public boolean startInWriteAction() { - return false; + protected String getChooserTitle() { + return "Implement Members"; } } diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java new file mode 100644 index 00000000000..ddc4aa1dfe4 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java @@ -0,0 +1,183 @@ +package org.jetbrains.jet.plugin.codeInsight; + +import com.intellij.codeInsight.hint.HintManager; +import com.intellij.ide.util.MemberChooser; +import com.intellij.lang.LanguageCodeInsightActionHandler; +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.types.JetStandardLibrary; +import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +/** + * @author yole + */ +public abstract class OverrideImplementMethodsHandler implements LanguageCodeInsightActionHandler { + public static List membersFromDescriptors(Set missingImplementations) { + List members = new ArrayList(); + for (CallableMemberDescriptor memberDescriptor : missingImplementations) { + members.add(new DescriptorClassMember(memberDescriptor)); + } + return members; + } + + public Set collectMethodsToGenerate(JetClassOrObject classOrObject) { + BindingContext bindingContext = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) classOrObject.getContainingFile()); + final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject); + if (descriptor instanceof MutableClassDescriptor) { + return collectMethodsToGenerate((MutableClassDescriptor) descriptor); + } + return Collections.emptySet(); + } + + protected abstract Set collectMethodsToGenerate(MutableClassDescriptor descriptor); + + public static void generateMethods(Project project, Editor editor, JetClassOrObject classOrObject, List selectedElements) { + final JetClassBody body = classOrObject.getBody(); + if (body == null) { + return; + } + for (DescriptorClassMember selectedElement : selectedElements) { + final DeclarationDescriptor descriptor = selectedElement.getDescriptor(); + if (descriptor instanceof FunctionDescriptor) { + JetElement target = overrideFunction(project, (FunctionDescriptor) descriptor); + body.addBefore(target, body.getRBrace()); + } + else if (descriptor instanceof PropertyDescriptor) { + JetElement target = overrideProperty(project, (PropertyDescriptor) descriptor); + body.addBefore(target, body.getRBrace()); + } + } + } + + private static JetElement overrideProperty(Project project, PropertyDescriptor descriptor) { + StringBuilder bodyBuilder = new StringBuilder("override "); + if (descriptor.isVar()) { + bodyBuilder.append("var "); + } + else { + bodyBuilder.append("val "); + } + bodyBuilder.append(descriptor.getName()).append(": ").append(descriptor.getOutType()); + String initializer = defaultInitializer(descriptor.getOutType(), JetStandardLibrary.getJetStandardLibrary(project)); + if (initializer != null) { + bodyBuilder.append("=").append(initializer); + } + else { + bodyBuilder.append("= ?"); + } + return JetPsiFactory.createProperty(project, bodyBuilder.toString()); + } + + private static JetElement overrideFunction(Project project, FunctionDescriptor descriptor) { + StringBuilder bodyBuilder = new StringBuilder("override fun "); + bodyBuilder.append(descriptor.getName()); + bodyBuilder.append("("); + boolean first = true; + for (ValueParameterDescriptor parameterDescriptor : descriptor.getValueParameters()) { + if (!first) { + bodyBuilder.append(","); + } + first = false; + bodyBuilder.append(parameterDescriptor.getName()); + bodyBuilder.append(": "); + bodyBuilder.append(parameterDescriptor.getOutType().toString()); + } + bodyBuilder.append(")"); + final JetType returnType = descriptor.getReturnType(); + final JetStandardLibrary stdlib = JetStandardLibrary.getJetStandardLibrary(project); + if (!returnType.equals(stdlib.getTuple0Type())) { + bodyBuilder.append(": ").append(returnType.toString()); + } + bodyBuilder.append("{"); + final String initializer = defaultInitializer(returnType, stdlib); + if (initializer != null) { + bodyBuilder.append("return " ).append(initializer); + } + bodyBuilder.append("}"); + return JetPsiFactory.createFunction(project, bodyBuilder.toString()); + } + + private static String defaultInitializer(JetType returnType, JetStandardLibrary stdlib) { + if (returnType.isNullable()) { + return "null"; + } + else if (returnType.equals(stdlib.getIntType()) || returnType.equals(stdlib.getLongType()) || + returnType.equals(stdlib.getShortType()) || returnType.equals(stdlib.getByteType()) || + returnType.equals(stdlib.getFloatType()) || returnType.equals(stdlib.getDoubleType())) { + return "0"; + } + else if (returnType.equals(stdlib.getBooleanType())) { + return "false"; + } + return null; + } + + private MemberChooser showOverrideImplementChooser(Project project, + DescriptorClassMember[] members) { + final MemberChooser chooser = new MemberChooser(members, true, true, project); + chooser.setTitle(getChooserTitle()); + chooser.show(); + if (chooser.getExitCode() != DialogWrapper.OK_EXIT_CODE) return null; + return chooser; + } + + protected abstract String getChooserTitle(); + + @Override + public boolean isValidFor(Editor editor, PsiFile file) { + if (!(file instanceof JetFile)) { + return false; + } + final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); + final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + return classOrObject != null; + } + + @Override + public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file) { + final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); + final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + Set missingImplementations = collectMethodsToGenerate(classOrObject); + if (missingImplementations.isEmpty()) { + HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found"); + return; + } + List members = membersFromDescriptors(missingImplementations); + final MemberChooser chooser = showOverrideImplementChooser(project, + members.toArray(new DescriptorClassMember[members.size()])); + if (chooser == null) { + return; + } + + final List selectedElements = chooser.getSelectedElements(); + if (selectedElements == null || selectedElements.isEmpty()) return; + + new WriteCommandAction(project, file) { + protected void run(final Result result) throws Throwable { + generateMethods(project, editor, classOrObject, selectedElements); + } + }.execute(); + + } + + @Override + public boolean startInWriteAction() { + return false; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java new file mode 100644 index 00000000000..c3fdd6ce0b9 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java @@ -0,0 +1,24 @@ +package org.jetbrains.jet.plugin.codeInsight; + +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; +import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor; +import org.jetbrains.jet.lang.resolve.OverrideResolver; + +import java.util.Set; + +/** + * @author yole + */ +public class OverrideMethodsHandler extends OverrideImplementMethodsHandler { + protected Set collectMethodsToGenerate(MutableClassDescriptor descriptor) { + final Set superMethods = OverrideResolver.collectSuperMethods(descriptor).keySet(); + for (CallableMemberDescriptor member : descriptor.getCallableMembers()) { + superMethods.removeAll(member.getOverriddenDescriptors()); + } + return superMethods; + } + + protected String getChooserTitle() { + return "Override Members"; + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java index b5d6d95016c..8d528827964 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -62,13 +62,13 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { private void doImplement() { final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset()); final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); - final Set descriptors = ImplementMethodsHandler.collectMethodsToImplement(classOrObject); + final Set descriptors = new ImplementMethodsHandler().collectMethodsToGenerate(classOrObject); assertEquals(1, descriptors.size()); new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) { @Override protected void run(Result result) throws Throwable { - ImplementMethodsHandler.overrideOrImplementMethodsInRightPlace(myFixture.getProject(), myFixture.getEditor(), classOrObject, - ImplementMethodsHandler.membersFromDescriptors(descriptors)); + ImplementMethodsHandler.generateMethods(myFixture.getProject(), myFixture.getEditor(), classOrObject, + ImplementMethodsHandler.membersFromDescriptors(descriptors)); } }.execute(); } diff --git a/stdlib/ktSrc/ModuleBuilder.kt b/stdlib/ktSrc/ModuleBuilder.kt index b15302eab63..ca94ba92ea1 100644 --- a/stdlib/ktSrc/ModuleBuilder.kt +++ b/stdlib/ktSrc/ModuleBuilder.kt @@ -35,7 +35,7 @@ class JarBuilder(val parent: ModuleBuilder) { } } -class ModuleBuilder(val name: String): IModuleBuilder { +open class ModuleBuilder(val name: String): IModuleBuilder { val sourceFiles: ArrayList = ArrayList() val classpathRoots: ArrayList = ArrayList() var _jarName: String? = null @@ -67,4 +67,10 @@ class ModuleBuilder(val name: String): IModuleBuilder { override fun getJarName(): String? = _jarName } + +class ModuleBuilder2(name: String): ModuleBuilder(name) { + + } +} + From 7b668a7e619a365482cba12bd9c15076b7188143 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 19:14:30 +0100 Subject: [PATCH 7/8] equals/hashCode for descriptors --- .../codeInsight/DescriptorClassMember.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java index fc89fba21aa..f22e8db19d5 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/DescriptorClassMember.java @@ -37,4 +37,21 @@ public class DescriptorClassMember implements ClassMember { public DeclarationDescriptor getDescriptor() { return myDescriptor; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DescriptorClassMember that = (DescriptorClassMember) o; + + if (myDescriptor != null ? !myDescriptor.equals(that.myDescriptor) : that.myDescriptor != null) return false; + + return true; + } + + @Override + public int hashCode() { + return myDescriptor != null ? myDescriptor.hashCode() : 0; + } } From d7aa7e3044ed1000596f83b5a8d454536b8b649d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 19:17:15 +0100 Subject: [PATCH 8/8] override methods checks modality --- .../jet/plugin/codeInsight/OverrideMethodsHandler.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java index c3fdd6ce0b9..2cb0be4bb09 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java @@ -4,6 +4,7 @@ import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.MutableClassDescriptor; import org.jetbrains.jet.lang.resolve.OverrideResolver; +import java.util.HashSet; import java.util.Set; /** @@ -15,7 +16,13 @@ public class OverrideMethodsHandler extends OverrideImplementMethodsHandler { for (CallableMemberDescriptor member : descriptor.getCallableMembers()) { superMethods.removeAll(member.getOverriddenDescriptors()); } - return superMethods; + Set result = new HashSet(); + for (CallableMemberDescriptor superMethod : superMethods) { + if (superMethod.getModality().isOverridable()) { + result.add(superMethod); + } + } + return result; } protected String getChooserTitle() {