All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.analyzer.AnalyzerFacade.kt Maven / Gradle / Ivy

There is a newer version: 2.0.20-RC
Show newest version
/*
 * Copyright 2010-2015 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.analyzer

import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.config.TargetPlatformVersion
import org.jetbrains.kotlin.container.ComponentProvider
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.context.withModule
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.PackagePartProvider
import org.jetbrains.kotlin.descriptors.impl.LazyModuleDependencies
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CompilerEnvironment
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.storage.NotNullLazyValue
import org.jetbrains.kotlin.utils.keysToMap
import java.util.*
import kotlin.coroutines.experimental.buildSequence

class ResolverForModule(
        val packageFragmentProvider: PackageFragmentProvider,
        val componentProvider: ComponentProvider
)

abstract class ResolverForProject {
    fun resolverForModule(moduleInfo: M): ResolverForModule = resolverForModuleDescriptor(descriptorForModule(moduleInfo))
    abstract fun tryGetResolverForModule(moduleInfo: M): ResolverForModule?
    abstract fun descriptorForModule(moduleInfo: M): ModuleDescriptor
    abstract fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule

    abstract val name: String
    abstract val allModules: Collection

    override fun toString() = name
}

class EmptyResolverForProject : ResolverForProject() {
    override val name: String
        get() = "Empty resolver"

    override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? = null
    override fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule = throw IllegalStateException("$descriptor is not contained in this resolver")
    override fun descriptorForModule(moduleInfo: M) = throw IllegalStateException("Should not be called for $moduleInfo")
    override val allModules: Collection = listOf()
}

class ResolverForProjectImpl(
        private val debugName: String,
        val descriptorByModule: Map,
        val delegateResolver: ResolverForProject = EmptyResolverForProject()
) : ResolverForProject() {
    override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? {
        if (!isCorrectModuleInfo(moduleInfo)) {
            return null
        }
        return resolverForModuleDescriptor(doGetDescriptorForModule(moduleInfo))
    }

    internal val resolverByModuleDescriptor: MutableMap> = HashMap()

    override val allModules: Collection by lazy {
        (descriptorByModule.keys + delegateResolver.allModules).toSet()
    }

    override val name: String
        get() = "Resolver for '$debugName'"

    private fun isCorrectModuleInfo(moduleInfo: M) = moduleInfo in allModules

    override fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule {
        val computation = resolverByModuleDescriptor[descriptor] ?: run {
            if (delegateResolver is EmptyResolverForProject<*>) {
                throw IllegalStateException("$descriptor is not contained in resolver $name")
            }
            return delegateResolver.resolverForModuleDescriptor(descriptor)
        }
        return computation()
    }

    override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
        if (!isCorrectModuleInfo(moduleInfo)) {
            throw AssertionError("$name does not know how to resolve $moduleInfo")
        }
        return doGetDescriptorForModule(moduleInfo)
    }

    private fun doGetDescriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
        return descriptorByModule[moduleInfo] ?: delegateResolver.descriptorForModule(moduleInfo) as ModuleDescriptorImpl
    }
}

data class ModuleContent(
        val syntheticFiles: Collection,
        val moduleContentScope: GlobalSearchScope
)

interface PlatformAnalysisParameters

interface ModuleInfo {
    val isLibrary: Boolean
        get() = false
    val name: Name
    val displayedName: String get() = name.asString()
    fun dependencies(): List
    val platform: TargetPlatform? get() = null
    fun modulesWhoseInternalsAreVisible(): Collection = listOf()
    val capabilities: Map, Any?>
        get() = mapOf(Capability to this)

    // For common modules, we add built-ins at the beginning of the dependencies list, after the SDK.
    // This is needed because if a JVM module depends on the common module, we should use JVM built-ins for resolution of both modules.
    // The common module usually depends on kotlin-stdlib-common which may or may not have its own (common, non-JVM) built-ins,
    // but if they are present, they should come after JVM built-ins in the dependencies list, because JVM built-ins contain
    // additional members dependent on the JDK
    fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
            if (platform == TargetPlatform.Default)
                ModuleInfo.DependencyOnBuiltIns.AFTER_SDK
            else
                ModuleInfo.DependencyOnBuiltIns.LAST

    //TODO: (module refactoring) provide dependency on builtins after runtime in IDEA
    enum class DependencyOnBuiltIns { NONE, AFTER_SDK, LAST }

    companion object {
        val Capability = ModuleDescriptor.Capability("ModuleInfo")
    }
}

abstract class AnalyzerFacade {
    companion object {
        fun 

setupResolverForProject( debugName: String, projectContext: ProjectContext, modules: Collection, analyzerFacade: (M) -> AnalyzerFacade

, modulesContent: (M) -> ModuleContent, platformParameters: P, targetEnvironment: TargetEnvironment = CompilerEnvironment, builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance, delegateResolver: ResolverForProject = EmptyResolverForProject(), packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty }, firstDependency: M? = null, modulePlatforms: (M) -> MultiTargetPlatform?, packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory ): ResolverForProject { val storageManager = projectContext.storageManager val resolverForProject = ResolverForProjectImpl(debugName, modules.keysToMap { module -> ModuleDescriptorImpl(module.name, storageManager, builtIns, modulePlatforms(module), module.capabilities) }, delegateResolver) for (module in modules) { val moduleDescriptor = resolverForProject.descriptorForModule(module) moduleDescriptor.setDependencies(LazyModuleDependencies( storageManager, computeDependencies = { buildSequence { if (firstDependency != null) { yield(resolverForProject.descriptorForModule(firstDependency)) } if (module.dependencyOnBuiltIns() == ModuleInfo.DependencyOnBuiltIns.AFTER_SDK) { yield(moduleDescriptor.builtIns.builtInsModule) } for (dependency in module.dependencies()) { yield(resolverForProject.descriptorForModule(dependency as M)) } if (module.dependencyOnBuiltIns() == ModuleInfo.DependencyOnBuiltIns.LAST) { yield(moduleDescriptor.builtIns.builtInsModule) } }.toList() }, computeModulesWhoseInternalsAreVisible = { module.modulesWhoseInternalsAreVisible().mapTo(LinkedHashSet()) { resolverForProject.descriptorForModule(it as M) } }, computeImplementingModules = { if (modulePlatforms(module) != MultiTargetPlatform.Common) emptySet() else modules .filter { modulePlatforms(it) != MultiTargetPlatform.Common && module in it.dependencies() } .mapTo(mutableSetOf(), resolverForProject::descriptorForModule) } )) } for (module in modules) { val descriptor = resolverForProject.descriptorForModule(module) val content = modulesContent(module) val computeResolverForModule = storageManager.createLazyValue { ResolverForModuleComputationTracker.getInstance(projectContext.project)?.onResolverComputed(module) analyzerFacade(module).createResolverForModule( module, descriptor, projectContext.withModule(descriptor), modulesContent(module), platformParameters, targetEnvironment, resolverForProject, packagePartProviderFactory(module, content) ) } descriptor.initialize( DelegatingPackageFragmentProvider(content, packageOracleFactory.createOracle(module), computeResolverForModule)) resolverForProject.resolverByModuleDescriptor[descriptor] = computeResolverForModule } return resolverForProject } } protected abstract fun createResolverForModule( moduleInfo: M, moduleDescriptor: ModuleDescriptorImpl, moduleContext: ModuleContext, moduleContent: ModuleContent, platformParameters: P, targetEnvironment: TargetEnvironment, resolverForProject: ResolverForProject, packagePartProvider: PackagePartProvider ): ResolverForModule abstract val targetPlatform: TargetPlatform } private class DelegatingPackageFragmentProvider( moduleContent: ModuleContent, private val packageOracle: PackageOracle, private val resolverForModule: NotNullLazyValue ) : PackageFragmentProvider { private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet() override fun getPackageFragments(fqName: FqName): List { if (certainlyDoesNotExist(fqName)) return emptyList() return resolverForModule().packageFragmentProvider.getPackageFragments(fqName) } override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection { if (certainlyDoesNotExist(fqName)) return emptyList() return resolverForModule().packageFragmentProvider.getSubPackagesOf(fqName, nameFilter) } private fun certainlyDoesNotExist(fqName: FqName): Boolean { if (resolverForModule.isComputed()) return false // let this request get cached inside delegate return !packageOracle.packageExists(fqName) && fqName !in syntheticFilePackages } } interface PackageOracle { fun packageExists(fqName: FqName): Boolean object Optimistic : PackageOracle { override fun packageExists(fqName: FqName): Boolean = true } } interface PackageOracleFactory { fun createOracle(moduleInfo: ModuleInfo): PackageOracle object OptimisticFactory : PackageOracleFactory { override fun createOracle(moduleInfo: ModuleInfo) = PackageOracle.Optimistic } } interface LanguageSettingsProvider { fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project): LanguageVersionSettings fun getTargetPlatform(moduleInfo: ModuleInfo): TargetPlatformVersion object Default : LanguageSettingsProvider { override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = LanguageVersionSettingsImpl.DEFAULT override fun getTargetPlatform(moduleInfo: ModuleInfo): TargetPlatformVersion = TargetPlatformVersion.NoVersion } companion object { fun getInstance(project: Project) = ServiceManager.getService(project, LanguageSettingsProvider::class.java) ?: Default } } interface ResolverForModuleComputationTracker { fun onResolverComputed(moduleInfo: ModuleInfo) companion object { fun getInstance(project: Project): ResolverForModuleComputationTracker? = ServiceManager.getService(project, ResolverForModuleComputationTracker::class.java) ?: null } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy