Implemented compacting type names and adding valid imports in override/implements handler.

#KT-1602 fixed
This commit is contained in:
Evgeny Gerashchenko
2012-05-02 13:47:21 +04:00
parent 298d98ee12
commit 2fcc7b0cbb
5 changed files with 91 additions and 16 deletions
@@ -61,6 +61,7 @@ public interface BindingContext {
WritableSlice<JetExpression, JetType> AUTOCAST = Slices.createSimpleSlice();
/** A scope where type of expression has been resolved */
WritableSlice<JetTypeReference, JetScope> TYPE_RESOLUTION_SCOPE = Slices.createSimpleSlice();
WritableSlice<JetExpression, JetScope> RESOLUTION_SCOPE = Slices.createSimpleSlice();
/** Collected during analyze, used in IDE in auto-cast completion */
@@ -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;
}
@@ -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);
@@ -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<JetElement> elementsToCompact = new ArrayList<JetElement>();
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<JetElement> 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<JetElement> generateOverridingMembers(List<DescriptorClassMember> selectedElements, JetFile file, boolean fqNames) {
private static List<JetElement> generateOverridingMembers(List<DescriptorClassMember> selectedElements, JetFile file) {
List<JetElement> overridingMembers = new ArrayList<JetElement>();
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, ", "));
@@ -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) {