diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 5ebff0f781e..7ca4410b790 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -61,6 +61,7 @@ public interface BindingContext { WritableSlice AUTOCAST = Slices.createSimpleSlice(); /** A scope where type of expression has been resolved */ + WritableSlice TYPE_RESOLUTION_SCOPE = Slices.createSimpleSlice(); WritableSlice RESOLUTION_SCOPE = Slices.createSimpleSlice(); /** Collected during analyze, used in IDE in auto-cast completion */ diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java index 8c17ffb46ba..1b5ed4faee3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/TypeResolver.java @@ -69,6 +69,7 @@ public class TypeResolver { JetTypeElement typeElement = typeReference.getTypeElement(); JetType type = resolveTypeElement(scope, annotations, typeElement, false, trace, checkBounds); trace.record(BindingContext.TYPE, typeReference, type); + trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference, scope); return type; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 8fd10ab9ae9..8be063268e3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -472,6 +472,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (result != null) { context.trace.record(BindingContext.EXPRESSION_TYPE, expression.getInstanceReference(), result); context.trace.record(BindingContext.REFERENCE_TARGET, expression.getInstanceReference(), result.getConstructor().getDeclarationDescriptor()); + if (superTypeQualifier != null) { + context.trace.record(BindingContext.TYPE_RESOLUTION_SCOPE, superTypeQualifier, context.scope); + } } } return DataFlowUtils.checkType(result, expression, context); diff --git a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java index 0e348a4d6fd..d9652d18a31 100644 --- a/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java +++ b/idea/src/org/jetbrains/jet/plugin/codeInsight/OverrideImplementMethodsHandler.java @@ -33,6 +33,8 @@ import org.jetbrains.annotations.Nullable; 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.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.JetStandardClasses; import org.jetbrains.jet.lang.types.lang.JetStandardLibrary; @@ -81,11 +83,80 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns return; } - for (JetElement element : generateOverridingMembers(selectedElements, (JetFile)classOrObject.getContainingFile(), false)) { - afterAnchor = body.addAfter(element, afterAnchor); + List elementsToCompact = new ArrayList(); + final JetFile file = (JetFile)classOrObject.getContainingFile(); + for (JetElement element : generateOverridingMembers(selectedElements, file)) { + PsiElement added = body.addAfter(element, afterAnchor); + afterAnchor = added; + elementsToCompact.add((JetElement)added); + } + compactReferenceToClasses(elementsToCompact); + } + + private static void compactReferenceToClasses(List elementsToCompact) { + if (elementsToCompact.isEmpty()) { + return; + } + final JetFile file = (JetFile) elementsToCompact.get(0).getContainingFile(); + final BindingContext bc = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file).getBindingContext(); + for (JetElement element : elementsToCompact) { + element.accept(new JetVisitorVoid() { + @Override + public void visitJetElement(JetElement element) { + element.acceptChildren(this); + } + + @Override + public void visitTypeReference(JetTypeReference typeReference) { + super.visitTypeReference(typeReference); + + JetTypeElement typeElement = typeReference.getTypeElement(); + if (typeElement instanceof JetNullableType) { + typeElement = ((JetNullableType) typeElement).getInnerType(); + } + if (typeElement instanceof JetUserType) { + JetUserType userType = (JetUserType) typeElement; + DeclarationDescriptor target = bc.get(BindingContext.REFERENCE_TARGET, + userType.getReferenceExpression()); + if (target instanceof ClassDescriptor) { + ClassDescriptor targetClass = (ClassDescriptor) target; + ClassDescriptor targetTopLevelClass = ImportInsertHelper.getTopLevelClass(targetClass); + + JetScope scope = bc.get(BindingContext.TYPE_RESOLUTION_SCOPE, typeReference); + ClassifierDescriptor classifier = scope.getClassifier(targetTopLevelClass.getName()); + if (targetTopLevelClass == classifier) { + compactReferenceToClass(userType, targetClass); + } + else if (classifier == null) { + ImportInsertHelper.addImportDirective(DescriptorUtils.getFQName(targetTopLevelClass).toSafe(), file); + compactReferenceToClass(userType, targetClass); + } + else { + // leave FQ name + } + } + } + } + + private void compactReferenceToClass(JetUserType userType, ClassDescriptor targetClass) { + if (targetClass == JetStandardClasses.getUnitType().getConstructor().getDeclarationDescriptor()) { + // do not replace "Unit" with "Tuple0" + return; + } + String name = targetClass.getName(); + DeclarationDescriptor parent = targetClass.getContainingDeclaration(); + while (parent instanceof ClassDescriptor) { + name = parent.getName() + "." + name; + parent = parent.getContainingDeclaration(); + } + JetTypeArgumentList typeArgumentList = userType.getTypeArgumentList(); + userType.replace(JetPsiFactory.createType(userType.getProject(), name + (typeArgumentList == null ? "" : typeArgumentList.getText()))); + } + }); } } + @Nullable private static PsiElement findInsertAfterAnchor(Editor editor, final JetClassBody body) { PsiElement afterAnchor = body.getLBrace(); @@ -109,21 +180,21 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns return afterAnchor; } - private static List generateOverridingMembers(List selectedElements, JetFile file, boolean fqNames) { + private static List generateOverridingMembers(List selectedElements, JetFile file) { List overridingMembers = new ArrayList(); for (DescriptorClassMember selectedElement : selectedElements) { final DeclarationDescriptor descriptor = selectedElement.getDescriptor(); if (descriptor instanceof SimpleFunctionDescriptor) { - overridingMembers.add(overrideFunction(file.getProject(), file, (SimpleFunctionDescriptor)descriptor, fqNames)); + overridingMembers.add(overrideFunction(file.getProject(), (SimpleFunctionDescriptor)descriptor)); } else if (descriptor instanceof PropertyDescriptor) { - overridingMembers.add(overrideProperty(file.getProject(), file, (PropertyDescriptor)descriptor, fqNames)); + overridingMembers.add(overrideProperty(file.getProject(), (PropertyDescriptor)descriptor)); } } return overridingMembers; } - private static JetElement overrideProperty(Project project, JetFile file, PropertyDescriptor descriptor, boolean fqNames) { + private static JetElement overrideProperty(Project project, PropertyDescriptor descriptor) { StringBuilder bodyBuilder = new StringBuilder(); bodyBuilder.append(displayableVisibility(descriptor)).append("override "); if (descriptor.isVar()) { @@ -134,7 +205,6 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns } bodyBuilder.append(descriptor.getName()).append(" : ").append(DescriptorRenderer.COMPACT.renderTypeWithShortNames( descriptor.getType())); - ImportInsertHelper.addImportDirectivesIfNeeded(descriptor.getType(), file); String initializer = defaultInitializer(descriptor.getType(), JetStandardLibrary.getInstance()); if (initializer != null) { bodyBuilder.append(" = ").append(initializer); @@ -145,7 +215,11 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns return JetPsiFactory.createProperty(project, bodyBuilder.toString()); } - private static JetElement overrideFunction(Project project, JetFile file, SimpleFunctionDescriptor descriptor, boolean fqNames) { + private static String renderType(JetType type) { + return DescriptorRenderer.TEXT.renderType(type); + } + + private static JetElement overrideFunction(Project project, SimpleFunctionDescriptor descriptor) { StringBuilder bodyBuilder = new StringBuilder(); bodyBuilder.append(displayableVisibility(descriptor)); bodyBuilder.append("override fun "); @@ -164,7 +238,7 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns if (!upperBounds.isEmpty()) { boolean firstUpperBound = true; for (JetType upperBound : upperBounds) { - String upperBoundText = " : " + DescriptorRenderer.TEXT.renderTypeWithShortNames(upperBound); + String upperBoundText = " : " + renderType(upperBound); if (upperBound != JetStandardClasses.getDefaultBound()) { if (firstUpperBound) { bodyBuilder.append(upperBoundText); @@ -172,7 +246,6 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns whereRestrictions.add(param.getName() + upperBoundText); } } - ImportInsertHelper.addImportDirectivesIfNeeded(upperBound, file); firstUpperBound = false; } } @@ -202,9 +275,7 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns first = false; bodyBuilder.append(parameterDescriptor.getName()); bodyBuilder.append(" : "); - bodyBuilder.append(DescriptorRenderer.TEXT.renderTypeWithShortNames(parameterDescriptor.getType())); - - ImportInsertHelper.addImportDirectivesIfNeeded(parameterDescriptor.getType(), file); + bodyBuilder.append(renderType(parameterDescriptor.getType())); if (!isAbstractFun) { delegationBuilder.append(parameterDescriptor.getName()); @@ -219,8 +290,7 @@ public abstract class OverrideImplementMethodsHandler implements LanguageCodeIns boolean returnsNotUnit = returnType != null && !stdlib.getTuple0Type().equals(returnType); if (returnsNotUnit) { - bodyBuilder.append(" : ").append(DescriptorRenderer.TEXT.renderTypeWithShortNames(returnType)); - ImportInsertHelper.addImportDirectivesIfNeeded(returnType, file); + bodyBuilder.append(" : ").append(renderType(returnType)); } if (!whereRestrictions.isEmpty()) { bodyBuilder.append("\n").append("where ").append(StringUtil.join(whereRestrictions, ", ")); diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java index 6e5a16b837e..de4c45cb2fe 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/ImportInsertHelper.java @@ -181,7 +181,7 @@ public class ImportInsertHelper { return true; } - private static ClassDescriptor getTopLevelClass(ClassDescriptor classDescriptor) { + public static ClassDescriptor getTopLevelClass(ClassDescriptor classDescriptor) { while (true) { DeclarationDescriptor parent = classDescriptor.getContainingDeclaration(); if (parent instanceof ClassDescriptor) {