[Expect/Actual] Remove PlatformExpectedAnnotator

This commit is contained in:
Dmitry Savvinov
2019-04-10 10:48:08 +03:00
parent 29beed9b21
commit 174ef56991
6 changed files with 83 additions and 140 deletions
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
@@ -54,67 +55,7 @@ class CommonAnalysisParameters(
* A facade that is used to analyze common (platform-independent) modules in multi-platform projects.
* See [CommonPlatform]
*/
object CommonResolverForModuleFactory : ResolverForModuleFactory() {
private class SourceModuleInfo(
override val name: Name,
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
private val dependOnOldBuiltIns: Boolean
) : ModuleInfo {
override fun dependencies() = listOf(this)
override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
if (dependOnOldBuiltIns) ModuleInfo.DependencyOnBuiltIns.LAST else ModuleInfo.DependencyOnBuiltIns.NONE
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
override val analyzerServices: PlatformDependentAnalyzerServices
get() = CommonPlatformAnalyzerServices
}
fun analyzeFiles(
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap(),
metadataPartProviderFactory: (ModuleContent<ModuleInfo>) -> MetadataPartProvider
): AnalysisResult {
val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns)
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
val multiplatformLanguageSettings = object : LanguageVersionSettings by languageVersionSettings {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
else languageVersionSettings.getFeatureSupport(feature)
}
@Suppress("NAME_SHADOWING")
val resolver = ResolverForProjectImpl(
"sources for metadata serializer",
ProjectContext(project, "metadata serializer"),
listOf(moduleInfo),
modulesContent = { ModuleContent(it, files, GlobalSearchScope.allScope(project)) },
moduleLanguageSettingsProvider = object : LanguageSettingsProvider {
override fun getLanguageVersionSettings(
moduleInfo: ModuleInfo,
project: Project,
isReleaseCoroutines: Boolean?
) = multiplatformLanguageSettings
override fun getTargetPlatform(
moduleInfo: ModuleInfo,
project: Project
) = TargetPlatformVersion.NoVersion
},
resolverForModuleFactoryByPlatform = { CommonResolverForModuleFactory },
platformParameters = { _ -> CommonAnalysisParameters(metadataPartProviderFactory) }
)
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
val container = resolver.resolverForModule(moduleInfo).componentProvider
container.get<LazyTopDownAnalyzer>().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
return AnalysisResult.success(container.get<BindingTrace>().bindingContext, moduleDescriptor)
}
class CommonResolverForModuleFactory(private val shouldCheckExpectActual: Boolean) : ResolverForModuleFactory() {
override fun <M : ModuleInfo> createResolverForModule(
moduleDescriptor: ModuleDescriptorImpl,
@@ -137,7 +78,7 @@ object CommonResolverForModuleFactory : ResolverForModuleFactory() {
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
val container = createContainerToResolveCommonCode(
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, metadataPartProvider,
languageVersionSettings, CommonPlatforms.defaultCommonPlatform, CommonPlatformAnalyzerServices
languageVersionSettings, CommonPlatforms.defaultCommonPlatform, CommonPlatformAnalyzerServices, shouldCheckExpectActual
)
val packageFragmentProviders = listOf(
@@ -147,6 +88,70 @@ object CommonResolverForModuleFactory : ResolverForModuleFactory() {
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
}
companion object {
private class SourceModuleInfo(
override val name: Name,
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
private val dependOnOldBuiltIns: Boolean
) : ModuleInfo {
override fun dependencies() = listOf(this)
override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
if (dependOnOldBuiltIns) ModuleInfo.DependencyOnBuiltIns.LAST else ModuleInfo.DependencyOnBuiltIns.NONE
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
override val analyzerServices: PlatformDependentAnalyzerServices
get() = CommonPlatformAnalyzerServices
}
fun analyzeFiles(
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap(),
shouldCheckExpectActual: Boolean = false,
metadataPartProviderFactory: (ModuleContent<ModuleInfo>) -> MetadataPartProvider
): AnalysisResult {
val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns)
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
val multiplatformLanguageSettings = object : LanguageVersionSettings by languageVersionSettings {
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
else languageVersionSettings.getFeatureSupport(feature)
}
@Suppress("NAME_SHADOWING")
val resolver = ResolverForProjectImpl(
"sources for metadata serializer",
ProjectContext(project, "metadata serializer"),
listOf(moduleInfo),
modulesContent = { ModuleContent(it, files, GlobalSearchScope.allScope(project)) },
moduleLanguageSettingsProvider = object : LanguageSettingsProvider {
override fun getLanguageVersionSettings(
moduleInfo: ModuleInfo,
project: Project,
isReleaseCoroutines: Boolean?
) = multiplatformLanguageSettings
override fun getTargetPlatform(
moduleInfo: ModuleInfo,
project: Project
) = TargetPlatformVersion.NoVersion
},
resolverForModuleFactoryByPlatform = { CommonResolverForModuleFactory(shouldCheckExpectActual) },
platformParameters = { _ -> CommonAnalysisParameters(metadataPartProviderFactory) }
)
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
val container = resolver.resolverForModule(moduleInfo).componentProvider
container.get<LazyTopDownAnalyzer>().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files)
return AnalysisResult.success(container.get<BindingTrace>().bindingContext, moduleDescriptor)
}
}
}
private fun createContainerToResolveCommonCode(
@@ -158,7 +163,8 @@ private fun createContainerToResolveCommonCode(
metadataPartProvider: MetadataPartProvider,
languageVersionSettings: LanguageVersionSettings,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices
analyzerServices: PlatformDependentAnalyzerServices,
shouldCheckExpectActual: Boolean
): StorageComponentContainer =
createContainer("ResolveCommonCode", analyzerServices) {
configureModule(moduleContext, platform, analyzerServices, bindingTrace, languageVersionSettings)
@@ -179,6 +185,10 @@ private fun createContainerToResolveCommonCode(
useInstance(metadataFinderFactory.create(moduleContentScope))
targetEnvironment.configure(this)
if (shouldCheckExpectActual) {
useImpl<ExpectedActualDeclarationChecker>()
}
}
fun StorageComponentContainer.configureCommonSpecificComponents() {
@@ -27,10 +27,12 @@ import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.platform.TargetPlatformVersion
import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.components.ClassicTypeSystemContextForCS
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbacksImpl
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.lazy.*
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
@@ -140,6 +142,12 @@ fun createContainerForLazyBodyResolve(
useImpl<LazyTopDownAnalyzer>()
useImpl<BasicAbsentDescriptorHandler>()
useInstance(moduleStructureOracle)
// All containers except common inject ExpectedActualDeclarationChecker, so for common we do that
// explicitly.
// Note that it is not possible to move this code to [CommonPlatformConfigurator], because during
// compilation of common-module to metadata we should skip those checks
if (platform.isCommon()) useImpl<ExpectedActualDeclarationChecker>()
}
fun createContainerForLazyLocalClassifierAnalyzer(
@@ -28,7 +28,7 @@ class CommonPlatformKindResolution : IdePlatformKindResolution {
override val kind get() = CommonIdePlatformKind
override val resolverForModuleFactory: ResolverForModuleFactory
get() = CommonResolverForModuleFactory
get() = CommonResolverForModuleFactory(shouldCheckExpectActual = true)
override fun createBuiltIns(settings: PlatformAnalysisSettings, projectContext: ProjectContext): KotlinBuiltIns {
return DefaultBuiltIns.Instance
@@ -34,7 +34,7 @@ object CommonIdePlatformKindTooling : IdePlatformKindTooling() {
override fun compilerArgumentsForProject(project: Project): CommonCompilerArguments? = null
override val resolverForModuleFactory = CommonResolverForModuleFactory
override val resolverForModuleFactory = CommonResolverForModuleFactory(true)
override val mavenLibraryIds = listOf(MAVEN_COMMON_STDLIB_ID)
override val gradlePluginId = "kotlin-platform-common"
@@ -594,7 +594,6 @@
<annotator language="kotlin" implementationClass="org.jetbrains.kotlin.idea.highlighter.DebugInfoAnnotator"/>
<annotator language="kotlin" implementationClass="org.jetbrains.kotlin.idea.highlighter.DuplicateJvmSignatureAnnotator"/>
<annotator language="kotlin" implementationClass="org.jetbrains.kotlin.idea.highlighter.PlatformExpectedAnnotator"/>
<problemHighlightFilter implementation="org.jetbrains.kotlin.idea.highlighter.KotlinProblemHighlightFilter"/>
<highlightVisitor implementation="org.jetbrains.kotlin.idea.highlighter.KotlinRainbowVisitor"/>
@@ -1,74 +0,0 @@
/*
* 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.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.MemberDescriptor
import org.jetbrains.kotlin.idea.caches.project.implementingDescriptors
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.core.toDescriptor
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.diagnostics.SimpleDiagnostics
import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.resolve.jvm.multiplatform.JavaActualAnnotationArgumentExtractor
class PlatformExpectedAnnotator : Annotator {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
val declaration = element as? KtNamedDeclaration ?: return
if (!isExpectedDeclaration(declaration)) return
if (!TargetPlatformDetector.getPlatform(declaration.containingKtFile).isCommon()) return
val implementingModules = declaration.findModuleDescriptor().implementingDescriptors
if (implementingModules.isEmpty()) return
val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return
if (!descriptor.isExpect) return
// TODO: obtain the list of annotation argument extractors from platform somehow
val checker = ExpectedActualDeclarationChecker(listOf(JavaActualAnnotationArgumentExtractor()))
val trace = BindingTraceContext()
for (module in implementingModules) {
checker.checkExpectedDeclarationHasActual(declaration, descriptor, trace, module, ExpectActualTracker.DoNothing)
}
val suppressionCache = KotlinCacheService.getInstance(declaration.project).getSuppressionCache()
val filteredList = trace.bindingContext.diagnostics.filter { diagnostic ->
!suppressionCache.isSuppressed(declaration, diagnostic.factory.name, diagnostic.severity)
}
if (filteredList.isEmpty()) return
KotlinPsiChecker().annotateElement(declaration, holder, SimpleDiagnostics(filteredList))
}
private fun isExpectedDeclaration(declaration: KtDeclaration): Boolean {
return declaration.hasExpectModifier() ||
declaration is KtClassOrObject && KtPsiUtil.getOutermostClassOrObject(declaration)?.hasExpectModifier() == true
}
}