KT-2849 Object that are not imported do not show up in completion
#KT-2849 Fixed
This commit is contained in:
@@ -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;
|
||||||
@@ -74,6 +78,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) {
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user