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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user