KT-1648 Function0<Tuple0> appears in the result of the Implement abstract members quick fix
#KT-1648 fixed
This commit is contained in:
@@ -91,6 +91,14 @@ public class DescriptorRenderer implements Renderer<DeclarationDescriptor> {
|
||||
}
|
||||
|
||||
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<DeclarationDescriptor> {
|
||||
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<DeclarationDescriptor> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void appendTypes(StringBuilder result, List<JetType> types) {
|
||||
private void appendTypes(StringBuilder result, List<JetType> types, boolean shortNamesOnly) {
|
||||
for (Iterator<JetType> 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<TypeProjection> typeProjections) {
|
||||
private void appendTypeProjections(StringBuilder result, List<TypeProjection> typeProjections, boolean shortNamesOnly) {
|
||||
for (Iterator<TypeProjection> 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<DeclarationDescriptor> {
|
||||
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 + ")?";
|
||||
|
||||
@@ -34,12 +34,14 @@ import java.util.Set;
|
||||
*/
|
||||
public class ImplementMethodsHandler extends OverrideImplementMethodsHandler implements IntentionAction {
|
||||
|
||||
@Override
|
||||
protected Set<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor) {
|
||||
Set<CallableMemberDescriptor> missingImplementations = Sets.newLinkedHashSet();
|
||||
OverrideResolver.collectMissingImplementations(descriptor, missingImplementations, missingImplementations);
|
||||
return missingImplementations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getChooserTitle() {
|
||||
return "Implement Members";
|
||||
}
|
||||
|
||||
+23
-20
@@ -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<CallableMemberDescriptor> collectMethodsToGenerate(JetClassOrObject classOrObject) {
|
||||
@NotNull
|
||||
public Set<CallableMemberDescriptor> 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<CallableMemberDescriptor> 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<DescriptorClassMember> chooser = showOverrideImplementChooser(project,
|
||||
members.toArray(
|
||||
new DescriptorClassMember[members
|
||||
.size()]));
|
||||
final MemberChooser<DescriptorClassMember> chooser = showOverrideImplementChooser(
|
||||
project,
|
||||
members.toArray(new DescriptorClassMember[members.size()]));
|
||||
|
||||
if (chooser == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.Set;
|
||||
* @author yole
|
||||
*/
|
||||
public class OverrideMethodsHandler extends OverrideImplementMethodsHandler {
|
||||
@Override
|
||||
protected Set<CallableMemberDescriptor> collectMethodsToGenerate(MutableClassDescriptor descriptor) {
|
||||
final Set<CallableMemberDescriptor> 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";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// From KT-1648
|
||||
trait A {
|
||||
val method:() -> Unit?
|
||||
}
|
||||
|
||||
fun some() : A {
|
||||
return object A {<caret>}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// From KT-1648
|
||||
trait A {
|
||||
val method:() -> Unit?
|
||||
}
|
||||
|
||||
fun some() : A {
|
||||
return object A {
|
||||
override val method : () -> Unit? = ?
|
||||
}
|
||||
}
|
||||
@@ -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<CallableMemberDescriptor> 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<CallableMemberDescriptor> descriptors = new ImplementMethodsHandler().collectMethodsToGenerate(classOrObject);
|
||||
|
||||
final ArrayList<CallableMemberDescriptor> descriptorsList = new ArrayList<CallableMemberDescriptor>(descriptors);
|
||||
|
||||
Reference in New Issue
Block a user