diff --git a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index a586891775c..d69880658cf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/compiler/frontend/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -91,6 +91,14 @@ public class DescriptorRenderer implements Renderer { } public String renderType(JetType type) { + return renderType(type, false); + } + + public String renderTypeWithShortNames(JetType type) { + return renderType(type, true); + } + + private String renderType(JetType type, boolean shortNamesOnly) { if (type == null) { return escape("[NULL]"); } @@ -98,24 +106,33 @@ public class DescriptorRenderer implements Renderer { return escape("Unit" + (type.isNullable() ? "?" : "")); } else if (JetStandardClasses.isTupleType(type)) { - return escape(renderTupleType(type)); + return escape(renderTupleType(type, shortNamesOnly)); } else if (JetStandardClasses.isFunctionType(type)) { - return escape(renderFunctionType(type)); + return escape(renderFunctionType(type, shortNamesOnly)); } else { - return escape(renderDefaultType(type)); + return escape(renderDefaultType(type, shortNamesOnly)); } } - private String renderDefaultType(JetType type) { + private String renderDefaultType(JetType type, boolean shortNamesOnly) { StringBuilder sb = new StringBuilder(); ClassifierDescriptor cd = type.getConstructor().getDeclarationDescriptor(); - sb.append(cd == null || cd instanceof TypeParameterDescriptor - ? type.getConstructor() : DescriptorUtils.getFQName(cd)); + + Object typeNameObject; + + if (cd == null || cd instanceof TypeParameterDescriptor) { + typeNameObject = type.getConstructor(); + } + else { + typeNameObject = shortNamesOnly ? cd.getName() : DescriptorUtils.getFQName(cd); + } + + sb.append(typeNameObject); if (!type.getArguments().isEmpty()) { sb.append("<"); - appendTypeProjections(sb, type.getArguments()); + appendTypeProjections(sb, type.getArguments(), shortNamesOnly); sb.append(">"); } if (type.isNullable()) { @@ -124,31 +141,31 @@ public class DescriptorRenderer implements Renderer { return sb.toString(); } - private void appendTypes(StringBuilder result, List types) { + private void appendTypes(StringBuilder result, List types, boolean shortNamesOnly) { for (Iterator iterator = types.iterator(); iterator.hasNext(); ) { - result.append(renderType(iterator.next())); + result.append(renderType(iterator.next(), shortNamesOnly)); if (iterator.hasNext()) { result.append(", "); } } } - private void appendTypeProjections(StringBuilder result, List typeProjections) { + private void appendTypeProjections(StringBuilder result, List typeProjections, boolean shortNamesOnly) { for (Iterator iterator = typeProjections.iterator(); iterator.hasNext(); ) { TypeProjection typeProjection = iterator.next(); if (typeProjection.getProjectionKind() != Variance.INVARIANT) { result.append(typeProjection.getProjectionKind()).append(" "); } - result.append(renderType(typeProjection.getType())); + result.append(renderType(typeProjection.getType(), shortNamesOnly)); if (iterator.hasNext()) { result.append(", "); } } } - protected String renderTupleType(JetType type) { + protected String renderTupleType(JetType type, boolean shortNamesOnly) { StringBuilder sb = new StringBuilder("#("); - appendTypes(sb, JetStandardClasses.getTupleElementTypes(type)); + appendTypes(sb, JetStandardClasses.getTupleElementTypes(type), shortNamesOnly); sb.append(")"); if (type.isNullable()) { @@ -158,19 +175,19 @@ public class DescriptorRenderer implements Renderer { return sb.toString(); } - private String renderFunctionType(JetType type) { + private String renderFunctionType(JetType type, boolean shortNamesOnly) { StringBuilder sb = new StringBuilder(); JetType receiverType = JetStandardClasses.getReceiverType(type); if (receiverType != null) { - sb.append(renderType(receiverType)); + sb.append(renderType(receiverType, shortNamesOnly)); sb.append("."); } sb.append("("); - appendTypeProjections(sb, JetStandardClasses.getParameterTypeProjectionsFromFunctionType(type)); + appendTypeProjections(sb, JetStandardClasses.getParameterTypeProjectionsFromFunctionType(type), shortNamesOnly); sb.append(") -> "); - sb.append(renderType(JetStandardClasses.getReturnTypeFromFunctionType(type))); + sb.append(renderType(JetStandardClasses.getReturnTypeFromFunctionType(type), shortNamesOnly)); if (type.isNullable()) { return "(" + sb + ")?"; diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java index 57f0952e678..f16b0e62fe6 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/ImplementMethodsHandler.java @@ -34,12 +34,14 @@ import java.util.Set; */ public class ImplementMethodsHandler extends OverrideImplementMethodsHandler implements IntentionAction { + @Override protected Set collectMethodsToGenerate(MutableClassDescriptor descriptor) { Set missingImplementations = Sets.newLinkedHashSet(); OverrideResolver.collectMissingImplementations(descriptor, missingImplementations, missingImplementations); return missingImplementations; } + @Override 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 index d4b668ac33f..58f11204410 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java @@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; import org.jetbrains.jet.plugin.compiler.WholeProjectAnalyzerFacade; import org.jetbrains.jet.plugin.quickfix.ImportInsertHelper; +import org.jetbrains.jet.resolve.DescriptorRenderer; import java.util.ArrayList; import java.util.Collections; @@ -54,9 +55,10 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns return members; } - public Set collectMethodsToGenerate(JetClassOrObject classOrObject) { + @NotNull + public Set collectMethodsToGenerate(@NotNull JetClassOrObject classOrObject) { BindingContext bindingContext = - WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile)classOrObject.getContainingFile()); + WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile)classOrObject.getContainingFile()); final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject); if (descriptor instanceof MutableClassDescriptor) { return collectMethodsToGenerate((MutableClassDescriptor)descriptor); @@ -75,10 +77,6 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns return; } - // NOTE + TODO: If you try to cache findInsertBeforeAnchor element, there will be failed assertion - // "PSI/document inconsistency before reparse: file=" from DocumentCommitThread after inserting two overriding - // with the caret right before existing function start. - PsiElement afterAnchor = findInsertAfterAnchor(editor, body); if (afterAnchor == null) { @@ -115,7 +113,7 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns } }); - if (offsetCursorElement != null) { + if (offsetCursorElement != null && offsetCursorElement != body.getRBrace()) { afterAnchor = offsetCursorElement; } @@ -130,14 +128,15 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns else { bodyBuilder.append("val "); } - bodyBuilder.append(descriptor.getName()).append(":").append(descriptor.getType()); + bodyBuilder.append(descriptor.getName()).append(" : ").append(DescriptorRenderer.COMPACT.renderTypeWithShortNames( + descriptor.getType())); ImportInsertHelper.addImportDirectiveIfNeeded(descriptor.getType(), file); String initializer = defaultInitializer(descriptor.getType(), JetStandardLibrary.getInstance()); if (initializer != null) { - bodyBuilder.append("=").append(initializer); + bodyBuilder.append(" = ").append(initializer); } else { - bodyBuilder.append("= ?"); + bodyBuilder.append(" = ?"); } return JetPsiFactory.createProperty(project, bodyBuilder.toString()); } @@ -153,16 +152,17 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns } first = false; bodyBuilder.append(parameterDescriptor.getName()); - bodyBuilder.append(":"); - bodyBuilder.append(parameterDescriptor.getType().toString()); + bodyBuilder.append(" : "); + bodyBuilder.append(DescriptorRenderer.COMPACT.renderTypeWithShortNames(parameterDescriptor.getType())); ImportInsertHelper.addImportDirectiveIfNeeded(parameterDescriptor.getType(), file); } bodyBuilder.append(")"); final JetType returnType = descriptor.getReturnType(); final JetStandardLibrary stdlib = JetStandardLibrary.getInstance(); - if (!returnType.equals(stdlib.getTuple0Type())) { - bodyBuilder.append(":").append(returnType.toString()); + + if (returnType != null && !stdlib.getTuple0Type().equals(returnType)) { + bodyBuilder.append(" : ").append(returnType.toString()); ImportInsertHelper.addImportDirectiveIfNeeded(returnType, file); } @@ -183,6 +183,7 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns else if (returnType.equals(stdlib.getBooleanType())) { return "false"; } + return null; } @@ -209,10 +210,12 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns protected abstract String getNoMethodsFoundHint(); - public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file, - boolean implementAll) { + public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file, boolean implementAll) { final PsiElement elementAtCaret = file.findElementAt(editor.getCaretModel().getOffset()); final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + + assert classOrObject != null : "ClassObject should be checked in isValidFor method"; + Set missingImplementations = collectMethodsToGenerate(classOrObject); if (missingImplementations.isEmpty() && !implementAll) { HintManager.getInstance().showErrorHint(editor, getNoMethodsFoundHint()); @@ -225,10 +228,10 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns selectedElements = members; } else { - final MemberChooser chooser = showOverrideImplementChooser(project, - members.toArray( - new DescriptorClassMember[members - .size()])); + final MemberChooser chooser = showOverrideImplementChooser( + project, + members.toArray(new DescriptorClassMember[members.size()])); + if (chooser == null) { return; } diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java index 29e2eb3a404..72f1bebcd98 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideMethodsHandler.java @@ -27,6 +27,7 @@ import java.util.Set; * @author yole */ public class OverrideMethodsHandler extends OverrideImplementMethodsHandler { + @Override protected Set collectMethodsToGenerate(MutableClassDescriptor descriptor) { final Set superMethods = OverrideResolver.collectSuperMethods(descriptor).keySet(); for (CallableMemberDescriptor member : descriptor.getCallableMembers()) { @@ -41,6 +42,7 @@ public class OverrideMethodsHandler extends OverrideImplementMethodsHandler { return result; } + @Override protected String getChooserTitle() { return "Override Members"; } diff --git a/idea/testData/codeInsight/overrideImplement/functionProperty.kt b/idea/testData/codeInsight/overrideImplement/functionProperty.kt new file mode 100644 index 00000000000..c8adcbdfe9b --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/functionProperty.kt @@ -0,0 +1,8 @@ +// From KT-1648 +trait A { + val method:() -> Unit? +} + +fun some() : A { + return object A {} +} \ No newline at end of file diff --git a/idea/testData/codeInsight/overrideImplement/functionProperty.kt.after b/idea/testData/codeInsight/overrideImplement/functionProperty.kt.after new file mode 100644 index 00000000000..74d3266d01a --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/functionProperty.kt.after @@ -0,0 +1,10 @@ +// From KT-1648 +trait A { + val method:() -> Unit? +} + +fun some() : A { + return object A { + override val method : () -> Unit? = ? + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java index 43d3e4ad078..83a8cb9a83d 100644 --- a/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/jet/plugin/codeInsight/OverrideImplementTest.java @@ -49,6 +49,10 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { myFixture.setTestDataPath(PluginTestCaseBase.getTestDataPathBase() + "/codeInsight/overrideImplement"); } + public void testFunctionProperty() { + doFileTest(); + } + public void testJavaInterfaceMethod() { doDirectoryTest(); } @@ -103,6 +107,7 @@ 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); + assertNotNull("Caret should be inside class or object", classOrObject); final Set descriptors = new ImplementMethodsHandler().collectMethodsToGenerate(classOrObject); assertEquals("Invalid number of available descriptors for override", 1, descriptors.size()); new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) { @@ -118,6 +123,7 @@ public class OverrideImplementTest extends LightCodeInsightFixtureTestCase { private void doMultiImplement() { final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset()); final JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class); + assertNotNull("Caret should be inside class or object", classOrObject); final Set descriptors = new ImplementMethodsHandler().collectMethodsToGenerate(classOrObject); final ArrayList descriptorsList = new ArrayList(descriptors);