Converted JetShortNamesCache to Kotlin
This commit is contained in:
+1
@@ -193,6 +193,7 @@ public class ExpressionTypingUtils {
|
||||
* @param scope
|
||||
* @return
|
||||
*/
|
||||
@NotNull
|
||||
public static List<CallableDescriptor> canFindSuitableCall(
|
||||
@NotNull FqName callableFQN,
|
||||
@NotNull JetExpression receiverExpression,
|
||||
|
||||
+2
@@ -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<String> getPossiblePackageDeclarationsNames(Project project, GlobalSearchScope scope) {
|
||||
Collection<String> result = new ArrayList<String>();
|
||||
|
||||
@@ -71,6 +72,7 @@ public class JetFromJavaDescriptorHelper {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static Collection<PsiClass> getCompiledClassesForTopLevelObjects(Project project, GlobalSearchScope scope) {
|
||||
Set<PsiClass> jetObjectClasses = Sets.newHashSet();
|
||||
|
||||
|
||||
@@ -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<String> classNames = JetClassShortNameIndex.getInstance().getAllKeys(project);
|
||||
|
||||
// package classes can not be indexed, since they have no explicit declarations
|
||||
IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project);
|
||||
Set<String> 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<PsiClass> result = new ArrayList<PsiClass>();
|
||||
|
||||
IDELightClassGenerationSupport lightClassGenerationSupport = IDELightClassGenerationSupport.getInstanceForIDE(project);
|
||||
MultiMap<String, FqName> packageClasses = lightClassGenerationSupport.getAllPossiblePackageClasses(scope);
|
||||
|
||||
// package classes can not be indexed, since they have no explicit declarations
|
||||
Collection<FqName> 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<JetClassOrObject> 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<String> 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<String> getAllTopLevelFunctionNames() {
|
||||
Set<String> functionNames = new HashSet<String>();
|
||||
functionNames.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project));
|
||||
functionNames.addAll(JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, GlobalSearchScope.allScope(project)));
|
||||
return functionNames;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<String> getAllTopLevelObjectNames() {
|
||||
Set<String> topObjectNames = new HashSet<String>();
|
||||
topObjectNames.addAll(JetTopLevelObjectShortNameIndex.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 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<ClassDescriptor> result = Sets.newHashSet();
|
||||
|
||||
Collection<JetObjectDeclaration> 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<FunctionDescriptor> 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<FunctionDescriptor> 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<FqName> topLevelFunctionFqNames =
|
||||
ContainerUtil.filter(JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames(project, scope, false), new Condition<FqName>() {
|
||||
@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<? extends DeclarationDescriptor> declarationDescriptors = new QualifiedExpressionResolver().analyseImportReference(
|
||||
importDirective, jetScope, new BindingTraceContext(), resolveSession.getModuleDescriptor());
|
||||
for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
|
||||
if (declarationDescriptor instanceof FunctionDescriptor) {
|
||||
result.add((FunctionDescriptor) declarationDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<FqName> affectedPackages = Sets.newHashSet();
|
||||
Collection<JetNamedFunction> 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<PsiElement> getJetExtensionFunctionsByName(@NotNull String name, @NotNull GlobalSearchScope scope) {
|
||||
HashSet<PsiElement> functions = new HashSet<PsiElement>();
|
||||
functions.addAll(JetTopLevelExtensionFunctionShortNameIndex.getInstance().get(name, project, scope));
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
// TODO: Make it work for properties
|
||||
@NotNull
|
||||
public Collection<DeclarationDescriptor> getJetCallableExtensions(
|
||||
@NotNull final Condition<String> 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<FqName> functionFQNs = extensionFunctionsFromSourceFqNames(acceptedNameCondition, searchScope);
|
||||
functionFQNs.addAll(ContainerUtil.filter(JetFromJavaDescriptorHelper.getTopLevelFunctionFqNames(project, searchScope, true), new Condition<FqName>() {
|
||||
@Override
|
||||
public boolean value(FqName fqName) {
|
||||
return acceptedNameCondition.value(fqName.shortName().asString());
|
||||
}
|
||||
}));
|
||||
|
||||
Collection<DeclarationDescriptor> resultDescriptors = new ArrayList<DeclarationDescriptor>();
|
||||
// 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<FqName> extensionFunctionsFromSourceFqNames(
|
||||
@NotNull Condition<String> acceptedNameCondition,
|
||||
@NotNull GlobalSearchScope searchScope
|
||||
) {
|
||||
Set<String> extensionFunctionNames = new HashSet<String>(JetTopLevelExtensionFunctionShortNameIndex.getInstance().getAllKeys(project));
|
||||
|
||||
Set<FqName> functionFQNs = new java.util.HashSet<FqName>();
|
||||
|
||||
// Collect all possible extension function qualified names
|
||||
for (String name : extensionFunctionNames) {
|
||||
if (acceptedNameCondition.value(name)) {
|
||||
Collection<PsiElement> 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<ClassDescriptor> getJetClassesDescriptors(
|
||||
@NotNull Condition<String> acceptedShortNameCondition,
|
||||
@NotNull KotlinCodeAnalyzer analyzer,
|
||||
@NotNull GlobalSearchScope searchScope
|
||||
) {
|
||||
Collection<ClassDescriptor> classDescriptors = new ArrayList<ClassDescriptor>();
|
||||
|
||||
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<ClassDescriptor> getJetClassesDescriptorsByFQName(
|
||||
@NotNull KotlinCodeAnalyzer analyzer, @NotNull FqName classFQName, @NotNull GlobalSearchScope searchScope) {
|
||||
Collection<JetClassOrObject> 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<PsiMethod> processor
|
||||
) {
|
||||
return ContainerUtil.process(getMethodsByName(name, scope), processor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String[] getAllMethodNames() {
|
||||
return ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAllMethodNames(@NotNull HashSet<String> 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<String> set) {
|
||||
}
|
||||
}
|
||||
+1
@@ -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);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public class JetClassShortNameIndex extends StringStubIndexExtension<JetClassOrO
|
||||
|
||||
private static final JetClassShortNameIndex ourInstance = new JetClassShortNameIndex();
|
||||
|
||||
@NotNull
|
||||
public static JetClassShortNameIndex getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
+1
@@ -26,6 +26,7 @@ public class JetTopLevelExtensionFunctionShortNameIndex extends StringStubIndexE
|
||||
|
||||
private static final JetTopLevelExtensionFunctionShortNameIndex instance = new JetTopLevelExtensionFunctionShortNameIndex();
|
||||
|
||||
@NotNull
|
||||
public static JetTopLevelExtensionFunctionShortNameIndex getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ public class JetTopLevelNonExtensionFunctionShortNameIndex extends StringStubInd
|
||||
|
||||
private static final JetTopLevelNonExtensionFunctionShortNameIndex ourInstance = new JetTopLevelNonExtensionFunctionShortNameIndex();
|
||||
|
||||
@NotNull
|
||||
public static JetTopLevelNonExtensionFunctionShortNameIndex getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ public class JetTopLevelObjectShortNameIndex extends StringStubIndexExtension<Je
|
||||
|
||||
private static final JetTopLevelObjectShortNameIndex ourInstance = new JetTopLevelObjectShortNameIndex();
|
||||
|
||||
@NotNull
|
||||
public static JetTopLevelObjectShortNameIndex getInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.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 org.jetbrains.annotations.NonNls
|
||||
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.*
|
||||
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.*
|
||||
import com.intellij.util.containers
|
||||
|
||||
/**
|
||||
* 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(private val project: Project) : PsiShortNamesCache() {
|
||||
class object {
|
||||
public fun getKotlinInstance(project: Project): JetShortNamesCache {
|
||||
val extensions = Extensions.getArea(project).getExtensionPoint<PsiShortNamesCache>(PsiShortNamesCache.EP_NAME).getExtensions()
|
||||
for (extension in extensions) {
|
||||
if (extension is JetShortNamesCache) {
|
||||
return extension as JetShortNamesCache
|
||||
}
|
||||
}
|
||||
throw IllegalStateException(javaClass<JetShortNamesCache>().getSimpleName() + " is not found for project " + project)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return kotlin class names from project sources which should be visible from java.
|
||||
*/
|
||||
override fun getAllClassNames(): Array<String> {
|
||||
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<PsiClass> {
|
||||
val result = ArrayList<PsiClass>()
|
||||
|
||||
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<String>) {
|
||||
destination.addAll(Arrays.asList<String>(*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<String> {
|
||||
return (JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project)
|
||||
+ JetFromJavaDescriptorHelper.getPossiblePackageDeclarationsNames(project, GlobalSearchScope.allScope(project))).toSet()
|
||||
}
|
||||
|
||||
public fun getAllTopLevelObjectNames(): Collection<String> {
|
||||
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<ClassDescriptor> {
|
||||
val result = hashSetOf<ClassDescriptor>()
|
||||
|
||||
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<FunctionDescriptor> {
|
||||
|
||||
val jetScope = resolveSession.resolveToElement(context).get<JetExpression, JetScope>(BindingContext.RESOLUTION_SCOPE, context) ?: return listOf()
|
||||
|
||||
val result = hashSetOf<FunctionDescriptor>()
|
||||
|
||||
//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<JetFile>())
|
||||
.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<PsiElement>
|
||||
= 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<DeclarationDescriptor> {
|
||||
val context = resolveSession.resolveToElement(expression)
|
||||
val receiverExpression = expression.getReceiverExpression() ?: return listOf()
|
||||
val expressionType = context.get<JetExpression, JetType>(BindingContext.EXPRESSION_TYPE, receiverExpression)
|
||||
val scope = context.get<JetExpression, JetScope>(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<FqName> {
|
||||
val extensionFunctionNames = HashSet(JetTopLevelExtensionFunctionShortNameIndex.getInstance().getAllKeys(project))
|
||||
|
||||
val functionFQNs = HashSet<FqName>()
|
||||
|
||||
// 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<ClassDescriptor> {
|
||||
val classDescriptors = ArrayList<ClassDescriptor>()
|
||||
|
||||
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<ClassDescriptor> {
|
||||
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<PsiMethod>
|
||||
= array()
|
||||
|
||||
override fun getMethodsByNameIfNotMoreThan(NonNls name: String, scope: GlobalSearchScope, maxCount: Int): Array<PsiMethod>
|
||||
= array()
|
||||
|
||||
override fun getFieldsByNameIfNotMoreThan(NonNls s: String, scope: GlobalSearchScope, i: Int): Array<PsiField>
|
||||
= array()
|
||||
|
||||
override fun processMethodsWithName(NonNls name: String, scope: GlobalSearchScope, processor: Processor<PsiMethod>): Boolean
|
||||
= ContainerUtil.process(getMethodsByName(name, scope), processor)
|
||||
|
||||
override fun getAllMethodNames(): Array<String>
|
||||
= array()
|
||||
|
||||
override fun getAllMethodNames(set: containers.HashSet<String>) {
|
||||
set.addAll(JetTopLevelNonExtensionFunctionShortNameIndex.getInstance().getAllKeys(project))
|
||||
}
|
||||
|
||||
override fun getFieldsByName(NonNls name: String, scope: GlobalSearchScope): Array<PsiField>
|
||||
= array()
|
||||
|
||||
override fun getAllFieldNames(): Array<String>
|
||||
= array()
|
||||
|
||||
override fun getAllFieldNames(set: containers.HashSet<String>) {
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<JetSimpleNameExpression> implem
|
||||
@NotNull ResolveSessionForBodies resolveSession,
|
||||
@NotNull Project project
|
||||
) {
|
||||
JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project);
|
||||
JetShortNamesCache namesCache = JetShortNamesCache.OBJECT$.getKotlinInstance(project);
|
||||
|
||||
Collection<FunctionDescriptor> topLevelFunctions = namesCache.getTopLevelFunctionDescriptorsByName(
|
||||
referenceName, context, resolveSession, searchScope);
|
||||
@@ -151,11 +151,11 @@ public class AutoImportFix extends JetHintAction<JetSimpleNameExpression> implem
|
||||
@NotNull ResolveSessionForBodies resolveSession,
|
||||
@NotNull Project project
|
||||
) {
|
||||
JetShortNamesCache namesCache = JetShortNamesCache.getKotlinInstance(project);
|
||||
JetShortNamesCache namesCache = JetShortNamesCache.OBJECT$.getKotlinInstance(project);
|
||||
Collection<DeclarationDescriptor> jetCallableExtensions = namesCache.getJetCallableExtensions(
|
||||
new Condition<String>() {
|
||||
new Function1<String, Boolean>() {
|
||||
@Override
|
||||
public boolean value(String callableExtensionName) {
|
||||
public Boolean invoke(String callableExtensionName) {
|
||||
return callableExtensionName.equals(referenceName);
|
||||
}
|
||||
},
|
||||
@@ -216,17 +216,17 @@ public class AutoImportFix extends JetHintAction<JetSimpleNameExpression> 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<FqName> getJetClasses(@NotNull final String typeName, @NotNull GlobalSearchScope searchScope, @NotNull Project project, @NotNull KotlinCodeAnalyzer resolveSession) {
|
||||
JetShortNamesCache cache = JetShortNamesCache.getKotlinInstance(project);
|
||||
Collection<ClassDescriptor> descriptors = cache.getJetClassesDescriptors(new Condition<String>() {
|
||||
JetShortNamesCache cache = JetShortNamesCache.OBJECT$.getKotlinInstance(project);
|
||||
Collection<ClassDescriptor> descriptors = cache.getJetClassesDescriptors(new Function1<String, Boolean>() {
|
||||
@Override
|
||||
public boolean value(String s) {
|
||||
public Boolean invoke(String s) {
|
||||
return typeName.equals(s);
|
||||
}
|
||||
}, resolveSession, searchScope);
|
||||
|
||||
Reference in New Issue
Block a user