KT-2849 Object that are not imported do not show up in completion

#KT-2849 Fixed
This commit is contained in:
Nikolay Krasko
2012-11-09 14:33:45 +04:00
parent cb602496e3
commit aca747390b
15 changed files with 181 additions and 18 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.jet.plugin.caches; package org.jetbrains.jet.plugin.caches;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.psi.*; import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex; import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
@@ -24,10 +25,13 @@ import com.intellij.psi.impl.java.stubs.index.JavaMethodNameIndex;
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.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import jet.runtime.typeinfo.JetClass;
import jet.runtime.typeinfo.JetValueParameter; import jet.runtime.typeinfo.JetValueParameter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation;
import org.jetbrains.jet.lang.resolve.java.kt.JetValueParameterAnnotation; import org.jetbrains.jet.lang.resolve.java.kt.JetValueParameterAnnotation;
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;
@@ -75,6 +79,25 @@ class JetFromJavaDescriptorHelper {
return result; return result;
} }
static Collection<PsiClass> getCompiledClassesForTopLevelObjects(Project project, GlobalSearchScope scope) {
Set<PsiClass> jetObjectClasses = Sets.newHashSet();
Collection<PsiAnnotation> annotations = JavaAnnotationIndex.getInstance().get(JetClass.class.getSimpleName(), project, scope);
for (PsiAnnotation annotation : annotations) {
PsiModifierList modifierList = (PsiModifierList)annotation.getParent();
final PsiElement owner = modifierList.getParent();
if (owner instanceof PsiClass) {
PsiClass psiClass = (PsiClass) owner;
JetClassAnnotation jetAnnotation = JetClassAnnotation.get(psiClass);
if (psiClass.getContainingClass() == null && jetAnnotation.kind() == JvmStdlibNames.FLAG_CLASS_KIND_OBJECT) {
jetObjectClasses.add(psiClass);
}
}
}
return jetObjectClasses;
}
static Collection<String> getTopExtensionFunctionNames(Project project, GlobalSearchScope scope) { static Collection<String> getTopExtensionFunctionNames(Project project, GlobalSearchScope scope) {
// Extension function should have an parameter of type JetValueParameter with explicit receiver parameter. // Extension function should have an parameter of type JetValueParameter with explicit receiver parameter.
@@ -16,6 +16,8 @@
package org.jetbrains.jet.plugin.caches; package org.jetbrains.jet.plugin.caches;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Condition;
@@ -27,6 +29,7 @@ import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet; import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
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.*;
@@ -41,10 +44,7 @@ import org.jetbrains.jet.lang.resolve.name.Name;
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;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
import org.jetbrains.jet.plugin.stubindex.JetExtensionFunctionNameIndex; import org.jetbrains.jet.plugin.stubindex.*;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetShortClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetShortFunctionNameIndex;
import java.util.*; import java.util.*;
@@ -123,7 +123,56 @@ public class JetShortNamesCache extends PsiShortNamesCache {
return functionNames; return functionNames;
} }
// TODO: Make it work for properties @NotNull
public Collection<String> getAllTopLevelObjectNames() {
Set<String> topObjectNames = new HashSet<String>();
topObjectNames.addAll(JetTopLevelShortObjectNameIndex.getInstance().getAllKeys(project));
Collection<PsiClass> classObjects = JetFromJavaDescriptorHelper.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project));
topObjectNames.addAll(Collections2.transform(classObjects, new Function<PsiClass, String>() {
@Override
public String apply(@Nullable PsiClass aClass) {
assert aClass != null;
return aClass.getName();
}
}));
return topObjectNames;
}
@NotNull
public Collection<ClassDescriptor> getTopLevelObjectsByName(
@NotNull String name,
@NotNull JetSimpleNameExpression expression,
@NotNull ResolveSession resolveSession,
@NotNull GlobalSearchScope scope
) {
BindingContext context = ResolveSessionUtils.resolveToExpression(resolveSession, expression);
JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (jetScope == null) {
return Collections.emptyList();
}
Set<ClassDescriptor> result = Sets.newHashSet();
Collection<JetObjectDeclaration> topObjects = JetTopLevelShortObjectNameIndex.getInstance().get(name, project, scope);
for (JetObjectDeclaration objectDeclaration : topObjects) {
result.add(resolveSession.getClassDescriptor(objectDeclaration));
}
for (PsiClass psiClass : JetFromJavaDescriptorHelper
.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project))) {
String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName != null) {
FqName fqName = new FqName(qualifiedName);
result.addAll(ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession, fqName));
}
}
return result;
}
@NotNull @NotNull
public Collection<FunctionDescriptor> getTopLevelFunctionDescriptorsByName( public Collection<FunctionDescriptor> getTopLevelFunctionDescriptorsByName(
@NotNull String name, @NotNull String name,
@@ -190,6 +190,7 @@ public class JetCompletionContributor extends CompletionContributor {
if (shouldRunTopLevelCompletion()) { if (shouldRunTopLevelCompletion()) {
JetTypesCompletionHelper.addJetTypes(parameters, jetResult); JetTypesCompletionHelper.addJetTypes(parameters, jetResult);
addJetTopLevelFunctions(); addJetTopLevelFunctions();
addJetTopLevelObjects();
} }
if (shouldRunExtensionsCompletion()) { if (shouldRunExtensionsCompletion()) {
@@ -214,9 +215,17 @@ public class JetCompletionContributor extends CompletionContributor {
} }
public static boolean isPartOfTypeDeclaration(@NotNull DeclarationDescriptor descriptor) { public static boolean isPartOfTypeDeclaration(@NotNull DeclarationDescriptor descriptor) {
return (descriptor instanceof ClassDescriptor) || if (descriptor instanceof NamespaceDescriptor || descriptor instanceof TypeParameterDescriptor) {
(descriptor instanceof NamespaceDescriptor) || return true;
(descriptor instanceof TypeParameterDescriptor); }
if (descriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
ClassKind kind = classDescriptor.getKind();
return !(kind == ClassKind.OBJECT || kind == ClassKind.CLASS_OBJECT);
}
return false;
} }
private void addJetTopLevelFunctions() { private void addJetTopLevelFunctions() {
@@ -236,6 +245,18 @@ public class JetCompletionContributor extends CompletionContributor {
} }
} }
private void addJetTopLevelObjects() {
JetShortNamesCache namesCache = JetCacheManager.getInstance(getPosition().getProject()).getNamesCache();
GlobalSearchScope scope = GlobalSearchScope.allScope(getPosition().getProject());
Collection<String> objectNames = namesCache.getAllTopLevelObjectNames();
for (String name : objectNames) {
if (jetResult.getResult().getPrefixMatcher().prefixMatches(name)) {
jetResult.addAllElements(namesCache.getTopLevelObjectsByName(name, jetReference.getExpression(), getResolveSession(), scope));
}
}
}
private boolean shouldRunOnlyTypeCompletion() { private boolean shouldRunOnlyTypeCompletion() {
// Check that completion in the type annotation context and if there's a qualified // Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it // expression we are at first of it
@@ -91,12 +91,13 @@ public class JetTypesCompletionHelper {
} }
if (DecompiledDataFactory.isCompiledFromKotlin(aClass)) { if (DecompiledDataFactory.isCompiledFromKotlin(aClass)) {
// TODO: Filter classes for compiled kotlin objects if (!DecompiledDataFactory.isKotlinObject(aClass)) {
String qualifiedName = aClass.getQualifiedName(); String qualifiedName = aClass.getQualifiedName();
if (qualifiedName != null) { if (qualifiedName != null) {
FqName fqName = new FqName(qualifiedName); FqName fqName = new FqName(qualifiedName);
jetCompletionResult.addAllElements( jetCompletionResult.addAllElements(
ResolveSessionUtils.getClassDescriptorsByFqName(jetCompletionResult.getResolveSession(), fqName)); ResolveSessionUtils.getClassDescriptorsByFqName(jetCompletionResult.getResolveSession(), fqName));
}
} }
return true; return true;
@@ -35,6 +35,8 @@ import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule; import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule;
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver; import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.lang.resolve.java.kt.JetClassAnnotation;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.resolve.DescriptorRenderer; import org.jetbrains.jet.resolve.DescriptorRenderer;
@@ -214,4 +216,8 @@ public class DecompiledDataFactory {
public static boolean isCompiledFromKotlin(@NotNull PsiClass psiClass) { public static boolean isCompiledFromKotlin(@NotNull PsiClass psiClass) {
return isKotlinClass(psiClass) || isKotlinNamespaceClass(psiClass); return isKotlinClass(psiClass) || isKotlinNamespaceClass(psiClass);
} }
public static boolean isKotlinObject(PsiClass aClass) {
return JetClassAnnotation.get(aClass).kind() == JvmStdlibNames.FLAG_CLASS_KIND_OBJECT;
}
} }
@@ -24,10 +24,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.DefaultModuleConfiguration; import org.jetbrains.jet.lang.DefaultModuleConfiguration;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; 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.psi.JetFile; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetImportDirective;
import org.jetbrains.jet.lang.psi.JetPsiFactory;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.DescriptorUtils;
@@ -101,6 +98,12 @@ public class ImportInsertHelper {
} }
} }
if (!same) {
if (target instanceof JetObjectDeclarationName) {
same = file.getManager().areElementsEquivalent(target.getParent(), targetElement);
}
}
if (!same) { if (!same) {
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
TextRange refRange = reference.getElement().getTextRange(); TextRange refRange = reference.getElement().getTextRange();
@@ -0,0 +1,8 @@
object NamedObject
fun test() {
val a : Named<caret>
}
// TIMES: 2
// ABSENT: NamedObject
@@ -0,0 +1,9 @@
package first
fun testFun() {
NamedObject<caret>
}
// EXIST: NamedObjectTopLevel1, NamedObjectTopLevel2
// ABSENT: NamedObjectInClassObject
// ABSENT: NamedObjectInFun
@@ -0,0 +1,14 @@
package test
object NamedObjectTopLevel1
object NamedObjectTopLevel2
fun some() {
object NamedObjectInFun
}
class Some {
class object {
NamedObjectInClassObject
}
}
@@ -0,0 +1,7 @@
package some
import test.SomeTestObject
fun test() {
SomeTestObject<caret>
}
@@ -0,0 +1,3 @@
package test
object SomeTestObject
@@ -0,0 +1,7 @@
package some
import test.SomeTestObject
fun test() {
SomeTestObject<caret>
}
@@ -213,6 +213,10 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
doTest(); doTest();
} }
public void testNoObjectInTypePosition() {
doTest();
}
public void testNoTopLevelCompletionInQualifiedUserTypes() { public void testNoTopLevelCompletionInQualifiedUserTypes() {
doTest(); doTest();
} }
@@ -56,6 +56,10 @@ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase
doFileTest(2); doFileTest(2);
} }
public void testNotImportedObject() throws Exception {
doFileTest();
}
@Override @Override
protected String getTestDataPath() { protected String getTestDataPath() {
return PluginTestCaseBase.getTestDataPathBase() + "/completion/basic/multifile/"; return PluginTestCaseBase.getTestDataPathBase() + "/completion/basic/multifile/";
@@ -30,6 +30,10 @@ public class CompletionMultifileHandlerTest extends CompletionTestCase {
doTest(); doTest();
} }
public void testImportAlreadyImportedObject() throws Exception {
doTest();
}
public void testJetClassCompletionImport() throws Exception { public void testJetClassCompletionImport() throws Exception {
doTest(); doTest();
} }