diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java index 85732859908..0f042bd75c6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -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 analyseImportReference(@NotNull JetImportDirective importDirective, @NotNull JetScope scope, @NotNull BindingTrace trace) { + public static Collection 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); } diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index 50f95fb2150..9ac9a6778f9 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -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 getTopExtensionFunctionByName(String name, Project project, GlobalSearchScope scope) { + static Collection getTopExtensionFunctionPrototypesByName(String name, Project project, GlobalSearchScope scope) { + return filterJetJavaPrototypesByName( + name, project, scope, + new Predicate() { + @Override + public boolean apply(@Nullable JetValueParameterAnnotation jetValueParameterAnnotation) { + assert jetValueParameterAnnotation != null; + return jetValueParameterAnnotation.receiver(); + } + }); + } + static Collection getTopLevelFunctionPrototypesByName(String name, Project project, GlobalSearchScope scope) { + return filterJetJavaPrototypesByName( + name, project, scope, + new Predicate() { + @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 filterJetJavaPrototypesByName( + String name, Project project, GlobalSearchScope scope, + Predicate filterPredicate) { Set selectedMethods = new HashSet(); Collection 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); } } diff --git a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java index c336cf9f56e..f7e6e24245c 100644 --- a/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java +++ b/idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java @@ -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 getTopLevelFunctionDescriptorsByName(@NotNull String name, - @NotNull GlobalSearchScope scope) { + public Collection getTopLevelFunctionDescriptorsByName( + @NotNull String name, + @NotNull JetSimpleNameExpression expression, + @NotNull GlobalSearchScope scope + ) { + HashSet result = new HashSet(); + + JetFile jetFile = (JetFile) expression.getContainingFile(); + BindingContext context = WholeProjectAnalyzerFacade.analyzeProjectWithCacheOnAFile(jetFile); + JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); + + if (jetScope == null) { + return result; + } + + Collection 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 declarationDescriptors = ImportsResolver.analyseImportReference(importDirective, jetScope, new BindingTraceContext()); + for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { + if (declarationDescriptor instanceof FunctionDescriptor) { + result.add((FunctionDescriptor) declarationDescriptor); + } + } + } + } Collection jetNamedFunctions = JetShortFunctionNameIndex.getInstance().get(name, project, scope); - - BindingContext context = getResolutionContext(scope); - - HashSet result = new HashSet(); - 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 getJetExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) { HashSet functions = new HashSet(); 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 resultDescriptors = new ArrayList(); - 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 getAllJetFunctionsNames() { + public Collection getAllJetOnlyTopFunctionsNames() { return JetShortFunctionNameIndex.getInstance().getAllKeys(project); } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java index 27c945cdb88..c60188fe769 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java +++ b/idea/src/org/jetbrains/jet/plugin/completion/JetCompletionContributor.java @@ -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() { @@ -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 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); } } diff --git a/idea/testData/completion/basic/TopLevelFromStandardLibrary.kt b/idea/testData/completion/basic/TopLevelFromStandardLibrary.kt new file mode 100644 index 00000000000..d8fc717363c --- /dev/null +++ b/idea/testData/completion/basic/TopLevelFromStandardLibrary.kt @@ -0,0 +1,11 @@ +package testing + +fun someFun() { + measureTime +} + +// 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 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java index 1044269ae4c..37830db0d69 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java @@ -105,6 +105,10 @@ public class JetBasicCompletionTest extends JetCompletionTestBase { doTest(); } + public void testTopLevelFromStandardLibrary() { + doTest(); + } + public void testVariableClassName() { doTest(); }