Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2017 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.kotlin.javac
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.SearchScope
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.javac.wrappers.trees.find
import org.jetbrains.kotlin.javac.wrappers.trees.findInner
import org.jetbrains.kotlin.javac.wrappers.trees.tryToResolveByFqName
import org.jetbrains.kotlin.javac.wrappers.trees.tryToResolveInJavaLang
import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
class KotlinClassifiersCache(sourceFiles: Collection,
private val javac: JavacWrapper) {
private val kotlinClasses: Map = sourceFiles.flatMap { ktFile ->
ktFile.collectDescendantsOfType().map { it.fqName to it } +
(ktFile.javaFileFacadeFqName to null)
}.toMap()
private val classifiers = hashMapOf()
fun getKotlinClassifier(fqName: FqName) = classifiers[fqName] ?: createClassifier(fqName)
private fun createClassifier(fqName: FqName): JavaClass? {
if (!kotlinClasses.containsKey(fqName)) return null
val kotlinClassifier = kotlinClasses[fqName] ?: return null
return MockKotlinClassifier(fqName,
kotlinClassifier,
kotlinClassifier.typeParameters.isNotEmpty(),
javac)
.apply { classifiers[fqName] = this }
}
}
class MockKotlinClassifier(override val fqName: FqName,
private val classOrObject: KtClassOrObject,
val hasTypeParameters: Boolean,
private val javac: JavacWrapper) : VirtualFileBoundJavaClass {
override val isAbstract: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val isStatic: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val isFinal: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val visibility: Visibility
get() = throw UnsupportedOperationException("Should not be called")
override val typeParameters: List
get() = throw UnsupportedOperationException("Should not be called")
override val supertypes: Collection
get() = classOrObject.superTypeListEntries
.map { superTypeListEntry ->
val userType = superTypeListEntry.typeAsUserType
arrayListOf().apply {
userType?.referencedName?.let { add(it) }
var qualifier = userType?.qualifier
while (qualifier != null) {
qualifier.referencedName?.let { add(it) }
qualifier = qualifier.qualifier
}
}.reversed().joinToString(separator = ".") { it }
}
.mapNotNull { resolveSupertype(it, classOrObject, javac) }
.map { MockKotlinClassifierType(it) }
val innerClasses: Collection
get() = classOrObject.declarations.filterIsInstance()
.mapNotNull { nestedClassOrObject ->
nestedClassOrObject.fqName?.let {
javac.getKotlinClassifier(it)
}
}
override val outerClass: JavaClass?
get() = throw UnsupportedOperationException("Should not be called")
override val isInterface: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val isAnnotationType: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val isEnum: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val lightClassOriginKind
get() = LightClassOriginKind.SOURCE
override val virtualFile: VirtualFile?
get() = null
override val methods: Collection
get() = throw UnsupportedOperationException("Should not be called")
override val fields: Collection
get() = throw UnsupportedOperationException("Should not be called")
override val constructors: Collection
get() = throw UnsupportedOperationException("Should not be called")
override val name
get() = fqName.shortNameOrSpecial()
override val annotations
get() = throw UnsupportedOperationException("Should not be called")
override val isDeprecatedInJavaDoc: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override fun isFromSourceCodeInScope(scope: SearchScope) = true
override fun findAnnotation(fqName: FqName) =
throw UnsupportedOperationException("Should not be called")
override val innerClassNames
get() = innerClasses.map(JavaClass::name)
override fun findInnerClass(name: Name) =
innerClasses.find { it.name == name }
}
class MockKotlinClassifierType(override val classifier: JavaClassifier) : JavaClassifierType {
override val typeArguments: List
get() = throw UnsupportedOperationException("Should not be called")
override val isRaw: Boolean
get() = throw UnsupportedOperationException("Should not be called")
override val annotations: Collection
get() = throw UnsupportedOperationException("Should not be called")
override val classifierQualifiedName: String
get() = throw UnsupportedOperationException("Should not be called")
override val presentableText: String
get() = throw UnsupportedOperationException("Should not be called")
override fun findAnnotation(fqName: FqName) =
throw UnsupportedOperationException("Should not be called")
override val isDeprecatedInJavaDoc: Boolean
get() = throw UnsupportedOperationException("Should not be called")
}
private fun resolveSupertype(name: String,
classOrObject: KtClassOrObject,
javac: JavacWrapper): JavaClass? {
val nameParts = name.split(".")
val ktFile = classOrObject.containingKtFile
tryToResolveInner(name, classOrObject, javac, nameParts)?.let { return it }
ktFile.tryToResolvePackageClass(name, javac, nameParts)?.let { return it }
tryToResolveByFqName(name, javac)?.let { return it }
ktFile.tryToResolveSingleTypeImport(name, javac, nameParts)?.let { return it }
ktFile.tryToResolveTypeImportOnDemand(name, javac, nameParts)?.let { return it }
tryToResolveInJavaLang(name, javac)?.let { return it }
return null
}
private fun tryToResolveInner(name: String,
classOrObject: KtClassOrObject,
javac: JavacWrapper,
nameParts: List) =
classOrObject.containingClassOrObject?.let { containingClass ->
containingClass.fqName?.let {
javac.findClass(it) ?: javac.getKotlinClassifier(it)
}
}?.findInner(name, javac, nameParts)
private fun KtFile.tryToResolvePackageClass(name: String,
javac: JavacWrapper,
nameParts: List = emptyList()): JavaClass? {
if (nameParts.size > 1) {
return find(FqName("${packageFqName.asString()}.${nameParts.first()}"), javac, nameParts)
}
else {
return javac.findClass(FqName("${packageFqName.asString()}.$name"))
?: javac.getKotlinClassifier(FqName("${packageFqName.asString()}.$name"))
}
}
private fun KtFile.tryToResolveSingleTypeImport(name: String,
javac: JavacWrapper,
nameParts: List = emptyList()): JavaClass? {
if (nameParts.size > 1) {
val foundImports = importDirectives.filter { it.text.endsWith(".${nameParts.first()}") }
foundImports.forEach { importDirective ->
importDirective.importedFqName?.let { importedFqName ->
find(importedFqName, javac, nameParts)?.let { importedClass ->
return importedClass
}
}
}
return null
}
else {
return importDirectives.find { importDirective ->
importDirective.text.endsWith(".$name")
}?.let { importDirective ->
importDirective.importedFqName?.let { fqName ->
javac.findClass(fqName) ?: javac.getKotlinClassifier(fqName)
}
}
}
}
private fun KtFile.tryToResolveTypeImportOnDemand(name: String,
javac: JavacWrapper,
nameParts: List = emptyList()): JavaClass? {
val packagesWithAsterisk = importDirectives.filter { it.text.endsWith("*") }
if (nameParts.size > 1) {
packagesWithAsterisk.forEach { importDirective ->
find(FqName("${importDirective.importedFqName?.asString()}.${nameParts.first()}"),
javac,
nameParts)?.let { return it }
}
return null
}
else {
packagesWithAsterisk.forEach { importDirective ->
val fqName = "${importDirective.importedFqName?.asString()}.$name".let(::FqName)
javac.findClass(fqName)?.let { return it } ?: javac.getKotlinClassifier(fqName)?.let { return it }
}
return null
}
}