From ca59391e5642a694937485580349864ccff30d12 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 8 Aug 2014 20:50:54 +0400 Subject: [PATCH] Converted JetShortNamesCache to Kotlin --- .../expressions/ExpressionTypingUtils.java | 1 + .../caches/JetFromJavaDescriptorHelper.java | 2 + .../jet/plugin/caches/JetShortNamesCache.java | 431 ------------------ .../IDELightClassGenerationSupport.java | 1 + .../stubindex/JetClassShortNameIndex.java | 1 + ...pLevelExtensionFunctionShortNameIndex.java | 1 + ...velNonExtensionFunctionShortNameIndex.java | 1 + .../JetTopLevelObjectShortNameIndex.java | 1 + .../jet/plugin/caches/JetShortNamesCache.kt | 296 ++++++++++++ .../plugin/completion/CompletionSession.kt | 4 +- .../jet/plugin/completion/TypesCompletion.kt | 2 +- .../jet/plugin/quickfix/AutoImportFix.java | 18 +- 12 files changed, 316 insertions(+), 443 deletions(-) delete mode 100644 idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java create mode 100644 idea/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java index 700746049a5..39b0a78413a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingUtils.java @@ -193,6 +193,7 @@ public class ExpressionTypingUtils { * @param scope * @return */ + @NotNull public static List canFindSuitableCall( @NotNull FqName callableFQN, @NotNull JetExpression receiverExpression, diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java index 849003409bd..1c0af4e6ecc 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetFromJavaDescriptorHelper.java @@ -57,6 +57,7 @@ public class JetFromJavaDescriptorHelper { /** * Get names that could have jet descriptor equivalents. It could be inaccurate and return more results than necessary. */ + @NotNull static Collection getPossiblePackageDeclarationsNames(Project project, GlobalSearchScope scope) { Collection result = new ArrayList(); @@ -71,6 +72,7 @@ public class JetFromJavaDescriptorHelper { return result; } + @NotNull static Collection getCompiledClassesForTopLevelObjects(Project project, GlobalSearchScope scope) { Set jetObjectClasses = Sets.newHashSet(); diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java deleted file mode 100644 index 54d1d4becce..00000000000 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/JetShortNamesCache.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -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.extensions.Extensions; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.PsiShortNamesCache; -import com.intellij.util.ArrayUtil; -import com.intellij.util.Processor; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashSet; -import com.intellij.util.containers.MultiMap; -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.*; -import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingTraceContext; -import org.jetbrains.jet.lang.resolve.ImportPath; -import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; -import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer; -import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils; -import org.jetbrains.jet.lang.resolve.name.FqName; -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.caches.resolve.IDELightClassGenerationSupport; -import org.jetbrains.jet.plugin.project.ResolveSessionForBodies; -import org.jetbrains.jet.plugin.stubindex.*; - -import java.util.*; - -/** - * Will provide both java elements from kotlin context and some declarations special to kotlin. - * All those declaration are planned to be used in completion. - */ -public class JetShortNamesCache extends PsiShortNamesCache { - - @NotNull - public static JetShortNamesCache getKotlinInstance(@NotNull Project project) { - PsiShortNamesCache[] extensions = Extensions.getArea(project).getExtensionPoint(PsiShortNamesCache.EP_NAME).getExtensions(); - for (PsiShortNamesCache extension : extensions) { - if (extension instanceof JetShortNamesCache) { - return (JetShortNamesCache) extension; - } - } - throw new IllegalStateException(JetShortNamesCache.class.getSimpleName() + " is not found for project " + project); - } - - private static final PsiMethod[] NO_METHODS = new PsiMethod[0]; - private static final PsiField[] NO_FIELDS = new PsiField[0]; - private final Project project; - - public JetShortNamesCache(Project project) { - this.project = project; - } - - /** - * Return kotlin class names from project sources which should be visible from java. - */ - @NotNull - @Override - public String[] getAllClassNames() { - Collection classNames = JetClassShortNameIndex.getInstance().getAllKeys(project); - - // package classes can not be indexed, since they have no explicit declarations - IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project); - Set packageClassShortNames = - lightClassGenerationSupport.getAllPossiblePackageClasses(GlobalSearchScope.allScope(project)).keySet(); - classNames.addAll(packageClassShortNames); - - return ArrayUtil.toStringArray(classNames); - } - - /** - * Return class names form kotlin sources in given scope which should be visible as Java classes. - */ - @NotNull - @Override - public PsiClass[] getClassesByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { - List result = new ArrayList(); - - IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project); - MultiMap packageClasses = lightClassGenerationSupport.getAllPossiblePackageClasses(scope); - - // package classes can not be indexed, since they have no explicit declarations - Collection fqNames = packageClasses.get(name); - if (!fqNames.isEmpty()) { - for (FqName fqName : fqNames) { - PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope); - if (psiClass != null) { - result.add(psiClass); - } - } - } - - // Quick check for classes from getAllClassNames() - Collection classOrObjects = JetClassShortNameIndex.getInstance().get(name, project, scope); - if (classOrObjects.isEmpty()) { - return result.toArray(new PsiClass[result.size()]); - } - - for (JetClassOrObject classOrObject : classOrObjects) { - FqName fqName = classOrObject.getFqName(); - if (fqName != null) { - assert fqName.shortName().asString().equals(name) : "A declaration obtained from index has non-matching name:\n" + - "in index: " + name + "\n" + - "declared: " + fqName.shortName() + "(" + fqName + ")"; - PsiClass psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope); - if (psiClass != null) { - result.add(psiClass); - } - } - } - - return result.toArray(new PsiClass[result.size()]); - } - - @Override - public void getAllClassNames(@NotNull HashSet destination) { - destination.addAll(Arrays.asList(getAllClassNames())); - } - - /** - * Get kotlin non-extension top-level function names. Method is allowed to give invalid names - all result should be - * checked with getTopLevelFunctionDescriptorsByName(). - */ - @NotNull - public Collection getAllTopLevelFunctionNames() { - Set functionNames = new HashSet(); - functionNames.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project)); - functionNames.addAll(JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, GlobalSearchScope.allScope(project))); - return functionNames; - } - - @NotNull - public Collection getAllTopLevelObjectNames() { - Set topObjectNames = new HashSet(); - topObjectNames.addAll(JetTopLevelObjectShortNameIndex.getInstance().getAllKeys(project)); - - Collection classObjects = - JetFromJavaDescriptorHelper.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project)); - topObjectNames.addAll(Collections2.transform(classObjects, new Function() { - @Override - public String apply(@Nullable PsiClass aClass) { - assert aClass != null; - return aClass.getName(); - } - })); - - return topObjectNames; - } - - @NotNull - public Collection getTopLevelObjectsByName( - @NotNull String name, - @NotNull JetSimpleNameExpression expression, - @NotNull ResolveSessionForBodies resolveSession, - @NotNull GlobalSearchScope scope - ) { - BindingContext context = resolveSession.resolveToElement(expression); - JetScope jetScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); - - if (jetScope == null) { - return Collections.emptyList(); - } - - Set result = Sets.newHashSet(); - - Collection topObjects = JetTopLevelObjectShortNameIndex.getInstance().get(name, project, scope); - for (JetObjectDeclaration objectDeclaration : topObjects) { - FqName fqName = objectDeclaration.getFqName(); - assert fqName != null : "Local object declaration in JetTopLevelShortObjectNameIndex:" + objectDeclaration.getText(); - result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession, fqName, ResolveSessionUtils.SINGLETON_FILTER)); - } - - for (PsiClass psiClass : JetFromJavaDescriptorHelper - .getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project))) { - String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName != null) { - FqName fqName = new FqName(qualifiedName); - result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession, fqName, ResolveSessionUtils.SINGLETON_FILTER)); - } - } - - return result; - } - - @NotNull - public Collection getTopLevelFunctionDescriptorsByName( - @NotNull String name, - @NotNull JetExpression context /*TODO: to be dropped*/, - @NotNull ResolveSessionForBodies resolveSession, - @NotNull GlobalSearchScope scope) { - - JetScope jetScope = resolveSession.resolveToElement(context).get(BindingContext.RESOLUTION_SCOPE, context); - if (jetScope == null) { - return Collections.emptyList(); - } - - Set result = Sets.newHashSet(); - - //TODO: this code is temporary and is to be dropped when compiled top level functions are indexed - final Name identifier = Name.identifier(name); - Collection topLevelFunctionFqNames = - ContainerUtil.filter(JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames(project, scope, false), new Condition() { - @Override - public boolean value(FqName fqName) { - return fqName.lastSegmentIs(identifier); - } - }); - for (FqName fqName : topLevelFunctionFqNames) { - JetImportDirective importDirective = new JetPsiFactory(context.getProject()).createImportDirective(new ImportPath(fqName, false)); - Collection declarationDescriptors = new QualifiedExpressionResolver().analyseImportReference( - importDirective, jetScope, new BindingTraceContext(), resolveSession.getModuleDescriptor()); - for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { - if (declarationDescriptor instanceof FunctionDescriptor) { - result.add((FunctionDescriptor) declarationDescriptor); - } - } - } - - Set affectedPackages = Sets.newHashSet(); - Collection jetNamedFunctions = JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().get(name, project, scope); - for (JetNamedFunction jetNamedFunction : jetNamedFunctions) { - PsiFile containingFile = jetNamedFunction.getContainingFile(); - if (containingFile instanceof JetFile) { - JetFile jetFile = (JetFile) containingFile; - affectedPackages.add(jetFile.getPackageFqName()); - } - } - - for (FqName affectedPackage : affectedPackages) { - PackageViewDescriptor packageDescriptor = resolveSession.getModuleDescriptor().getPackage(affectedPackage); - assert packageDescriptor != null : "There's a function in stub index with invalid package: " + affectedPackage; - JetScope memberScope = packageDescriptor.getMemberScope(); - result.addAll(memberScope.getFunctions(identifier)); - } - - return result; - } - - private Collection getJetExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) { - HashSet functions = new HashSet(); - functions.addAll(JetTopLevelExtensionFunctionShortNameIndex.getInstance().get(name, project, scope)); - - return functions; - } - - // TODO: Make it work for properties - @NotNull - public Collection getJetCallableExtensions( - @NotNull final Condition acceptedNameCondition, - @NotNull JetSimpleNameExpression expression, - @NotNull ResolveSessionForBodies resolveSession, - @NotNull GlobalSearchScope searchScope - ) { - BindingContext context = resolveSession.resolveToElement(expression); - JetExpression receiverExpression = PsiUtilPackage.getReceiverExpression(expression); - if (receiverExpression == null) { - return Collections.emptyList(); - } - JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression); - JetScope scope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression); - - if (expressionType == null || scope == null || expressionType.isError()) { - return Collections.emptyList(); - } - - Set functionFQNs = extensionFunctionsFromSourceFqNames(acceptedNameCondition, searchScope); - functionFQNs.addAll(ContainerUtil.filter(JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames(project, searchScope, true), new Condition() { - @Override - public boolean value(FqName fqName) { - return acceptedNameCondition.value(fqName.shortName().asString()); - } - })); - - Collection resultDescriptors = new ArrayList(); - // Iterate through the function with attempt to resolve found functions - for (FqName functionFQN : functionFQNs) { - for (CallableDescriptor functionDescriptor : ExpressionTypingUtils.canFindSuitableCall( - functionFQN, receiverExpression, expressionType, scope, resolveSession.getModuleDescriptor())) { - - resultDescriptors.add(functionDescriptor); - } - } - - return resultDescriptors; - } - - @NotNull - private Set extensionFunctionsFromSourceFqNames( - @NotNull Condition acceptedNameCondition, - @NotNull GlobalSearchScope searchScope - ) { - Set extensionFunctionNames = new HashSet(JetTopLevelExtensionFunctionShortNameIndex.getInstance().getAllKeys(project)); - - Set functionFQNs = new java.util.HashSet(); - - // Collect all possible extension function qualified names - for (String name : extensionFunctionNames) { - if (acceptedNameCondition.value(name)) { - Collection extensionFunctions = getJetExtensionFunctionsByName(name, searchScope); - - for (PsiElement extensionFunction : extensionFunctions) { - if (extensionFunction instanceof JetNamedFunction) { - functionFQNs.add(((JetNamedFunction) extensionFunction).getFqName()); - } - else if (extensionFunction instanceof PsiMethod) { - FqName functionFQN = - JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN((PsiMethod) extensionFunction); - if (functionFQN != null) { - functionFQNs.add(functionFQN); - } - } - } - } - } - return functionFQNs; - } - - @NotNull - public Collection getJetClassesDescriptors( - @NotNull Condition acceptedShortNameCondition, - @NotNull KotlinCodeAnalyzer analyzer, - @NotNull GlobalSearchScope searchScope - ) { - Collection classDescriptors = new ArrayList(); - - for (String fqName : JetFullClassNameIndex.getInstance().getAllKeys(project)) { - FqName classFQName = new FqName(fqName); - if (acceptedShortNameCondition.value(classFQName.shortName().asString())) { - classDescriptors.addAll(getJetClassesDescriptorsByFQName(analyzer, classFQName, searchScope)); - } - } - - return classDescriptors; - } - - private Collection getJetClassesDescriptorsByFQName( - @NotNull KotlinCodeAnalyzer analyzer, @NotNull FqName classFQName, @NotNull GlobalSearchScope searchScope) { - Collection jetClassOrObjects = JetFullClassNameIndex.getInstance().get( - classFQName.asString(), project, searchScope); - - if (jetClassOrObjects.isEmpty()) { - // This fqn is absent in caches, dead or not in scope - return Collections.emptyList(); - } - - // Note: Can't search with psi element as analyzer could be built over temp files - return ResolveSessionUtils.getClassDescriptorsByFqName(analyzer, classFQName); - } - - @NotNull - @Override - public PsiMethod[] getMethodsByName(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope) { - return NO_METHODS; - } - - @NotNull - @Override - public PsiMethod[] getMethodsByNameIfNotMoreThan(@NonNls @NotNull String name, @NotNull GlobalSearchScope scope, int maxCount) { - return NO_METHODS; - } - - @NotNull - @Override - public PsiField[] getFieldsByNameIfNotMoreThan(@NonNls @NotNull String s, @NotNull GlobalSearchScope scope, int i) { - return NO_FIELDS; - } - - @Override - public boolean processMethodsWithName( - @NonNls @NotNull String name, - @NotNull GlobalSearchScope scope, - @NotNull Processor processor - ) { - return ContainerUtil.process(getMethodsByName(name, scope), processor); - } - - @NotNull - @Override - public String[] getAllMethodNames() { - return ArrayUtil.EMPTY_STRING_ARRAY; - } - - @Override - public void getAllMethodNames(@NotNull HashSet set) { - set.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project)); - } - - @NotNull - @Override - public PsiField[] getFieldsByName(@NotNull @NonNls String name, @NotNull GlobalSearchScope scope) { - return NO_FIELDS; - } - - @NotNull - @Override - public String[] getAllFieldNames() { - return ArrayUtil.EMPTY_STRING_ARRAY; - } - - @Override - public void getAllFieldNames(@NotNull HashSet set) { - } -} diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/IDELightClassGenerationSupport.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/IDELightClassGenerationSupport.java index df2d1522b8f..08d4ccc8972 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/IDELightClassGenerationSupport.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/caches/resolve/IDELightClassGenerationSupport.java @@ -57,6 +57,7 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport private static final Logger LOG = Logger.getInstance(IDELightClassGenerationSupport.class); + @NotNull public static IDELightClassGenerationSupport getInstanceForIDE(@NotNull Project project) { return (IDELightClassGenerationSupport) ServiceManager.getService(project, LightClassGenerationSupport.class); } diff --git a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/JetClassShortNameIndex.java b/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/JetClassShortNameIndex.java index 084f9de9c89..7632ee8a2a8 100644 --- a/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/JetClassShortNameIndex.java +++ b/idea/idea-analysis/src/org/jetbrains/jet/plugin/stubindex/JetClassShortNameIndex.java @@ -30,6 +30,7 @@ public class JetClassShortNameIndex extends StringStubIndexExtension(PsiShortNamesCache.EP_NAME).getExtensions() + for (extension in extensions) { + if (extension is JetShortNamesCache) { + return extension as JetShortNamesCache + } + } + throw IllegalStateException(javaClass().getSimpleName() + " is not found for project " + project) + } + } + + /** + * Return kotlin class names from project sources which should be visible from java. + */ + override fun getAllClassNames(): Array { + val classNames = JetClassShortNameIndex.getInstance().getAllKeys(project) + + // package classes can not be indexed, since they have no explicit declarations + val lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project) + val packageClassShortNames = lightClassGenerationSupport.getAllPossiblePackageClasses(GlobalSearchScope.allScope(project)).keySet() + classNames.addAll(packageClassShortNames) + + return ArrayUtil.toStringArray(classNames) + } + + /** + * Return class names form kotlin sources in given scope which should be visible as Java classes. + */ + override fun getClassesByName(NonNls name: String, scope: GlobalSearchScope): Array { + val result = ArrayList() + + val lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project) + val packageClasses = lightClassGenerationSupport.getAllPossiblePackageClasses(scope) + + // package classes can not be indexed, since they have no explicit declarations + val fqNames = packageClasses.get(name) + if (!fqNames.isEmpty()) { + for (fqName in fqNames) { + val psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope) + if (psiClass != null) { + result.add(psiClass) + } + } + } + + // Quick check for classes from getAllClassNames() + val classOrObjects = JetClassShortNameIndex.getInstance().get(name, project, scope) + if (classOrObjects.isEmpty()) { + return result.copyToArray() + } + + for (classOrObject in classOrObjects) { + val fqName = classOrObject.getFqName() + if (fqName != null) { + assert(fqName.shortName().asString() == name) { "A declaration obtained from index has non-matching name:\n" + "in index: " + name + "\n" + "declared: " + fqName.shortName() + "(" + fqName + ")" } + val psiClass = JavaElementFinder.getInstance(project).findClass(fqName.asString(), scope) + if (psiClass != null) { + result.add(psiClass) + } + } + } + + return result.copyToArray() + } + + override fun getAllClassNames(destination: containers.HashSet) { + destination.addAll(Arrays.asList(*getAllClassNames())) + } + + /** + * Get kotlin non-extension top-level function names. Method is allowed to give invalid names - all result should be + * checked with getTopLevelFunctionDescriptorsByName(). + */ + public fun getAllTopLevelFunctionNames(): Collection { + return (JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project) + + JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, GlobalSearchScope.allScope(project))).toSet() + } + + public fun getAllTopLevelObjectNames(): Collection { + return (JetTopLevelObjectShortNameIndex.getInstance().getAllKeys(project) + + JetFromJavaDescriptorHelper.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project)).map { it.getName()!! }).toSet() + } + + public fun getTopLevelObjectsByName(name: String, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection { + val result = hashSetOf() + + val topObjects = JetTopLevelObjectShortNameIndex.getInstance().get(name, project, scope) + for (objectDeclaration in topObjects) { + val fqName = objectDeclaration.getFqName() ?: error("Local object declaration in JetTopLevelShortObjectNameIndex:${objectDeclaration.getText()}") + result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession, fqName, ResolveSessionUtils.SINGLETON_FILTER)) + } + + for (psiClass in JetFromJavaDescriptorHelper.getCompiledClassesForTopLevelObjects(project, GlobalSearchScope.allScope(project))) { + val qualifiedName = psiClass.getQualifiedName() + if (qualifiedName != null) { + result.addAll(ResolveSessionUtils.getClassOrObjectDescriptorsByFqName(resolveSession, FqName(qualifiedName), ResolveSessionUtils.SINGLETON_FILTER)) + } + } + + return result + } + + public fun getTopLevelFunctionDescriptorsByName(name: String, context: JetExpression /*TODO: to be dropped*/, resolveSession: ResolveSessionForBodies, scope: GlobalSearchScope): Collection { + + val jetScope = resolveSession.resolveToElement(context).get(BindingContext.RESOLUTION_SCOPE, context) ?: return listOf() + + val result = hashSetOf() + + //TODO: this code is temporary and is to be dropped when compiled top level functions are indexed + val identifier = Name.identifier(name) + val topLevelFunctionFqNames = JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames(project, scope, false) + for (fqName in topLevelFunctionFqNames) { + if (fqName.lastSegmentIs(identifier)) { + val importDirective = JetPsiFactory(context.getProject()).createImportDirective(ImportPath(fqName, false)) + val declarationDescriptors = QualifiedExpressionResolver().analyseImportReference(importDirective, jetScope, BindingTraceContext(), resolveSession.getModuleDescriptor()) + for (declarationDescriptor in declarationDescriptors) { + if (declarationDescriptor is FunctionDescriptor) { + result.add(declarationDescriptor as FunctionDescriptor) + } + } + } + } + + val affectedPackages = JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().get(name, project, scope) + .map { it.getContainingFile() } + .filterIsInstance(javaClass()) + .map { it.getPackageFqName() } + .toSet() + + for (affectedPackage in affectedPackages) { + val packageDescriptor = resolveSession.getModuleDescriptor().getPackage(affectedPackage) + ?: error("There's a function in stub index with invalid package: $affectedPackage") + result.addAll(packageDescriptor.getMemberScope().getFunctions(identifier)) + } + + return result + } + + private fun getJetExtensionFunctionsByName(name: String, scope: GlobalSearchScope): Collection + = JetTopLevelExtensionFunctionShortNameIndex.getInstance().get(name, project, scope) + + // TODO: Make it work for properties + public fun getJetCallableExtensions(nameFilter: (String) -> Boolean, expression: JetSimpleNameExpression, resolveSession: ResolveSessionForBodies, searchScope: GlobalSearchScope): Collection { + val context = resolveSession.resolveToElement(expression) + val receiverExpression = expression.getReceiverExpression() ?: return listOf() + val expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression) + val scope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression) + + if (expressionType == null || scope == null || expressionType.isError()) { + return listOf() + } + + val functionFQNs = extensionFunctionsFromSourceFqNames(nameFilter, searchScope) + + JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames(project, searchScope, true) + .filterTo(functionFQNs) { nameFilter(it.shortName().asString()) } + + // Iterate through the function with attempt to resolve found functions + return functionFQNs.flatMap { ExpressionTypingUtils.canFindSuitableCall(it, receiverExpression, expressionType, scope, resolveSession.getModuleDescriptor()) } + } + + private fun extensionFunctionsFromSourceFqNames(nameFilter: (String) -> Boolean, searchScope: GlobalSearchScope): HashSet { + val extensionFunctionNames = HashSet(JetTopLevelExtensionFunctionShortNameIndex.getInstance().getAllKeys(project)) + + val functionFQNs = HashSet() + + // Collect all possible extension function qualified names + for (name in extensionFunctionNames) { + if (nameFilter(name)) { + val extensionFunctions = getJetExtensionFunctionsByName(name, searchScope) + + for (extensionFunction in extensionFunctions) { + if (extensionFunction is JetNamedFunction) { + functionFQNs.add(extensionFunction.getFqName()!!) + } + else if (extensionFunction is PsiMethod) { + val functionFQN = JetFromJavaDescriptorHelper.getJetTopLevelDeclarationFQN(extensionFunction) + if (functionFQN != null) { + functionFQNs.add(functionFQN) + } + } + } + } + } + return functionFQNs + } + + public fun getJetClassesDescriptors(acceptedShortNameCondition: (String) -> Boolean, analyzer: KotlinCodeAnalyzer, searchScope: GlobalSearchScope): Collection { + val classDescriptors = ArrayList() + + for (fqName in JetFullClassNameIndex.getInstance().getAllKeys(project)) { + val classFQName = FqName(fqName) + if (acceptedShortNameCondition(classFQName.shortName().asString())) { + classDescriptors.addAll(getJetClassesDescriptorsByFQName(analyzer, classFQName, searchScope)) + } + } + + return classDescriptors + } + + private fun getJetClassesDescriptorsByFQName(analyzer: KotlinCodeAnalyzer, classFQName: FqName, searchScope: GlobalSearchScope): Collection { + val jetClassOrObjects = JetFullClassNameIndex.getInstance().get(classFQName.asString(), project, searchScope) + + if (jetClassOrObjects.isEmpty()) { + // This fqn is absent in caches, dead or not in scope + return listOf() + } + + // Note: Can't search with psi element as analyzer could be built over temp files + return ResolveSessionUtils.getClassDescriptorsByFqName(analyzer, classFQName) + } + + override fun getMethodsByName(NonNls name: String, scope: GlobalSearchScope): Array + = array() + + override fun getMethodsByNameIfNotMoreThan(NonNls name: String, scope: GlobalSearchScope, maxCount: Int): Array + = array() + + override fun getFieldsByNameIfNotMoreThan(NonNls s: String, scope: GlobalSearchScope, i: Int): Array + = array() + + override fun processMethodsWithName(NonNls name: String, scope: GlobalSearchScope, processor: Processor): Boolean + = ContainerUtil.process(getMethodsByName(name, scope), processor) + + override fun getAllMethodNames(): Array + = array() + + override fun getAllMethodNames(set: containers.HashSet) { + set.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project)) + } + + override fun getFieldsByName(NonNls name: String, scope: GlobalSearchScope): Array + = array() + + override fun getAllFieldNames(): Array + = array() + + override fun getAllFieldNames(set: containers.HashSet) { + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt index ae7ff7c962b..65e0abb0dcb 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt @@ -166,13 +166,13 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, private fun addKotlinTopLevelObjects() { for (name in shortNamesCache.getAllTopLevelObjectNames()) { if (prefixMatcher.prefixMatches(name)) { - collector.addDescriptorElements(shortNamesCache.getTopLevelObjectsByName(name, jetReference!!.expression, resolveSession, searchScope)) + collector.addDescriptorElements(shortNamesCache.getTopLevelObjectsByName(name, resolveSession, searchScope)) } } } private fun addKotlinExtensions() { - collector.addDescriptorElements(shortNamesCache.getJetCallableExtensions({ prefixMatcher.prefixMatches(it!!) }, jetReference!!.expression, resolveSession, searchScope)) + collector.addDescriptorElements(shortNamesCache.getJetCallableExtensions({ prefixMatcher.prefixMatches(it) }, jetReference!!.expression, resolveSession, searchScope)) } private fun shouldRunOnlyTypeCompletion(): Boolean { diff --git a/idea/src/org/jetbrains/jet/plugin/completion/TypesCompletion.kt b/idea/src/org/jetbrains/jet/plugin/completion/TypesCompletion.kt index 8fce96c34ad..9375f2db690 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/TypesCompletion.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/TypesCompletion.kt @@ -44,7 +44,7 @@ class TypesCompletion(val parameters: CompletionParameters, val resolveSession: val namesCache = JetShortNamesCache.getKotlinInstance(project) val module = ModuleUtilCore.findModuleForPsiElement(parameters.getOriginalFile()) ?: return val searchScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) - result.addDescriptorElements(namesCache.getJetClassesDescriptors({ prefixMatcher.prefixMatches(it!!) }, resolveSession, searchScope)) + result.addDescriptorElements(namesCache.getJetClassesDescriptors({ prefixMatcher.prefixMatches(it) }, resolveSession, searchScope)) if (!ProjectStructureUtil.isJsKotlinModule(parameters.getOriginalFile() as JetFile)) { addAdaptedJavaCompletion(result) diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AutoImportFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AutoImportFix.java index 2194f08a774..4d6df47c496 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/AutoImportFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AutoImportFix.java @@ -30,12 +30,12 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiShortNamesCache; import com.intellij.util.IncorrectOperationException; +import kotlin.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -130,7 +130,7 @@ public class AutoImportFix extends JetHintAction implem @NotNull ResolveSessionForBodies resolveSession, @NotNull Project project ) { - JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project); + JetShortNamesCache namesCache = JetShortNamesCache.OBJECT$.getKotlinInstance(project); Collection topLevelFunctions = namesCache.getTopLevelFunctionDescriptorsByName( referenceName, context, resolveSession, searchScope); @@ -151,11 +151,11 @@ public class AutoImportFix extends JetHintAction implem @NotNull ResolveSessionForBodies resolveSession, @NotNull Project project ) { - JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project); + JetShortNamesCache namesCache = JetShortNamesCache.OBJECT$.getKotlinInstance(project); Collection jetCallableExtensions = namesCache.getJetCallableExtensions( - new Condition() { + new Function1() { @Override - public boolean value(String callableExtensionName) { + public Boolean invoke(String callableExtensionName) { return callableExtensionName.equals(referenceName); } }, @@ -216,17 +216,17 @@ public class AutoImportFix extends JetHintAction implem private static PsiShortNamesCache getShortNamesCache(@NotNull JetFile jetFile) { if (ProjectStructureUtil.isJsKotlinModule(jetFile)) { - return JetShortNamesCache.getKotlinInstance(jetFile.getProject()); + return JetShortNamesCache.OBJECT$.getKotlinInstance(jetFile.getProject()); } return PsiShortNamesCache.getInstance(jetFile.getProject()); } private static Collection getJetClasses(@NotNull final String typeName, @NotNull GlobalSearchScope searchScope, @NotNull Project project, @NotNull KotlinCodeAnalyzer resolveSession) { - JetShortNamesCache cache = JetShortNamesCache.getKotlinInstance(project); - Collection descriptors = cache.getJetClassesDescriptors(new Condition() { + JetShortNamesCache cache = JetShortNamesCache.OBJECT$.getKotlinInstance(project); + Collection descriptors = cache.getJetClassesDescriptors(new Function1() { @Override - public boolean value(String s) { + public Boolean invoke(String s) { return typeName.equals(s); } }, resolveSession, searchScope);