Rewrite optimize imports using JetReference#resolveToDescriptors
#KT-4451 Fixed
This commit is contained in:
@@ -375,7 +375,7 @@ private fun PsiElement.isInCopiedArea(fileCopiedFrom: JetFile, startOffsets: Int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DeclarationDescriptor.importableFqName: FqName?
|
public val DeclarationDescriptor.importableFqName: FqName?
|
||||||
get() {
|
get() {
|
||||||
if (this is ConstructorDescriptor) return getContainingDeclaration().importableFqName
|
if (this is ConstructorDescriptor) return getContainingDeclaration().importableFqName
|
||||||
val mayBeUnsafe = DescriptorUtils.getFqName(this)
|
val mayBeUnsafe = DescriptorUtils.getFqName(this)
|
||||||
|
|||||||
@@ -20,24 +20,25 @@ import com.google.common.collect.Lists;
|
|||||||
import com.intellij.lang.ImportOptimizer;
|
import com.intellij.lang.ImportOptimizer;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||||
import com.intellij.psi.*;
|
import com.intellij.psi.PsiElement;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import com.intellij.psi.PsiReference;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
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.ImportPath;
|
import org.jetbrains.jet.lang.resolve.ImportPath;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.jet.lang.resolve.java.JavaResolverPsiUtils;
|
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||||
import org.jetbrains.jet.lang.resolve.name.NamePackage;
|
import org.jetbrains.jet.lang.resolve.name.NamePackage;
|
||||||
|
import org.jetbrains.jet.plugin.codeInsight.CodeInsightPackage;
|
||||||
|
import org.jetbrains.jet.plugin.references.JetReference;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.jetbrains.jet.plugin.quickfix.ImportInsertHelper.needImport;
|
import static org.jetbrains.jet.plugin.quickfix.ImportInsertHelper.needImport;
|
||||||
|
|
||||||
@@ -128,196 +129,25 @@ public class JetImportOptimizer implements ImportOptimizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitReferenceExpression(@NotNull JetReferenceExpression expression) {
|
public void visitJetElement(@NotNull JetElement element) {
|
||||||
if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class) == null &&
|
if (PsiTreeUtil.getParentOfType(element, JetImportDirective.class) != null ||
|
||||||
PsiTreeUtil.getParentOfType(expression, JetPackageDirective.class) == null) {
|
PsiTreeUtil.getParentOfType(element, JetPackageDirective.class) != null) {
|
||||||
|
return;
|
||||||
PsiReference reference = expression.getReference();
|
}
|
||||||
if (reference != null) {
|
PsiReference reference = element.getReference();
|
||||||
List<PsiElement> references = new ArrayList<PsiElement>();
|
if (reference instanceof JetReference) {
|
||||||
PsiElement resolve = reference.resolve();
|
Collection<DeclarationDescriptor> referencedDescriptors = ((JetReference) reference).resolveToDescriptors();
|
||||||
if (resolve != null) {
|
for (DeclarationDescriptor descriptor : referencedDescriptors) {
|
||||||
references.add(resolve);
|
FqName importableFqName = CodeInsightPackage.getImportableFqName(descriptor);
|
||||||
}
|
if (importableFqName != null) {
|
||||||
|
usedQualifiedNames.add(importableFqName);
|
||||||
if (references.isEmpty() && reference instanceof PsiPolyVariantReference) {
|
|
||||||
for (ResolveResult resolveResult : ((PsiPolyVariantReference)reference).multiResolve(true)) {
|
|
||||||
references.add(resolveResult.getElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (PsiElement psiReference : references) {
|
|
||||||
FqName fqName = getElementUsageFQName(psiReference);
|
|
||||||
if (fqName != null) {
|
|
||||||
usedQualifiedNames.add(fqName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
super.visitJetElement(element);
|
||||||
super.visitReferenceExpression(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitForExpression(@NotNull JetForExpression expression) {
|
|
||||||
BindingContext context = AnalyzerFacadeWithCache.getContextForElement(expression);
|
|
||||||
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, expression.getLoopRange());
|
|
||||||
addResolvedCallFqName(resolvedCall);
|
|
||||||
|
|
||||||
super.visitForExpression(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitMultiDeclaration(@NotNull JetMultiDeclaration declaration) {
|
|
||||||
BindingContext context = AnalyzerFacadeWithCache.getContextForElement(declaration);
|
|
||||||
List<JetMultiDeclarationEntry> entries = declaration.getEntries();
|
|
||||||
for (JetMultiDeclarationEntry entry : entries) {
|
|
||||||
ResolvedCall<FunctionDescriptor> resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry);
|
|
||||||
addResolvedCallFqName(resolvedCall);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.visitMultiDeclaration(declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addResolvedCallFqName(@Nullable ResolvedCall resolvedCall) {
|
|
||||||
if (resolvedCall != null) {
|
|
||||||
CallableDescriptor resultingDescriptor = resolvedCall.getResultingDescriptor();
|
|
||||||
usedQualifiedNames.add(DescriptorUtils.getFqNameSafe(resultingDescriptor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return usedQualifiedNames;
|
return usedQualifiedNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static FqName getElementUsageFQName(PsiElement element) {
|
|
||||||
if (element instanceof JetFile) {
|
|
||||||
return JetPsiUtil.getFQName((JetFile) element);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element instanceof JetSimpleNameExpression) {
|
|
||||||
JetPackageDirective packageDirective = PsiTreeUtil.getParentOfType(element, JetPackageDirective.class);
|
|
||||||
if (packageDirective != null) {
|
|
||||||
List<JetSimpleNameExpression> simpleNameExpressions = PsiTreeUtil.getChildrenOfTypeAsList(packageDirective, JetSimpleNameExpression.class);
|
|
||||||
FqName fqName = null;
|
|
||||||
for (JetSimpleNameExpression nameExpression : simpleNameExpressions) {
|
|
||||||
Name referencedName = nameExpression.getReferencedNameAsName();
|
|
||||||
if (fqName == null) {
|
|
||||||
fqName = new FqName(referencedName.asString());
|
|
||||||
} else {
|
|
||||||
fqName = fqName.child(referencedName);
|
|
||||||
}
|
|
||||||
if (nameExpression.equals(element)) {
|
|
||||||
return fqName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element instanceof JetNamedDeclaration) {
|
|
||||||
return JetPsiUtil.getFQName((JetNamedDeclaration) element);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element instanceof PsiClass) {
|
|
||||||
String qualifiedName = ((PsiClass) element).getQualifiedName();
|
|
||||||
if (qualifiedName != null) {
|
|
||||||
return new FqName(qualifiedName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element instanceof PsiField) {
|
|
||||||
PsiField field = (PsiField) element;
|
|
||||||
|
|
||||||
FqName classFQN = getFqNameOfContainingClassForPsiMember(field);
|
|
||||||
if (classFQN == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return combineClassFqNameWithMemberName(field.getContainingClass(), classFQN, field.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Still problem with kotlin global properties imported from class files
|
|
||||||
if (element instanceof PsiMethod) {
|
|
||||||
PsiMethod method = (PsiMethod) element;
|
|
||||||
|
|
||||||
FqName classFQN = getFqNameOfContainingClassForPsiMember(method);
|
|
||||||
if (classFQN == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (method.isConstructor()) {
|
|
||||||
return classFQN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return combineClassFqNameWithMemberName(method.getContainingClass(), classFQN, method.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element instanceof PsiPackage) {
|
|
||||||
return new FqName(((PsiPackage) element).getQualifiedName());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static FqName combineClassFqNameWithMemberName(PsiClass containingClass, FqName classFQN, String memberName) {
|
|
||||||
if (memberName == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (JavaResolverPsiUtils.isCompiledKotlinPackageClass(containingClass)) {
|
|
||||||
return classFQN.parent().child(Name.identifier(memberName));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return classFQN.child(Name.identifier(memberName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static FqName getFqNameOfContainingClassForPsiMember(PsiMember member) {
|
|
||||||
PsiClass containingClass = member.getContainingClass();
|
|
||||||
if (containingClass != null) {
|
|
||||||
String classFQNStr = containingClass.getQualifiedName();
|
|
||||||
if (classFQNStr != null) {
|
|
||||||
return new FqName(classFQNStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PsiElement getWithPreviousWhitespaces(PsiElement element) {
|
|
||||||
PsiElement result = element;
|
|
||||||
|
|
||||||
PsiElement siblingIterator = element.getPrevSibling();
|
|
||||||
while (siblingIterator != null) {
|
|
||||||
if (siblingIterator.getNode().getElementType() != TokenType.WHITE_SPACE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = siblingIterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
siblingIterator = siblingIterator.getPrevSibling();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PsiElement getWithFollowedWhitespaces(PsiElement element) {
|
|
||||||
PsiElement result = element;
|
|
||||||
|
|
||||||
PsiElement siblingIterator = element.getNextSibling();
|
|
||||||
while (siblingIterator != null) {
|
|
||||||
if (siblingIterator.getNode().getElementType() != TokenType.WHITE_SPACE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result = siblingIterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
siblingIterator = siblingIterator.getNextSibling();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user