override methods initial

This commit is contained in:
Dmitry Jemerov
2011-11-04 19:12:02 +01:00
parent 7171fe8b02
commit fc4b810065
7 changed files with 254 additions and 195 deletions
@@ -163,32 +163,7 @@ public class OverrideResolver {
public static void collectMissingImplementations(MutableClassDescriptor classDescriptor, Set<CallableMemberDescriptor> abstractNoImpl, Set<CallableMemberDescriptor> manyImpl) {
// Everything from supertypes
Map<CallableMemberDescriptor, CallableMemberDescriptor> implementedWithDelegationBy = Maps.newHashMap();
Set<CallableMemberDescriptor> 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<CallableMemberDescriptor> filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions);
// Group members with "the same" signature
Multimap<CallableMemberDescriptor, CallableMemberDescriptor> 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<CallableMemberDescriptor, CallableMemberDescriptor> factoredMembers = collectSuperMethods(classDescriptor);
for (CallableMemberDescriptor key : factoredMembers.keySet()) {
Collection<CallableMemberDescriptor> mutuallyOverridable = factoredMembers.get(key);
@@ -219,6 +194,36 @@ public class OverrideResolver {
manyImpl.removeAll(actuallyOverridden);
}
public static Multimap<CallableMemberDescriptor, CallableMemberDescriptor> collectSuperMethods(MutableClassDescriptor classDescriptor) {
Set<CallableMemberDescriptor> 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<CallableMemberDescriptor> filteredMembers = OverridingUtil.filterOverrides(inheritedFunctions);
// Group members with "the same" signature
Multimap<CallableMemberDescriptor, CallableMemberDescriptor> 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) {
+1
View File
@@ -55,5 +55,6 @@
<elementDescriptionProvider implementation="org.jetbrains.jet.plugin.findUsages.JetElementDescriptionProvider"/>
<debugger.positionManagerFactory implementation="org.jetbrains.jet.plugin.debugger.JetPositionManagerFactory"/>
<codeInsight.implementMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler"/>
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
</extensions>
</idea-plugin>
@@ -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<CallableMemberDescriptor> missingImplementations = collectMethodsToImplement(classOrObject);
if (missingImplementations.isEmpty()) {
HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found");
return;
}
List<DescriptorClassMember> members = membersFromDescriptors(missingImplementations);
final MemberChooser<DescriptorClassMember> chooser = showOverrideImplementChooser(project,
members.toArray(new DescriptorClassMember[members.size()]));
if (chooser == null) {
return;
}
final List<DescriptorClassMember> 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<DescriptorClassMember> membersFromDescriptors(Set<CallableMemberDescriptor> missingImplementations) {
List<DescriptorClassMember> members = new ArrayList<DescriptorClassMember>();
for (CallableMemberDescriptor memberDescriptor : missingImplementations) {
members.add(new DescriptorClassMember(memberDescriptor));
}
return members;
}
public static Set<CallableMemberDescriptor> 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<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor) {
Set<CallableMemberDescriptor> 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<DescriptorClassMember> 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<DescriptorClassMember> showOverrideImplementChooser(Project project,
DescriptorClassMember[] members) {
final MemberChooser<DescriptorClassMember> chooser = new MemberChooser<DescriptorClassMember>(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";
}
}
@@ -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<DescriptorClassMember> membersFromDescriptors(Set<CallableMemberDescriptor> missingImplementations) {
List<DescriptorClassMember> members = new ArrayList<DescriptorClassMember>();
for (CallableMemberDescriptor memberDescriptor : missingImplementations) {
members.add(new DescriptorClassMember(memberDescriptor));
}
return members;
}
public Set<CallableMemberDescriptor> 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<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor);
public static void generateMethods(Project project, Editor editor, JetClassOrObject classOrObject, List<DescriptorClassMember> 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<DescriptorClassMember> showOverrideImplementChooser(Project project,
DescriptorClassMember[] members) {
final MemberChooser<DescriptorClassMember> chooser = new MemberChooser<DescriptorClassMember>(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<CallableMemberDescriptor> missingImplementations = collectMethodsToGenerate(classOrObject);
if (missingImplementations.isEmpty()) {
HintManager.getInstance().showErrorHint(editor, "No methods to implement have been found");
return;
}
List<DescriptorClassMember> members = membersFromDescriptors(missingImplementations);
final MemberChooser<DescriptorClassMember> chooser = showOverrideImplementChooser(project,
members.toArray(new DescriptorClassMember[members.size()]));
if (chooser == null) {
return;
}
final List<DescriptorClassMember> 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;
}
}
@@ -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<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor) {
final Set<CallableMemberDescriptor> superMethods = OverrideResolver.collectSuperMethods(descriptor).keySet();
for (CallableMemberDescriptor member : descriptor.getCallableMembers()) {
superMethods.removeAll(member.getOverriddenDescriptors());
}
return superMethods;
}
protected String getChooserTitle() {
return "Override Members";
}
}
@@ -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<CallableMemberDescriptor> descriptors = ImplementMethodsHandler.collectMethodsToImplement(classOrObject);
final Set<CallableMemberDescriptor> 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();
}
+7 -1
View File
@@ -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<String?> = ArrayList<String?>()
val classpathRoots: ArrayList<String?> = ArrayList<String?>()
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) {
}
}