Completion for top-level functions from class and jar files.
This commit is contained in:
@@ -24,18 +24,8 @@ import com.google.inject.Inject;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.Configuration;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.psi.JetImportDirective;
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
@@ -45,13 +35,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.CANNOT_BE_IMPORTED;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.CANNOT_IMPORT_FROM_ELEMENT;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.NO_CLASS_OBJECT;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.UNSUPPORTED;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.USELESS_HIDDEN_IMPORT;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.USELESS_SIMPLE_IMPORT;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -166,7 +150,10 @@ public class ImportsResolver {
|
||||
}
|
||||
}
|
||||
|
||||
public static Collection<? extends DeclarationDescriptor> analyseImportReference(@NotNull JetImportDirective importDirective, @NotNull JetScope scope, @NotNull BindingTrace trace) {
|
||||
public static Collection<? extends DeclarationDescriptor> analyseImportReference(
|
||||
@NotNull JetImportDirective importDirective,
|
||||
@NotNull JetScope scope, @NotNull BindingTrace trace
|
||||
) {
|
||||
ImportsResolver.SingleImportResolver importResolver = new ImportsResolver.SingleImportResolver(trace, false);
|
||||
return importResolver.processImportReference(importDirective, scope, Importer.DO_NOTHING);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.plugin.caches;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
|
||||
@@ -24,8 +25,11 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.PsiShortNamesCache;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
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.kt.JetValueParameterAnnotation;
|
||||
import org.jetbrains.jet.util.QualifiedNamesUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -33,8 +37,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Get jet declarations from java that could be used in completion. Unlike the real jet resolver this helper is allowed
|
||||
* to return partially unresolved descriptors in exchange of execution speed.
|
||||
* Number of helper methods for searching jet element prototypes in java. Methods use java indices for search.
|
||||
*
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
@@ -47,6 +50,9 @@ class JetFromJavaDescriptorHelper {
|
||||
* Get java equivalents for jet top level classes.
|
||||
*/
|
||||
static PsiClass[] getClassesForJetNamespaces(Project project, GlobalSearchScope scope) {
|
||||
/* Will iterate through short name caches
|
||||
Kotlin namespaces from jar a class files will be collected from java cache
|
||||
Kotlin namespaces classes from sources will be collected with JetShortNamesCache.getClassesByName */
|
||||
return PsiShortNamesCache.getInstance(project).getClassesByName(JvmAbi.PACKAGE_CLASS, scope);
|
||||
}
|
||||
|
||||
@@ -96,8 +102,51 @@ class JetFromJavaDescriptorHelper {
|
||||
return extensionNames;
|
||||
}
|
||||
|
||||
static Collection<PsiMethod> getTopExtensionFunctionByName(String name, Project project, GlobalSearchScope scope) {
|
||||
static Collection<PsiMethod> getTopExtensionFunctionPrototypesByName(String name, Project project, GlobalSearchScope scope) {
|
||||
return filterJetJavaPrototypesByName(
|
||||
name, project, scope,
|
||||
new Predicate<JetValueParameterAnnotation>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable JetValueParameterAnnotation jetValueParameterAnnotation) {
|
||||
assert jetValueParameterAnnotation != null;
|
||||
return jetValueParameterAnnotation.receiver();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static Collection<PsiMethod> getTopLevelFunctionPrototypesByName(String name, Project project, GlobalSearchScope scope) {
|
||||
return filterJetJavaPrototypesByName(
|
||||
name, project, scope,
|
||||
new Predicate<JetValueParameterAnnotation>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable JetValueParameterAnnotation jetValueParameterAnnotation) {
|
||||
assert jetValueParameterAnnotation != null;
|
||||
return !jetValueParameterAnnotation.receiver();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static String getJetTopLevelDeclarationFQN(@NotNull PsiMethod method) {
|
||||
PsiClass containingClass = method.getContainingClass();
|
||||
|
||||
if (containingClass != null) {
|
||||
String classFQN = containingClass.getQualifiedName();
|
||||
|
||||
if (classFQN != null) {
|
||||
if (QualifiedNamesUtil.fqnToShortName(classFQN).equals(JvmAbi.PACKAGE_CLASS)) {
|
||||
String classParentFQN = QualifiedNamesUtil.withoutLastSegment(classFQN);
|
||||
return QualifiedNamesUtil.combine(classParentFQN, method.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Collection<PsiMethod> filterJetJavaPrototypesByName(
|
||||
String name, Project project, GlobalSearchScope scope,
|
||||
Predicate<JetValueParameterAnnotation> filterPredicate) {
|
||||
Set<PsiMethod> selectedMethods = new HashSet<PsiMethod>();
|
||||
|
||||
Collection<PsiMethod> psiMethods = JavaMethodNameIndex.getInstance().get(name, project, scope);
|
||||
@@ -121,7 +170,7 @@ class JetFromJavaDescriptorHelper {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (new JetValueParameterAnnotation(psiAnnotation).receiver()) {
|
||||
if (filterPredicate.apply(new JetValueParameterAnnotation(psiAnnotation))) {
|
||||
selectedMethods.add(psiMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,12 +34,11 @@ 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.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
||||
import org.jetbrains.jet.lang.resolve.ImportsResolver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils;
|
||||
@@ -157,15 +156,36 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<SimpleFunctionDescriptor> getTopLevelFunctionDescriptorsByName(@NotNull String name,
|
||||
@NotNull GlobalSearchScope scope) {
|
||||
public Collection<FunctionDescriptor> getTopLevelFunctionDescriptorsByName(
|
||||
@NotNull String name,
|
||||
@NotNull JetSimpleNameExpression expression,
|
||||
@NotNull GlobalSearchScope scope
|
||||
) {
|
||||
HashSet<FunctionDescriptor> result = new HashSet<FunctionDescriptor>();
|
||||
|
||||
JetFile jetFile = (JetFile) expression.getContainingFile();
|
||||
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile);
|
||||
JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
|
||||
|
||||
if (jetScope == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Collection<PsiMethod> topLevelFunctionPrototypes = JetFromJavaDescriptorHelper.getTopLevelFunctionPrototypesByName(name, project, scope);
|
||||
for (PsiMethod method : topLevelFunctionPrototypes) {
|
||||
String functionFQN = JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN(method);
|
||||
if (functionFQN != null) {
|
||||
JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, functionFQN);
|
||||
Collection<? extends DeclarationDescriptor> declarationDescriptors = ImportsResolver.analyseImportReference(importDirective, jetScope, new BindingTraceContext());
|
||||
for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
|
||||
if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
result.add((FunctionDescriptor) declarationDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collection<JetNamedFunction> jetNamedFunctions = JetShortFunctionNameIndex.getInstance().get(name, project, scope);
|
||||
|
||||
BindingContext context = getResolutionContext(scope);
|
||||
|
||||
HashSet<SimpleFunctionDescriptor> result = new HashSet<SimpleFunctionDescriptor>();
|
||||
|
||||
for (JetNamedFunction jetNamedFunction : jetNamedFunctions) {
|
||||
SimpleFunctionDescriptor functionDescriptor = context.get(BindingContext.FUNCTION, jetNamedFunction);
|
||||
if (functionDescriptor != null) {
|
||||
@@ -204,7 +224,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
||||
public Collection<PsiElement> getJetExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
|
||||
HashSet<PsiElement> functions = new HashSet<PsiElement>();
|
||||
functions.addAll(JetExtensionFunctionNameIndex.getInstance().get(name, project, scope));
|
||||
functions.addAll(JetFromJavaDescriptorHelper.getTopExtensionFunctionByName(name, project, scope));
|
||||
functions.addAll(JetFromJavaDescriptorHelper.getTopExtensionFunctionPrototypesByName(name, project, scope));
|
||||
|
||||
return functions;
|
||||
}
|
||||
@@ -217,10 +237,6 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
||||
) {
|
||||
Collection<DeclarationDescriptor> resultDescriptors = new ArrayList<DeclarationDescriptor>();
|
||||
|
||||
if (!(expression.getContainingFile() instanceof JetFile)) {
|
||||
return resultDescriptors;
|
||||
}
|
||||
|
||||
JetFile jetFile = (JetFile) expression.getContainingFile();
|
||||
|
||||
BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile);
|
||||
@@ -245,16 +261,9 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
||||
functionFQNs.add(JetPsiUtil.getFQName((JetNamedFunction) extensionFunction));
|
||||
}
|
||||
else if (extensionFunction instanceof PsiMethod) {
|
||||
PsiMethod function = (PsiMethod) extensionFunction;
|
||||
PsiClass containingClass = function.getContainingClass();
|
||||
|
||||
if (containingClass != null) {
|
||||
String classFQN = containingClass.getQualifiedName();
|
||||
|
||||
if (classFQN != null) {
|
||||
String classParentFQN = QualifiedNamesUtil.withoutLastSegment(classFQN);
|
||||
functionFQNs.add(QualifiedNamesUtil.combine(classParentFQN, function.getName()));
|
||||
}
|
||||
String functionFQN = JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN((PsiMethod) extensionFunction);
|
||||
if (functionFQN != null) {
|
||||
functionFQNs.add(functionFQN);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,7 +288,7 @@ public class JetShortNamesCache extends PsiShortNamesCache {
|
||||
return JetShortFunctionNameIndex.getInstance().get(name, project, scope);
|
||||
}
|
||||
|
||||
public Collection<String> getAllJetFunctionsNames() {
|
||||
public Collection<String> getAllJetOnlyTopFunctionsNames() {
|
||||
return JetShortFunctionNameIndex.getInstance().getAllKeys(project);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ import java.util.Set;
|
||||
* @author Nikolay Krasko
|
||||
*/
|
||||
public class JetCompletionContributor extends CompletionContributor {
|
||||
|
||||
public JetCompletionContributor() {
|
||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement(),
|
||||
new CompletionProvider<CompletionParameters>() {
|
||||
@@ -86,7 +87,7 @@ public class JetCompletionContributor extends CompletionContributor {
|
||||
|
||||
if (shouldRunTopLevelCompletion(parameters, prefix)) {
|
||||
addClasses(parameters, result);
|
||||
addJetTopLevelFunctions(result, position, positions);
|
||||
addJetTopLevelFunctions(jetReference.getExpression(), result, position, positions);
|
||||
}
|
||||
|
||||
if (shouldRunExtensionsCompletion(parameters, prefix)) {
|
||||
@@ -132,7 +133,7 @@ public class JetCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addJetTopLevelFunctions(@NotNull CompletionResultSet result, @NotNull PsiElement position,
|
||||
private static void addJetTopLevelFunctions(JetSimpleNameExpression expression, @NotNull CompletionResultSet result, @NotNull PsiElement position,
|
||||
@NotNull Set<LookupPositionObject> positions) {
|
||||
|
||||
String actualPrefix = result.getPrefixMatcher().getPrefix();
|
||||
@@ -147,7 +148,7 @@ public class JetCompletionContributor extends CompletionContributor {
|
||||
|
||||
for (String name : functionNames) {
|
||||
if (name.contains(actualPrefix)) {
|
||||
for (FunctionDescriptor function : namesCache.getTopLevelFunctionDescriptorsByName(name, scope)) {
|
||||
for (FunctionDescriptor function : namesCache.getTopLevelFunctionDescriptorsByName(name, expression, scope)) {
|
||||
addCompletionToResult(result, DescriptorLookupConverter.createLookupElement(resolutionContext, function), positions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package testing
|
||||
|
||||
fun someFun() {
|
||||
measureTime<caret>
|
||||
}
|
||||
|
||||
// Important: This test checks that completion will find top level functions from jars.
|
||||
// If you going to update it make sure that methods are not auto-imported
|
||||
|
||||
// RUNTIME: 1
|
||||
// EXIST: measureTimeNano, measureTimeMillis
|
||||
@@ -105,6 +105,10 @@ public class JetBasicCompletionTest extends JetCompletionTestBase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTopLevelFromStandardLibrary() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testVariableClassName() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user