KT-1808 Auto import offers private static Java classes
#KT-1808 fixed
This commit is contained in:
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.jet.plugin.caches;
|
package org.jetbrains.jet.plugin.caches;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.Condition;
|
import com.intellij.openapi.util.Condition;
|
||||||
@@ -36,7 +35,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.jet.asJava.JavaElementFinder;
|
import org.jetbrains.jet.asJava.JavaElementFinder;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.*;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.ImportPath;
|
||||||
|
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
@@ -48,7 +50,6 @@ import org.jetbrains.jet.plugin.stubindex.JetExtensionFunctionNameIndex;
|
|||||||
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
|
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
|
||||||
import org.jetbrains.jet.plugin.stubindex.JetShortClassNameIndex;
|
import org.jetbrains.jet.plugin.stubindex.JetShortClassNameIndex;
|
||||||
import org.jetbrains.jet.plugin.stubindex.JetShortFunctionNameIndex;
|
import org.jetbrains.jet.plugin.stubindex.JetShortFunctionNameIndex;
|
||||||
import org.jetbrains.jet.util.QualifiedNamesUtil;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -93,7 +94,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
|||||||
List<PsiClass> result = new ArrayList<PsiClass>();
|
List<PsiClass> result = new ArrayList<PsiClass>();
|
||||||
|
|
||||||
for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) {
|
for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) {
|
||||||
if (QualifiedNamesUtil.fqnToShortName(new FqName(fqName)).getName().equals(name)) {
|
if ((new FqName(fqName)).shortName().getName().equals(name)) {
|
||||||
PsiClass psiClass = javaElementFinder.findClass(fqName, scope);
|
PsiClass psiClass = javaElementFinder.findClass(fqName, scope);
|
||||||
if (psiClass != null) {
|
if (psiClass != null) {
|
||||||
result.add(psiClass);
|
result.add(psiClass);
|
||||||
@@ -129,17 +130,6 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
|||||||
return standardTypes;
|
return standardTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Collection<FqName> getFQNamesByName(@NotNull final String name, JetFile file, @NotNull GlobalSearchScope scope) {
|
|
||||||
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(file).getBindingContext();
|
|
||||||
return Collections2.filter(context.getKeys(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR), new Predicate<FqName>() {
|
|
||||||
@Override
|
|
||||||
public boolean apply(@Nullable FqName fqName) {
|
|
||||||
return fqName != null && QualifiedNamesUtil.isShortNameForFQN(name, fqName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get jet non-extension top-level function names. Method is allowed to give invalid names - all result should be
|
* Get jet non-extension top-level function names. Method is allowed to give invalid names - all result should be
|
||||||
* checked with getTopLevelFunctionDescriptorsByName().
|
* checked with getTopLevelFunctionDescriptorsByName().
|
||||||
|
|||||||
@@ -30,28 +30,32 @@ import com.intellij.openapi.editor.Editor;
|
|||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.Condition;
|
import com.intellij.openapi.util.Condition;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
import com.intellij.psi.PsiMember;
|
||||||
|
import com.intellij.psi.PsiModifier;
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope;
|
||||||
import com.intellij.psi.search.PsiShortNamesCache;
|
import com.intellij.psi.search.PsiShortNamesCache;
|
||||||
import com.intellij.util.IncorrectOperationException;
|
import com.intellij.util.IncorrectOperationException;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.asJava.JetLightClass;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.Visibilities;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
|
||||||
import org.jetbrains.jet.lang.resolve.ImportPath;
|
import org.jetbrains.jet.lang.resolve.ImportPath;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.plugin.JetBundle;
|
import org.jetbrains.jet.plugin.JetBundle;
|
||||||
import org.jetbrains.jet.plugin.JetFileType;
|
|
||||||
import org.jetbrains.jet.plugin.actions.JetAddImportAction;
|
import org.jetbrains.jet.plugin.actions.JetAddImportAction;
|
||||||
import org.jetbrains.jet.plugin.caches.JetCacheManager;
|
import org.jetbrains.jet.plugin.caches.JetCacheManager;
|
||||||
import org.jetbrains.jet.plugin.caches.JetShortNamesCache;
|
import org.jetbrains.jet.plugin.caches.JetShortNamesCache;
|
||||||
|
import org.jetbrains.jet.plugin.project.WholeProjectAnalyzerFacade;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -101,7 +105,9 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection<FqName> getJetTopLevelFunctions(@NotNull String referenceName, JetSimpleNameExpression expression, @NotNull Project project) {
|
private static Collection<FqName> getJetTopLevelFunctions(@NotNull String referenceName,
|
||||||
|
JetSimpleNameExpression expression,
|
||||||
|
@NotNull Project project) {
|
||||||
JetShortNamesCache namesCache = JetCacheManager.getInstance(project).getNamesCache();
|
JetShortNamesCache namesCache = JetCacheManager.getInstance(project).getNamesCache();
|
||||||
Collection<FunctionDescriptor> topLevelFunctions = namesCache.getTopLevelFunctionDescriptorsByName(
|
Collection<FunctionDescriptor> topLevelFunctions = namesCache.getTopLevelFunctionDescriptorsByName(
|
||||||
referenceName,
|
referenceName,
|
||||||
@@ -148,33 +154,58 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
|
|||||||
public static Collection<FqName> getClassNames(@NotNull String referenceName, @NotNull JetFile file) {
|
public static Collection<FqName> getClassNames(@NotNull String referenceName, @NotNull JetFile file) {
|
||||||
final GlobalSearchScope scope = GlobalSearchScope.allScope(file.getProject());
|
final GlobalSearchScope scope = GlobalSearchScope.allScope(file.getProject());
|
||||||
Set<FqName> possibleResolveNames = Sets.newHashSet();
|
Set<FqName> possibleResolveNames = Sets.newHashSet();
|
||||||
possibleResolveNames.addAll(JetCacheManager.getInstance(file.getProject()).getNamesCache().getFQNamesByName(referenceName, file, scope));
|
|
||||||
possibleResolveNames.addAll(getJavaClasses(referenceName, file.getProject(), scope));
|
possibleResolveNames.addAll(getJavaClasses(referenceName, file.getProject(), scope));
|
||||||
|
|
||||||
// TODO: Do appropriate sorting
|
// TODO: Do appropriate sorting
|
||||||
return Lists.newArrayList(possibleResolveNames);
|
return Lists.newArrayList(possibleResolveNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Collection<FqName> getJavaClasses(@NotNull final String typeName, @NotNull Project project, final GlobalSearchScope scope) {
|
private static Collection<FqName> getJavaClasses(@NotNull final String typeName,
|
||||||
|
@NotNull Project project,
|
||||||
|
final GlobalSearchScope scope) {
|
||||||
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
|
PsiShortNamesCache cache = PsiShortNamesCache.getInstance(project);
|
||||||
|
|
||||||
PsiClass[] classes = cache.getClassesByName(typeName, new DelegatingGlobalSearchScope(scope) {
|
PsiClass[] classes = cache.getClassesByName(typeName, scope);
|
||||||
|
|
||||||
|
Collection<PsiClass> accessibleClasses = Collections2.filter(Lists.newArrayList(classes), new Predicate<PsiClass>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(@NotNull VirtualFile file) {
|
public boolean apply(PsiClass psiClass) {
|
||||||
return myBaseScope.contains(file) && file.getFileType() != JetFileType.INSTANCE;
|
assert psiClass != null;
|
||||||
|
return isAccessible(psiClass);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Collections2.transform(Lists.newArrayList(classes), new Function<PsiClass, FqName>() {
|
return Collections2.transform(accessibleClasses, new Function<PsiClass, FqName>() {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public FqName apply(@Nullable PsiClass javaClass) {
|
public FqName apply(@Nullable PsiClass javaClass) {
|
||||||
assert javaClass != null;
|
assert javaClass != null;
|
||||||
return new FqName(javaClass.getQualifiedName());
|
String qualifiedName = javaClass.getQualifiedName();
|
||||||
|
assert qualifiedName != null;
|
||||||
|
return new FqName(qualifiedName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isAccessible(PsiMember member) {
|
||||||
|
if (member instanceof JetLightClass) {
|
||||||
|
// TODO: Now light class can't losing accessibility information
|
||||||
|
JetLightClass lightClass = (JetLightClass) member;
|
||||||
|
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile((JetFile) lightClass.getContainingFile()).getBindingContext();
|
||||||
|
ClassDescriptor descriptor = context.get(BindingContext.FQNAME_TO_CLASS_DESCRIPTOR, lightClass.getFqName());
|
||||||
|
|
||||||
|
if (descriptor != null) {
|
||||||
|
return descriptor.getVisibility() == Visibilities.PUBLIC || descriptor.getVisibility() == Visibilities.INTERNAL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert false : "Descriptor of the class isn't found in the binding context";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return member.hasModifierProperty(PsiModifier.PUBLIC) || member.hasModifierProperty(PsiModifier.PROTECTED);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean showHint(@NotNull Editor editor) {
|
public boolean showHint(@NotNull Editor editor) {
|
||||||
if (suggestions.isEmpty()) {
|
if (suggestions.isEmpty()) {
|
||||||
@@ -220,7 +251,8 @@ public class ImportClassAndFunFix extends JetHintAction<JetSimpleNameExpression>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(@NotNull final Project project, @NotNull final Editor editor, final PsiFile file) throws IncorrectOperationException {
|
public void invoke(@NotNull final Project project, @NotNull final Editor editor, final PsiFile file)
|
||||||
|
throws IncorrectOperationException {
|
||||||
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
|
CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// "Import Class" "false"
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
PrivateClass
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// "Import" "false"
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
<caret>PrivateClass
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package sometest
|
||||||
|
|
||||||
|
private class PrivateClass
|
||||||
@@ -38,6 +38,10 @@ public class AutoImportFixTest extends JetQuickFixMultiFileTest {
|
|||||||
doTest();
|
doTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testNoImportForPrivateClass() throws Exception {
|
||||||
|
doTest();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getCheckFileName() {
|
protected String getCheckFileName() {
|
||||||
return getTestName(true) + ".after.kt";
|
return getTestName(true) + ".after.kt";
|
||||||
|
|||||||
Reference in New Issue
Block a user