Remove all usages of JetFromJavaDescriptorHelper

Rewrite some utilities in KotlinIndicesHelper
ResolutionFacade#resolveToDescriptor() should be avoided on psi from compiled kotlin for now
This commit is contained in:
Pavel V. Talanov
2014-12-09 14:50:32 +03:00
parent dbdf3c0e98
commit ba22c3d790
3 changed files with 29 additions and 255 deletions
@@ -1,193 +0,0 @@
/*
* 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.google.common.collect.Sets;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.resolve.java.JavaResolverUtils;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_CLASS;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_PACKAGE;
/**
* Number of helper methods for searching kotlin element prototypes in java. Methods use java indices for search.
*/
public class JetFromJavaDescriptorHelper {
private JetFromJavaDescriptorHelper() {
}
static Collection<PsiClass> getClassesForKotlinPackages(Project project, GlobalSearchScope scope) {
/* Will iterate through short name caches
Kotlin packages from jar a class files will be collected from java cache
Kotlin package classes from sources will be collected with JetShortNamesCache.getClassesByName */
return getClassesByAnnotation(KOTLIN_PACKAGE.shortName().asString(), project, scope);
}
/**
* 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>();
for (PsiClass packageClass : getClassesForKotlinPackages(project, scope)) {
for (PsiMethod psiMethod : packageClass.getMethods()) {
if (psiMethod.getModifierList().hasModifierProperty(PsiModifier.STATIC)) {
result.add(psiMethod.getName());
}
}
}
return result;
}
@NotNull
static Collection<PsiClass> getCompiledClassesForTopLevelObjects(Project project, GlobalSearchScope scope) {
Set<PsiClass> jetObjectClasses = Sets.newHashSet();
Collection<PsiClass> classesByAnnotation = getClassesByAnnotation(KOTLIN_CLASS.shortName().asString(), project, scope);
for (PsiClass psiClass : classesByAnnotation) {
ClassKind kind = getCompiledClassKind(psiClass);
if (kind == ClassKind.OBJECT && psiClass.getContainingClass() == null) {
jetObjectClasses.add(psiClass);
}
}
return jetObjectClasses;
}
@Nullable
public static ClassKind getCompiledClassKind(@NotNull PsiClass psiClass) {
ClassData classData = getClassData(psiClass);
if (classData == null) return null;
return SerializationPackage.classKind(Flags.CLASS_KIND.get(classData.getClassProto().getFlags()));
}
@Nullable
private static ClassData getClassData(@NotNull PsiClass psiClass) {
String[] data = getAnnotationDataForKotlinClass(psiClass);
return data == null ? null : JavaProtoBufUtil.readClassDataFrom(data);
}
@Nullable
private static PackageData getPackageData(@NotNull PsiClass psiClass) {
String[] data = getAnnotationDataForKotlinClass(psiClass);
return data == null ? null : JavaProtoBufUtil.readPackageDataFrom(data);
}
@Nullable
private static String[] getAnnotationDataForKotlinClass(@NotNull PsiClass psiClass) {
VirtualFile virtualFile = getVirtualFileForPsiClass(psiClass);
if (virtualFile != null) {
KotlinJvmBinaryClass kotlinClass = KotlinBinaryClassCache.getKotlinBinaryClass(virtualFile);
if (kotlinClass != null) {
return kotlinClass.getClassHeader().getAnnotationData();
}
}
return null;
}
//TODO: common utility
//TODO: doesn't work for inner classes and stuff
@Nullable
private static VirtualFile getVirtualFileForPsiClass(@NotNull PsiClass psiClass) {
PsiFile psiFile = psiClass.getContainingFile();
return psiFile == null ? null : psiFile.getVirtualFile();
}
@Nullable
static FqName getJetTopLevelDeclarationFQN(@NotNull PsiMethod method) {
PsiClass containingClass = method.getContainingClass();
if (containingClass != null) {
String qualifiedName = containingClass.getQualifiedName();
assert qualifiedName != null;
FqName classFQN = new FqName(qualifiedName);
if (JavaResolverUtils.isCompiledKotlinPackageClass(containingClass)) {
return classFQN.parent().child(Name.identifier(method.getName()));
}
}
return null;
}
private static Collection<PsiClass> getClassesByAnnotation(
String annotationName, Project project, GlobalSearchScope scope
) {
Collection<PsiClass> classes = Sets.newHashSet();
Collection<PsiAnnotation> annotations = JavaAnnotationIndex.getInstance().get(annotationName, project, scope);
for (PsiAnnotation annotation : annotations) {
PsiModifierList modifierList = (PsiModifierList) annotation.getParent();
PsiElement owner = modifierList.getParent();
if (owner instanceof PsiClass) {
classes.add((PsiClass) owner);
}
}
return classes;
}
@NotNull
public static Collection<FqName> getTopLevelCallableFqNames(
@NotNull Project project,
@NotNull GlobalSearchScope scope,
boolean shouldBeExtension
) {
Collection<FqName> result = Sets.newHashSet();
Collection<PsiClass> packageClasses = getClassesByAnnotation(KOTLIN_PACKAGE.shortName().asString(), project, scope);
for (PsiClass psiClass : packageClasses) {
String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName == null) {
continue;
}
FqName packageFqName = new FqName(qualifiedName).parent();
PackageData data = getPackageData(psiClass);
if (data == null) {
continue;
}
NameResolver nameResolver = data.getNameResolver();
for (ProtoBuf.Callable callable : data.getPackageProto().getMemberList()) {
if (callable.hasReceiverType() == shouldBeExtension) {
Name name = nameResolver.getName(callable.getName());
result.add(packageFqName.child(name));
}
}
}
return result;
}
}
@@ -23,7 +23,6 @@ import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.lang.resolve.*
import org.jetbrains.jet.lang.resolve.name.Name
import org.jetbrains.jet.lang.resolve.scopes.JetScope
import com.intellij.openapi.project.Project
import java.util.HashSet
@@ -37,6 +36,7 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolutionFacade
import org.jetbrains.jet.plugin.util.substituteExtensionIfCallable
import org.jetbrains.jet.plugin.util.CallType
import org.jetbrains.jet.plugin.codeInsight.ReferenceVariantsHelper
import org.jetbrains.jet.utils.addToStdlib.singletonOrEmptyList
public class KotlinIndicesHelper(
private val project: Project,
@@ -47,36 +47,32 @@ public class KotlinIndicesHelper(
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
) {
public fun getTopLevelCallablesByName(name: String, context: JetExpression /*TODO: to be dropped*/): Collection<CallableDescriptor> {
val jetScope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] ?: return listOf()
val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] ?: return listOf()
val result = HashSet<CallableDescriptor>()
//TODO: this code is temporary and is to be dropped when compiled top level functions are indexed
val identifier = Name.identifier(name)
for (fqName in JetFromJavaDescriptorHelper.getTopLevelCallableFqNames(project, scope, false)) {
if (fqName.lastSegmentIs(identifier)) {
result.addAll(findTopLevelCallables(fqName, context, jetScope))
val declarations = HashSet<JetNamedDeclaration>()
declarations.addTopLevelNonExtensionCallablesByName(JetFunctionShortNameIndex.getInstance(), name)
declarations.addTopLevelNonExtensionCallablesByName(JetPropertyShortNameIndex.getInstance(), name)
return declarations.flatMap {
if (it.getContainingJetFile().isCompiled()) {
val importDirective = JetPsiFactory(project).createImportDirective(it.getFqName().asString())
analyzeImportReference(importDirective, resolutionScope, BindingTraceContext(), moduleDescriptor).filterIsInstance<CallableDescriptor>()
}
}
result.addTopLevelNonExtensionCallablesByName(JetFunctionShortNameIndex.getInstance(), name)
result.addTopLevelNonExtensionCallablesByName(JetPropertyShortNameIndex.getInstance(), name)
return result.filter(visibilityFilter)
else {
(resolutionFacade.resolveToDescriptor(it) as? CallableDescriptor).singletonOrEmptyList()
}
}.filter { it.getExtensionReceiverParameter() == null && visibilityFilter(it) }
}
private fun MutableSet<CallableDescriptor>.addTopLevelNonExtensionCallablesByName(
private fun MutableSet<JetNamedDeclaration>.addTopLevelNonExtensionCallablesByName(
index: StringStubIndexExtension<out JetCallableDeclaration>,
name: String
) {
index.get(name, project, scope)
.filter { it.getParent() is JetFile && it.getReceiverTypeReference() == null }
.mapTo(this) { resolutionFacade.resolveToDescriptor(it) as CallableDescriptor }
index.get(name, project, scope).filterTo(this) { it.getParent() is JetFile && it.getReceiverTypeReference() == null }
}
public fun getTopLevelCallables(nameFilter: (String) -> Boolean, context: JetExpression /*TODO: to be dropped*/): Collection<CallableDescriptor> {
val sourceNames = JetTopLevelFunctionFqnNameIndex.getInstance().getAllKeys(project).stream() + JetTopLevelPropertyFqnNameIndex.getInstance().getAllKeys(project).stream()
val allFqNames = sourceNames.map { FqName(it) } + JetFromJavaDescriptorHelper.getTopLevelCallableFqNames(project, scope, false).stream()
val allFqNames = sourceNames.map { FqName(it) }
val jetScope = bindingContext[BindingContext.RESOLUTION_SCOPE, context] ?: return listOf()
@@ -93,19 +89,17 @@ public class KotlinIndicesHelper(
val sourceFunctionNames = functionsIndex.getAllKeys(project).stream().map { FqName(it) }
val sourcePropertyNames = propertiesIndex.getAllKeys(project).stream().map { FqName(it) }
val compiledFqNames = JetFromJavaDescriptorHelper.getTopLevelCallableFqNames(project, scope, true).stream()
val result = HashSet<CallableDescriptor>()
result.fqNamesToSuitableExtensions(sourceFunctionNames, nameFilter, functionsIndex, expression, bindingContext, dataFlowInfo)
result.fqNamesToSuitableExtensions(sourcePropertyNames, nameFilter, propertiesIndex, expression, bindingContext, dataFlowInfo)
result.fqNamesToSuitableExtensions(compiledFqNames, nameFilter, null, expression, bindingContext, dataFlowInfo)
return result
}
private fun MutableCollection<CallableDescriptor>.fqNamesToSuitableExtensions(
fqNames: Stream<FqName>,
nameFilter: (String) -> Boolean,
index: StringStubIndexExtension<out JetCallableDeclaration>?,
index: StringStubIndexExtension<out JetCallableDeclaration>,
expression: JetSimpleNameExpression,
bindingContext: BindingContext,
dataFlowInfo: DataFlowInfo) {
@@ -141,7 +135,7 @@ public class KotlinIndicesHelper(
* Check that function or property with the given qualified name can be resolved in given scope and called on given receiver
*/
private fun findSuitableExtensions(callableFQN: FqName,
index: StringStubIndexExtension<out JetCallableDeclaration>?,
index: StringStubIndexExtension<out JetCallableDeclaration>,
receiverValue: ReceiverValue,
dataFlowInfo: DataFlowInfo,
callType: CallType,
@@ -149,18 +143,14 @@ public class KotlinIndicesHelper(
module: ModuleDescriptor,
bindingContext: BindingContext): Stream<CallableDescriptor> {
val fqnString = callableFQN.asString()
val descriptors = if (index != null) {
index.get(fqnString, project, scope)
.filter { it.getReceiverTypeReference() != null }
.map { resolutionFacade.resolveToDescriptor(it) as CallableDescriptor }
}
else {
val extensions = index.get(fqnString, project, scope).filter { it.getReceiverTypeReference() != null }
val descriptors = if (extensions.any { it.getContainingJetFile().isCompiled() } ) {
val importDirective = JetPsiFactory(project).createImportDirective(fqnString)
analyzeImportReference(importDirective, resolutionScope, BindingTraceContext(), module)
.filterIsInstance<CallableDescriptor>()
.filter { it.getExtensionReceiverParameter() != null }
}
else extensions.map { resolutionFacade.resolveToDescriptor(it) as CallableDescriptor }
return descriptors.stream()
.filter(visibilityFilter)
.flatMap { it.substituteExtensionIfCallable(receiverValue, callType, bindingContext, dataFlowInfo).stream() }
@@ -17,15 +17,10 @@
package org.jetbrains.jet.plugin.completion
import com.intellij.codeInsight.completion.*
import com.intellij.psi.PsiClass
import org.jetbrains.jet.asJava.KotlinLightClass
import org.jetbrains.jet.lang.descriptors.ClassKind
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.resolve.java.JavaResolverUtils
import org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import org.jetbrains.jet.plugin.caches.JetFromJavaDescriptorHelper
import org.jetbrains.jet.plugin.project.ProjectStructureUtil
import org.jetbrains.jet.plugin.caches.KotlinIndicesHelper
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
@@ -56,37 +51,19 @@ class AllClassesCompletion(val parameters: CompletionParameters,
}
}
/**
* Add java elements with performing conversion to kotlin elements if necessary.
*/
private fun addAdaptedJavaCompletion(collector: LookupElementsCollector) {
AllClassesGetter.processJavaClasses(parameters, prefixMatcher, true, { psiClass ->
if (psiClass!! !is KotlinLightClass) { // Kotlin non-compiled class should have already been added as kotlin element before
if (JavaResolverUtils.isCompiledKotlinClass(psiClass)) {
addLookupElementForCompiledKotlinClass(psiClass, collector)
if (psiClass!! !is KotlinLightClass) { // Kotlin class should have already been added as kotlin element before
val kind = when {
psiClass.isAnnotationType() -> ClassKind.ANNOTATION_CLASS
psiClass.isInterface() -> ClassKind.TRAIT
psiClass.isEnum() -> ClassKind.ENUM_CLASS
else -> ClassKind.CLASS
}
else if (!JavaResolverUtils.isCompiledKotlinPackageClass(psiClass)) {
val kind = when {
psiClass.isAnnotationType() -> ClassKind.ANNOTATION_CLASS
psiClass.isInterface() -> ClassKind.TRAIT
psiClass.isEnum() -> ClassKind.ENUM_CLASS
else -> ClassKind.CLASS
}
if (kindFilter(kind)) {
collector.addElementWithAutoInsertionSuppressed(lookupElementFactory.createLookupElementForJavaClass(psiClass))
}
if (kindFilter(kind)) {
collector.addElementWithAutoInsertionSuppressed(lookupElementFactory.createLookupElementForJavaClass(psiClass))
}
}
})
}
private fun addLookupElementForCompiledKotlinClass(aClass: PsiClass, collector: LookupElementsCollector) {
if (kindFilter(JetFromJavaDescriptorHelper.getCompiledClassKind(aClass))) {
val qualifiedName = aClass.getQualifiedName()
if (qualifiedName != null) {
val descriptors = ResolveSessionUtils.getClassDescriptorsByFqName(moduleDescriptor, FqName(qualifiedName)).filter(visibilityFilter)
collector.addDescriptorElements(descriptors, suppressAutoInsertion = true)
}
}
}
}