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;
import com.google.common.base.Predicate;
import com.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
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.PsiShortNamesCache;
import com.intellij.psi.util.PsiTreeUtil;
import jet.runtime.typeinfo.JetClass;
import jet.runtime.typeinfo.JetValueParameter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -74,6 +78,25 @@ class JetFromJavaDescriptorHelper {
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) {
@@ -16,6 +16,8 @@
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.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
@@ -27,6 +29,7 @@ import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.JavaElementFinder;
import org.jetbrains.jet.lang.descriptors.*;
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.types.JetType;
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
import org.jetbrains.jet.plugin.stubindex.JetExtensionFunctionNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetFullClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetShortClassNameIndex;
import org.jetbrains.jet.plugin.stubindex.JetShortFunctionNameIndex;
import org.jetbrains.jet.plugin.stubindex.*;
import java.util.*;
@@ -123,7 +123,56 @@ public class JetShortNamesCache extends PsiShortNamesCache {
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
public Collection<FunctionDescriptor> getTopLevelFunctionDescriptorsByName(
@NotNull String name,
@@ -190,6 +190,7 @@ public class JetCompletionContributor extends CompletionContributor {
if (shouldRunTopLevelCompletion()) {
JetTypesCompletionHelper.addJetTypes(parameters, jetResult);
addJetTopLevelFunctions();
addJetTopLevelObjects();
}
if (shouldRunExtensionsCompletion()) {
@@ -214,9 +215,17 @@ public class JetCompletionContributor extends CompletionContributor {
}
public static boolean isPartOfTypeDeclaration(@NotNull DeclarationDescriptor descriptor) {
return (descriptor instanceof ClassDescriptor) ||
(descriptor instanceof NamespaceDescriptor) ||
(descriptor instanceof TypeParameterDescriptor);
if (descriptor instanceof NamespaceDescriptor || descriptor instanceof TypeParameterDescriptor) {
return true;
}
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() {
@@ -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() {
// Check that completion in the type annotation context and if there's a qualified
// expression we are at first of it
@@ -91,12 +91,13 @@ public class JetTypesCompletionHelper {
}
if (DecompiledDataFactory.isCompiledFromKotlin(aClass)) {
// TODO: Filter classes for compiled kotlin objects
String qualifiedName = aClass.getQualifiedName();
if (qualifiedName != null) {
FqName fqName = new FqName(qualifiedName);
jetCompletionResult.addAllElements(
ResolveSessionUtils.getClassDescriptorsByFqName(jetCompletionResult.getResolveSession(), fqName));
if (!DecompiledDataFactory.isKotlinObject(aClass)) {
String qualifiedName = aClass.getQualifiedName();
if (qualifiedName != null) {
FqName fqName = new FqName(qualifiedName);
jetCompletionResult.addAllElements(
ResolveSessionUtils.getClassDescriptorsByFqName(jetCompletionResult.getResolveSession(), fqName));
}
}
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.JavaDescriptorResolver;
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.resolve.DescriptorRenderer;
@@ -214,4 +216,8 @@ public class DecompiledDataFactory {
public static boolean isCompiledFromKotlin(@NotNull PsiClass 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.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
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) {
Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
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();
}
public void testNoObjectInTypePosition() {
doTest();
}
public void testNoTopLevelCompletionInQualifiedUserTypes() {
doTest();
}
@@ -56,6 +56,10 @@ public class JetMultifileBasicCompletionTest extends JetCompletionMultiTestBase
doFileTest(2);
}
public void testNotImportedObject() throws Exception {
doFileTest();
}
@Override
protected String getTestDataPath() {
return PluginTestCaseBase.getTestDataPathBase() + "/completion/basic/multifile/";
@@ -30,6 +30,10 @@ public class CompletionMultifileHandlerTest extends CompletionTestCase {
doTest();
}
public void testImportAlreadyImportedObject() throws Exception {
doTest();
}
public void testJetClassCompletionImport() throws Exception {
doTest();
}