From fc4b810065844b4e19d5313b86773e17a1708da0 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Fri, 4 Nov 2011 19:12:02 +0100 Subject: [PATCH] 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) { + + } +} +