Reformat the rest of 'frontend'-module according to new codestyle

This commit is contained in:
Dmitry Savvinov
2018-01-16 18:24:10 +03:00
parent e5f0ffb0c2
commit c2b532b167
132 changed files with 4906 additions and 4081 deletions
@@ -48,8 +48,8 @@ import java.util.*
import kotlin.coroutines.experimental.buildSequence
class ResolverForModule(
val packageFragmentProvider: PackageFragmentProvider,
val componentProvider: ComponentProvider
val packageFragmentProvider: PackageFragmentProvider,
val componentProvider: ComponentProvider
)
abstract class ResolverForProject<M : ModuleInfo> {
@@ -70,34 +70,36 @@ class EmptyResolverForProject<M : ModuleInfo> : ResolverForProject<M>() {
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 resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule =
throw IllegalStateException("$descriptor is not contained in this resolver")
override fun descriptorForModule(moduleInfo: M) = diagnoseUnknownModuleInfo(listOf(moduleInfo))
override val allModules: Collection<M> = listOf()
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
}
class ResolverForProjectImpl<M : ModuleInfo>(
private val debugName: String,
private val projectContext: ProjectContext,
modules: Collection<M>,
private val analyzerFacade: (M) -> AnalyzerFacade,
private val modulesContent: (M) -> ModuleContent,
private val platformParameters: PlatformAnalysisParameters,
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
private val firstDependency: M? = null,
private val modulePlatforms: (M) -> MultiTargetPlatform?,
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
private val languageSettingsProvider: LanguageSettingsProvider = LanguageSettingsProvider.Default,
private val invalidateOnOOCB: Boolean = true
private val debugName: String,
private val projectContext: ProjectContext,
modules: Collection<M>,
private val analyzerFacade: (M) -> AnalyzerFacade,
private val modulesContent: (M) -> ModuleContent,
private val platformParameters: PlatformAnalysisParameters,
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
private val firstDependency: M? = null,
private val modulePlatforms: (M) -> MultiTargetPlatform?,
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
private val languageSettingsProvider: LanguageSettingsProvider = LanguageSettingsProvider.Default,
private val invalidateOnOOCB: Boolean = true
) : ResolverForProject<M>() {
private class ModuleData(
val moduleDescriptor: ModuleDescriptorImpl,
val modificationTracker: ModificationTracker?,
val modificationCount: Long?
val moduleDescriptor: ModuleDescriptorImpl,
val modificationTracker: ModificationTracker?,
val modificationCount: Long?
) {
fun isOutOfDate(): Boolean {
val currentModCount = modificationTracker?.modificationCount
@@ -117,16 +119,22 @@ class ResolverForProjectImpl<M : ModuleInfo>(
}
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
moduleDescriptor.setDependencies(LazyModuleDependencies(
moduleDescriptor.setDependencies(
LazyModuleDependencies(
projectContext.storageManager,
module,
firstDependency,
this))
this
)
)
val content = modulesContent(module)
moduleDescriptor.initialize(
DelegatingPackageFragmentProvider(this, moduleDescriptor, content,
packageOracleFactory.createOracle(module)))
DelegatingPackageFragmentProvider(
this, moduleDescriptor, content,
packageOracleFactory.createOracle(module)
)
)
}
private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>()
@@ -153,16 +161,17 @@ class ResolverForProjectImpl<M : ModuleInfo>(
ResolverForModuleComputationTracker.getInstance(projectContext.project)?.onResolverComputed(module)
analyzerFacade(module).createResolverForModule(
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
platformParameters, targetEnvironment, this@ResolverForProjectImpl,
languageSettingsProvider,
packagePartProviderFactory(module, modulesContent(module)))
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
platformParameters, targetEnvironment, this@ResolverForProjectImpl,
languageSettingsProvider,
packagePartProviderFactory(module, modulesContent(module))
)
}
}
}
internal fun isResolverForModuleDescriptorComputed(descriptor: ModuleDescriptor) =
descriptor in resolverByModuleDescriptor
descriptor in resolverByModuleDescriptor
override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
if (!isCorrectModuleInfo(moduleInfo)) {
@@ -172,7 +181,7 @@ class ResolverForProjectImpl<M : ModuleInfo>(
}
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) =
throw AssertionError("$name does not know how to resolve $infos")
throw AssertionError("$name does not know how to resolve $infos")
private fun doGetDescriptorForModule(module: M): ModuleDescriptorImpl {
if (module in modules) {
@@ -204,19 +213,21 @@ class ResolverForProjectImpl<M : ModuleInfo>(
}
private fun createModuleDescriptor(module: M): ModuleData {
val moduleDescriptor = ModuleDescriptorImpl(module.name,
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities)
val moduleDescriptor = ModuleDescriptorImpl(
module.name,
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities
)
moduleInfoByDescriptor[moduleDescriptor] = module
setupModuleDescriptor(module, moduleDescriptor)
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker() ?:
(PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker()
?: (PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
return ModuleData(moduleDescriptor, modificationTracker, modificationTracker?.modificationCount)
}
}
data class ModuleContent(
val syntheticFiles: Collection<KtFile>,
val moduleContentScope: GlobalSearchScope
val syntheticFiles: Collection<KtFile>,
val moduleContentScope: GlobalSearchScope
)
interface PlatformAnalysisParameters
@@ -238,10 +249,10 @@ interface ModuleInfo {
// 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.Common)
ModuleInfo.DependencyOnBuiltIns.AFTER_SDK
else
ModuleInfo.DependencyOnBuiltIns.LAST
if (platform == TargetPlatform.Common)
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 }
@@ -257,25 +268,25 @@ interface TrackableModuleInfo : ModuleInfo {
abstract class AnalyzerFacade {
abstract fun <M : ModuleInfo> createResolverForModule(
moduleInfo: M,
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent,
platformParameters: PlatformAnalysisParameters,
targetEnvironment: TargetEnvironment,
resolverForProject: ResolverForProject<M>,
languageSettingsProvider: LanguageSettingsProvider,
packagePartProvider: PackagePartProvider
moduleInfo: M,
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent,
platformParameters: PlatformAnalysisParameters,
targetEnvironment: TargetEnvironment,
resolverForProject: ResolverForProject<M>,
languageSettingsProvider: LanguageSettingsProvider,
packagePartProvider: PackagePartProvider
): ResolverForModule
abstract val targetPlatform: TargetPlatform
}
class LazyModuleDependencies<M: ModuleInfo>(
storageManager: StorageManager,
private val module: M,
firstDependency: M? = null,
private val resolverForProject: ResolverForProjectImpl<M>
class LazyModuleDependencies<M : ModuleInfo>(
storageManager: StorageManager,
private val module: M,
firstDependency: M? = null,
private val resolverForProject: ResolverForProjectImpl<M>
) : ModuleDependencies {
private val dependencies = storageManager.createLazyValue {
val moduleDescriptor = resolverForProject.descriptorForModule(module)
@@ -307,10 +318,10 @@ class LazyModuleDependencies<M: ModuleInfo>(
private class DelegatingPackageFragmentProvider<M : ModuleInfo>(
private val resolverForProject: ResolverForProjectImpl<M>,
private val module: ModuleDescriptor,
moduleContent: ModuleContent,
private val packageOracle: PackageOracle
private val resolverForProject: ResolverForProjectImpl<M>,
private val module: ModuleDescriptor,
moduleContent: ModuleContent,
private val packageOracle: PackageOracle
) : PackageFragmentProvider {
private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet()
@@ -366,6 +377,7 @@ interface ResolverForModuleComputationTracker {
fun onResolverComputed(moduleInfo: ModuleInfo)
companion object {
fun getInstance(project: Project): ResolverForModuleComputationTracker? = ServiceManager.getService(project, ResolverForModuleComputationTracker::class.java) ?: null
fun getInstance(project: Project): ResolverForModuleComputationTracker? =
ServiceManager.getService(project, ResolverForModuleComputationTracker::class.java) ?: null
}
}
@@ -51,42 +51,42 @@ import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmen
*/
object CommonAnalyzerFacade : AnalyzerFacade() {
private class SourceModuleInfo(
override val name: Name,
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
private val dependOnOldBuiltIns: Boolean
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
if (dependOnOldBuiltIns) ModuleInfo.DependencyOnBuiltIns.LAST else ModuleInfo.DependencyOnBuiltIns.NONE
}
fun analyzeFiles(
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
): 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)
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
else languageVersionSettings.getFeatureSupport(feature)
}
@Suppress("NAME_SHADOWING")
val resolver = ResolverForProjectImpl (
"sources for metadata serializer",
ProjectContext(project), listOf(moduleInfo), { CommonAnalyzerFacade },
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
object : PlatformAnalysisParameters {},
languageSettingsProvider = object : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
},
packagePartProviderFactory = packagePartProviderFactory,
modulePlatforms = { MultiTargetPlatform.Common }
val resolver = ResolverForProjectImpl(
"sources for metadata serializer",
ProjectContext(project), listOf(moduleInfo), { CommonAnalyzerFacade },
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
object : PlatformAnalysisParameters {},
languageSettingsProvider = object : LanguageSettingsProvider {
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
},
packagePartProviderFactory = packagePartProviderFactory,
modulePlatforms = { MultiTargetPlatform.Common }
)
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
@@ -98,46 +98,46 @@ object CommonAnalyzerFacade : AnalyzerFacade() {
}
override fun <M : ModuleInfo> createResolverForModule(
moduleInfo: M,
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent,
platformParameters: PlatformAnalysisParameters,
targetEnvironment: TargetEnvironment,
resolverForProject: ResolverForProject<M>,
languageSettingsProvider: LanguageSettingsProvider,
packagePartProvider: PackagePartProvider
moduleInfo: M,
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent,
platformParameters: PlatformAnalysisParameters,
targetEnvironment: TargetEnvironment,
resolverForProject: ResolverForProject<M>,
languageSettingsProvider: LanguageSettingsProvider,
packagePartProvider: PackagePartProvider
): ResolverForModule {
val (syntheticFiles, moduleContentScope) = moduleContent
val project = moduleContext.project
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
project, moduleContext.storageManager, syntheticFiles,
if (moduleInfo.isLibrary) GlobalSearchScope.EMPTY_SCOPE else moduleContentScope,
moduleInfo
project, moduleContext.storageManager, syntheticFiles,
if (moduleInfo.isLibrary) GlobalSearchScope.EMPTY_SCOPE else moduleContentScope,
moduleInfo
)
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
val container = createContainerToResolveCommonCode(
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
)
val packageFragmentProviders = listOf(
container.get<ResolveSession>().packageFragmentProvider,
container.get<MetadataPackageFragmentProvider>()
container.get<ResolveSession>().packageFragmentProvider,
container.get<MetadataPackageFragmentProvider>()
)
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
}
private fun createContainerToResolveCommonCode(
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
declarationProviderFactory: DeclarationProviderFactory,
moduleContentScope: GlobalSearchScope,
targetEnvironment: TargetEnvironment,
packagePartProvider: PackagePartProvider,
languageVersionSettings: LanguageVersionSettings
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
declarationProviderFactory: DeclarationProviderFactory,
moduleContentScope: GlobalSearchScope,
targetEnvironment: TargetEnvironment,
packagePartProvider: PackagePartProvider,
languageVersionSettings: LanguageVersionSettings
): StorageComponentContainer = createContainer("ResolveCommonCode", targetPlatform) {
configureModule(moduleContext, targetPlatform, TargetPlatformVersion.NoVersion, bindingTrace)
@@ -154,7 +154,7 @@ object CommonAnalyzerFacade : AnalyzerFacade() {
useImpl<MetadataPackageFragmentProvider>()
val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java)
?: error("No MetadataFinderFactory in project")
?: error("No MetadataFinderFactory in project")
useInstance(metadataFinderFactory.create(moduleContentScope))
targetEnvironment.configure(this)
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
interface ControlFlowBuilder {
// Subroutines
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
val currentSubroutine: KtElement
@@ -624,7 +624,7 @@ class ControlFlowInformationProvider private constructor(
if (!VariableUseState.isUsed(variableUseState)) {
if (element.isSingleUnderscore) return
when {
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
element is KtDestructuringDeclarationEntry && element.parent.parent?.parent is KtParameterList ->
report(Errors.UNUSED_DESTRUCTURED_PARAMETER_ENTRY.on(element, variableDescriptor), ctxt)
@@ -866,7 +866,7 @@ class ControlFlowInformationProvider private constructor(
class KindAndCall(var kind: TailRecursionKind, internal val call: ResolvedCall<*>)
val calls = HashMap<KtElement, KindAndCall>()
traverseCalls traverse@{ instruction, resolvedCall ->
traverseCalls traverse@ { instruction, resolvedCall ->
// is this a recursive call?
val functionDescriptor = resolvedCall.resultingDescriptor
if (functionDescriptor.original != subroutineDescriptor) return@traverse
@@ -1021,23 +1021,23 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, invocationKind: InvocationKind) {
// Defer emitting of inlined declaration
deferredGeneratorsStack.peek().add({ builder ->
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
builder.bindLabel(beforeDeclaration)
builder.bindLabel(beforeDeclaration)
if (!invocationKind.isDefinitelyVisited()) {
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
}
if (!invocationKind.isDefinitelyVisited()) {
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
}
generate(lambdaFunctionLiteral, invocationKind)
generate(lambdaFunctionLiteral, invocationKind)
if (invocationKind.canBeRevisited()) {
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
}
if (invocationKind.canBeRevisited()) {
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
}
builder.bindLabel(afterDeclaration)
})
builder.bindLabel(afterDeclaration)
})
}
override fun visitNamedFunction(function: KtNamedFunction) {
@@ -1544,8 +1544,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
//noinspection EnumSwitchStatementWhichMissesCases
when (kind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver = resolvedCall.extensionReceiver
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {}
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver =
resolvedCall.extensionReceiver
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {
}
}
}
@@ -29,28 +29,28 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContextUtils
class PseudocodeVariableDataCollector(
private val bindingContext: BindingContext,
private val pseudocode: Pseudocode
private val bindingContext: BindingContext,
private val pseudocode: Pseudocode
) {
val blockScopeVariableInfo = computeBlockScopeVariableInfo(pseudocode)
fun <I : ControlFlowInfo<*, *>> collectData(
traversalOrder: TraversalOrder,
initialInfo: I,
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
traversalOrder: TraversalOrder,
initialInfo: I,
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
): Map<Instruction, Edges<I>> {
return pseudocode.collectData(
traversalOrder,
instructionDataMergeStrategy,
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
initialInfo
traversalOrder,
instructionDataMergeStrategy,
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
initialInfo
)
}
private fun <I : ControlFlowInfo<*, *>> filterOutVariablesOutOfScope(
from: Instruction,
to: Instruction,
info: I
from: Instruction,
to: Instruction,
info: I
): I {
// If an edge goes from deeper scope to a less deep one, this means that it points outside of the deeper scope.
val toDepth = to.blockScope.depth
@@ -74,9 +74,11 @@ class PseudocodeVariableDataCollector(
val variableDeclarationElement = instruction.variableDeclarationElement
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse
val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor)
?: throw AssertionError("Variable or class descriptor should correspond to " +
"the instruction for ${instruction.element.text}.\n" +
"Descriptor: $descriptor")
?: throw AssertionError(
"Variable or class descriptor should correspond to " +
"the instruction for ${instruction.element.text}.\n" +
"Descriptor: $descriptor"
)
blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope)
}
})
@@ -85,8 +87,8 @@ class PseudocodeVariableDataCollector(
}
interface BlockScopeVariableInfo {
val declaredIn : Map<VariableDescriptor, BlockScope>
val scopeVariables : Map<BlockScope, Collection<VariableDescriptor>>
val declaredIn: Map<VariableDescriptor, BlockScope>
val scopeVariables: Map<BlockScope, Collection<VariableDescriptor>>
}
class BlockScopeVariableInfoImpl : BlockScopeVariableInfo {
@@ -42,14 +42,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode)
private class VariablesForDeclaration(
val valsWithTrivialInitializer: Set<VariableDescriptor>,
val nonTrivialVariables: Set<VariableDescriptor>
val valsWithTrivialInitializer: Set<VariableDescriptor>,
val nonTrivialVariables: Set<VariableDescriptor>
) {
val allVars =
if (nonTrivialVariables.isEmpty())
valsWithTrivialInitializer
else
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
if (nonTrivialVariables.isEmpty())
valsWithTrivialInitializer
else
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
}
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, VariablesForDeclaration>()
@@ -65,10 +65,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
get() = pseudocodeVariableDataCollector.blockScopeVariableInfo
fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set<VariableDescriptor> =
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
fun isVariableWithTrivialInitializer(variableDescriptor: VariableDescriptor) =
variableDescriptor in rootVariables.valsWithTrivialInitializer
variableDescriptor in rootVariables.valsWithTrivialInitializer
private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration {
if (!includeInsideLocalDeclarations) {
@@ -86,9 +86,9 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
private fun addVariablesFromPseudocode(
pseudocode: Pseudocode,
nonTrivialVariables: MutableSet<VariableDescriptor>,
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
pseudocode: Pseudocode,
nonTrivialVariables: MutableSet<VariableDescriptor>,
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
) {
getUpperLevelDeclaredVariables(pseudocode).let {
nonTrivialVariables.addAll(it.nonTrivialVariables)
@@ -107,14 +107,13 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (instruction is VariableDeclarationInstruction) {
val variableDeclarationElement = instruction.variableDeclarationElement
val descriptor =
variableDescriptorForDeclaration(
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
) ?: continue
variableDescriptorForDeclaration(
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
) ?: continue
if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) {
valsWithTrivialInitializer.add(descriptor)
}
else {
} else {
nonTrivialVariables.add(descriptor)
}
}
@@ -124,8 +123,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
private fun isValWithTrivialInitializer(variableDeclarationElement: KtDeclaration, descriptor: VariableDescriptor) =
variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
variableDeclarationElement.safeAs<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
variableDeclarationElement.safeAs<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean {
if (descriptor.isPropertyWithoutBackingField()) return true
@@ -148,18 +147,20 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) {
instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
return pseudocodeVariableDataCollector.collectData(
TraversalOrder.FORWARD,
InitControlFlowInfo()
) { instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
val enterInstructionData = mergeIncomingEdgesDataForInitializers(instruction, incomingEdgesData, blockScopeVariableInfo)
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
instruction, enterInstructionData, blockScopeVariableInfo)
instruction, enterInstructionData, blockScopeVariableInfo
)
Edges(enterInstructionData, exitInstructionData)
}.mapValues {
(instruction, edges) ->
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
}
}.mapValues { (instruction, edges) ->
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
}
}
private fun computeInitInfoForTrivialVals(): Map<Instruction, Edges<ReadOnlyInitControlFlowInfoImpl>> {
@@ -170,8 +171,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null)
when (instruction) {
is VariableDeclarationInstruction ->
extractValWithTrivialInitializer(instruction)?.let {
variableDescriptor ->
extractValWithTrivialInitializer(instruction)?.let { variableDescriptor ->
declaredSet = declaredSet.add(variableDescriptor)
}
is WriteValueInstruction -> {
@@ -193,12 +193,12 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
// WriteValueInstruction having KtDeclaration as an element means
// it must be a write happened at the same time when
// the variable (common variable/parameter/object) has been declared
element is KtDeclaration
element is KtDeclaration
private inner class ReadOnlyInitControlFlowInfoImpl(
val declaredSet: ImmutableSet<VariableDescriptor>,
val initSet: ImmutableSet<VariableDescriptor>,
private val delegate: ReadOnlyInitControlFlowInfo?
val declaredSet: ImmutableSet<VariableDescriptor>,
val initSet: ImmutableSet<VariableDescriptor>,
private val delegate: ReadOnlyInitControlFlowInfo?
) : ReadOnlyInitControlFlowInfo {
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableControlFlowState? {
if (variableDescriptor in declaredSet) {
@@ -208,16 +208,15 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean =
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
fun replaceDelegate(newDelegate: ReadOnlyInitControlFlowInfo): ReadOnlyInitControlFlowInfo =
ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
return declaredSet.fold(initial) {
acc, variableDescriptor ->
return declaredSet.fold(initial) { acc, variableDescriptor ->
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
}
}
@@ -244,17 +243,16 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
private fun addVariableInitStateFromCurrentInstructionIfAny(
instruction: Instruction,
enterInstructionData: InitControlFlowInfo,
blockScopeVariableInfo: BlockScopeVariableInfo): InitControlFlowInfo {
instruction: Instruction,
enterInstructionData: InitControlFlowInfo,
blockScopeVariableInfo: BlockScopeVariableInfo
): InitControlFlowInfo {
if (instruction is MagicInstruction) {
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
return enterInstructionData.iterator().fold(enterInstructionData) {
result, (key, value) ->
return enterInstructionData.iterator().fold(enterInstructionData) { result, (key, value) ->
if (!value.definitelyInitialized()) {
result.put(key, VariableControlFlowState.createInitializedExhaustively(value.isDeclared))
}
else result
} else result
}
}
}
@@ -262,9 +260,9 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
return enterInstructionData
}
val variable =
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
?.takeIf { it in rootVariables.nonTrivialVariables }
?: return enterInstructionData
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
?.takeIf { it in rootVariables.nonTrivialVariables }
?: return enterInstructionData
var exitInstructionData = enterInstructionData
if (instruction is WriteValueInstruction) {
// if writing to already initialized object
@@ -275,12 +273,11 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
val enterInitState = enterInstructionData.getOrNull(variable)
val initializationAtThisElement = VariableControlFlowState.create(instruction.element is KtProperty, enterInitState)
exitInstructionData = exitInstructionData.put(variable, initializationAtThisElement, enterInitState)
}
else {
} else {
// instruction instanceof VariableDeclarationInstruction
val enterInitState =
enterInstructionData.getOrNull(variable)
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
enterInstructionData.getOrNull(variable)
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
if (!enterInitState.mayBeInitialized() || !enterInitState.isDeclared) {
val variableDeclarationInfo = VariableControlFlowState.create(enterInitState.initState, isDeclared = true)
@@ -303,12 +300,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
}
return pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
return pseudocodeVariableDataCollector.collectData(
TraversalOrder.BACKWARD,
UseControlFlowInfo()
) { instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) {
incomingEdgesData.single()
}
else {
} else {
incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
@@ -317,38 +316,35 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
val variableDescriptor =
PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
?.takeIf { it in rootVariables.nonTrivialVariables }
PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
?.takeIf { it in rootVariables.nonTrivialVariables }
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
Edges(enterResult, enterResult)
}
else {
} else {
val exitResult =
if (instruction is ReadValueInstruction) {
enterResult.put(variableDescriptor, VariableUseState.READ)
if (instruction is ReadValueInstruction) {
enterResult.put(variableDescriptor, VariableUseState.READ)
} else {
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
if (variableUseState == null) {
variableUseState = VariableUseState.UNUSED
}
else {
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
if (variableUseState == null) {
variableUseState = VariableUseState.UNUSED
}
when (variableUseState) {
VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
}
when (variableUseState) {
VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
}
}
Edges(enterResult, exitResult)
}
}.mapValues {
(_, edges) ->
}.mapValues { (_, edges) ->
Edges(
Edges(
edgesForTrivialVals.incoming.replaceDelegate(edges.incoming),
edgesForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
)
}
)
}
}
private fun computeUseInfoForTrivialVals(): Edges<ReadOnlyUseControlFlowInfoImpl> {
@@ -373,8 +369,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
private inner class ReadOnlyUseControlFlowInfoImpl(
val used: Set<VariableDescriptor>,
val delegate: ReadOnlyUseControlFlowInfo?
val used: Set<VariableDescriptor>,
val delegate: ReadOnlyUseControlFlowInfo?
) : ReadOnlyUseControlFlowInfo {
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableUseState? {
if (variableDescriptor in used) return VariableUseState.READ
@@ -382,13 +378,12 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
}
fun replaceDelegate(newDelegate: ReadOnlyUseControlFlowInfo): ReadOnlyUseControlFlowInfo =
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
return used.fold(initial) {
acc, variableDescriptor ->
return used.fold(initial) { acc, variableDescriptor ->
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
}
}
@@ -417,24 +412,24 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
@JvmStatic
fun getDefaultValueForInitializers(
variable: VariableDescriptor,
instruction: Instruction,
blockScopeVariableInfo: BlockScopeVariableInfo
variable: VariableDescriptor,
instruction: Instruction,
blockScopeVariableInfo: BlockScopeVariableInfo
): VariableControlFlowState {
//todo: think of replacing it with "MapWithDefaultValue"
val declaredIn = blockScopeVariableInfo.declaredIn[variable]
val declaredOutsideThisDeclaration =
declaredIn == null //declared outside this pseudocode
|| declaredIn.blockScopeForContainingDeclaration != instruction.blockScope.blockScopeForContainingDeclaration
declaredIn == null //declared outside this pseudocode
|| declaredIn.blockScopeForContainingDeclaration != instruction.blockScope.blockScopeForContainingDeclaration
return VariableControlFlowState.create(isInitialized = declaredOutsideThisDeclaration)
}
private val EMPTY_INIT_CONTROL_FLOW_INFO = InitControlFlowInfo()
private fun mergeIncomingEdgesDataForInitializers(
instruction: Instruction,
incomingEdgesData: Collection<InitControlFlowInfo>,
blockScopeVariableInfo: BlockScopeVariableInfo
instruction: Instruction,
incomingEdgesData: Collection<InitControlFlowInfo>,
blockScopeVariableInfo: BlockScopeVariableInfo
): InitControlFlowInfo {
if (incomingEdgesData.size == 1) return incomingEdgesData.single()
if (incomingEdgesData.isEmpty()) return EMPTY_INIT_CONTROL_FLOW_INFO
@@ -448,7 +443,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
var isDeclared = true
for (edgeData in incomingEdgesData) {
val varControlFlowState = edgeData.getOrNull(variable)
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
if (!varControlFlowState.isDeclared) {
isDeclared = false
@@ -33,8 +33,8 @@ interface UnreachableCode {
}
class UnreachableCodeImpl(
private val reachableElements: Set<KtElement>,
private val unreachableElements: Set<KtElement>
private val reachableElements: Set<KtElement>,
private val unreachableElements: Set<KtElement>
) : UnreachableCode {
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
@@ -42,30 +42,29 @@ class UnreachableCodeImpl(
override fun getUnreachableTextRanges(element: KtElement): List<TextRange> {
return if (element.hasChildrenInSet(reachableElements)) {
with (element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) {
with(element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) {
if (isNotEmpty()) this
// Specific case like condition in when:
// element is dead but its only child is alive and has the same text range
else listOf(element.textRange.endOffset.let { TextRange(it, it) })
}
}
else {
} else {
listOf(element.textRange!!)
}
}
private fun KtElement.hasChildrenInSet(set: Set<KtElement>): Boolean =
PsiTreeUtil.collectElements(this) { it != this }.any { it in set }
PsiTreeUtil.collectElements(this) { it != this }.any { it in set }
private fun KtElement.getLeavesOrReachableChildren(): List<PsiElement> {
val children = ArrayList<PsiElement>()
acceptChildren(object : PsiElementVisitor() {
override fun visitElement(element: PsiElement) {
val isReachable = element is KtElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements)
val isReachable =
element is KtElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements)
if (isReachable || element.children.isEmpty()) {
children.add(element)
}
else {
} else {
element.acceptChildren(this)
}
}
@@ -102,8 +101,7 @@ class UnreachableCodeImpl(
private fun List<PsiElement>.mergeAdjacentTextRanges(): List<TextRange> {
val result = ArrayList<TextRange>()
val lastRange = fold(null as TextRange?) {
currentTextRange, element ->
val lastRange = fold(null as TextRange?) { currentTextRange, element ->
val elementRange = element.textRange!!
when {
@@ -54,10 +54,10 @@ val List<WhenMissingCase>.hasUnknown: Boolean
private interface WhenExhaustivenessChecker {
fun getMissingCases(
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
): List<WhenMissingCase>
fun isApplicable(subjectType: KotlinType): Boolean = false
@@ -72,7 +72,7 @@ object NullMissingCase : WhenMissingCase() {
// It's not a regular exhaustiveness checker, invoke it only inside other checkers
private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecker*/ {
fun getMissingCases(expression: KtWhenExpression, context: BindingContext, nullable: Boolean) =
if (nullable) getNullCaseIfMissing(expression, context) else listOf()
if (nullable) getNullCaseIfMissing(expression, context) else listOf()
private fun getNullCaseIfMissing(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
for (entry in expression.entries) {
@@ -99,10 +99,10 @@ class BooleanMissingCase(val b: Boolean) : WhenMissingCase() {
private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
override fun getMissingCases(
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
): List<WhenMissingCase> {
// It's assumed (and not checked) that expression is of the boolean type
var containsFalse = false
@@ -117,8 +117,8 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
}
}
return (if (!containsTrue) listOf(BooleanMissingCase(true)) else listOf()) +
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
}
override fun isApplicable(subjectType: KotlinType): Boolean {
@@ -126,7 +126,7 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
}
}
class ClassMissingCase(val descriptor: ClassDescriptor): WhenMissingCase() {
class ClassMissingCase(val descriptor: ClassDescriptor) : WhenMissingCase() {
val classIsSingleton get() = descriptor.kind.isSingleton
val classFqName get() = DescriptorUtils.getFqNameFromTopLevelClass(descriptor)
@@ -138,11 +138,11 @@ class ClassMissingCase(val descriptor: ClassDescriptor): WhenMissingCase() {
internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChecker {
private fun getReference(expression: KtExpression?): KtSimpleNameExpression? =
when (expression) {
is KtSimpleNameExpression -> expression
is KtQualifiedExpression -> getReference(expression.selectorExpression)
else -> null
}
when (expression) {
is KtSimpleNameExpression -> expression
is KtQualifiedExpression -> getReference(expression.selectorExpression)
else -> null
}
protected val ClassDescriptor.deepSealedSubclasses: List<ClassDescriptor>
get() = this.sealedSubclasses.flatMap {
@@ -154,9 +154,9 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
get() = (this as? KtWhenConditionIsPattern)?.isNegated ?: false
private fun KtWhenCondition.isRelevant(checkedDescriptor: ClassDescriptor) =
this !is KtWhenConditionWithExpression ||
DescriptorUtils.isObject(checkedDescriptor) ||
DescriptorUtils.isEnumEntry(checkedDescriptor)
this !is KtWhenConditionWithExpression ||
DescriptorUtils.isObject(checkedDescriptor) ||
DescriptorUtils.isEnumEntry(checkedDescriptor)
private fun KtWhenCondition.getCheckedDescriptor(context: BindingContext): ClassDescriptor? {
return when (this) {
@@ -175,9 +175,9 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
}
protected fun getMissingClassCases(
whenExpression: KtWhenExpression,
subclasses: Set<ClassDescriptor>,
context: BindingContext
whenExpression: KtWhenExpression,
subclasses: Set<ClassDescriptor>,
context: BindingContext
): List<WhenMissingCase> {
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
if (subclasses.isEmpty()) return listOf(UnknownMissingCase)
@@ -188,8 +188,8 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
val negated = condition.negated
val checkedDescriptor = condition.getCheckedDescriptor(context) ?: continue
val checkedDescriptorSubclasses =
if (checkedDescriptor.modality == Modality.SEALED) checkedDescriptor.deepSealedSubclasses
else listOf(checkedDescriptor)
if (checkedDescriptor.modality == Modality.SEALED) checkedDescriptor.deepSealedSubclasses
else listOf(checkedDescriptor)
// Checks are important only for nested subclasses of the sealed class
// In additional, check without "is" is important only for objects
@@ -201,8 +201,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
if (checkedDescriptors.containsAll(checkedDescriptorSubclasses)) return listOf()
checkedDescriptors.addAll(subclasses)
checkedDescriptors.removeAll(checkedDescriptorSubclasses)
}
else {
} else {
checkedDescriptors.addAll(checkedDescriptorSubclasses)
}
}
@@ -213,19 +212,19 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
override fun getMissingCases(
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
): List<WhenMissingCase> {
assert(isEnumClass(subjectDescriptor)) { "isWhenOnEnumExhaustive should be called with an enum class descriptor" }
val entryDescriptors =
DescriptorUtils.getAllDescriptors(subjectDescriptor!!.unsubstitutedInnerClassesScope)
.filter(::isEnumEntry)
.filterIsInstance<ClassDescriptor>()
.toSet()
DescriptorUtils.getAllDescriptors(subjectDescriptor!!.unsubstitutedInnerClassesScope)
.filter(::isEnumEntry)
.filterIsInstance<ClassDescriptor>()
.toSet()
return getMissingClassCases(expression, entryDescriptors, context) +
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
}
override fun isApplicable(subjectType: KotlinType): Boolean {
@@ -236,10 +235,10 @@ private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecke
internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
override fun getMissingCases(
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
expression: KtWhenExpression,
context: BindingContext,
subjectDescriptor: ClassDescriptor?,
nullable: Boolean
): List<WhenMissingCase> {
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
@@ -247,7 +246,7 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
val allSubclasses = subjectDescriptor!!.deepSealedSubclasses
return getMissingClassCases(expression, allSubclasses.toSet(), context) +
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
}
override fun isApplicable(subjectType: KotlinType): Boolean {
@@ -258,13 +257,15 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
object WhenChecker {
private val exhaustivenessCheckers = listOf(WhenOnBooleanExhaustivenessChecker,
WhenOnEnumExhaustivenessChecker,
WhenOnSealedExhaustivenessChecker)
private val exhaustivenessCheckers = listOf(
WhenOnBooleanExhaustivenessChecker,
WhenOnEnumExhaustivenessChecker,
WhenOnSealedExhaustivenessChecker
)
@JvmStatic
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) =
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
@JvmStatic
fun getClassDescriptorOfTypeIfEnum(type: KotlinType?): ClassDescriptor? {
@@ -276,26 +277,26 @@ object WhenChecker {
}
@JvmStatic
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor?
= type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor? =
type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
@JvmStatic
fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) =
expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) }
expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) }
@JvmStatic
fun getEnumMissingCases(
expression: KtWhenExpression,
context: BindingContext,
enumClassDescriptor: ClassDescriptor
expression: KtWhenExpression,
context: BindingContext,
enumClassDescriptor: ClassDescriptor
) = WhenOnEnumExhaustivenessChecker.getMissingCases(expression, context, enumClassDescriptor, false)
@JvmStatic
fun getSealedMissingCases(
expression: KtWhenExpression,
context: BindingContext,
sealedClassDescriptor: ClassDescriptor
expression: KtWhenExpression,
context: BindingContext,
sealedClassDescriptor: ClassDescriptor
) = WhenOnSealedExhaustivenessChecker.getMissingCases(expression, context, sealedClassDescriptor, false)
fun getMissingCases(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
@@ -308,15 +309,15 @@ object WhenChecker {
@JvmStatic
fun isWhenExhaustive(expression: KtWhenExpression, trace: BindingTrace) =
if (getMissingCases(expression, trace.bindingContext).isEmpty()) {
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
true
} else {
false
}
if (getMissingCases(expression, trace.bindingContext).isEmpty()) {
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
true
} else {
false
}
fun containsNullCase(expression: KtWhenExpression, context: BindingContext) =
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, true).isEmpty()
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, true).isEmpty()
fun checkDuplicatedLabels(expression: KtWhenExpression, trace: BindingTrace) {
if (expression.subjectExpression == null) return
@@ -331,11 +332,11 @@ object WhenChecker {
is KtWhenConditionWithExpression -> {
val constantExpression = condition.expression ?: continue@conditions
val constant = ConstantExpressionEvaluator.getConstant(
constantExpression, trace.bindingContext) ?: continue@conditions
constantExpression, trace.bindingContext
) ?: continue@conditions
if (checkedConstants.contains(constant)) {
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression))
}
else {
} else {
checkedConstants.add(constant)
}
@@ -346,12 +347,12 @@ object WhenChecker {
val typeWithIsNegation = type to condition.isNegated
if (checkedTypes.contains(typeWithIsNegation)) {
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(typeReference))
}
else {
} else {
checkedTypes.add(typeWithIsNegation)
}
}
else -> {}
else -> {
}
}
}
}
@@ -58,8 +58,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val worker = builders.pop()
builder = if (!builders.isEmpty()) {
builders.peek()
}
else {
} else {
null
}
return worker
@@ -70,8 +69,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val shouldInlnie = invocationKind != null
if (builder != null && subroutine is KtFunctionLiteral) {
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
}
else {
} else {
pushBuilder(subroutine, subroutine, shouldInlnie)
}
delegateBuilder.enterBlockScope(subroutine)
@@ -86,8 +84,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val builder = builders.peek()
if (invocationKind == null) {
builder.declareFunction(subroutine, worker.pseudocode)
}
else {
} else {
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
}
}
@@ -95,9 +92,9 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
private inner class ControlFlowInstructionsGeneratorWorker(
scopingElement: KtElement,
override val returnSubroutine: KtElement,
shouldInline: Boolean
scopingElement: KtElement,
override val returnSubroutine: KtElement,
shouldInline: Boolean
) : ControlFlowBuilder {
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement, shouldInline)
@@ -128,12 +125,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
val info = LoopInfo(
expression,
createUnboundLabel("loop entry point"),
createUnboundLabel("loop exit point"),
createUnboundLabel("body entry point"),
createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point"))
expression,
createUnboundLabel("loop entry point"),
createUnboundLabel("loop exit point"),
createUnboundLabel("body entry point"),
createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point")
)
bindLabel(info.entryPoint)
elementToLoopInfo.put(expression, info)
return info
@@ -158,9 +156,10 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
val blockInfo = SubroutineInfo(
subroutine,
/* entry point */ createUnboundLabel(),
/* exit point */ createUnboundLabel())
subroutine,
/* entry point */ createUnboundLabel(),
/* exit point */ createUnboundLabel()
)
elementToSubroutineInfo.put(subroutine, blockInfo)
allBlocks.push(blockInfo)
bindLabel(blockInfo.entryPoint)
@@ -173,10 +172,11 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? = elementToLoopInfo[loop]?.conditionEntryPoint
override fun getLoopExitPoint(loop: KtLoopExpression): Label? =// It's quite possible to have null here, see testBreakInsideLocal
elementToLoopInfo[loop]?.exitPoint
elementToLoopInfo[loop]?.exitPoint
override fun getSubroutineExitPoint(labelElement: KtElement): Label? =// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
elementToSubroutineInfo[labelElement]?.exitPoint
override fun getSubroutineExitPoint(labelElement: KtElement): Label? =
// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
elementToSubroutineInfo[labelElement]?.exitPoint
private val currentScope: BlockScope
get() = blockScopes.peek()
@@ -191,8 +191,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val currentScope = currentScope
assert(currentScope.block === block) {
"Exit from not the current block scope.\n" +
"Current scope is for a block: " + currentScope.block.text + ".\n" +
"Exit from the scope for: " + block.text
"Current scope is for a block: " + currentScope.block.text + ".\n" +
"Exit from the scope for: " + block.text
}
blockScopes.pop()
}
@@ -252,11 +252,12 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
override fun write(
assignment: KtElement,
lValue: KtElement,
rValue: PseudoValue,
target: AccessTarget,
receiverValues: Map<PseudoValue, ReceiverValue>) {
assignment: KtElement,
lValue: KtElement,
rValue: PseudoValue,
target: AccessTarget,
receiverValues: Map<PseudoValue, ReceiverValue>
) {
add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue))
}
@@ -342,22 +343,24 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun createAnonymousObject(expression: KtObjectLiteralExpression) = read(expression)
override fun createLambda(expression: KtFunction) =
read(if (expression is KtFunctionLiteral) expression.getParent() as KtLambdaExpression else expression)
read(if (expression is KtFunctionLiteral) expression.getParent() as KtLambdaExpression else expression)
override fun loadStringTemplate(
expression: KtStringTemplateExpression,
inputValues: List<PseudoValue>
expression: KtStringTemplateExpression,
inputValues: List<PseudoValue>
): InstructionWithValue =
if (inputValues.isEmpty()) read(expression)
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
if (inputValues.isEmpty()) read(expression)
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
override fun magic(
instructionElement: KtElement,
valueElement: KtElement?,
inputValues: List<PseudoValue>,
kind: MagicKind): MagicInstruction {
instructionElement: KtElement,
valueElement: KtElement?,
inputValues: List<PseudoValue>,
kind: MagicKind
): MagicInstruction {
val instruction = MagicInstruction(
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory)
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory
)
add(instruction)
return instruction
}
@@ -369,32 +372,35 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
override fun readVariable(
expression: KtExpression,
resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>
expression: KtExpression,
resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>
) = read(expression, resolvedCall, receiverValues)
override fun call(
valueElement: KtElement,
resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>,
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction {
valueElement: KtElement,
resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>,
arguments: Map<PseudoValue, ValueParameterDescriptor>
): CallInstruction {
val returnType = resolvedCall.resultingDescriptor.returnType
val instruction = CallInstruction(
valueElement,
currentScope,
resolvedCall,
receiverValues,
arguments,
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory)
valueElement,
currentScope,
resolvedCall,
receiverValues,
arguments,
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory
)
add(instruction)
return instruction
}
override fun predefinedOperation(
expression: KtExpression,
operation: ControlFlowBuilder.PredefinedOperation,
inputValues: List<PseudoValue>): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
expression: KtExpression,
operation: ControlFlowBuilder.PredefinedOperation,
inputValues: List<PseudoValue>
): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) {
ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND
@@ -403,17 +409,17 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
}
override fun read(
element: KtElement,
target: AccessTarget,
receiverValues: Map<PseudoValue, ReceiverValue>
element: KtElement,
target: AccessTarget,
receiverValues: Map<PseudoValue, ReceiverValue>
) = ReadValueInstruction(element, currentScope, target, receiverValues, valueFactory).apply {
add(this)
}
private fun read(
expression: KtExpression,
resolvedCall: ResolvedCall<*>? = null,
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
expression: KtExpression,
resolvedCall: ResolvedCall<*>? = null,
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
) = read(expression, if (resolvedCall != null) AccessTarget.Call(resolvedCall) else AccessTarget.BlackBox, receiverValues)
}
@@ -23,28 +23,28 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
interface TypePredicate: (KotlinType) -> Boolean {
interface TypePredicate : (KotlinType) -> Boolean {
override fun invoke(typeToCheck: KotlinType): Boolean
}
data class SingleType(val targetType: KotlinType): TypePredicate {
data class SingleType(val targetType: KotlinType) : TypePredicate {
override fun invoke(typeToCheck: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.equalTypes(typeToCheck, targetType)
override fun toString(): String = targetType.render()
}
data class AllSubtypes(val upperBound: KotlinType): TypePredicate {
data class AllSubtypes(val upperBound: KotlinType) : TypePredicate {
override fun invoke(typeToCheck: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.isSubtypeOf(typeToCheck, upperBound)
override fun toString(): String = "{<: ${upperBound.render()}}"
}
data class ForAllTypes(val typeSets: List<TypePredicate>): TypePredicate {
data class ForAllTypes(val typeSets: List<TypePredicate>) : TypePredicate {
override fun invoke(typeToCheck: KotlinType): Boolean = typeSets.all { it(typeToCheck) }
override fun toString(): String = "AND{${typeSets.joinToString(", ")}}"
}
data class ForSomeType(val typeSets: List<TypePredicate>): TypePredicate {
data class ForSomeType(val typeSets: List<TypePredicate>) : TypePredicate {
override fun invoke(typeToCheck: KotlinType): Boolean = typeSets.any { it(typeToCheck) }
override fun toString(): String = "OR{${typeSets.joinToString(", ")}}"
@@ -58,18 +58,18 @@ object AllTypes : TypePredicate {
// todo: simplify computed type predicate when possible
fun and(predicates: Collection<TypePredicate>): TypePredicate =
when (predicates.size) {
0 -> AllTypes
1 -> predicates.first()
else -> ForAllTypes(predicates.toList())
}
when (predicates.size) {
0 -> AllTypes
1 -> predicates.first()
else -> ForAllTypes(predicates.toList())
}
fun or(predicates: Collection<TypePredicate>): TypePredicate? =
when (predicates.size) {
0 -> null
1 -> predicates.first()
else -> ForSomeType(predicates.toList())
}
when (predicates.size) {
0 -> null
1 -> predicates.first()
else -> ForSomeType(predicates.toList())
}
fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
KotlinBuiltIns.isAnyOrNullableAny(this) && isMarkedNullable -> AllTypes
@@ -81,4 +81,4 @@ fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
private fun KotlinType.render(): String = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(this)
fun <T> TypePredicate.expectedTypeFor(keys: Iterable<T>): Map<T, TypePredicate> =
keys.fold(SmartFMap.emptyMap<T, TypePredicate>()) { map, key -> map.plus(key, this) }
keys.fold(SmartFMap.emptyMap<T, TypePredicate>()) { map, key -> map.plus(key, this) }
@@ -24,9 +24,9 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
abstract class AbstractJumpInstruction(
element: KtElement,
val targetLabel: Label,
blockScope: BlockScope
element: KtElement,
val targetLabel: Label,
blockScope: BlockScope
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
var resolvedTarget: Instruction? = null
set(value) {
@@ -27,17 +27,17 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
class NondeterministicJumpInstruction(
element: KtElement,
targetLabels: List<Label>,
blockScope: BlockScope,
private val inputValue: PseudoValue?
element: KtElement,
targetLabels: List<Label>,
blockScope: BlockScope,
private val inputValue: PseudoValue?
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
private var _next: Instruction? = null
private val _resolvedTargets: MutableMap<Label, Instruction> = linkedMapOf()
val targetLabels: List<Label> = ArrayList(targetLabels)
private val resolvedTargets: Map<Label, Instruction>
get() = _resolvedTargets
get() = _resolvedTargets
fun setResolvedTarget(label: Label, resolvedTarget: Instruction) {
_resolvedTargets[label] = outgoingEdgeTo(resolvedTarget)!!
@@ -76,5 +76,5 @@ class NondeterministicJumpInstruction(
fun copy(newTargetLabels: MutableList<Label>): Instruction = updateCopyInfo(createCopy(newTargetLabels))
private fun createCopy(newTargetLabels: List<Label>): InstructionImpl =
NondeterministicJumpInstruction(element, newTargetLabels, blockScope, inputValue)
NondeterministicJumpInstruction(element, newTargetLabels, blockScope, inputValue)
}
@@ -63,7 +63,8 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
resolvedCall.dispatchReceiver -> {
val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors()
return or(rootCallableDescriptors.mapNotNull {
it.dispatchReceiverParameter?.type?.let { TypeUtils.makeNullableIfNeeded(it, resolvedCall.call.isSafeCall()) }?.getSubtypesPredicate()
it.dispatchReceiverParameter?.type?.let { TypeUtils.makeNullableIfNeeded(it, resolvedCall.call.isSafeCall()) }
?.getSubtypesPredicate()
})
}
}
@@ -72,9 +73,9 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
}
fun getExpectedTypePredicate(
value: PseudoValue,
bindingContext: BindingContext,
builtIns: KotlinBuiltIns
value: PseudoValue,
bindingContext: BindingContext,
builtIns: KotlinBuiltIns
): TypePredicate {
val pseudocode = value.createdAt?.owner ?: return AllTypes
val typePredicates = LinkedHashSet<TypePredicate?>()
@@ -92,8 +93,8 @@ fun getExpectedTypePredicate(
val callee = call.calleeExpression ?: return null
val candidates = callee.getReferenceTargets(bindingContext)
.filterIsInstance<FunctionDescriptor>()
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
.filterIsInstance<FunctionDescriptor>()
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
if (candidates.isEmpty()) return null
val explicitReceiver = call.explicitReceiver
@@ -103,17 +104,17 @@ fun getExpectedTypePredicate(
for (candidate in candidates) {
val resolutionCandidate = ResolutionCandidate.create(
call,
candidate,
null,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
null
call,
candidate,
null,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
null
)
val candidateCall = ResolvedCallImpl.create(
resolutionCandidate,
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
TracingStrategy.EMPTY,
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
resolutionCandidate,
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
TracingStrategy.EMPTY,
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
)
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(call, TracingStrategy.EMPTY, candidateCall)
if (!status.isSuccess) continue
@@ -143,7 +144,7 @@ fun getExpectedTypePredicate(
when (it) {
is ReturnValueInstruction -> {
val returnElement = it.element
val functionDescriptor = when(returnElement) {
val functionDescriptor = when (returnElement) {
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
}
@@ -164,8 +165,7 @@ fun getExpectedTypePredicate(
val receiverValue = it.receiverValues[value]
if (receiverValue != null) {
typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue))
}
else {
} else {
val expectedType = when (accessTarget) {
is AccessTarget.Call ->
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
@@ -182,8 +182,7 @@ fun getExpectedTypePredicate(
val receiverValue = it.receiverValues[value]
if (receiverValue != null) {
typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue))
}
else {
} else {
it.arguments[value]?.let { parameter ->
val expectedType = when (it.resolvedCall.valueArguments[parameter]) {
is VarargValueArgument ->
@@ -281,8 +280,8 @@ fun Pseudocode.getElementValuesRecursively(element: KtElement): List<PseudoValue
}
val KtElement.containingDeclarationForPseudocode: KtDeclaration?
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
?: getNonStrictParentOfType<KtProperty>()
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
?: getNonStrictParentOfType<KtProperty>()
fun KtDeclaration.getContainingPseudocode(context: BindingContext): Pseudocode? {
val enclosingPseudocodeDeclaration = (this as? KtFunctionLiteral)?.let {
@@ -44,9 +44,9 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
val contractDescriptor = when {
!isFeatureTurnedOn || !isContractDescriptionCallPreciseCheck(expression, trace.bindingContext) -> null
@@ -63,20 +63,20 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
}
private fun parseContract(expression: KtExpression?, trace: BindingTrace, ownerDescriptor: FunctionDescriptor): ContractDescription? =
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
private fun isContractAllowedHere(element: KtElement): Boolean =
element is KtNamedFunction && element.isTopLevel && element.hasBlockBody() && !element.hasModifier(KtTokens.OPERATOR_KEYWORD)
element is KtNamedFunction && element.isTopLevel && element.hasBlockBody() && !element.hasModifier(KtTokens.OPERATOR_KEYWORD)
private fun isContractAllowedHere(scope: LexicalScope): Boolean =
scope.kind == LexicalScopeKind.CODE_BLOCK && (scope.parent as? LexicalScope)?.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE
scope.kind == LexicalScopeKind.CODE_BLOCK && (scope.parent as? LexicalScope)?.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE
private fun isContractDescriptionCallFastCheck(expression: KtExpression): Boolean =
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
private fun isContractDescriptionCallPreciseCheck(expression: KtExpression, context: BindingContext): Boolean =
expression.getResolvedCall(context)?.resultingDescriptor?.isContractCallDescriptor() ?: false
expression.getResolvedCall(context)?.resultingDescriptor?.isContractCallDescriptor() ?: false
}
@@ -27,7 +27,8 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiContractParserDispatcher) : KtVisitor<BooleanExpression?, Unit>() {
internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiContractParserDispatcher) :
KtVisitor<BooleanExpression?, Unit>() {
override fun visitIsExpression(expression: KtIsExpression, data: Unit): BooleanExpression? {
val variable = dispatcher.parseVariable(expression.leftHandSide) ?: return null
val typeReference = expression.typeReference ?: return null
@@ -101,11 +102,16 @@ internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiCo
if (expression.operationToken != KtTokens.EXCL) return super.visitUnaryExpression(expression, data)
val arg = expression.baseExpression?.accept(this, data) ?: return null
if (arg !is ContractDescriptionValue) {
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression.baseExpression!!, "negations in contract description can be applied only to variables/values"))
trace.report(
Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(
expression.baseExpression!!,
"negations in contract description can be applied only to variables/values"
)
)
}
return LogicalNot(arg)
}
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): BooleanExpression? =
KtPsiUtil.deparenthesize(expression)?.accept(this, data)
KtPsiUtil.deparenthesize(expression)?.accept(this, data)
}
@@ -24,4 +24,5 @@ internal interface PsiEffectParser {
fun tryParseEffect(expression: KtExpression): EffectDeclaration?
}
internal abstract class AbstractPsiEffectParser(val trace: BindingTrace, val contractParserDispatcher: PsiContractParserDispatcher) : PsiEffectParser
internal abstract class AbstractPsiEffectParser(val trace: BindingTrace, val contractParserDispatcher: PsiContractParserDispatcher) :
PsiEffectParser
@@ -47,7 +47,8 @@ object PositioningStrategies {
}
}
@JvmField val DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
@JvmField
val DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
when (element) {
is KtObjectLiteralExpression -> {
@@ -61,8 +62,8 @@ object PositioningStrategies {
}
is KtObjectDeclaration -> {
return markRange(
element.getObjectKeyword()!!,
element.nameIdentifier ?: element.getObjectKeyword()!!
element.getObjectKeyword()!!,
element.nameIdentifier ?: element.getObjectKeyword()!!
)
}
is KtConstructorDelegationCall -> {
@@ -75,7 +76,8 @@ object PositioningStrategies {
}
}
@JvmField val DECLARATION_RETURN_TYPE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
@JvmField
val DECLARATION_RETURN_TYPE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
override fun mark(element: KtDeclaration): List<TextRange> {
return markElement(getElementToMark(element))
}
@@ -97,7 +99,8 @@ object PositioningStrategies {
}
}
@JvmField val ACTUAL_DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
@JvmField
val ACTUAL_DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
override fun mark(element: KtNamedDeclaration): List<TextRange> {
val nameIdentifier = element.nameIdentifier
return when {
@@ -112,11 +115,11 @@ object PositioningStrategies {
get() {
val map = when (factory) {
NO_ACTUAL_FOR_EXPECT ->
NO_ACTUAL_FOR_EXPECT.cast(this).c
NO_ACTUAL_FOR_EXPECT.cast(this).c
ACTUAL_WITHOUT_EXPECT ->
ACTUAL_WITHOUT_EXPECT.cast(this).b
ACTUAL_WITHOUT_EXPECT.cast(this).b
else ->
return null
return null
}
return map.keys.firstOrNull()
}
@@ -125,7 +128,8 @@ object PositioningStrategies {
private val classKindTokens = TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD, KtTokens.INTERFACE_KEYWORD)
@JvmField val INCOMPATIBLE_DECLARATION: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
@JvmField
val INCOMPATIBLE_DECLARATION: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out KtNamedDeclaration>): List<TextRange> {
val element = diagnostic.psiElement
val callableDeclaration = element as? KtCallableDeclaration
@@ -134,15 +138,14 @@ object PositioningStrategies {
null, Unknown, is ClassScopes, EnumEntries -> null
ClassKind -> {
val startElement =
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
val endElement =
element.node.findChildByType(classKindTokens)?.psi
?: element.nameIdentifier
element.node.findChildByType(classKindTokens)?.psi
?: element.nameIdentifier
if (startElement != null && endElement != null) {
return markRange(startElement, endElement)
}
else {
} else {
endElement
}
}
@@ -181,15 +184,16 @@ object PositioningStrategies {
}
}
@JvmField val DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
@JvmField
val DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
override fun mark(element: KtNamedDeclaration): List<TextRange> {
val nameIdentifier = element.nameIdentifier
if (nameIdentifier != null) {
if (element is KtClassOrObject) {
val startElement =
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
?: element
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
?: element
return markRange(startElement, nameIdentifier)
}
@@ -202,7 +206,8 @@ object PositioningStrategies {
}
}
@JvmField val DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : DeclarationHeader<KtDeclaration>() {
@JvmField
val DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : DeclarationHeader<KtDeclaration>() {
override fun mark(element: KtDeclaration): List<TextRange> {
when (element) {
is KtConstructor<*> -> {
@@ -212,17 +217,15 @@ object PositioningStrategies {
}
is KtFunction -> {
val endOfSignatureElement =
element.typeReference
?: element.valueParameterList
?: element.nameIdentifier
?: element
val startElement
= if (element is KtFunctionLiteral) {
element.getReceiverTypeReference()
element.typeReference
?: element.valueParameterList
?: element.nameIdentifier
?: element
val startElement = if (element is KtFunctionLiteral) {
element.getReceiverTypeReference()
?: element.getValueParameterList()
?: element
}
else element
} else element
return markRange(startElement, endOfSignatureElement)
}
is KtProperty -> {
@@ -231,15 +234,16 @@ object PositioningStrategies {
}
is KtPropertyAccessor -> {
val endOfSignatureElement =
element.returnTypeReference
?: element.rightParenthesis?.psi
?: element.namePlaceholder
element.returnTypeReference
?: element.rightParenthesis?.psi
?: element.namePlaceholder
return markRange(element, endOfSignatureElement)
}
is KtClass -> {
val nameAsDeclaration = element.nameIdentifier ?: return markElement(element)
val primaryConstructorParameterList = element.getPrimaryConstructorParameterList() ?: return markElement(nameAsDeclaration)
val primaryConstructorParameterList =
element.getPrimaryConstructorParameterList() ?: return markElement(nameAsDeclaration)
return markRange(nameAsDeclaration, primaryConstructorParameterList)
}
is KtObjectDeclaration -> {
@@ -253,7 +257,8 @@ object PositioningStrategies {
}
}
@JvmField val DECLARATION_SIGNATURE_OR_DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
@JvmField
val DECLARATION_SIGNATURE_OR_DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
return if (element is KtDeclaration)
DECLARATION_SIGNATURE.mark(element)
@@ -269,26 +274,24 @@ object PositioningStrategies {
}
}
@JvmField val NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
@JvmField
val NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
override fun mark(element: KtDeclaration): List<TextRange> =
markElement(
when (element) {
is KtClassOrObject ->
element.getDeclarationKeyword() ?:
element.nameIdentifier ?:
element
markElement(
when (element) {
is KtClassOrObject ->
element.getDeclarationKeyword() ?: element.nameIdentifier ?: element
is KtNamedFunction ->
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?:
element.funKeyword ?:
element
is KtNamedFunction ->
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?: element.funKeyword ?: element
else -> element
}
)
else -> element
}
)
}
@JvmField val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
@JvmField
val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
override fun mark(element: KtDeclaration): List<TextRange> {
if (element is KtTypeParameterListOwner) {
val jetTypeParameterList = element.typeParameterList
@@ -300,19 +303,26 @@ object PositioningStrategies {
}
}
@JvmField val ABSTRACT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ABSTRACT_KEYWORD)
@JvmField
val ABSTRACT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ABSTRACT_KEYWORD)
@JvmField val OPEN_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OPEN_KEYWORD)
@JvmField
val OPEN_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OPEN_KEYWORD)
@JvmField val OVERRIDE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OVERRIDE_KEYWORD)
@JvmField
val OVERRIDE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OVERRIDE_KEYWORD)
@JvmField val PRIVATE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.PRIVATE_KEYWORD)
@JvmField
val PRIVATE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.PRIVATE_KEYWORD)
@JvmField val LATEINIT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.LATEINIT_KEYWORD)
@JvmField
val LATEINIT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.LATEINIT_KEYWORD)
@JvmField val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
@JvmField
val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
@JvmField val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
@JvmField
val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
val nameIdentifier = when (element) {
is KtNamedDeclaration -> element.nameIdentifier
@@ -325,7 +335,8 @@ object PositioningStrategies {
return markElement(nameIdentifier ?: element)
}
}
@JvmField val FOR_UNRESOLVED_REFERENCE: PositioningStrategy<KtReferenceExpression> = object : PositioningStrategy<KtReferenceExpression>() {
@JvmField
val FOR_UNRESOLVED_REFERENCE: PositioningStrategy<KtReferenceExpression> = object : PositioningStrategy<KtReferenceExpression>() {
override fun mark(element: KtReferenceExpression): List<TextRange> {
if (element is KtArrayAccessExpression) {
val ranges = element.bracketRanges
@@ -337,7 +348,8 @@ object PositioningStrategies {
}
}
@JvmStatic fun modifierSetPosition(vararg tokens: KtModifierKeywordToken): PositioningStrategy<KtModifierListOwner> {
@JvmStatic
fun modifierSetPosition(vararg tokens: KtModifierKeywordToken): PositioningStrategy<KtModifierListOwner> {
return object : PositioningStrategy<KtModifierListOwner>() {
override fun mark(element: KtModifierListOwner): List<TextRange> {
val modifierList = element.modifierList.sure { "No modifier list, but modifier has been found by the analyzer" }
@@ -353,15 +365,18 @@ object PositioningStrategies {
}
}
@JvmField val ARRAY_ACCESS: PositioningStrategy<KtArrayAccessExpression> = object : PositioningStrategy<KtArrayAccessExpression>() {
@JvmField
val ARRAY_ACCESS: PositioningStrategy<KtArrayAccessExpression> = object : PositioningStrategy<KtArrayAccessExpression>() {
override fun mark(element: KtArrayAccessExpression): List<TextRange> {
return markElement(element.indicesNode)
}
}
@JvmField val VISIBILITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = object : PositioningStrategy<KtModifierListOwner>() {
@JvmField
val VISIBILITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = object : PositioningStrategy<KtModifierListOwner>() {
override fun mark(element: KtModifierListOwner): List<TextRange> {
val visibilityTokens = listOf(KtTokens.PRIVATE_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PUBLIC_KEYWORD, KtTokens.INTERNAL_KEYWORD)
val visibilityTokens =
listOf(KtTokens.PRIVATE_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PUBLIC_KEYWORD, KtTokens.INTERNAL_KEYWORD)
val modifierList = element.modifierList
val result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange }
@@ -380,38 +395,44 @@ object PositioningStrategies {
is KtPropertyAccessor -> element.namePlaceholder
is KtAnonymousInitializer -> element
else -> throw IllegalArgumentException(
"Can't find text range for element '${element::class.java.canonicalName}' with the text '${element.text}'")
"Can't find text range for element '${element::class.java.canonicalName}' with the text '${element.text}'"
)
}
return markElement(elementToMark)
}
}
@JvmField val VARIANCE_IN_PROJECTION: PositioningStrategy<KtTypeProjection> = object : PositioningStrategy<KtTypeProjection>() {
@JvmField
val VARIANCE_IN_PROJECTION: PositioningStrategy<KtTypeProjection> = object : PositioningStrategy<KtTypeProjection>() {
override fun mark(element: KtTypeProjection): List<TextRange> {
return markElement(element.projectionToken!!)
}
}
@JvmField val PARAMETER_DEFAULT_VALUE: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
@JvmField
val PARAMETER_DEFAULT_VALUE: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
override fun mark(element: KtParameter): List<TextRange> {
return markNode(element.defaultValue!!.node)
}
}
@JvmField val PARAMETER_VARARG_MODIFIER: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
@JvmField
val PARAMETER_VARARG_MODIFIER: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
override fun mark(element: KtParameter): List<TextRange> {
val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!!
return markNode(varargModifier.node)
}
}
@JvmField val CALL_ELEMENT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
@JvmField
val CALL_ELEMENT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
return markElement((element as? KtCallElement)?.calleeExpression ?: element)
}
}
@JvmField val DECLARATION_WITH_BODY: PositioningStrategy<KtDeclarationWithBody> = object : PositioningStrategy<KtDeclarationWithBody>() {
@JvmField
val DECLARATION_WITH_BODY: PositioningStrategy<KtDeclarationWithBody> = object : PositioningStrategy<KtDeclarationWithBody>() {
override fun mark(element: KtDeclarationWithBody): List<TextRange> {
val lastBracketRange = (element.bodyExpression as? KtBlockExpression)?.lastBracketRange
return if (lastBracketRange != null)
@@ -425,7 +446,8 @@ object PositioningStrategies {
}
}
@JvmField val VAL_OR_VAR_NODE: PositioningStrategy<KtNamedDeclaration> = object : PositioningStrategy<KtNamedDeclaration>() {
@JvmField
val VAL_OR_VAR_NODE: PositioningStrategy<KtNamedDeclaration> = object : PositioningStrategy<KtNamedDeclaration>() {
override fun mark(element: KtNamedDeclaration): List<TextRange> {
return when (element) {
is KtParameter -> markElement(element.valOrVarKeyword ?: element)
@@ -435,41 +457,47 @@ object PositioningStrategies {
}
}
@JvmField val ELSE_ENTRY: PositioningStrategy<KtWhenEntry> = object : PositioningStrategy<KtWhenEntry>() {
@JvmField
val ELSE_ENTRY: PositioningStrategy<KtWhenEntry> = object : PositioningStrategy<KtWhenEntry>() {
override fun mark(element: KtWhenEntry): List<TextRange> {
return markElement(element.elseKeyword!!)
}
}
@JvmField val WHEN_EXPRESSION: PositioningStrategy<KtWhenExpression> = object : PositioningStrategy<KtWhenExpression>() {
@JvmField
val WHEN_EXPRESSION: PositioningStrategy<KtWhenExpression> = object : PositioningStrategy<KtWhenExpression>() {
override fun mark(element: KtWhenExpression): List<TextRange> {
return markElement(element.whenKeyword)
}
}
@JvmField val WHEN_CONDITION_IN_RANGE: PositioningStrategy<KtWhenConditionInRange> = object : PositioningStrategy<KtWhenConditionInRange>() {
@JvmField
val WHEN_CONDITION_IN_RANGE: PositioningStrategy<KtWhenConditionInRange> = object : PositioningStrategy<KtWhenConditionInRange>() {
override fun mark(element: KtWhenConditionInRange): List<TextRange> {
return markElement(element.operationReference)
}
}
@JvmField val SPECIAL_CONSTRUCT_TOKEN: PositioningStrategy<KtExpression> = object : PositioningStrategy<KtExpression>() {
@JvmField
val SPECIAL_CONSTRUCT_TOKEN: PositioningStrategy<KtExpression> = object : PositioningStrategy<KtExpression>() {
override fun mark(element: KtExpression): List<TextRange> =
when (element) {
is KtWhenExpression -> markElement(element.whenKeyword)
is KtIfExpression -> markElement(element.ifKeyword)
is KtOperationExpression -> markElement(element.operationReference)
else -> error("Expression is not an if, when or operation expression: ${element.getElementTextWithContext()}")
}
when (element) {
is KtWhenExpression -> markElement(element.whenKeyword)
is KtIfExpression -> markElement(element.ifKeyword)
is KtOperationExpression -> markElement(element.operationReference)
else -> error("Expression is not an if, when or operation expression: ${element.getElementTextWithContext()}")
}
}
@JvmField val NULLABLE_TYPE: PositioningStrategy<KtNullableType> = object : PositioningStrategy<KtNullableType>() {
@JvmField
val NULLABLE_TYPE: PositioningStrategy<KtNullableType> = object : PositioningStrategy<KtNullableType>() {
override fun mark(element: KtNullableType): List<TextRange> {
return markNode(element.questionMarkNode)
}
}
@JvmField val CALL_EXPRESSION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
@JvmField
val CALL_EXPRESSION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
if (element is KtCallExpression) {
return markRange(element, element.typeArgumentList ?: element.calleeExpression ?: element)
@@ -478,13 +506,15 @@ object PositioningStrategies {
}
}
@JvmField val VALUE_ARGUMENTS: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
@JvmField
val VALUE_ARGUMENTS: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
override fun mark(element: KtElement): List<TextRange> {
return markElement((element as? KtValueArgumentList)?.rightParenthesis ?: element)
}
}
@JvmField val FUNCTION_PARAMETERS: PositioningStrategy<KtFunction> = object : PositioningStrategy<KtFunction>() {
@JvmField
val FUNCTION_PARAMETERS: PositioningStrategy<KtFunction> = object : PositioningStrategy<KtFunction>() {
override fun mark(element: KtFunction): List<TextRange> {
val valueParameterList = element.valueParameterList
if (valueParameterList != null) {
@@ -497,7 +527,8 @@ object PositioningStrategies {
}
}
@JvmField val CUT_CHAR_QUOTES: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
@JvmField
val CUT_CHAR_QUOTES: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
override fun mark(element: KtElement): List<TextRange> {
if (element is KtConstantExpression) {
if (element.node.elementType == KtNodeTypes.CHARACTER_CONSTANT) {
@@ -509,7 +540,8 @@ object PositioningStrategies {
}
}
@JvmField val LONG_LITERAL_SUFFIX: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
@JvmField
val LONG_LITERAL_SUFFIX: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
override fun mark(element: KtElement): List<TextRange> {
if (element is KtConstantExpression) {
if (element.node.elementType == KtNodeTypes.INTEGER_CONSTANT) {
@@ -521,19 +553,22 @@ object PositioningStrategies {
}
}
@JvmField val UNREACHABLE_CODE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
@JvmField
val UNREACHABLE_CODE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out PsiElement>): List<TextRange> {
return Errors.UNREACHABLE_CODE.cast(diagnostic).a
}
}
@JvmField val AS_TYPE: PositioningStrategy<KtBinaryExpressionWithTypeRHS> = object : PositioningStrategy<KtBinaryExpressionWithTypeRHS>() {
@JvmField
val AS_TYPE: PositioningStrategy<KtBinaryExpressionWithTypeRHS> = object : PositioningStrategy<KtBinaryExpressionWithTypeRHS>() {
override fun mark(element: KtBinaryExpressionWithTypeRHS): List<TextRange> {
return markRange(element.operationReference, element)
}
}
@JvmField val COMPANION_OBJECT: PositioningStrategy<KtObjectDeclaration> = object : PositioningStrategy<KtObjectDeclaration>() {
@JvmField
val COMPANION_OBJECT: PositioningStrategy<KtObjectDeclaration> = object : PositioningStrategy<KtObjectDeclaration>() {
override fun mark(element: KtObjectDeclaration): List<TextRange> {
if (element.hasModifier(KtTokens.COMPANION_KEYWORD)) {
return modifierSetPosition(KtTokens.COMPANION_KEYWORD).mark(element)
@@ -542,38 +577,43 @@ object PositioningStrategies {
}
}
@JvmField val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
object : PositioningStrategy<KtConstructorDelegationCall>() {
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
if (element.isImplicit) {
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
}
return markElement(element.calleeExpression ?: element)
@JvmField
val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
object : PositioningStrategy<KtConstructorDelegationCall>() {
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
if (element.isImplicit) {
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
}
return markElement(element.calleeExpression ?: element)
}
}
@JvmField val DELEGATOR_SUPER_CALL: PositioningStrategy<KtEnumEntry> = object: PositioningStrategy<KtEnumEntry>() {
@JvmField
val DELEGATOR_SUPER_CALL: PositioningStrategy<KtEnumEntry> = object : PositioningStrategy<KtEnumEntry>() {
override fun mark(element: KtEnumEntry): List<TextRange> {
val specifiers = element.superTypeListEntries
return markElement(if (specifiers.isEmpty()) element else specifiers[0])
}
}
@JvmField val UNUSED_VALUE: PositioningStrategy<KtBinaryExpression> = object: PositioningStrategy<KtBinaryExpression>() {
@JvmField
val UNUSED_VALUE: PositioningStrategy<KtBinaryExpression> = object : PositioningStrategy<KtBinaryExpression>() {
override fun mark(element: KtBinaryExpression): List<TextRange> {
return listOf(TextRange(element.left!!.startOffset, element.operationReference.endOffset))
}
}
@JvmField val USELESS_ELVIS: PositioningStrategy<KtBinaryExpression> = object: PositioningStrategy<KtBinaryExpression>() {
@JvmField
val USELESS_ELVIS: PositioningStrategy<KtBinaryExpression> = object : PositioningStrategy<KtBinaryExpression>() {
override fun mark(element: KtBinaryExpression): List<TextRange> {
return listOf(TextRange(element.operationReference.startOffset, element.endOffset))
}
}
@JvmField val IMPORT_ALIAS: PositioningStrategy<KtImportDirective> = object: PositioningStrategy<KtImportDirective>() {
@JvmField
val IMPORT_ALIAS: PositioningStrategy<KtImportDirective> = object : PositioningStrategy<KtImportDirective>() {
override fun mark(element: KtImportDirective): List<TextRange> {
element.alias?.nameIdentifier?.let { return markElement(it) }
element.importedReference?.let {
@@ -586,7 +626,8 @@ object PositioningStrategies {
}
}
@JvmField val RETURN_WITH_LABEL: PositioningStrategy<KtReturnExpression> = object: PositioningStrategy<KtReturnExpression>() {
@JvmField
val RETURN_WITH_LABEL: PositioningStrategy<KtReturnExpression> = object : PositioningStrategy<KtReturnExpression>() {
override fun mark(element: KtReturnExpression): List<TextRange> {
val labeledExpression = element.labeledExpression
if (labeledExpression != null) {
@@ -597,7 +638,8 @@ object PositioningStrategies {
}
}
@JvmField val RECEIVER: PositioningStrategy<KtCallableDeclaration> = object : DeclarationHeader<KtCallableDeclaration>() {
@JvmField
val RECEIVER: PositioningStrategy<KtCallableDeclaration> = object : DeclarationHeader<KtCallableDeclaration>() {
override fun mark(element: KtCallableDeclaration): List<TextRange> {
element.receiverTypeReference?.let { return markElement(it) }
return DEFAULT.mark(element)
@@ -20,10 +20,11 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.renderer.DescriptorRenderer
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any
= renderer?.render(parameter, context) ?: parameter
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any =
renderer?.render(parameter, context) ?: parameter
fun ClassifierDescriptorWithTypeParameters.renderKindWithName(): String = DescriptorRenderer.getClassifierKindPrefix(this) + " '" + name + "'"
fun ClassifierDescriptorWithTypeParameters.renderKindWithName(): String =
DescriptorRenderer.getClassifierKindPrefix(this) + " '" + name + "'"
fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassifierKindPrefix(this)
@@ -57,27 +57,33 @@ object Renderers {
private val LOG = Logger.getInstance(Renderers::class.java)
@JvmField val TO_STRING = Renderer<Any> {
element ->
@JvmField
val TO_STRING = Renderer<Any> { element ->
if (element is DeclarationDescriptor) {
LOG.warn("Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n"
+ "This is usually a bad idea, because descriptors' toString() includes some debug information, "
+ "which should not be seen by the user.\nDescriptor: " + element)
LOG.warn(
"Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n"
+ "This is usually a bad idea, because descriptors' toString() includes some debug information, "
+ "which should not be seen by the user.\nDescriptor: " + element
)
}
element.toString()
}
@JvmField val STRING = Renderer<String> { it }
@JvmField
val STRING = Renderer<String> { it }
@JvmField val THROWABLE = Renderer<Throwable> {
@JvmField
val THROWABLE = Renderer<Throwable> {
val writer = StringWriter()
it.printStackTrace(PrintWriter(writer))
StringUtil.first(writer.toString(), 2048, true)
}
@JvmField val NAME = Renderer<Named> { it.name.asString() }
@JvmField
val NAME = Renderer<Named> { it.name.asString() }
@JvmField val PLATFORM = Renderer<ModuleDescriptor> {
@JvmField
val PLATFORM = Renderer<ModuleDescriptor> {
val platform = it.getMultiTargetPlatform()
" ${it.getCapability(ModuleInfo.Capability)?.displayedName ?: ""}" + when (platform) {
MultiTargetPlatform.Common -> ""
@@ -86,13 +92,15 @@ object Renderers {
}
}
@JvmField val VISIBILITY = Renderer<Visibility> {
@JvmField
val VISIBILITY = Renderer<Visibility> {
if (it == Visibilities.INVISIBLE_FAKE)
"invisible (private in a supertype)"
else it.displayName
}
@JvmField val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
@JvmField
val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
val name = it.name.asString()
when (it) {
is PackageFragmentDescriptor -> "package '$name'"
@@ -108,7 +116,8 @@ object Renderers {
}
}
@JvmField val CAPITALIZED_DECLARATION_NAME_WITH_KIND_AND_PLATFORM = ContextDependentRenderer<DeclarationDescriptor> { descriptor, context ->
@JvmField
val CAPITALIZED_DECLARATION_NAME_WITH_KIND_AND_PLATFORM = ContextDependentRenderer<DeclarationDescriptor> { descriptor, context ->
val declarationWithNameAndKind = DECLARATION_NAME_WITH_KIND.render(descriptor, context)
val withPlatform = if (descriptor is MemberDescriptor && descriptor.isActual)
"actual $declarationWithNameAndKind"
@@ -119,37 +128,40 @@ object Renderers {
}
@JvmField val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer<DeclarationDescriptor> {
@JvmField
val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer<DeclarationDescriptor> {
if (DescriptorUtils.isTopLevelDeclaration(it) && it is DeclarationDescriptorWithVisibility && it.visibility == Visibilities.PRIVATE) {
"file"
}
else {
} else {
val containingDeclaration = it.containingDeclaration
if (containingDeclaration is PackageFragmentDescriptor) {
containingDeclaration.fqName.asString().wrapIntoQuotes()
}
else {
} else {
containingDeclaration!!.name.asString().wrapIntoQuotes()
}
}
}
@JvmField val ELEMENT_TEXT = Renderer<PsiElement> { it.text }
@JvmField
val ELEMENT_TEXT = Renderer<PsiElement> { it.text }
@JvmField val DECLARATION_NAME = Renderer<KtNamedDeclaration> { it.nameAsSafeName.asString() }
@JvmField
val DECLARATION_NAME = Renderer<KtNamedDeclaration> { it.nameAsSafeName.asString() }
@JvmField val RENDER_CLASS_OR_OBJECT = Renderer {
classOrObject: KtClassOrObject ->
@JvmField
val RENDER_CLASS_OR_OBJECT = Renderer { classOrObject: KtClassOrObject ->
val name = classOrObject.name?.let { " ${it.wrapIntoQuotes()}" } ?: ""
if (classOrObject is KtClass) "Class" + name else "Object" + name
}
@JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassifierDescriptorWithTypeParameters> { it.renderKindWithName() }
@JvmField
val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassifierDescriptorWithTypeParameters> { it.renderKindWithName() }
@JvmField val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false })
@JvmField
val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false })
@JvmField val RENDER_POSITION_VARIANCE = Renderer {
variance: Variance ->
@JvmField
val RENDER_POSITION_VARIANCE = Renderer { variance: Variance ->
when (variance) {
Variance.INVARIANT -> "invariant"
Variance.IN_VARIANCE -> "in"
@@ -157,17 +169,17 @@ object Renderers {
}
}
@JvmField val AMBIGUOUS_CALLS = Renderer {
calls: Collection<ResolvedCall<*>> ->
@JvmField
val AMBIGUOUS_CALLS = Renderer { calls: Collection<ResolvedCall<*>> ->
val descriptors = calls.map { it.resultingDescriptor }
val context = RenderingContext.Impl(descriptors)
descriptors
.sortedWith(MemberComparator.INSTANCE)
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
.sortedWith(MemberComparator.INSTANCE)
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
}
@JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> {
collection, context ->
@JvmStatic
fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> { collection, context ->
buildString {
val iterator = collection.iterator()
while (iterator.hasNext()) {
@@ -180,31 +192,39 @@ object Renderers {
}
}
@JvmField val TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER = Renderer<InferenceErrorData> {
@JvmField
val TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER = Renderer<InferenceErrorData> {
renderConflictingSubstitutionsInferenceError(it, TabledDescriptorRenderer.create()).toString()
}
@JvmField val TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER = Renderer<InferenceErrorData> {
@JvmField
val TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER = Renderer<InferenceErrorData> {
renderParameterConstraintError(it, TabledDescriptorRenderer.create()).toString()
}
@JvmField val TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER = Renderer<InferenceErrorData> {
@JvmField
val TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER = Renderer<InferenceErrorData> {
renderNoInformationForParameterError(it, TabledDescriptorRenderer.create()).toString()
}
@JvmField val TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = Renderer<InferenceErrorData> {
@JvmField
val TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = Renderer<InferenceErrorData> {
renderUpperBoundViolatedInferenceError(it, TabledDescriptorRenderer.create()).toString()
}
@JvmField val TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER = Renderer<InferenceErrorData> {
@JvmField
val TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER = Renderer<InferenceErrorData> {
renderCannotCaptureTypeParameterError(it, TabledDescriptorRenderer.create()).toString()
}
@JvmStatic fun renderConflictingSubstitutionsInferenceError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
@JvmStatic
fun renderConflictingSubstitutionsInferenceError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer {
LOG.assertTrue(inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData))
LOG.assertTrue(
inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData)
)
val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>()
val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
@@ -219,10 +239,12 @@ object Renderers {
return result
}
result.text(newText()
.normal("Cannot infer type parameter ")
.strong(firstConflictingVariable.name)
.normal(" in "))
result.text(
newText()
.normal("Cannot infer type parameter ")
.strong(firstConflictingVariable.name)
.normal(" in ")
)
val table = newTable()
result.table(table)
table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions")
@@ -249,29 +271,33 @@ object Renderers {
table.functionArgumentTypeList(receiverType, parameterTypes, { errorPositions.contains(it) })
}
table.text("can be applied to").functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes)
table.text("can be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes)
return result
}
@JvmStatic fun renderParameterConstraintError(
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
@JvmStatic
fun renderParameterConstraintError(
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
): TabledDescriptorRenderer {
val constraintErrors = inferenceErrorData.constraintSystem.status.constraintErrors
val errorPositions = constraintErrors.filter { it is ParameterConstraintError }.map { it.constraintPosition }
return renderer.table(
TabledDescriptorRenderer
.newTable()
.descriptor(inferenceErrorData.descriptor)
.text("cannot be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
inferenceErrorData.valueArgumentsTypes,
{ errorPositions.contains(it) }))
TabledDescriptorRenderer
.newTable()
.descriptor(inferenceErrorData.descriptor)
.text("cannot be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
inferenceErrorData.valueArgumentsTypes,
{ errorPositions.contains(it) })
)
}
@JvmStatic fun renderNoInformationForParameterError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
@JvmStatic
fun renderNoInformationForParameterError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer {
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty()
@@ -280,21 +306,28 @@ object Renderers {
}
return result
.text(newText().normal("Not enough information to infer parameter ")
.strong(firstUnknownVariable.name)
.normal(" in "))
.table(newTable()
.descriptor(inferenceErrorData.descriptor)
.text("Please specify it explicitly."))
.text(
newText().normal("Not enough information to infer parameter ")
.strong(firstUnknownVariable.name)
.normal(" in ")
)
.table(
newTable()
.descriptor(inferenceErrorData.descriptor)
.text("Please specify it explicitly.")
)
}
@JvmStatic fun renderUpperBoundViolatedInferenceError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
@JvmStatic
fun renderUpperBoundViolatedInferenceError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer {
val constraintSystem = inferenceErrorData.constraintSystem
val status = constraintSystem.status
LOG.assertTrue(status.hasViolatedUpperBound(),
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData))
LOG.assertTrue(
status.hasViolatedUpperBound(),
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData)
)
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION)
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
@@ -304,7 +337,7 @@ object Renderers {
if (typeParameterDescriptor == null) {
if (inferenceErrorData.descriptor is TypeAliasConstructorDescriptor) {
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
inferenceErrorData, result, systemWithoutWeakConstraints
inferenceErrorData, result, systemWithoutWeakConstraints
)?.let {
return it
}
@@ -313,7 +346,12 @@ object Renderers {
return if (status.hasConflictingConstraints())
renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
else {
LOG.error(debugMessage("There is no type parameter with violated upper bound for 'upper bound violated' error", inferenceErrorData))
LOG.error(
debugMessage(
"There is no type parameter with violated upper bound for 'upper bound violated' error",
inferenceErrorData
)
)
result
}
}
@@ -321,21 +359,30 @@ object Renderers {
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
if (inferredValueForTypeParameter == null) {
LOG.error(debugMessage("System without weak constraints is not successful, there is no value for type parameter " +
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData))
LOG.error(
debugMessage(
"System without weak constraints is not successful, there is no value for type parameter " +
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData
)
)
return result
}
result.text(newText()
.normal("Type parameter bound for ")
.strong(typeParameterDescriptor.name)
.normal(" in "))
.table(newTable()
.descriptor(inferenceErrorData.descriptor))
result.text(
newText()
.normal("Type parameter bound for ")
.strong(typeParameterDescriptor.name)
.normal(" in ")
)
.table(
newTable()
.descriptor(inferenceErrorData.descriptor)
)
var violatedUpperBound: KotlinType? = null
for (upperBound in typeParameterDescriptor.upperBounds) {
val upperBoundWithSubstitutedInferredTypes = systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
val upperBoundWithSubstitutedInferredTypes =
systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
if (upperBoundWithSubstitutedInferredTypes != null
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
violatedUpperBound = upperBoundWithSubstitutedInferredTypes
@@ -343,26 +390,32 @@ object Renderers {
}
}
if (violatedUpperBound == null) {
LOG.error(debugMessage("Type parameter (chosen as violating its upper bound)" +
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData))
LOG.error(
debugMessage(
"Type parameter (chosen as violating its upper bound)" +
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData
)
)
return result
}
// TODO: context should be in fact shared for the table and these two types
val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound)
val typeRenderer = result.typeRenderer
result.text(newText()
.normal(" is not satisfied: inferred type ")
.error(typeRenderer.render(inferredValueForTypeParameter, context))
.normal(" is not a subtype of ")
.strong(typeRenderer.render(violatedUpperBound, context)))
result.text(
newText()
.normal(" is not satisfied: inferred type ")
.error(typeRenderer.render(inferredValueForTypeParameter, context))
.normal(" is not a subtype of ")
.strong(typeRenderer.render(violatedUpperBound, context))
)
return result
}
private fun renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
inferenceErrorData: InferenceErrorData,
result: TabledDescriptorRenderer,
systemWithoutWeakConstraints: ConstraintSystem
inferenceErrorData: InferenceErrorData,
result: TabledDescriptorRenderer,
systemWithoutWeakConstraints: ConstraintSystem
): TabledDescriptorRenderer? {
val descriptor = inferenceErrorData.descriptor
if (descriptor !is TypeAliasConstructorDescriptor) {
@@ -391,12 +444,16 @@ object Renderers {
val context = RenderingContext.of(violatingInferredType, violatedUpperBound)
val typeRenderer = result.typeRenderer
result.text(newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
.normal(" in type inferred from type alias expansion for "))
.table(newTable().descriptor(inferenceErrorData.descriptor))
result.text(
newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
.normal(" in type inferred from type alias expansion for ")
)
.table(newTable().descriptor(inferenceErrorData.descriptor))
result.text(newText().normal(" is not satisfied: inferred type ").error(typeRenderer.render(violatingInferredType, context))
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context)))
result.text(
newText().normal(" is not satisfied: inferred type ").error(typeRenderer.render(violatingInferredType, context))
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context))
)
return result
}
@@ -404,8 +461,9 @@ object Renderers {
return null
}
@JvmStatic fun renderCannotCaptureTypeParameterError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
@JvmStatic
fun renderCannotCaptureTypeParameterError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer {
val system = inferenceErrorData.constraintSystem
val errors = system.status.constraintErrors
@@ -419,7 +477,12 @@ object Renderers {
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
if (capturedTypeConstructor == null) {
LOG.error(debugMessage("There is no captured type in bounds, but there is an error 'cannot capture type parameter'", inferenceErrorData))
LOG.error(
debugMessage(
"There is no captured type in bounds, but there is an error 'cannot capture type parameter'",
inferenceErrorData
)
)
return result
}
@@ -431,20 +494,25 @@ object Renderers {
}
val explanation =
"Type parameter has an upper bound ${result.typeRenderer.render(upperBound, RenderingContext.of(upperBound)).wrapIntoQuotes()}" +
" that cannot be satisfied capturing 'in' projection"
"Type parameter has an upper bound ${result.typeRenderer.render(
upperBound,
RenderingContext.of(upperBound)
).wrapIntoQuotes()}" +
" that cannot be satisfied capturing 'in' projection"
result.text(newText().normal(
result.text(
newText().normal(
typeParameter.name.wrapIntoQuotes() +
" cannot capture " +
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
explanation
))
" cannot capture " +
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
explanation
)
)
return result
}
@JvmField val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> {
descriptors ->
@JvmField
val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> { descriptors ->
buildString {
var index = 0
for (descriptor in descriptors) {
@@ -452,17 +520,18 @@ object Renderers {
index++
if (index <= descriptors.size - 2) {
append(", ")
}
else if (index == descriptors.size - 1) {
} else if (index == descriptors.size - 1) {
append(" or ")
}
}
}
}
private fun renderTypes(types: Collection<KotlinType>, context: RenderingContext) = StringUtil.join(types, { RENDER_TYPE.render(it, context) }, ", ")
private fun renderTypes(types: Collection<KotlinType>, context: RenderingContext) =
StringUtil.join(types, { RENDER_TYPE.render(it, context) }, ", ")
@JvmField val RENDER_COLLECTION_OF_TYPES = ContextDependentRenderer<Collection<KotlinType>> { types, context -> renderTypes(types, context) }
@JvmField
val RENDER_COLLECTION_OF_TYPES = ContextDependentRenderer<Collection<KotlinType>> { types, context -> renderTypes(types, context) }
fun renderConstraintSystem(constraintSystem: ConstraintSystem, shortTypeBounds: Boolean): String {
val typeBounds = linkedSetOf<TypeBounds>()
@@ -470,8 +539,8 @@ object Renderers {
typeBounds.add(constraintSystem.getTypeBounds(variable))
}
return "type parameter bounds:\n" +
StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
}
private fun renderTypeBounds(typeBounds: TypeBounds, short: Boolean): String {
@@ -482,14 +551,13 @@ object Renderers {
else -> ":= "
}
val renderer = if (short) DescriptorRenderer.SHORT_NAMES_IN_TYPES else DescriptorRenderer.FQ_NAMES_IN_TYPES
val renderedBound = arrow + renderer.renderType(bound.constrainingType) + if (!bound.isProper) "*" else ""
val renderedBound = arrow + renderer.renderType(bound.constrainingType) + if (!bound.isProper) "*" else ""
if (short) renderedBound else renderedBound + '(' + bound.position + ')'
}
val typeVariableName = typeBounds.typeVariable.name
return if (typeBounds.bounds.isEmpty()) {
typeVariableName.asString()
}
else
} else
"$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}"
}
@@ -503,8 +571,7 @@ object Renderers {
val context = RenderingContext.Empty
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
append(inferenceErrorData.expectedType)
}
else {
} else {
append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
}
append("\nArgument types:\n")
@@ -519,26 +586,33 @@ object Renderers {
private val WHEN_MISSING_LIMIT = 7
@JvmField val RENDER_WHEN_MISSING_CASES = Renderer<List<WhenMissingCase>> {
@JvmField
val RENDER_WHEN_MISSING_CASES = Renderer<List<WhenMissingCase>> {
if (!it.hasUnknown) {
val list = it.joinToString(", ", limit = WHEN_MISSING_LIMIT) { "'$it'" }
val branches = if (it.size > 1) "branches" else "branch"
"$list $branches or 'else' branch instead"
}
else {
} else {
"'else' branch"
}
}
@JvmField val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
@JvmField val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
@JvmField val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
@JvmField val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
@JvmField
val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
@JvmField
val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
@JvmField
val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
@JvmField
val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
modifiers = emptySet()
}.asRenderer()
@JvmField val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
@JvmField val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
@JvmField val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
@JvmField
val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
@JvmField
val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
@JvmField
val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
withoutTypeParameters = false
receiverAfterName = false
renderAccessors = true
@@ -37,7 +37,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
return when {
hasUniqueName(classifier) -> ClassifierNamePolicy.SHORT.renderClassifier(classifier, renderer)
classifier is ClassDescriptor ||
classifier is TypeAliasDescriptor ->
classifier is TypeAliasDescriptor ->
ClassifierNamePolicy.FULLY_QUALIFIED.renderClassifier(classifier, renderer)
classifier is TypeParameterDescriptor -> {
val name = classifier.name
@@ -55,7 +55,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
}
private fun DescriptorRenderer.renderAmbiguousTypeParameter(
typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean
typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean
) = buildString {
append(typeParameter.name)
append("#$index")
@@ -68,7 +68,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
private val ADAPTIVE_CLASSIFIER_POLICY_KEY = object : RenderingContext.Key<ClassifierNamePolicy>("ADAPTIVE_CLASSIFIER_POLICY") {
override fun compute(objectsToRender: Collection<Any?>): ClassifierNamePolicy {
val ambiguousNames =
collectClassifiersFqNames(objectsToRender).groupBy { it.shortNameOrSpecial() }.filter { it.value.size > 1 }.map { it.key }
collectClassifiersFqNames(objectsToRender).groupBy { it.shortNameOrSpecial() }.filter { it.value.size > 1 }.map { it.key }
return AdaptiveClassifierNamePolicy(ambiguousNames)
}
}
@@ -83,8 +83,7 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
}
contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType ->
diagnosticType.contains {
innerType ->
diagnosticType.contains { innerType ->
innerType.addMentionedTypeConstructor()
innerType.getAbbreviation()?.addMentionedTypeConstructor()
false
@@ -101,12 +100,14 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
collectMentionedClassifiersFqNames(it.upperBounds, result)
}
contextObjects.filterIsInstance<CallableDescriptor>().forEach {
collectMentionedClassifiersFqNames(listOf(
collectMentionedClassifiersFqNames(
listOf(
it.typeParameters,
it.returnType,
it.valueParameters,
it.dispatchReceiverParameter?.type,
it.extensionReceiverParameter?.type
), result)
), result
)
}
}
@@ -38,9 +38,9 @@ import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
fun StorageComponentContainer.configureModule(
moduleContext: ModuleContext,
platform: TargetPlatform,
platformVersion: TargetPlatformVersion
moduleContext: ModuleContext,
platform: TargetPlatform,
platformVersion: TargetPlatformVersion
) {
useInstance(moduleContext)
useInstance(moduleContext.module)
@@ -54,7 +54,7 @@ fun StorageComponentContainer.configureModule(
platform.platformConfigurator.configureModuleComponents(this)
for (extension in StorageComponentContainerContributor.getInstances(moduleContext.project)) {
extension.registerModuleComponents(this, platform, moduleContext.module)
extension.registerModuleComponents(this, platform, moduleContext.module)
}
configurePlatformIndependentComponents()
@@ -66,22 +66,22 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
}
fun StorageComponentContainer.configureModule(
moduleContext: ModuleContext,
platform: TargetPlatform,
platformVersion: TargetPlatformVersion,
trace: BindingTrace
moduleContext: ModuleContext,
platform: TargetPlatform,
platformVersion: TargetPlatformVersion,
trace: BindingTrace
) {
configureModule(moduleContext, platform, platformVersion)
useInstance(trace)
}
fun createContainerForBodyResolve(
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
platform: TargetPlatform,
statementFilter: StatementFilter,
targetPlatformVersion: TargetPlatformVersion,
languageVersionSettings: LanguageVersionSettings
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
platform: TargetPlatform,
statementFilter: StatementFilter,
targetPlatformVersion: TargetPlatformVersion,
languageVersionSettings: LanguageVersionSettings
): StorageComponentContainer = createContainer("BodyResolve", platform) {
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
@@ -95,13 +95,13 @@ fun createContainerForBodyResolve(
}
fun createContainerForLazyBodyResolve(
moduleContext: ModuleContext,
kotlinCodeAnalyzer: KotlinCodeAnalyzer,
bindingTrace: BindingTrace,
platform: TargetPlatform,
bodyResolveCache: BodyResolveCache,
targetPlatformVersion: TargetPlatformVersion,
languageVersionSettings: LanguageVersionSettings
moduleContext: ModuleContext,
kotlinCodeAnalyzer: KotlinCodeAnalyzer,
bindingTrace: BindingTrace,
platform: TargetPlatform,
bodyResolveCache: BodyResolveCache,
targetPlatformVersion: TargetPlatformVersion,
languageVersionSettings: LanguageVersionSettings
): StorageComponentContainer = createContainer("LazyBodyResolve", platform) {
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
@@ -115,14 +115,14 @@ fun createContainerForLazyBodyResolve(
}
fun createContainerForLazyLocalClassifierAnalyzer(
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
platform: TargetPlatform,
lookupTracker: LookupTracker,
targetPlatformVersion: TargetPlatformVersion,
languageVersionSettings: LanguageVersionSettings,
statementFilter: StatementFilter,
localClassDescriptorHolder: LocalClassDescriptorHolder
moduleContext: ModuleContext,
bindingTrace: BindingTrace,
platform: TargetPlatform,
lookupTracker: LookupTracker,
targetPlatformVersion: TargetPlatformVersion,
languageVersionSettings: LanguageVersionSettings,
statementFilter: StatementFilter,
localClassDescriptorHolder: LocalClassDescriptorHolder
): StorageComponentContainer = createContainer("LocalClassifierAnalyzer", platform) {
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
@@ -147,13 +147,13 @@ fun createContainerForLazyLocalClassifierAnalyzer(
}
fun createContainerForLazyResolve(
moduleContext: ModuleContext,
declarationProviderFactory: DeclarationProviderFactory,
bindingTrace: BindingTrace,
platform: TargetPlatform,
targetPlatformVersion: TargetPlatformVersion,
targetEnvironment: TargetEnvironment,
languageVersionSettings: LanguageVersionSettings
moduleContext: ModuleContext,
declarationProviderFactory: DeclarationProviderFactory,
bindingTrace: BindingTrace,
platform: TargetPlatform,
targetPlatformVersion: TargetPlatformVersion,
targetEnvironment: TargetEnvironment,
languageVersionSettings: LanguageVersionSettings
): StorageComponentContainer = createContainer("LazyResolve", platform) {
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
@@ -168,12 +168,12 @@ fun createContainerForLazyResolve(
}
fun createLazyResolveSession(moduleContext: ModuleContext, files: Collection<KtFile>): ResolveSession =
createContainerForLazyResolve(
moduleContext,
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
BindingTraceContext(),
TargetPlatform.Common,
TargetPlatformVersion.NoVersion,
CompilerEnvironment,
LanguageVersionSettingsImpl.DEFAULT
).get<ResolveSession>()
createContainerForLazyResolve(
moduleContext,
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
BindingTraceContext(),
TargetPlatform.Common,
TargetPlatformVersion.NoVersion,
CompilerEnvironment,
LanguageVersionSettingsImpl.DEFAULT
).get<ResolveSession>()
@@ -34,7 +34,8 @@ class MainFunctionDetector {
/** Assumes that the function declaration is already resolved and the descriptor can be found in the `bindingContext`. */
constructor(bindingContext: BindingContext) {
this.getFunctionDescriptor = { function ->
bindingContext.get(BindingContext.FUNCTION, function) ?: throw IllegalStateException("No descriptor resolved for " + function + " " + function.text)
bindingContext.get(BindingContext.FUNCTION, function)
?: throw IllegalStateException("No descriptor resolved for " + function + " " + function.text)
}
}
@@ -83,9 +84,9 @@ class MainFunctionDetector {
private fun getMainFunction(module: ModuleDescriptor, packageView: PackageViewDescriptor): FunctionDescriptor? {
for (packageFragment in packageView.fragments.filter { it.module == module }) {
DescriptorUtils.getAllDescriptors(packageFragment.getMemberScope())
.filterIsInstance<FunctionDescriptor>()
.firstOrNull { isMain(it) }
?.let { return it }
.filterIsInstance<FunctionDescriptor>()
.firstOrNull { isMain(it) }
?.let { return it }
}
for (subpackageName in module.getSubPackagesOf(packageView.fqName, MemberScope.ALL_NAME_FILTER)) {
@@ -108,7 +109,7 @@ class MainFunctionDetector {
}
val parameters = descriptor.valueParameters.mapTo(mutableListOf()) { it.type }
descriptor.extensionReceiverParameter?.type?.let {parameters += it}
descriptor.extensionReceiverParameter?.type?.let { parameters += it }
if (parameters.size != 1 || !descriptor.typeParameters.isEmpty()) return false
@@ -127,14 +128,14 @@ class MainFunctionDetector {
}
val returnType = descriptor.returnType
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) return false
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) return false
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) return true
val containingDeclaration = descriptor.containingDeclaration
return containingDeclaration is ClassDescriptor
&& containingDeclaration.kind.isSingleton
&& (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation)
&& containingDeclaration.kind.isSingleton
&& (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation)
}
private fun getJVMFunctionName(functionDescriptor: FunctionDescriptor): String {
@@ -29,14 +29,17 @@ import org.jetbrains.kotlin.lexer.KtTokens
*/
class KDocLinkParser : PsiParser {
companion object {
@JvmStatic fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
@JvmStatic
fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
val parentElement = chameleon.treeParent.psi
val project = parentElement.project
val builder = PsiBuilderFactory.getInstance().createBuilder(project,
chameleon,
KotlinLexer(),
root.language,
chameleon.text)
val builder = PsiBuilderFactory.getInstance().createBuilder(
project,
chameleon,
KotlinLexer(),
root.language,
chameleon.text
)
val parser = KDocLinkParser()
return parser.parse(root, builder).firstChildNode
@@ -60,8 +63,7 @@ class KDocLinkParser : PsiParser {
if (builder.tokenType == KtTokens.RBRACKET) {
builder.advanceLexer()
}
}
else {
} else {
if (!builder.eof()) {
builder.error("Expression expected")
while (!builder.eof()) {
@@ -32,18 +32,17 @@ class KDocSection(node: ASTNode) : KDocTag(node) {
* or null for the default section).
*/
override fun getName(): String? =
(firstChild as? KDocTag)?.name
(firstChild as? KDocTag)?.name
override fun getSubjectName(): String? =
(firstChild as? KDocTag)?.getSubjectName()
(firstChild as? KDocTag)?.getSubjectName()
override fun getContent(): String =
(firstChild as? KDocTag)?.getContent() ?: super.getContent()
(firstChild as? KDocTag)?.getContent() ?: super.getContent()
fun findTagsByName(name: String): List<KDocTag> {
return getChildrenOfType<KDocTag>().filter { it.name == name }
}
fun findTagByName(name: String): KDocTag?
= findTagsByName(name).firstOrNull()
fun findTagByName(name: String): KDocTag? = findTagsByName(name).firstOrNull()
}
@@ -67,9 +67,9 @@ open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
}
private fun childrenAfterTagName(): List<ASTNode> =
node.getChildren(null)
.dropWhile { it.elementType == KDocTokens.TAG_NAME }
.dropWhile { it.elementType == TokenType.WHITE_SPACE }
node.getChildren(null)
.dropWhile { it.elementType == KDocTokens.TAG_NAME }
.dropWhile { it.elementType == TokenType.WHITE_SPACE }
/**
* Returns the content of this tag (all text following the tag name and the subject if present,
@@ -109,8 +109,7 @@ open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
if (!isCodeBlock())
indentedCodeBlock = indentedCodeBlock || node.text.startsWith(indentationWhiteSpaces) || node.text.startsWith("\t")
startCodeBlock()
}
else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
} else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
flushCodeBlock()
indentedCodeBlock = false
}
@@ -63,7 +63,9 @@ class KotlinParserDefinition : ParserDefinition {
return when (elementType) {
is KtStubElementType<*, *> -> elementType.createPsiFromAst(astNode)
KtNodeTypes.TYPE_CODE_FRAGMENT, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, KtNodeTypes.BLOCK_CODE_FRAGMENT -> ASTWrapperPsiElement(astNode)
KtNodeTypes.TYPE_CODE_FRAGMENT, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, KtNodeTypes.BLOCK_CODE_FRAGMENT -> ASTWrapperPsiElement(
astNode
)
is KDocElementType -> elementType.createPsi(astNode)
KDocTokens.MARKDOWN_LINK -> KDocLink(astNode)
else -> (elementType as KtNodeType).createPsi(astNode)
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.lexer.KtTokens
object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
if (tokens.isEmpty()) return 0
// 1. bind doc comment
@@ -44,7 +45,7 @@ object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
}
}
else -> break@tokens
else -> break@tokens
}
}
@@ -54,7 +55,8 @@ object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
if (tokens.isEmpty()) return 0
for (idx in tokens.indices.reversed()) {
@@ -68,7 +70,8 @@ object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
// Binds comments on the same line
object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
if (tokens.isEmpty()) return 0
var result = 0
@@ -89,7 +92,8 @@ object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
if (tokens.isEmpty()) return 0
val size = tokens.size
@@ -110,14 +114,16 @@ val TRAILING_ALL_COMMENTS_BINDER: WhitespacesAndCommentsBinder = AllCommentsBind
object DoNotBindAnything : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
return 0
}
}
object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
if (tokens.firstOrNull() == KtTokens.SHEBANG_COMMENT) {
return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1
}
@@ -128,7 +134,8 @@ object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
return if (!isTrailing) 0 else tokens.size
}
}
@@ -22,7 +22,7 @@ import gnu.trove.TIntArrayList
import org.jetbrains.kotlin.psi.psiUtil.getContentRange
import org.jetbrains.kotlin.psi.psiUtil.isSingleQuoted
class KotlinStringLiteralTextEscaper(host: KtStringTemplateExpression): LiteralTextEscaper<KtStringTemplateExpression>(host) {
class KotlinStringLiteralTextEscaper(host: KtStringTemplateExpression) : LiteralTextEscaper<KtStringTemplateExpression>(host) {
private var sourceOffsets: IntArray? = null
override fun decode(rangeInsideHost: TextRange, outChars: StringBuilder): Boolean {
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
// This node represents "fake" reference expression for ENUM_ENTRY(arguments) constructor syntax
// It uses the superclass enum node to provide access to the real constructor name
class KtEnumEntrySuperclassReferenceExpression :
KtExpressionImplStub<KotlinEnumEntrySuperclassReferenceExpressionStub>, KtSimpleNameExpression {
KtExpressionImplStub<KotlinEnumEntrySuperclassReferenceExpressionStub>, KtSimpleNameExpression {
constructor(node: ASTNode) : super(node)
@@ -37,7 +37,7 @@ class KtEnumEntrySuperclassReferenceExpression :
// It is the owner enum class (not an enum entry but the whole enum)
private val referencedElement: KtClass
get() = calcReferencedElement()!!
get() = calcReferencedElement()!!
private fun calcReferencedElement(): KtClass? {
val owner = this.getStrictParentOfType<KtEnumEntry>()
@@ -35,7 +35,8 @@ abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtExpressi
}
is KtSimpleNameStringTemplateEntry -> {
if (newElement !is KtSimpleNameExpression && !newElement.isThisWithoutLabel()) {
val newEntry = parent.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
val newEntry =
parent.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
return newEntry.expression!!
}
}
@@ -43,8 +43,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
if (this.modifierList == null) {
getConstructorKeyword()?.delete()
}
}
else {
} else {
if (modifier == KtTokens.PUBLIC_KEYWORD) return
val newModifierList = KtPsiFactory(this).createModifierList(modifier)
addBefore(newModifierList, getOrCreateConstructorKeyword())
@@ -62,8 +61,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
val modifierList = modifierList
return if (modifierList != null) {
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
}
else {
} else {
val parameterList = valueParameterList!!
val newModifierList = KtPsiFactory(project).createModifierList(annotationEntry.text)
(addBefore(newModifierList, parameterList) as KtModifierList).annotationEntries.first()
@@ -26,10 +26,11 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
fun KtPsiFactory(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated)
@JvmOverloads
fun KtPsiFactory(elementForProject: PsiElement, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(elementForProject.project, markGenerated)
fun KtPsiFactory(elementForProject: PsiElement, markGenerated: Boolean = true): KtPsiFactory =
KtPsiFactory(elementForProject.project, markGenerated)
private val DO_NOT_ANALYZE_NOTIFICATION = "This file was created by KtPsiFactory and should not be analyzed\n" +
"Use createAnalyzableFile to create file that can be analyzed\n"
"Use createAnalyzableFile to create file that can be analyzed\n"
var KtFile.doNotAnalyze: String? by UserDataProperty(Key.create("DO_NOT_ANALYZE"))
var KtFile.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS_CONTEXT"))
@@ -72,7 +73,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
fun createThisExpression() =
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
fun createThisExpression(qualifier: String) =
(createExpression("this@$qualifier.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
@@ -109,7 +110,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
fun createFunctionTypeParameter(typeReference: KtTypeReference): KtParameter {
return (createType("(A) -> B").typeElement as KtFunctionType).parameters.first().apply { this.typeReference!!.replace(typeReference) }
return (createType("(A) -> B").typeElement as KtFunctionType).parameters.first()
.apply { this.typeReference!!.replace(typeReference) }
}
fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
@@ -184,7 +186,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
return createFileAnnotationListWithAnnotation(annotationText).annotationEntries.first()
}
fun createFileAnnotationListWithAnnotation(annotationText: String) : KtFileAnnotationList {
fun createFileAnnotationListWithAnnotation(annotationText: String): KtFileAnnotationList {
return createFile("@file:$annotationText").fileAnnotationList!!
}
@@ -193,7 +195,14 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
private fun doCreateFile(fileName: String, text: String): KtFile {
return PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, LocalTimeCounter.currentTime(), false, markGenerated) as KtFile
return PsiFileFactory.getInstance(project).createFileFromText(
fileName,
KotlinFileType.INSTANCE,
text,
LocalTimeCounter.currentTime(),
false,
markGenerated
) as KtFile
}
fun createFile(fileName: String, text: String): KtFile {
@@ -217,13 +226,19 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
fun createPhysicalFile(fileName: String, text: String): KtFile {
return PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true) as KtFile
return PsiFileFactory.getInstance(project).createFileFromText(
fileName,
KotlinFileType.INSTANCE,
text,
LocalTimeCounter.currentTime(),
true
) as KtFile
}
fun createProperty(modifiers: String?, name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty {
val text = modifiers.let { "$it "} +
(if (isVar) " var " else " val ") + name +
(if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer)
val text = modifiers.let { "$it " } +
(if (isVar) " var " else " val ") + name +
(if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer)
return createProperty(text)
}
@@ -333,7 +348,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
return createClass("class A(){}").getBody()!!
}
fun createParameter(text : String): KtParameter {
fun createParameter(text: String): KtParameter {
return createClass("class A($text)").primaryConstructorParameters.first()
}
@@ -346,13 +361,13 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
fun createTypeParameter(text: String) = createTypeParameterList("<$text>").parameters.first()!!
fun createLambdaParameterListIfAny(text: String) =
createLambdaExpression(text, "0").functionLiteral.valueParameterList
createLambdaExpression(text, "0").functionLiteral.valueParameterList
fun createLambdaParameterList(text: String) = createLambdaParameterListIfAny(text)!!
fun createLambdaExpression(parameters: String, body: String): KtLambdaExpression =
(if (parameters.isNotEmpty()) createExpression("{ $parameters -> $body }")
else createExpression("{ $body }")) as KtLambdaExpression
(if (parameters.isNotEmpty()) createExpression("{ $parameters -> $body }")
else createExpression("{ $body }")) as KtLambdaExpression
fun createEnumEntry(text: String): KtEnumEntry {
@@ -404,7 +419,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
throw IllegalArgumentException("import path must not be empty")
}
val file = createFile(buildString { appendImport (importPath) })
val file = createFile(buildString { appendImport(importPath) })
return file.importDirectives.first()
}
@@ -435,7 +450,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
fun createPrimaryConstructor(text: String = ""): KtPrimaryConstructor {
return createClass(if (text.isNotEmpty())"class A $text" else "class A()" ).primaryConstructor!!
return createClass(if (text.isNotEmpty()) "class A $text" else "class A()").primaryConstructor!!
}
fun createPrimaryConstructorWithModifiers(modifiers: String?): KtPrimaryConstructor {
@@ -443,10 +458,9 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
fun createConstructorKeyword(): PsiElement =
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
fun createLabeledExpression(labelName: String): KtLabeledExpression
= createExpression("$labelName@ 1") as KtLabeledExpression
fun createLabeledExpression(labelName: String): KtLabeledExpression = createExpression("$labelName@ 1") as KtLabeledExpression
fun createTypeCodeFragment(text: String, context: PsiElement?): KtTypeCodeFragment {
return KtTypeCodeFragment(project, "fragment.kt", text, context)
@@ -512,6 +526,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
TYPE_CONSTRAINTS,
DONE
}
private val sb = StringBuilder()
private var state = State.MODIFIERS
@@ -820,7 +835,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
return BlockWrapper(block, expression)
}
private class BlockWrapper(fakeBlockExpression: KtBlockExpression, private val expression: KtExpression) : KtBlockExpression(fakeBlockExpression.node), KtPsiUtil.KtExpressionWrapper {
private class BlockWrapper(fakeBlockExpression: KtBlockExpression, private val expression: KtExpression) :
KtBlockExpression(fakeBlockExpression.node), KtPsiUtil.KtExpressionWrapper {
override fun getStatements(): List<KtExpression> {
return listOf(expression)
}
@@ -30,22 +30,22 @@ class KtTypeAlias : KtTypeParameterListOwnerStub<KotlinTypeAliasStub>, KtNamedDe
constructor(stub: KotlinTypeAliasStub) : super(stub, KtStubElementTypes.TYPEALIAS)
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D): R =
visitor.visitTypeAlias(this, data)
visitor.visitTypeAlias(this, data)
fun isTopLevel(): Boolean =
stub?.isTopLevel() ?: parent is KtFile
stub?.isTopLevel() ?: parent is KtFile
@IfNotParsed
fun getTypeAliasKeyword(): PsiElement? =
findChildByType(KtTokens.TYPE_ALIAS_KEYWORD)
findChildByType(KtTokens.TYPE_ALIAS_KEYWORD)
@IfNotParsed
fun getTypeReference(): KtTypeReference? {
return if (stub != null) {
val typeReferences = getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
val typeReferences =
getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
typeReferences[0]
}
else {
} else {
findChildByType(KtNodeTypes.TYPE_REFERENCE)
}
}
@@ -21,10 +21,10 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
class KtTypeCodeFragment(
project: Project,
name: String,
text: CharSequence,
context: PsiElement?
project: Project,
name: String,
text: CharSequence,
context: PsiElement?
) : KtCodeFragment(project, name, text, null, KtNodeTypes.TYPE_CODE_FRAGMENT, context) {
override fun getContentElement() = findChildByClass(KtTypeReference::class.java)
}
@@ -26,9 +26,9 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings
private fun KtModifierListOwner.addModifierList(newModifierList: KtModifierList): KtModifierList {
val anchor = firstChild!!
.siblings(forward = true)
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
.first()
.siblings(forward = true)
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
.first()
return addBefore(newModifierList, anchor) as KtModifierList
}
@@ -40,8 +40,7 @@ fun KtModifierListOwner.setModifierList(newModifierList: KtModifierList) {
val currentModifierList = modifierList
if (currentModifierList != null) {
currentModifierList.replace(newModifierList)
}
else {
} else {
addModifierList(newModifierList)
}
}
@@ -50,8 +49,7 @@ fun addModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken) {
val modifierList = owner.modifierList
if (modifierList == null) {
createModifierList(modifier.value, owner)
}
else {
} else {
addModifier(modifierList, modifier)
}
}
@@ -60,8 +58,7 @@ fun addAnnotationEntry(owner: KtModifierListOwner, annotationEntry: KtAnnotation
val modifierList = owner.modifierList
return if (modifierList == null) {
createModifierList(annotationEntry.text, owner).annotationEntries.first()
}
else {
} else {
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
}
}
@@ -71,8 +68,8 @@ internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywo
val newModifier = KtPsiFactory(modifierList).createModifier(modifier)
val modifierToReplace = MODIFIERS_TO_REPLACE[modifier]
?.mapNotNull { modifierList.getModifier(it) }
?.firstOrNull()
?.mapNotNull { modifierList.getModifier(it) }
?.firstOrNull()
if (modifier == FINAL_KEYWORD && !modifierList.hasModifier(OVERRIDE_KEYWORD)) {
if (modifierToReplace != null) {
@@ -85,8 +82,7 @@ internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywo
}
if (modifierToReplace != null && modifierList.firstChild == modifierList.lastChild) {
modifierToReplace.replace(newModifier)
}
else {
} else {
modifierToReplace?.delete()
val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier)
@@ -129,34 +125,36 @@ fun sortModifiers(modifiers: List<KtModifierKeywordToken>): List<KtModifierKeywo
}
private val MODIFIERS_TO_REPLACE = mapOf(
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
OPEN_KEYWORD to listOf(FINAL_KEYWORD, ABSTRACT_KEYWORD),
FINAL_KEYWORD to listOf(ABSTRACT_KEYWORD, OPEN_KEYWORD),
PUBLIC_KEYWORD to listOf(PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
PROTECTED_KEYWORD to listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
PRIVATE_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD),
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD),
HEADER_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, EXPECT_KEYWORD),
IMPL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD),
EXPECT_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD),
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
OPEN_KEYWORD to listOf(FINAL_KEYWORD, ABSTRACT_KEYWORD),
FINAL_KEYWORD to listOf(ABSTRACT_KEYWORD, OPEN_KEYWORD),
PUBLIC_KEYWORD to listOf(PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
PROTECTED_KEYWORD to listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
PRIVATE_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD),
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD),
HEADER_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, EXPECT_KEYWORD),
IMPL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD),
EXPECT_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD),
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
)
val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
CONST_KEYWORD,
EXTERNAL_KEYWORD,
OVERRIDE_KEYWORD,
LATEINIT_KEYWORD,
TAILREC_KEYWORD,
VARARG_KEYWORD,
SUSPEND_KEYWORD,
INNER_KEYWORD,
ENUM_KEYWORD, ANNOTATION_KEYWORD,
COMPANION_KEYWORD,
INLINE_KEYWORD,
INFIX_KEYWORD,
OPERATOR_KEYWORD,
DATA_KEYWORD)
val MODIFIERS_ORDER = listOf(
PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
CONST_KEYWORD,
EXTERNAL_KEYWORD,
OVERRIDE_KEYWORD,
LATEINIT_KEYWORD,
TAILREC_KEYWORD,
VARARG_KEYWORD,
SUSPEND_KEYWORD,
INNER_KEYWORD,
ENUM_KEYWORD, ANNOTATION_KEYWORD,
COMPANION_KEYWORD,
INLINE_KEYWORD,
INFIX_KEYWORD,
OPERATOR_KEYWORD,
DATA_KEYWORD
)
@@ -28,8 +28,7 @@ val SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE: Key<Boolean> = Key.create<Boolean>("SUPP
fun KtElement.suppressDiagnosticsInDebugMode(): Boolean {
return if (this is KtFile) {
this.suppressDiagnosticsInDebugMode
}
else {
} else {
val file = this.containingFile
file is KtFile && file.suppressDiagnosticsInDebugMode
}
@@ -31,23 +31,32 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.renderer.render
import java.util.*
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression
= createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression =
createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList
= createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList =
createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): TDeclaration
= createByPattern(pattern, *args, reformat = reformat) { createDeclaration<TDeclaration>(it) }
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(
pattern: String,
vararg args: Any,
reformat: Boolean = true
): TDeclaration = createByPattern(pattern, *args, reformat = reformat) { createDeclaration<TDeclaration>(it) }
fun KtPsiFactory.createDestructuringDeclarationByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtDestructuringDeclaration
= createByPattern(pattern, *args, reformat = reformat) { createDestructuringDeclaration(it) }
fun KtPsiFactory.createDestructuringDeclarationByPattern(
pattern: String,
vararg args: Any,
reformat: Boolean = true
): KtDestructuringDeclaration = createByPattern(pattern, *args, reformat = reformat) { createDestructuringDeclaration(it) }
private abstract class ArgumentType<T : Any>(val klass: Class<T>)
private class PlainTextArgumentType<T : Any>(klass: Class<T>, val toPlainText: (T) -> String) : ArgumentType<T>(klass)
private abstract class PsiElementPlaceholderArgumentType<T : Any, TPlaceholder : PsiElement>(klass: Class<T>, val placeholderClass: Class<TPlaceholder>) : ArgumentType<T>(klass) {
private abstract class PsiElementPlaceholderArgumentType<T : Any, TPlaceholder : PsiElement>(
klass: Class<T>,
val placeholderClass: Class<TPlaceholder>
) : ArgumentType<T>(klass) {
abstract fun replacePlaceholderElement(placeholder: TPlaceholder, argument: T): PsiChildRange
}
@@ -64,7 +73,8 @@ private class PsiElementArgumentType<T : PsiElement>(klass: Class<T>) : PsiEleme
}
}
private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<PsiChildRange, KtElement>(PsiChildRange::class.java, KtElement::class.java) {
private object PsiChildRangeArgumentType :
PsiElementPlaceholderArgumentType<PsiChildRange, KtElement>(PsiChildRange::class.java, KtElement::class.java) {
override fun replacePlaceholderElement(placeholder: KtElement, argument: PsiChildRange): PsiChildRange {
val project = placeholder.project
val codeStyleManager = CodeStyleManager.getInstance(project)
@@ -79,8 +89,7 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
}
PsiChildRange(first, last)
}
else {
} else {
placeholder.delete()
PsiChildRange.EMPTY
}
@@ -88,20 +97,25 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
}
private val SUPPORTED_ARGUMENT_TYPES = listOf(
PsiElementArgumentType(KtExpression::class.java),
PsiElementArgumentType(KtTypeReference::class.java),
PlainTextArgumentType(String::class.java, toPlainText = { it }),
PlainTextArgumentType(Name::class.java, toPlainText = Name::render),
PsiChildRangeArgumentType
PsiElementArgumentType(KtExpression::class.java),
PsiElementArgumentType(KtTypeReference::class.java),
PlainTextArgumentType(String::class.java, toPlainText = { it }),
PlainTextArgumentType(Name::class.java, toPlainText = Name::render),
PsiChildRangeArgumentType
)
@TestOnly
var CREATEBYPATTERN_MAY_NOT_REFORMAT = false
fun <TElement : KtElement> createByPattern(pattern: String, vararg args: Any, reformat: Boolean = true, factory: (String) -> TElement): TElement {
fun <TElement : KtElement> createByPattern(
pattern: String,
vararg args: Any,
reformat: Boolean = true,
factory: (String) -> TElement
): TElement {
val argumentTypes = args.map { arg ->
SUPPORTED_ARGUMENT_TYPES.firstOrNull { it.klass.isInstance(arg) }
?: throw IllegalArgumentException("Unsupported argument type: ${arg::class.java}, should be one of: ${SUPPORTED_ARGUMENT_TYPES.joinToString { it.klass.simpleName }}")
?: throw IllegalArgumentException("Unsupported argument type: ${arg::class.java}, should be one of: ${SUPPORTED_ARGUMENT_TYPES.joinToString { it.klass.simpleName }}")
}
// convert arguments that can be converted into plain text
@@ -155,17 +169,16 @@ fun <TElement : KtElement> createByPattern(pattern: String, vararg args: Any, re
throw java.lang.IllegalArgumentException("Reformatting is not allowed in the current context; please change the invocation to use reformat=false")
}
val stringPlaceholderRanges = allPlaceholders
.filter { args[it.key] is String }
.flatMap { it.value }
.map { it.range }
.filterNot { it.isEmpty }
.sortedByDescending { it.startOffset }
.filter { args[it.key] is String }
.flatMap { it.value }
.map { it.range }
.filterNot { it.isEmpty }
.sortedByDescending { it.startOffset }
// reformat whole text except for String arguments (as they can contain user's formatting to be preserved)
resultElement = if (stringPlaceholderRanges.none()) {
codeStyleManager.reformat(resultElement, true) as TElement
}
else {
} else {
var bound = resultElement.endOffset - 1
for (range in stringPlaceholderRanges) {
// we extend reformatting range by 1 to the right because otherwise some of spaces are not reformatted
@@ -223,8 +236,7 @@ private fun processPattern(pattern: String, args: List<Any>): PatternData {
val nextChar = charOrNull(++i)
if (nextChar == '$') {
append(nextChar)
}
else {
} else {
check(nextChar?.isDigit() ?: false, "unclosed '$'")
val lastIndex = (i..pattern.length - 1).firstOrNull { !pattern[it].isDigit() } ?: pattern.length
@@ -235,8 +247,7 @@ private fun processPattern(pattern: String, args: List<Any>): PatternData {
val arg: Any? = if (n < args.size) args[n] else null /* report wrong number of arguments later */
val placeholderText = if (charOrNull(i) != ':' || charOrNull(i + 1) != '\'') {
arg as? String ?: "xyz"
}
else {
} else {
check(arg !is String, "do not specify placeholder text for $$n - plain text argument passed")
i += 2 // skip ':' and '\''
val endIndex = pattern.indexOf('\'', i)
@@ -252,8 +263,7 @@ private fun processPattern(pattern: String, args: List<Any>): PatternData {
ranges.getOrPut(n, { ArrayList() }).add(Placeholder(range, placeholderText))
continue
}
}
else {
} else {
append(c)
}
i++
@@ -152,25 +152,24 @@ fun KtExpression.getQualifiedExpressionForReceiverOrThis(): KtExpression {
}
fun KtExpression.isDotReceiver(): Boolean =
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
// ---------- Block expression -------------------------------------------------------------------------------------------------------------
fun KtElement.blockExpressionsOrSingle(): Sequence<KtElement> =
if (this is KtBlockExpression) statements.asSequence() else sequenceOf(this)
if (this is KtBlockExpression) statements.asSequence() else sequenceOf(this)
fun KtExpression.lastBlockStatementOrThis(): KtExpression
= (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
fun KtExpression.lastBlockStatementOrThis(): KtExpression = (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
fun KtBlockExpression.contentRange(): PsiChildRange {
val first = (lBrace?.nextSibling ?: firstChild)
?.siblings(withItself = false)
?.firstOrNull { it !is PsiWhiteSpace }
?.siblings(withItself = false)
?.firstOrNull { it !is PsiWhiteSpace }
val rBrace = rBrace
if (first == rBrace) return PsiChildRange.EMPTY
val last = rBrace!!
.siblings(forward = false, withItself = false)
.first { it !is PsiWhiteSpace }
.siblings(forward = false, withItself = false)
.first { it !is PsiWhiteSpace }
if (last == lBrace) return PsiChildRange.EMPTY
return PsiChildRange(first, last)
}
@@ -248,8 +247,7 @@ fun KtAnnotationsContainer.collectAnnotationEntriesFromStubOrPsi(): List<KtAnnot
}
private fun StubElement<*>.collectAnnotationEntriesFromStubElement(): List<KtAnnotationEntry> {
return childrenStubs.flatMap {
child ->
return childrenStubs.flatMap { child ->
when (child.stubType) {
KtNodeTypes.ANNOTATION_ENTRY -> listOf(child.psi as KtAnnotationEntry)
KtNodeTypes.ANNOTATION -> (child.psi as KtAnnotation).entries
@@ -283,14 +281,17 @@ inline fun <reified T : KtElement> forEachDescendantOfTypeVisitor(noinline block
}
}
inline fun <reified T : KtElement, R> flatMapDescendantsOfTypeVisitor(accumulator: MutableCollection<R>, noinline map: (T) -> Collection<R>): KtVisitorVoid {
inline fun <reified T : KtElement, R> flatMapDescendantsOfTypeVisitor(
accumulator: MutableCollection<R>,
noinline map: (T) -> Collection<R>
): KtVisitorVoid {
return forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
}
// ----------- Other -----------------------------------------------------------------------------------------------------------------------
fun KtClassOrObject.effectiveDeclarations(): List<KtDeclaration> {
return when(this) {
return when (this) {
is KtClass -> getDeclarations() + getPrimaryConstructorParameters().filter { p -> p.hasValOrVar() }
else -> declarations
}
@@ -368,7 +369,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
is KtBinaryExpression -> parent.operationReference == this
else -> {
val callElement =
getStrictParentOfType<KtUserType>()
getStrictParentOfType<KtUserType>()
?.getStrictParentOfType<KtTypeReference>()
?.getStrictParentOfType<KtConstructorCalleeExpression>()
?.getStrictParentOfType<KtCallElement>()
@@ -376,8 +377,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
if (callElement != null) {
val ktConstructorCalleeExpression = callElement.calleeExpression as? KtConstructorCalleeExpression
(ktConstructorCalleeExpression?.typeReference?.typeElement as? KtUserType)?.referenceExpression == this
}
else {
} else {
false
}
}
@@ -387,8 +387,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
val KtStringTemplateExpression.plainContent: String
get() = getContentRange().substring(text)
fun KtStringTemplateExpression.isSingleQuoted(): Boolean
= node.firstChildNode.textLength == 1
fun KtStringTemplateExpression.isSingleQuoted(): Boolean = node.firstChildNode.textLength == 1
fun KtNamedDeclaration.getValueParameters(): List<KtParameter> {
return getValueParameterList()?.parameters ?: Collections.emptyList()
@@ -409,13 +408,13 @@ fun KtLambdaArgument.getLambdaArgumentName(bindingContext: BindingContext): Name
}
fun KtExpression.asAssignment(): KtBinaryExpression? =
if (KtPsiUtil.isAssignment(this)) this as KtBinaryExpression else null
if (KtPsiUtil.isAssignment(this)) this as KtBinaryExpression else null
private fun KtModifierList.modifierFromTokenSet(set: TokenSet): PsiElement? {
return set.types
.asSequence()
.map { getModifier(it as KtModifierKeywordToken) }
.firstOrNull { it != null }
.asSequence()
.map { getModifier(it as KtModifierKeywordToken) }
.firstOrNull { it != null }
}
@@ -423,34 +422,34 @@ private fun KtModifierListOwner.modifierFromTokenSet(set: TokenSet) = modifierLi
fun KtModifierList.visibilityModifier() = modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken?
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken? = visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
fun KtModifierListOwner.visibilityModifier() = modifierList?.modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken?
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken? =
visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
private val MODALITY_MODIFIERS = TokenSet.create(
KtTokens.ABSTRACT_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.SEALED_KEYWORD, KtTokens.OPEN_KEYWORD
KtTokens.ABSTRACT_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.SEALED_KEYWORD, KtTokens.OPEN_KEYWORD
)
fun KtDeclaration.modalityModifier() = modifierFromTokenSet(MODALITY_MODIFIERS)
fun KtStringTemplateExpression.isPlain() = entries.all { it is KtLiteralStringTemplateEntry }
fun KtStringTemplateExpression.isPlainWithEscapes() = entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
fun KtStringTemplateExpression.isPlainWithEscapes() =
entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
// Correct for class members only (including constructors and nested classes)
// Returns null e.g. for member function parameters, member function locals, property accessors
val KtDeclaration.containingClassOrObject: KtClassOrObject?
get() = parent.let {
when (it) {
is KtClassBody -> it.parent as? KtClassOrObject
is KtClassOrObject -> it
is KtParameterList -> (it.parent as? KtPrimaryConstructor)?.getContainingClassOrObject()
else -> null
}
get() = parent.let {
when (it) {
is KtClassBody -> it.parent as? KtClassOrObject
is KtClassOrObject -> it
is KtParameterList -> (it.parent as? KtPrimaryConstructor)?.getContainingClassOrObject()
else -> null
}
}
fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression {
return (parentsWithSelf.zip(parents)).firstOrNull {
@@ -506,7 +505,7 @@ fun KtElement.containingClass(): KtClass? = getStrictParentOfType()
fun KtClassOrObject.findPropertyByName(name: String): KtNamedDeclaration? {
return declarations.firstOrNull { it is KtProperty && it.name == name } as KtNamedDeclaration?
?: primaryConstructorParameters.firstOrNull { it.hasValOrVar() && it.name == name }
?: primaryConstructorParameters.firstOrNull { it.hasValOrVar() && it.name == name }
}
fun isTypeConstructorReference(e: PsiElement): Boolean {
@@ -516,7 +515,8 @@ fun isTypeConstructorReference(e: PsiElement): Boolean {
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
fun isDoubleColonReceiver(expression: KtExpression) = expression.getParentOfTypeAndBranch<KtDoubleColonExpression> { this.receiverExpression } != null
fun isDoubleColonReceiver(expression: KtExpression) =
expression.getParentOfTypeAndBranch<KtDoubleColonExpression> { this.receiverExpression } != null
fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
valueParameterList?.let { return it }
@@ -535,15 +535,16 @@ fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
valueArgumentList?.let { return it }
return addAfter(KtPsiFactory(this).createCallArguments("()"),
typeArgumentList ?: calleeExpression) as KtValueArgumentList
return addAfter(
KtPsiFactory(this).createCallArguments("()"),
typeArgumentList ?: calleeExpression
) as KtValueArgumentList
}
fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) {
if (typeArgumentList != null) {
typeArgumentList?.addArgument(typeArgument)
}
else {
} else {
addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
}
}
@@ -556,7 +557,7 @@ fun KtDeclaration.hasBody() = when (this) {
fun KtExpression.referenceExpression(): KtReferenceExpression? =
(if (this is KtCallExpression) calleeExpression else this) as? KtReferenceExpression
(if (this is KtCallExpression) calleeExpression else this) as? KtReferenceExpression
fun KtExpression.getLabeledParent(labelName: String): KtLabeledExpression? {
parents.forEach {
@@ -68,11 +68,9 @@ val PsiElement.parentsWithSelf: Sequence<PsiElement>
val PsiElement.parents: Sequence<PsiElement>
get() = parentsWithSelf.drop(1)
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement?
= PsiTreeUtil.prevLeaf(this, skipEmptyElements)
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.prevLeaf(this, skipEmptyElements)
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement?
= PsiTreeUtil.nextLeaf(this, skipEmptyElements)
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.nextLeaf(this, skipEmptyElements)
val PsiElement.prevLeafs: Sequence<PsiElement>
get() = generateSequence({ prevLeaf() }, { it.prevLeaf() })
@@ -97,7 +95,7 @@ fun PsiElement.nextLeaf(filter: (PsiElement) -> Boolean): PsiElement? {
}
fun <T : PsiElement> PsiElement.getParentOfTypesAndPredicate(
strict: Boolean = false, vararg parentClasses: Class<T>, predicate: (T) -> Boolean
strict: Boolean = false, vararg parentClasses: Class<T>, predicate: (T) -> Boolean
): T? {
var element = if (strict) parent else this
while (element != null) {
@@ -175,7 +173,10 @@ inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranch(strict:
return getParentOfType<T>(strict)?.getIfChildIsInBranch(this, branch)
}
inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranches(strict: Boolean = false, noinline branches: T.() -> Iterable<PsiElement?>): T? {
inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranches(
strict: Boolean = false,
noinline branches: T.() -> Iterable<PsiElement?>
): T? {
return getParentOfType<T>(strict)?.getIfChildIsInBranches(this, branches)
}
@@ -188,7 +189,9 @@ fun PsiElement.isInsideOf(elements: Iterable<PsiElement>): Boolean = elements.an
fun PsiChildRange.trimWhiteSpaces(): PsiChildRange {
if (first == null) return this
return PsiChildRange(first.siblings().firstOrNull { it !is PsiWhiteSpace }, last!!.siblings(forward = false).firstOrNull { it !is PsiWhiteSpace })
return PsiChildRange(
first.siblings().firstOrNull { it !is PsiWhiteSpace },
last!!.siblings(forward = false).firstOrNull { it !is PsiWhiteSpace })
}
// -------------------- Recursive tree visiting --------------------------------------------------------------------------------------------
@@ -197,7 +200,10 @@ inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline
forEachDescendantOfType({ true }, action)
}
inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline action: (T) -> Unit) {
inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(
crossinline canGoInside: (PsiElement) -> Boolean,
noinline action: (T) -> Unit
) {
this.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) {
if (canGoInside(element)) {
@@ -215,7 +221,10 @@ inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(noinline pred
return findDescendantOfType(predicate) != null
}
inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): Boolean {
inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(
crossinline canGoInside: (PsiElement) -> Boolean,
noinline predicate: (T) -> Boolean = { true }
): Boolean {
return findDescendantOfType(canGoInside, predicate) != null
}
@@ -223,7 +232,10 @@ inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(noinline pre
return findDescendantOfType({ true }, predicate)
}
inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): T? {
inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(
crossinline canGoInside: (PsiElement) -> Boolean,
noinline predicate: (T) -> Boolean = { true }
): T? {
var result: T? = null
this.accept(object : PsiRecursiveElementWalkingVisitor() {
override fun visitElement(element: PsiElement) {
@@ -245,7 +257,10 @@ inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(noinline
return collectDescendantsOfType({ true }, predicate)
}
inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): List<T> {
inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(
crossinline canGoInside: (PsiElement) -> Boolean,
noinline predicate: (T) -> Boolean = { true }
): List<T> {
val result = ArrayList<T>()
forEachDescendantOfType<T>(canGoInside) {
if (predicate(it)) {
@@ -294,11 +309,11 @@ fun PsiFile.elementsInRange(range: TextRange): List<PsiElement> {
val leaf = findFirstLeafWhollyInRange(this, currentRange) ?: break
val element = leaf
.parentsWithSelf
.first {
val parent = it.parent
it is PsiFile || parent.textRange !in currentRange
}
.parentsWithSelf
.first {
val parent = it.parent
it is PsiFile || parent.textRange !in currentRange
}
result.add(element)
offset = element.endOffset
@@ -333,8 +348,8 @@ fun PsiElement.getElementTextWithContext(): String {
}
// Find parent for element among file children
val topLevelElement = PsiTreeUtil.findFirstParent(this, { it.parent is PsiFile }) ?:
throw AssertionError("For non-file element we should always be able to find parent in file children")
val topLevelElement = PsiTreeUtil.findFirstParent(this, { it.parent is PsiFile })
?: throw AssertionError("For non-file element we should always be able to find parent in file children")
val startContextOffset = topLevelElement.startOffset
val elementContextOffset = textRange.startOffset
@@ -344,9 +359,9 @@ fun PsiElement.getElementTextWithContext(): String {
val isInjected = containingFile is VirtualFileWindow
return StringBuilder(topLevelElement.text)
.insert(inFileParentOffset, "<caret>")
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
.toString()
.insert(inFileParentOffset, "<caret>")
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
.toString()
}
fun PsiElement.getTextWithLocation(): String = "'${this.text}' at ${DiagnosticUtils.atLocation(this)}"
@@ -356,7 +371,7 @@ fun replaceFileAnnotationList(file: KtFile, annotationList: KtFileAnnotationList
return file.fileAnnotationList!!.replace(annotationList) as KtFileAnnotationList
}
val beforeAnchor : PsiElement? = when {
val beforeAnchor: PsiElement? = when {
file.packageDirective?.packageKeyword != null -> file.packageDirective!!
file.importList != null -> file.importList!!
file.declarations.firstOrNull() != null -> file.declarations.first()
@@ -379,7 +394,7 @@ fun replaceFileAnnotationList(file: KtFile, annotationList: KtFileAnnotationList
operator fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element)
fun <E : PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> =
SmartPointerManager.getInstance(project).createSmartPsiElementPointer(this)
SmartPointerManager.getInstance(project).createSmartPsiElementPointer(this)
fun PsiElement.before(element: PsiElement) = textRange.endOffset <= element.textRange.startOffset
@@ -113,7 +113,7 @@ interface KotlinPropertyStub : KotlinCallableStubBase<KtProperty> {
fun hasReturnTypeRef(): Boolean
}
interface KotlinCallableStubBase<TDeclaration: KtCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
interface KotlinCallableStubBase<TDeclaration : KtCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
fun isTopLevel(): Boolean
fun isExtension(): Boolean
}
@@ -25,9 +25,10 @@ import org.jetbrains.kotlin.psi.KtAnnotationUseSiteTarget
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinAnnotationUseSiteTargetStubImpl
class KtAnnotationUseSiteTargetElementType(debugName: String) : KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
class KtAnnotationUseSiteTargetElementType(debugName: String) :
KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
debugName, KtAnnotationUseSiteTarget::class.java, KotlinAnnotationUseSiteTargetStub::class.java
) {
) {
override fun createStub(psi: KtAnnotationUseSiteTarget, parentStub: StubElement<PsiElement>): KotlinAnnotationUseSiteTargetStub {
val useSiteTarget = psi.getAnnotationUseSiteTarget().name
@@ -25,14 +25,17 @@ import org.jetbrains.kotlin.psi.KtEnumEntrySuperclassReferenceExpression
import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinEnumEntrySuperclassReferenceExpressionStubImpl
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String)
: KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String) :
KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
debugName,
KtEnumEntrySuperclassReferenceExpression::class.java,
KotlinEnumEntrySuperclassReferenceExpressionStub::class.java
) {
override fun createStub(psi: KtEnumEntrySuperclassReferenceExpression, parentStub: StubElement<*>): KotlinEnumEntrySuperclassReferenceExpressionStub {
override fun createStub(
psi: KtEnumEntrySuperclassReferenceExpression,
parentStub: StubElement<*>
): KotlinEnumEntrySuperclassReferenceExpressionStub {
return KotlinEnumEntrySuperclassReferenceExpressionStubImpl(parentStub, StringRef.fromString(psi.getReferencedName())!!)
}
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinImportAliasStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinImportAliasStubImpl
class KtImportAliasElementType(debugName: String) :
KtStubElementType<KotlinImportAliasStub, KtImportAlias>(debugName, KtImportAlias::class.java, KotlinImportAliasStub::class.java) {
KtStubElementType<KotlinImportAliasStub, KtImportAlias>(debugName, KtImportAlias::class.java, KotlinImportAliasStub::class.java) {
override fun createStub(psi: KtImportAlias, parentStub: StubElement<PsiElement>?): KotlinImportAliasStub {
return KotlinImportAliasStubImpl(parentStub, StringRef.fromString(psi.name))
}
@@ -24,9 +24,9 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import com.intellij.psi.PsiElement
class KotlinAnnotationEntryStubImpl(
parent: StubElement<out PsiElement>?,
private val shortName: StringRef,
private val hasValueArguments: Boolean
parent: StubElement<out PsiElement>?,
private val shortName: StringRef,
private val hasValueArguments: Boolean
) : KotlinStubBaseImpl<KtAnnotationEntry>(parent, KtStubElementTypes.ANNOTATION_ENTRY), KotlinAnnotationEntryStub {
override fun getShortName() = shortName.string
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
class KotlinAnnotationUseSiteTargetStubImpl(
parent: StubElement<out PsiElement>?,
private val target: StringRef
parent: StubElement<out PsiElement>?,
private val target: StringRef
) : KotlinStubBaseImpl<KtAnnotationUseSiteTarget>(parent, KtStubElementTypes.ANNOTATION_TARGET), KotlinAnnotationUseSiteTargetStub {
override fun getUseSiteTarget() = target.string
@@ -25,20 +25,21 @@ import org.jetbrains.kotlin.name.FqName
import com.intellij.psi.PsiElement
class KotlinFunctionStubImpl(
parent: StubElement<out PsiElement>?,
private val nameRef: StringRef?,
private val isTopLevel: Boolean,
private val fqName: FqName?,
private val isExtension: Boolean,
private val hasBlockBody: Boolean,
private val hasBody: Boolean,
private val hasTypeParameterListBeforeFunctionName: Boolean
parent: StubElement<out PsiElement>?,
private val nameRef: StringRef?,
private val isTopLevel: Boolean,
private val fqName: FqName?,
private val isExtension: Boolean,
private val hasBlockBody: Boolean,
private val hasBody: Boolean,
private val hasTypeParameterListBeforeFunctionName: Boolean
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
init {
if (isTopLevel && fqName == null) {
throw IllegalArgumentException("fqName shouldn't be null for top level functions")
}
}
override fun getFqName() = fqName
override fun getName() = StringRef.toString(nameRef)
@@ -25,12 +25,12 @@ import org.jetbrains.kotlin.name.FqName
import com.intellij.psi.PsiElement
class KotlinParameterStubImpl(
parent: StubElement<out PsiElement>?,
private val fqName: StringRef?,
private val name: StringRef?,
private val isMutable: Boolean,
private val hasValOrVar: Boolean,
private val hasDefaultValue: Boolean
parent: StubElement<out PsiElement>?,
private val fqName: StringRef?,
private val name: StringRef?,
private val isMutable: Boolean,
private val hasValOrVar: Boolean,
private val hasDefaultValue: Boolean
) : KotlinStubBaseImpl<KtParameter>(parent, KtStubElementTypes.VALUE_PARAMETER), KotlinParameterStub {
override fun getName(): String? {
return StringRef.toString(name)
@@ -30,7 +30,8 @@ import java.util.ArrayList
val STUB_TO_STRING_PREFIX = "KotlinStub$"
open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?, elementType: IStubElementType<*, *>) : StubBase<T>(parent, elementType) {
open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?, elementType: IStubElementType<*, *>) :
StubBase<T>(parent, elementType) {
override fun toString(): String {
val stubInterface = this::class.java.interfaces.single { it.name.contains("Stub") }
@@ -62,8 +63,7 @@ open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?,
val value = property.invoke(this)
val name = getPropertyName(property)
"$name=$value"
}
catch (e: Exception) {
} catch (e: Exception) {
LOGGER.error(e)
null
}
@@ -80,6 +80,11 @@ open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?,
companion object {
private val LOGGER: Logger = Logger.getInstance(KotlinStubBaseImpl::class.java)
private val BASE_STUB_INTERFACES = listOf(KotlinStubWithFqName::class.java, KotlinClassOrObjectStub::class.java, NamedStub::class.java, KotlinCallableStubBase::class.java)
private val BASE_STUB_INTERFACES = listOf(
KotlinStubWithFqName::class.java,
KotlinClassOrObjectStub::class.java,
NamedStub::class.java,
KotlinCallableStubBase::class.java
)
}
}
@@ -23,5 +23,5 @@ import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
class KotlinUserTypeStubImpl(
parent: StubElement<out PsiElement>?
parent: StubElement<out PsiElement>?
) : KotlinStubBaseImpl<KtUserType>(parent, KtStubElementTypes.USER_TYPE), KotlinUserTypeStub
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.psi.stubs.impl
import com.intellij.util.io.StringRef
object Utils {
fun wrapStrings(names : List<String>) : Array<StringRef> {
fun wrapStrings(names: List<String>): Array<StringRef> {
return Array(names.size) { i -> StringRef.fromString(names[i])!! }
}
}
@@ -45,25 +45,27 @@ import org.jetbrains.kotlin.types.TypeConstructor
* This class has its own synthetic declaration inside.
*/
class SyntheticClassOrObjectDescriptor(
c: LazyClassContext,
parentClassOrObject: KtPureClassOrObject,
containingDeclaration: DeclarationDescriptor,
name: Name,
source: SourceElement,
outerScope: LexicalScope,
private val modality: Modality,
private val visibility: Visibility,
constructorVisibility: Visibility,
private val kind: ClassKind,
private val isCompanionObject: Boolean
c: LazyClassContext,
parentClassOrObject: KtPureClassOrObject,
containingDeclaration: DeclarationDescriptor,
name: Name,
source: SourceElement,
outerScope: LexicalScope,
private val modality: Modality,
private val visibility: Visibility,
constructorVisibility: Visibility,
private val kind: ClassKind,
private val isCompanionObject: Boolean
) : ClassDescriptorBase(c.storageManager, containingDeclaration, name, source, false), ClassDescriptorWithResolutionScopes {
val syntheticDeclaration: KtPureClassOrObject = SyntheticDeclaration(parentClassOrObject, name.asString())
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, { outerScope })
private val syntheticSupertypes = mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
private val unsubstitutedMemberScope = LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
private val syntheticSupertypes =
mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
private val unsubstitutedMemberScope =
LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
private val unsubstitutedPrimaryConstructor = createUnsubstitutedPrimaryConstructor(constructorVisibility)
override val annotations: Annotations get() = Annotations.EMPTY
@@ -97,11 +99,15 @@ class SyntheticClassOrObjectDescriptor(
override fun getScopeForClassHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForClassHeaderResolution()
override fun getScopeForConstructorHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForConstructorHeaderResolution()
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
override fun getScopeForMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForMemberDeclarationResolution()
override fun getScopeForStaticMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForStaticMemberDeclarationResolution()
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope =
resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
override fun getScopeForInitializerResolution(): LexicalScope = throw UnsupportedOperationException("Not supported for synthetic class or object")
override fun getScopeForMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForMemberDeclarationResolution()
override fun getScopeForStaticMemberDeclarationResolution(): LexicalScope =
resolutionScopesSupport.scopeForStaticMemberDeclarationResolution()
override fun getScopeForInitializerResolution(): LexicalScope =
throw UnsupportedOperationException("Not supported for synthetic class or object")
override fun toString(): String = "synthetic class " + name.toString() + " in " + containingDeclaration
@@ -121,7 +127,7 @@ class SyntheticClassOrObjectDescriptor(
}
private class SyntheticClassMemberDeclarationProvider(
override val correspondingClassOrObject: KtPureClassOrObject
override val correspondingClassOrObject: KtPureClassOrObject
) : ClassMemberDeclarationProvider {
override val ownerInfo: KtClassLikeInfo? = null
override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List<KtDeclaration> = emptyList()
@@ -134,8 +140,8 @@ class SyntheticClassOrObjectDescriptor(
}
internal inner class SyntheticDeclaration(
private val _parent: KtPureElement,
private val _name: String
private val _parent: KtPureElement,
private val _name: String
) : KtPureClassOrObject {
fun descriptor() = thisDescriptor
@@ -28,14 +28,13 @@ import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
class AllUnderImportScope(
descriptor: DeclarationDescriptor,
excludedImportNames: Collection<FqName>
descriptor: DeclarationDescriptor,
excludedImportNames: Collection<FqName>
) : BaseImportingScope(null) {
private val scopes: List<MemberScope> = if (descriptor is ClassDescriptor) {
listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope)
}
else {
} else {
assert(descriptor is PackageViewDescriptor) {
"Must be class or package view descriptor: $descriptor"
}
@@ -44,8 +43,7 @@ class AllUnderImportScope(
private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization
emptySet<Name>()
}
else {
} else {
val fqName = DescriptorUtils.getFqNameSafe(descriptor)
// toSet() is used here instead mapNotNullTo(hashSetOf()) because it results in not keeping empty sets as separate instances
excludedImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null }.toSet()
@@ -54,21 +52,20 @@ class AllUnderImportScope(
override fun computeImportedNames(): Set<Name>? = scopes.flatMapToNullable(hashSetOf(), MemberScope::computeAllNames)
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
changeNamesForAliased: Boolean
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
changeNamesForAliased: Boolean
): Collection<DeclarationDescriptor> {
val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization
nameFilter
}
else {
} else {
{ it !in excludedNames && nameFilter(it) }
}
val noPackagesKindFilter = kindFilter.withoutKinds(DescriptorKindFilter.PACKAGES_MASK)
return scopes
.flatMap { it.getContributedDescriptors(noPackagesKindFilter, nameFilterToUse) }
.filter { it !is PackageViewDescriptor } // subpackages are not imported
.flatMap { it.getContributedDescriptors(noPackagesKindFilter, nameFilterToUse) }
.filter { it !is PackageViewDescriptor } // subpackages are not imported
}
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.types.KotlinType
import java.util.*
class CompositeBindingContext private constructor(
private val delegates: LinkedHashSet<BindingContext>
private val delegates: LinkedHashSet<BindingContext>
) : BindingContext {
override fun getType(expression: KtExpression): KotlinType? {
return delegates.asSequence().map { it.getType(expression) }.firstOrNull { it != null }
@@ -67,7 +67,7 @@ class CompositeBindingContext private constructor(
}
private class CompositeDiagnostics(
private val delegates: List<Diagnostics>
private val delegates: List<Diagnostics>
) : Diagnostics {
override fun iterator(): Iterator<Diagnostic> {
@@ -34,22 +34,18 @@ object DataClassDescriptorResolver {
private val COMPONENT_FUNCTION_NAME_PREFIX = "component"
fun createComponentName(index: Int): Name
= Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
fun createComponentName(index: Int): Name = Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
fun getComponentIndex(componentName: String): Int
= componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
fun getComponentIndex(componentName: String): Int = componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
fun isComponentLike(name: Name): Boolean
= isComponentLike(name.asString())
fun isComponentLike(name: Name): Boolean = isComponentLike(name.asString())
private fun isComponentLike(name: String): Boolean {
if (!name.startsWith(COMPONENT_FUNCTION_NAME_PREFIX)) return false
try {
getComponentIndex(name)
}
catch (e: NumberFormatException) {
} catch (e: NumberFormatException) {
return false
}
@@ -57,58 +53,58 @@ object DataClassDescriptorResolver {
}
fun createEqualsFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME)
doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME)
fun createHashCodeFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME)
doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME)
fun createToStringFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
doCreateFunctionFromAny(classDescriptor, TO_STRING_METHOD_NAME)
doCreateFunctionFromAny(classDescriptor, TO_STRING_METHOD_NAME)
private fun doCreateFunctionFromAny(classDescriptor: ClassDescriptor, name: Name): SimpleFunctionDescriptor {
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
classDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, classDescriptor.source
classDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, classDescriptor.source
)
val functionFromAny = classDescriptor.builtIns.any.getMemberScope(emptyList())
.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
functionDescriptor.initialize(
null,
classDescriptor.thisAsReceiverParameter,
functionFromAny.typeParameters,
functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) },
functionFromAny.returnType,
Modality.OPEN,
Visibilities.PUBLIC
null,
classDescriptor.thisAsReceiverParameter,
functionFromAny.typeParameters,
functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) },
functionFromAny.returnType,
Modality.OPEN,
Visibilities.PUBLIC
)
return functionDescriptor
}
fun createComponentFunctionDescriptor(
parameterIndex: Int,
property: PropertyDescriptor,
parameter: ValueParameterDescriptor,
classDescriptor: ClassDescriptor,
trace: BindingTrace
parameterIndex: Int,
property: PropertyDescriptor,
parameter: ValueParameterDescriptor,
classDescriptor: ClassDescriptor,
trace: BindingTrace
): SimpleFunctionDescriptor {
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
classDescriptor,
Annotations.EMPTY,
createComponentName(parameterIndex),
CallableMemberDescriptor.Kind.SYNTHESIZED,
parameter.source
classDescriptor,
Annotations.EMPTY,
createComponentName(parameterIndex),
CallableMemberDescriptor.Kind.SYNTHESIZED,
parameter.source
)
functionDescriptor.initialize(
null,
classDescriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
emptyList<ValueParameterDescriptor>(),
property.type,
Modality.FINAL,
property.visibility
null,
classDescriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
emptyList<ValueParameterDescriptor>(),
property.type,
Modality.FINAL,
property.visibility
)
functionDescriptor.isOperator = true
@@ -117,16 +113,16 @@ object DataClassDescriptorResolver {
}
fun createCopyFunctionDescriptor(
constructorParameters: Collection<ValueParameterDescriptor>,
classDescriptor: ClassDescriptor,
trace: BindingTrace
constructorParameters: Collection<ValueParameterDescriptor>,
classDescriptor: ClassDescriptor,
trace: BindingTrace
): SimpleFunctionDescriptor {
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
classDescriptor,
Annotations.EMPTY,
COPY_METHOD_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED,
classDescriptor.source
classDescriptor,
Annotations.EMPTY,
COPY_METHOD_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED,
classDescriptor.source
)
val parameterDescriptors = arrayListOf<ValueParameterDescriptor>()
@@ -136,8 +132,8 @@ object DataClassDescriptorResolver {
// If a parameter doesn't have the corresponding property, it must not have a default value in the 'copy' function
val declaresDefaultValue = propertyDescriptor != null
val parameterDescriptor = ValueParameterDescriptorImpl(
functionDescriptor, null, parameter.index, parameter.annotations, parameter.name, parameter.type, declaresDefaultValue,
parameter.isCrossinline, parameter.isNoinline, parameter.varargElementType, parameter.source
functionDescriptor, null, parameter.index, parameter.annotations, parameter.name, parameter.type, declaresDefaultValue,
parameter.isCrossinline, parameter.isNoinline, parameter.varargElementType, parameter.source
)
parameterDescriptors.add(parameterDescriptor)
if (declaresDefaultValue) {
@@ -146,13 +142,13 @@ object DataClassDescriptorResolver {
}
functionDescriptor.initialize(
null,
classDescriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
parameterDescriptors,
classDescriptor.defaultType,
Modality.FINAL,
Visibilities.PUBLIC
null,
classDescriptor.thisAsReceiverParameter,
emptyList<TypeParameterDescriptor>(),
parameterDescriptors,
classDescriptor.defaultType,
Modality.FINAL,
Visibilities.PUBLIC
)
trace.record(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor, functionDescriptor)
@@ -38,8 +38,8 @@ import org.jetbrains.kotlin.utils.keysToMap
import java.util.*
class DeclarationResolver(
private val annotationResolver: AnnotationResolver,
private val trace: BindingTrace
private val annotationResolver: AnnotationResolver,
private val trace: BindingTrace
) {
fun resolveAnnotationsOnFiles(c: TopDownAnalysisContext, scopeProvider: FileScopeProvider) {
@@ -74,14 +74,17 @@ class DeclarationResolver(
}
}
fun checkRedeclarationsInPackages(topLevelDescriptorProvider: TopLevelDescriptorProvider, topLevelFqNames: Multimap<FqName, KtElement>) {
fun checkRedeclarationsInPackages(
topLevelDescriptorProvider: TopLevelDescriptorProvider,
topLevelFqNames: Multimap<FqName, KtElement>
) {
for ((fqName, declarationsOrPackageDirectives) in topLevelFqNames.asMap()) {
if (fqName.isRoot) continue
// TODO: report error on expected class and actual val, or vice versa
val (expected, actual) =
getTopLevelDescriptorsByFqName(topLevelDescriptorProvider, fqName, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
.partition { it is MemberDescriptor && it.isExpect }
.partition { it is MemberDescriptor && it.isExpect }
for (descriptors in listOf(expected, actual)) {
if (descriptors.size > 1) {
@@ -94,7 +97,11 @@ class DeclarationResolver(
}
}
private fun getTopLevelDescriptorsByFqName(topLevelDescriptorProvider: TopLevelDescriptorProvider, fqName: FqName, location: LookupLocation): Set<DeclarationDescriptor> {
private fun getTopLevelDescriptorsByFqName(
topLevelDescriptorProvider: TopLevelDescriptorProvider,
fqName: FqName,
location: LookupLocation
): Set<DeclarationDescriptor> {
val descriptors = HashSet<DeclarationDescriptor>()
descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName))
@@ -45,29 +45,29 @@ import org.jetbrains.kotlin.types.typeUtil.*
import java.util.*
internal class DeclarationsCheckerBuilder(
private val descriptorResolver: DescriptorResolver,
private val originalModifiersChecker: ModifiersChecker,
private val annotationChecker: AnnotationChecker,
private val identifierChecker: IdentifierChecker,
private val languageVersionSettings: LanguageVersionSettings,
private val typeSpecificityComparator: TypeSpecificityComparator,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
private val descriptorResolver: DescriptorResolver,
private val originalModifiersChecker: ModifiersChecker,
private val annotationChecker: AnnotationChecker,
private val identifierChecker: IdentifierChecker,
private val languageVersionSettings: LanguageVersionSettings,
private val typeSpecificityComparator: TypeSpecificityComparator,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
) {
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
typeSpecificityComparator, diagnosticSuppressor
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
typeSpecificityComparator, diagnosticSuppressor
)
}
class DeclarationsChecker(
private val descriptorResolver: DescriptorResolver,
modifiersChecker: ModifiersChecker,
private val annotationChecker: AnnotationChecker,
private val identifierChecker: IdentifierChecker,
private val trace: BindingTrace,
private val languageVersionSettings: LanguageVersionSettings,
typeSpecificityComparator: TypeSpecificityComparator,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
private val descriptorResolver: DescriptorResolver,
modifiersChecker: ModifiersChecker,
private val annotationChecker: AnnotationChecker,
private val identifierChecker: IdentifierChecker,
private val trace: BindingTrace,
private val languageVersionSettings: LanguageVersionSettings,
typeSpecificityComparator: TypeSpecificityComparator,
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
) {
private val modifiersChecker = modifiersChecker.withTrace(trace)
@@ -102,9 +102,9 @@ class DeclarationsChecker(
}
val destructuringDeclarations = bodiesResolveContext.destructuringDeclarationEntries.entries
.map { (entry, _) -> entry.parent }
.filterIsInstance<KtDestructuringDeclaration>()
.distinct()
.map { (entry, _) -> entry.parent }
.filterIsInstance<KtDestructuringDeclaration>()
.distinct()
for (multiDeclaration in destructuringDeclarations) {
modifiersChecker.checkModifiersForDestructuringDeclaration(multiDeclaration)
@@ -143,7 +143,7 @@ class DeclarationsChecker(
trace.report(TYPEALIAS_SHOULD_EXPAND_TO_CLASS.on(typeReference, expandedType))
}
if (TypeUtils.contains(expandedType) { it.isArrayOfNothing()} ) {
if (TypeUtils.contains(expandedType) { it.isArrayOfNothing() }) {
trace.report(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE.on(typeReference, expandedType, "Array<Nothing> is illegal"))
}
@@ -151,7 +151,7 @@ class DeclarationsChecker(
for (typeParameter in typeAliasDescriptor.declaredTypeParameters) {
if (typeParameter !in usedTypeAliasParameters) {
val source = DescriptorToSourceUtils.descriptorToDeclaration(typeParameter) as? KtTypeParameter
?: throw AssertionError("No source element for type parameter $typeParameter of $typeAliasDescriptor")
?: throw AssertionError("No source element for type parameter $typeParameter of $typeAliasDescriptor")
trace.report(UNUSED_TYPEALIAS_PARAMETER.on(source, typeParameter, expandedType))
}
}
@@ -180,31 +180,35 @@ class DeclarationsChecker(
}
if (rhs.arguments.map { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } !=
typeAliasDescriptor.declaredTypeParameters) {
typeAliasDescriptor.declaredTypeParameters) {
trace.report(ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION.on(declaration))
return
}
}
private fun getUsedTypeAliasParameters(type: KotlinType, typeAlias: TypeAliasDescriptor): Set<TypeParameterDescriptor> =
type.constituentTypes().mapNotNullTo(HashSet()) {
val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor
descriptor?.takeIf { it.containingDeclaration == typeAlias }
}
type.constituentTypes().mapNotNullTo(HashSet()) {
val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor
descriptor?.takeIf { it.containingDeclaration == typeAlias }
}
private class TypeAliasDeclarationCheckingReportStrategy(
private val trace: BindingTrace,
typeAliasDescriptor: TypeAliasDescriptor,
declaration: KtTypeAlias
private val trace: BindingTrace,
typeAliasDescriptor: TypeAliasDescriptor,
declaration: KtTypeAlias
) : TypeAliasExpansionReportStrategy {
private val typeReference = declaration.getTypeReference()
?: throw AssertionError("Incorrect type alias declaration for $typeAliasDescriptor")
?: throw AssertionError("Incorrect type alias declaration for $typeAliasDescriptor")
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {
// Do nothing: this should've been reported during type resolution.
}
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
override fun conflictingProjection(
typeAlias: TypeAliasDescriptor,
typeParameter: TypeParameterDescriptor?,
substitutedArgument: KotlinType
) {
trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(typeReference, substitutedArgument))
}
@@ -212,7 +216,12 @@ class DeclarationsChecker(
trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeReference, typeAlias))
}
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
override fun boundsViolationInSubstitution(
bound: KotlinType,
unsubstitutedArgument: KotlinType,
argument: KotlinType,
typeParameter: TypeParameterDescriptor
) {
// TODO more precise diagnostics
if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) {
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
@@ -272,8 +281,7 @@ class DeclarationsChecker(
val classDescriptor = constructorDescriptor.containingDeclaration
if (classDescriptor.kind == ClassKind.ENUM_CLASS) {
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_ENUM.on(visibilityModifier))
}
else if (classDescriptor.modality == Modality.SEALED) {
} else if (classDescriptor.modality == Modality.SEALED) {
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_SEALED.on(visibilityModifier))
}
}
@@ -301,7 +309,8 @@ class DeclarationsChecker(
is KtClass -> {
checkClassButNotObject(classOrObject, classDescriptor)
descriptorResolver.checkNamesInConstraints(
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace)
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace
)
}
is KtObjectDeclaration -> {
checkObject(classOrObject, classDescriptor)
@@ -346,32 +355,31 @@ class DeclarationsChecker(
}
private fun checkOnlyOneTypeParameterBound(
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
) {
val upperBounds = descriptor.upperBounds
val (boundsWhichAreTypeParameters, otherBounds) = upperBounds
.map(KotlinType::constructor)
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
.let { pair -> pair.first.toSet() to pair.second.toSet() }
.map(KotlinType::constructor)
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
.let { pair -> pair.first.toSet() to pair.second.toSet() }
if (boundsWhichAreTypeParameters.size > 1 || (boundsWhichAreTypeParameters.size == 1 && otherBounds.isNotEmpty())) {
val reportOn = if (boundsWhichAreTypeParameters.size + otherBounds.size == 2) {
// If there's only one problematic bound (either 2 type parameter bounds, or 1 type parameter bound + 1 other bound),
// report the diagnostic on that bound
val allBounds: List<Pair<KtTypeReference, KotlinType?>> =
owner.typeConstraints
.filter { constraint ->
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
}
.mapNotNull { constraint -> constraint.boundTypeReference }
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
owner.typeConstraints
.filter { constraint ->
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
}
.mapNotNull { constraint -> constraint.boundTypeReference }
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
val problematicBound =
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
problematicBound?.first ?: declaration
}
else {
} else {
// Otherwise report the diagnostic on the type parameter declaration
declaration
}
@@ -400,17 +408,20 @@ class DeclarationsChecker(
if (conflictingTypes.size <= 1) continue
val containingDeclaration = typeParameterDescriptor.containingDeclaration as? ClassDescriptor
?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration)
?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration)
if (sourceElement is KtClassOrObject) {
val delegationSpecifierList = sourceElement.getSuperTypeList() ?: continue
trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES.on(
trace.report(
INCONSISTENT_TYPE_PARAMETER_VALUES.on(
delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes
))
}
else if (sourceElement is KtTypeParameter) {
trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
)
)
} else if (sourceElement is KtTypeParameter) {
trace.report(
INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes
))
)
)
}
}
}
@@ -521,8 +532,7 @@ class DeclarationsChecker(
for (parameter in aClass.primaryConstructorParameters) {
if (!parameter.hasValOrVar()) {
trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter))
}
else if (parameter.isMutable) {
} else if (parameter.isMutable) {
trace.report(VAR_ANNOTATION_PARAMETER.on(parameter))
}
}
@@ -537,8 +547,7 @@ class DeclarationsChecker(
if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) {
if (classDescriptor.kind == ClassKind.OBJECT) {
trace.report(NON_FINAL_MEMBER_IN_OBJECT.on(member))
}
else {
} else {
trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member))
}
}
@@ -594,9 +603,9 @@ class DeclarationsChecker(
}
private fun checkMemberProperty(
property: KtProperty,
propertyDescriptor: PropertyDescriptor,
classDescriptor: ClassDescriptor
property: KtProperty,
propertyDescriptor: PropertyDescriptor,
classDescriptor: ClassDescriptor
) {
val modifierList = property.modifierList
@@ -607,8 +616,7 @@ class DeclarationsChecker(
trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, property.name ?: "", classDescriptor))
return
}
}
else if (classDescriptor.kind == ClassKind.INTERFACE &&
} else if (classDescriptor.kind == ClassKind.INTERFACE &&
modifierList.hasModifier(KtTokens.OPEN_KEYWORD) &&
propertyDescriptor.modality == Modality.ABSTRACT) {
trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(property))
@@ -659,35 +667,33 @@ class DeclarationsChecker(
!backingFieldRequired -> trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer))
property.receiverTypeReference != null -> trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer))
}
}
else if (delegate != null) {
} else if (delegate != null) {
if (inInterface) {
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
}
else if (isExpect) {
} else if (isExpect) {
trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
}
}
else {
} else {
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
val isExternal = propertyDescriptor.isEffectivelyExternal()
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
}
else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
} else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
trace.report(MUST_BE_INITIALIZED.on(property))
}
else {
} else {
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
}
}
}
else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(property, LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings))
}
else if (noExplicitTypeOrGetterType(property)) {
} else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
trace.report(
Errors.UNSUPPORTED_FEATURE.on(
property,
LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings
)
)
} else if (noExplicitTypeOrGetterType(property)) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
}
@@ -703,7 +709,7 @@ class DeclarationsChecker(
}
private fun noExplicitTypeOrGetterType(property: KtProperty) =
property.typeReference == null
property.typeReference == null
&& (property.getter == null || (property.getter!!.hasBlockBody() && property.getter!!.returnTypeReference == null))
fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
@@ -744,8 +750,7 @@ class DeclarationsChecker(
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor))
}
}
else /* top-level only */ {
} else /* top-level only */ {
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isExpect &&
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
@@ -779,16 +784,15 @@ class DeclarationsChecker(
if (declaration.typeReference == null) {
if (it.isNothing() && !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
trace.report(
(if (declaration is KtProperty) IMPLICIT_NOTHING_PROPERTY_TYPE else IMPLICIT_NOTHING_RETURN_TYPE).on(target)
(if (declaration is KtProperty) IMPLICIT_NOTHING_PROPERTY_TYPE else IMPLICIT_NOTHING_RETURN_TYPE).on(target)
)
}
if (it.contains { type -> type.constructor is IntersectionTypeConstructor }) {
trace.report(IMPLICIT_INTERSECTION_TYPE.on(target, it))
}
}
else if (it.isNothing() && it is AbbreviatedType) {
} else if (it.isNothing() && it is AbbreviatedType) {
trace.report(
(if (declaration is KtProperty) ABBREVIATED_NOTHING_PROPERTY_TYPE else ABBREVIATED_NOTHING_RETURN_TYPE).on(target)
(if (declaration is KtProperty) ABBREVIATED_NOTHING_PROPERTY_TYPE else ABBREVIATED_NOTHING_RETURN_TYPE).on(target)
)
}
}
@@ -800,8 +804,7 @@ class DeclarationsChecker(
if (accessor != null) {
modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor)
identifierChecker.checkDeclaration(accessor, trace)
}
else {
} else {
modifiersChecker.runDeclarationCheckers(property, accessorDescriptor)
}
}
@@ -816,9 +819,9 @@ class DeclarationsChecker(
}
private fun checkAccessor(
propertyDescriptor: PropertyDescriptor,
accessor: KtPropertyAccessor?,
accessorDescriptor: PropertyAccessorDescriptor?
propertyDescriptor: PropertyDescriptor,
accessor: KtPropertyAccessor?,
accessorDescriptor: PropertyAccessorDescriptor?
) {
if (accessor == null || accessorDescriptor == null) return
if (propertyDescriptor.isExpect && accessor.hasBody()) {
@@ -827,29 +830,25 @@ class DeclarationsChecker(
val accessorModifierList = accessor.modifierList ?: return
val tokens = modifiersChecker.getTokensCorrespondingToModifiers(
accessorModifierList,
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
accessorModifierList,
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
)
if (accessor.isGetter) {
if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
}
else {
} else {
reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER)
}
}
else {
} else {
if (propertyDescriptor.isOverridable
&& accessorDescriptor.visibility == Visibilities.PRIVATE
&& propertyDescriptor.visibility != Visibilities.PRIVATE) {
if (propertyDescriptor.modality == Modality.ABSTRACT) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
}
else {
} else {
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY)
}
}
else {
} else {
val compare = Visibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility)
if (compare == null || compare > 0) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY)
@@ -866,8 +865,7 @@ class DeclarationsChecker(
trace.report(EXPECTED_ENUM_ENTRY_WITH_BODY.on(enumEntry))
}
}
}
else {
} else {
assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass }
}
}
@@ -922,7 +920,10 @@ class DeclarationsChecker(
return isImplementingMethodOfAnyInternal(member, HashSet<ClassDescriptor>())
}
private fun isImplementingMethodOfAnyInternal(member: CallableMemberDescriptor, visitedClasses: MutableSet<ClassDescriptor>): Boolean {
private fun isImplementingMethodOfAnyInternal(
member: CallableMemberDescriptor,
visitedClasses: MutableSet<ClassDescriptor>
): Boolean {
for (overridden in member.overriddenDescriptors) {
val containingDeclaration = overridden.containingDeclaration
if (containingDeclaration !is ClassDescriptor) continue
@@ -33,14 +33,14 @@ import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
class DelegationResolver<T : CallableMemberDescriptor> private constructor(
private val classOrObject: KtPureClassOrObject,
private val ownerDescriptor: ClassDescriptor,
private val existingMembers: Collection<CallableDescriptor>,
private val trace: BindingTrace,
private val memberExtractor: MemberExtractor<T>,
private val typeResolver: TypeResolver,
private val delegationFilter: DelegationFilter,
private val languageVersionSettings: LanguageVersionSettings
private val classOrObject: KtPureClassOrObject,
private val ownerDescriptor: ClassDescriptor,
private val existingMembers: Collection<CallableDescriptor>,
private val trace: BindingTrace,
private val memberExtractor: MemberExtractor<T>,
private val typeResolver: TypeResolver,
private val delegationFilter: DelegationFilter,
private val languageVersionSettings: LanguageVersionSettings
) {
private fun generateDelegatedMembers(): Collection<T> {
@@ -61,24 +61,24 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
}
private fun generateDelegatesForInterface(existingDelegates: Collection<T>, delegatedInterfaceType: KotlinType): Collection<T> =
generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
!isOverridingAnyOf(candidate, existingMembers) &&
!checkClashWithOtherDelegatedMember(candidate, existingDelegates)
}
generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
!isOverridingAnyOf(candidate, existingMembers) &&
!checkClashWithOtherDelegatedMember(candidate, existingDelegates)
}
private fun generateDelegationCandidates(delegatedInterfaceType: KotlinType): Collection<T> =
getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
@Suppress("UNCHECKED_CAST")
memberDescriptor.newCopyBuilder()
.setOwner(ownerDescriptor)
.setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
.setModality(newModality)
.setVisibility(Visibilities.INHERITED)
.setKind(DELEGATION)
.setCopyOverrides(false)
.build() as T
}
getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
@Suppress("UNCHECKED_CAST")
memberDescriptor.newCopyBuilder()
.setOwner(ownerDescriptor)
.setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
.setModality(newModality)
.setVisibility(Visibilities.INHERITED)
.setKind(DELEGATION)
.setCopyOverrides(false)
.build() as T
}
private fun checkClashWithOtherDelegatedMember(candidate: T, delegatedMembers: Collection<T>): Boolean {
val alreadyDelegated = delegatedMembers.firstOrNull { isOverridableBy(it, candidate) }
@@ -92,16 +92,16 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
private fun getDelegatableMembers(interfaceType: KotlinType): Collection<T> =
memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
descriptor.isOverridable &&
(descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
delegationFilter.filter(descriptor, languageVersionSettings)
}
memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
descriptor.isOverridable &&
(descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
delegationFilter.filter(descriptor, languageVersionSettings)
}
private fun T.overridesClassMembersOnly() =
DescriptorUtils.getAllOverriddenDeclarations(this).all {
DescriptorUtils.isClass(it.containingDeclaration)
}
DescriptorUtils.getAllOverriddenDeclarations(this).all {
DescriptorUtils.isClass(it.containingDeclaration)
}
interface MemberExtractor<out T : CallableMemberDescriptor> {
fun getMembersByType(type: KotlinType): Collection<T>
@@ -113,26 +113,35 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
companion object {
fun <T : CallableMemberDescriptor> generateDelegatedMembers(
classOrObject: KtPureClassOrObject,
ownerDescriptor: ClassDescriptor,
existingMembers: Collection<CallableDescriptor>,
trace: BindingTrace,
memberExtractor: MemberExtractor<T>,
typeResolver: TypeResolver,
delegationFilter: DelegationFilter,
languageVersionSettings: LanguageVersionSettings
classOrObject: KtPureClassOrObject,
ownerDescriptor: ClassDescriptor,
existingMembers: Collection<CallableDescriptor>,
trace: BindingTrace,
memberExtractor: MemberExtractor<T>,
typeResolver: TypeResolver,
delegationFilter: DelegationFilter,
languageVersionSettings: LanguageVersionSettings
): Collection<T> =
DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver, delegationFilter, languageVersionSettings)
.generateDelegatedMembers()
DelegationResolver(
classOrObject,
ownerDescriptor,
existingMembers,
trace,
memberExtractor,
typeResolver,
delegationFilter,
languageVersionSettings
)
.generateDelegatedMembers()
private fun isOverridingAnyOf(
candidate: CallableMemberDescriptor,
possiblyOverriddenBy: Collection<CallableDescriptor>
candidate: CallableMemberDescriptor,
possiblyOverriddenBy: Collection<CallableDescriptor>
): Boolean =
possiblyOverriddenBy.any { isOverridableBy(it, candidate) }
possiblyOverriddenBy.any { isOverridableBy(it, candidate) }
private fun isOverridableBy(memberOne: CallableDescriptor, memberTwo: CallableDescriptor): Boolean =
OverridingUtil.DEFAULT.isOverridableBy(memberOne, memberTwo, null).result == OVERRIDABLE
OverridingUtil.DEFAULT.isOverridableBy(memberOne, memberTwo, null).result == OVERRIDABLE
// class Foo : Bar by baz
// descriptor = Foo
@@ -140,34 +149,34 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
// delegateExpressionType = typeof(baz)
// return Map<member of Foo, corresponding member of typeOf(baz)>
fun getDelegates(
descriptor: ClassDescriptor,
toInterface: ClassDescriptor,
delegateExpressionType: KotlinType? = null
descriptor: ClassDescriptor,
toInterface: ClassDescriptor,
delegateExpressionType: KotlinType? = null
): Map<CallableMemberDescriptor, CallableMemberDescriptor> {
if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()
val delegatedMembers = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
.asIterable()
.sortedWith(MemberComparator.INSTANCE)
.filterIsInstance<CallableMemberDescriptor>()
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
.asIterable()
.sortedWith(MemberComparator.INSTANCE)
return delegatedMembers
.keysToMapExceptNulls { delegatingMember ->
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
.filter { it.containingDeclaration == toInterface }
.map { overriddenDescriptor ->
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
val name = overriddenDescriptor.name
.keysToMapExceptNulls { delegatingMember ->
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
.filter { it.containingDeclaration == toInterface }
.map { overriddenDescriptor ->
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
val name = overriddenDescriptor.name
// this is the actual member of delegateExpressionType that we are delegating to
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
}
// this is the actual member of delegateExpressionType that we are delegating to
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
}
actualDelegates.firstOrNull()
}
actualDelegates.firstOrNull()
}
}
}
}
@@ -47,14 +47,16 @@ object DescriptorToSourceUtils {
result.add(descriptor)
}
@JvmStatic fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
@JvmStatic
fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
val result = ArrayList<DeclarationDescriptor>()
collectEffectiveReferencedDescriptors(result, descriptor.original)
return result
}
// TODO Fix in descriptor
@JvmStatic private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
@JvmStatic
private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
// Only for extension receivers
if (descriptor.source != SourceElement.NO_SOURCE || descriptor.value !is ExtensionReceiver) return null
val containingDeclaration = descriptor.containingDeclaration as? CallableDescriptor ?: return null
@@ -62,7 +64,8 @@ object DescriptorToSourceUtils {
return psi.receiverTypeReference
}
@JvmStatic fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
@JvmStatic
fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
if (descriptor is ReceiverParameterDescriptor) {
getSourceForExtensionReceiverParameterDescriptor(descriptor)?.let { return it }
}
@@ -70,7 +73,8 @@ object DescriptorToSourceUtils {
return (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()
}
@JvmStatic fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? {
@JvmStatic
fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? {
return descriptor.source.getPsi() as? KtAnnotationEntry
}
@@ -78,12 +82,14 @@ object DescriptorToSourceUtils {
// Returns PSI element for descriptor. If there are many relevant elements (e.g. it is fake override
// with multiple declarations), returns null. It can't find declarations in builtins or decompiled code.
// In IDE, use DescriptorToSourceUtilsIde instead.
@JvmStatic fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
@JvmStatic
fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
val effectiveReferencedDescriptors = getEffectiveReferencedDescriptors(descriptor)
return if (effectiveReferencedDescriptors.size == 1) getSourceFromDescriptor(effectiveReferencedDescriptors.firstOrNull()!!) else null
}
@JvmStatic fun getContainingFile(declarationDescriptor: DeclarationDescriptor): KtFile? {
@JvmStatic
fun getContainingFile(declarationDescriptor: DeclarationDescriptor): KtFile? {
// declarationDescriptor may describe a synthesized element which doesn't have PSI
// To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
val descriptor = findTopLevelParent(declarationDescriptor) ?: return null
@@ -38,16 +38,17 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
return result and checkFunction(constructor, constructorDescriptor)
}
fun checkDeclarationWithVisibility(modifierListOwner: KtModifierListOwner,
descriptor: DeclarationDescriptorWithVisibility,
visibility: Visibility
) : Boolean {
fun checkDeclarationWithVisibility(
modifierListOwner: KtModifierListOwner,
descriptor: DeclarationDescriptorWithVisibility,
visibility: Visibility
): Boolean {
return when {
modifierListOwner is KtFunction &&
descriptor is FunctionDescriptor -> checkFunction(modifierListOwner, descriptor, visibility)
descriptor is FunctionDescriptor -> checkFunction(modifierListOwner, descriptor, visibility)
modifierListOwner is KtProperty &&
descriptor is PropertyDescriptor -> checkProperty(modifierListOwner, descriptor, visibility)
descriptor is PropertyDescriptor -> checkProperty(modifierListOwner, descriptor, visibility)
else -> true
}
@@ -60,48 +61,66 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val typeAliasVisibility = typeAliasDescriptor.effectiveVisibility()
val restricting = expandedType.leastPermissiveDescriptor(typeAliasVisibility)
if (restricting != null) {
trace.report(Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(typeAlias.nameIdentifier ?: typeAlias,
typeAliasVisibility, restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(
typeAlias.nameIdentifier ?: typeAlias,
typeAliasVisibility, restricting, restricting.effectiveVisibility()
)
)
}
}
fun checkFunction(function: KtFunction,
functionDescriptor: FunctionDescriptor,
// for checking situation with modified basic visibility
visibility: Visibility = functionDescriptor.visibility
fun checkFunction(
function: KtFunction,
functionDescriptor: FunctionDescriptor,
// for checking situation with modified basic visibility
visibility: Visibility = functionDescriptor.visibility
): Boolean {
val functionVisibility = functionDescriptor.effectiveVisibility(visibility)
var result = true
if (function !is KtConstructor<*>) {
val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility)
if (restricting != null) {
trace.report(Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(function.nameIdentifier ?: function, functionVisibility,
restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(
function.nameIdentifier ?: function, functionVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false
}
}
functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility)
if (restricting != null && i < function.valueParameters.size) {
trace.report(Errors.EXPOSED_PARAMETER_TYPE.on(function.valueParameters[i], functionVisibility,
restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_PARAMETER_TYPE.on(
function.valueParameters[i], functionVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false
}
}
return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor)
}
fun checkProperty(property: KtProperty,
propertyDescriptor: PropertyDescriptor,
// for checking situation with modified basic visibility
visibility: Visibility = propertyDescriptor.visibility
fun checkProperty(
property: KtProperty,
propertyDescriptor: PropertyDescriptor,
// for checking situation with modified basic visibility
visibility: Visibility = propertyDescriptor.visibility
): Boolean {
val propertyVisibility = propertyDescriptor.effectiveVisibility(visibility)
val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility)
var result = true
if (restricting != null) {
trace.report(Errors.EXPOSED_PROPERTY_TYPE.on(property.nameIdentifier ?: property, propertyVisibility,
restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_PROPERTY_TYPE.on(
property.nameIdentifier ?: property, propertyVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false
}
return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor)
@@ -113,8 +132,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val memberVisibility = memberDescriptor.effectiveVisibility()
val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility)
if (restricting != null) {
trace.report(Errors.EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility,
restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_RECEIVER_TYPE.on(
typeReference, memberVisibility,
restricting, restricting.effectiveVisibility()
)
)
return false
}
return true
@@ -135,12 +158,19 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val restricting = superType.leastPermissiveDescriptor(classVisibility)
if (restricting != null) {
if (isInterface) {
trace.report(Errors.EXPOSED_SUPER_INTERFACE.on(delegationList[i], classVisibility,
restricting, restricting.effectiveVisibility()))
}
else {
trace.report(Errors.EXPOSED_SUPER_CLASS.on(delegationList[i], classVisibility,
restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_SUPER_INTERFACE.on(
delegationList[i], classVisibility,
restricting, restricting.effectiveVisibility()
)
)
} else {
trace.report(
Errors.EXPOSED_SUPER_CLASS.on(
delegationList[i], classVisibility,
restricting, restricting.effectiveVisibility()
)
)
}
result = false
}
@@ -157,8 +187,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
for (upperBound in typeParameterDescriptor.upperBounds) {
val restricting = upperBound.leastPermissiveDescriptor(classVisibility)
if (restricting != null) {
trace.report(Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameterList[i], classVisibility,
restricting, restricting.effectiveVisibility()))
trace.report(
Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(
typeParameterList[i], classVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false
break
}
@@ -34,27 +34,27 @@ import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
import java.util.*
class LazyTopDownAnalyzer(
private val trace: BindingTrace,
private val declarationResolver: DeclarationResolver,
private val overrideResolver: OverrideResolver,
private val overloadResolver: OverloadResolver,
private val varianceChecker: VarianceChecker,
private val moduleDescriptor: ModuleDescriptor,
private val lazyDeclarationResolver: LazyDeclarationResolver,
private val bodyResolver: BodyResolver,
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
private val fileScopeProvider: FileScopeProvider,
private val declarationScopeProvider: DeclarationScopeProvider,
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
private val identifierChecker: IdentifierChecker,
private val languageVersionSettings: LanguageVersionSettings,
private val deprecationResolver: DeprecationResolver,
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
private val trace: BindingTrace,
private val declarationResolver: DeclarationResolver,
private val overrideResolver: OverrideResolver,
private val overloadResolver: OverloadResolver,
private val varianceChecker: VarianceChecker,
private val moduleDescriptor: ModuleDescriptor,
private val lazyDeclarationResolver: LazyDeclarationResolver,
private val bodyResolver: BodyResolver,
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
private val fileScopeProvider: FileScopeProvider,
private val declarationScopeProvider: DeclarationScopeProvider,
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
private val identifierChecker: IdentifierChecker,
private val languageVersionSettings: LanguageVersionSettings,
private val deprecationResolver: DeprecationResolver,
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
) {
fun analyzeDeclarations(
topDownAnalysisMode: TopDownAnalysisMode,
declarations: Collection<PsiElement>,
outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
topDownAnalysisMode: TopDownAnalysisMode,
declarations: Collection<PsiElement>,
outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
): TopDownAnalysisContext {
val c = TopDownAnalysisContext(topDownAnalysisMode, outerDataFlowInfo, declarationScopeProvider)
@@ -82,8 +82,8 @@ class LazyTopDownAnalyzer(
override fun visitScript(script: KtScript) {
c.scripts.put(
script,
lazyDeclarationResolver.getScriptDescriptor(script, KotlinLookupLocation(script)) as LazyScriptDescriptor
script,
lazyDeclarationResolver.getScriptDescriptor(script, KotlinLookupLocation(script)) as LazyScriptDescriptor
)
registerDeclarations(script.declarations)
}
@@ -109,8 +109,10 @@ class LazyTopDownAnalyzer(
}
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
val location = if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
val descriptor = lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
val location =
if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
val descriptor =
lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
c.declaredClasses.put(classOrObject, descriptor)
registerDeclarations(classOrObject.declarations)
@@ -127,12 +129,10 @@ class LazyTopDownAnalyzer(
trace.report(MANY_COMPANION_OBJECTS.on(jetDeclaration))
}
companionObjectAlreadyFound = true
}
else if (jetDeclaration is KtSecondaryConstructor) {
} else if (jetDeclaration is KtSecondaryConstructor) {
if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) {
trace.report(CONSTRUCTOR_IN_OBJECT.on(jetDeclaration))
}
else if (classDescriptor.kind == ClassKind.INTERFACE) {
} else if (classDescriptor.kind == ClassKind.INTERFACE) {
trace.report(CONSTRUCTOR_IN_INTERFACE.on(jetDeclaration))
}
}
@@ -147,13 +147,19 @@ class LazyTopDownAnalyzer(
private fun registerPrimaryConstructorParameters(klass: KtClass) {
for (jetParameter in klass.primaryConstructorParameters) {
if (jetParameter.hasValOrVar()) {
c.primaryConstructorParameterProperties.put(jetParameter, lazyDeclarationResolver.resolveToDescriptor(jetParameter) as PropertyDescriptor)
c.primaryConstructorParameterProperties.put(
jetParameter,
lazyDeclarationResolver.resolveToDescriptor(jetParameter) as PropertyDescriptor
)
}
}
}
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) {
c.secondaryConstructors.put(constructor, lazyDeclarationResolver.resolveToDescriptor(constructor) as ClassConstructorDescriptor)
c.secondaryConstructors.put(
constructor,
lazyDeclarationResolver.resolveToDescriptor(constructor) as ClassConstructorDescriptor
)
}
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
@@ -165,7 +171,8 @@ class LazyTopDownAnalyzer(
}
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer) {
val containerDescriptor = lazyDeclarationResolver.resolveToDescriptor(initializer.containingDeclaration) as ClassDescriptorWithResolutionScopes
val containerDescriptor =
lazyDeclarationResolver.resolveToDescriptor(initializer.containingDeclaration) as ClassDescriptorWithResolutionScopes
c.anonymousInitializers.put(initializer, containerDescriptor)
}
@@ -237,7 +244,11 @@ class LazyTopDownAnalyzer(
fileScopeProvider.getImportResolver(file).forceResolveAllImports()
}
private fun createTypeAliasDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap<FqName, KtElement>, typeAliases: List<KtTypeAlias>) {
private fun createTypeAliasDescriptors(
c: TopDownAnalysisContext,
topLevelFqNames: Multimap<FqName, KtElement>,
typeAliases: List<KtTypeAlias>
) {
for (typeAlias in typeAliases) {
val descriptor = lazyDeclarationResolver.resolveToDescriptor(typeAlias) as TypeAliasDescriptor
@@ -247,7 +258,11 @@ class LazyTopDownAnalyzer(
}
}
private fun createPropertyDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap<FqName, KtElement>, properties: List<KtProperty>) {
private fun createPropertyDescriptors(
c: TopDownAnalysisContext,
topLevelFqNames: Multimap<FqName, KtElement>,
properties: List<KtProperty>
) {
for (property in properties) {
val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor
@@ -269,9 +284,10 @@ class LazyTopDownAnalyzer(
}
private fun createPropertiesFromDestructuringDeclarations(
c: TopDownAnalysisContext,
topLevelFqNames: Multimap<FqName, KtElement>,
destructuringDeclarations: List<KtDestructuringDeclaration>) {
c: TopDownAnalysisContext,
topLevelFqNames: Multimap<FqName, KtElement>,
destructuringDeclarations: List<KtDestructuringDeclaration>
) {
for (destructuringDeclaration in destructuringDeclarations) {
for (entry in destructuringDeclaration.entries) {
val descriptor = lazyDeclarationResolver.resolveToDescriptor(entry) as PropertyDescriptor
@@ -283,7 +299,11 @@ class LazyTopDownAnalyzer(
}
}
private fun registerTopLevelFqName(topLevelFqNames: Multimap<FqName, KtElement>, declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor) {
private fun registerTopLevelFqName(
topLevelFqNames: Multimap<FqName, KtElement>,
declaration: KtNamedDeclaration,
descriptor: DeclarationDescriptor
) {
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
val fqName = declaration.fqName
if (fqName != null) {
@@ -52,93 +52,123 @@ object ModifierCheckerCore {
COMPATIBLE_FOR_CLASSES_ONLY
}
private val defaultVisibilityTargets = EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS)
private val defaultVisibilityTargets = EnumSet.of(
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS
)
val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
PRIVATE_KEYWORD to defaultVisibilityTargets,
PUBLIC_KEYWORD to defaultVisibilityTargets,
INTERNAL_KEYWORD to defaultVisibilityTargets,
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS),
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
COMPANION_KEYWORD to EnumSet.of(OBJECT),
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION),
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS),
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
INFIX_KEYWORD to EnumSet.of(FUNCTION),
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
IMPL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS),
EXPECT_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
ACTUAL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS)
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
PRIVATE_KEYWORD to defaultVisibilityTargets,
PUBLIC_KEYWORD to defaultVisibilityTargets,
INTERNAL_KEYWORD to defaultVisibilityTargets,
PROTECTED_KEYWORD to EnumSet.of(
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS
),
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
COMPANION_KEYWORD to EnumSet.of(OBJECT),
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION),
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS),
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
INFIX_KEYWORD to EnumSet.of(FUNCTION),
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
IMPL_KEYWORD to EnumSet.of(
TOP_LEVEL_FUNCTION,
MEMBER_FUNCTION,
TOP_LEVEL_PROPERTY,
MEMBER_PROPERTY,
CONSTRUCTOR,
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS,
TYPEALIAS
),
EXPECT_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
ACTUAL_KEYWORD to EnumSet.of(
TOP_LEVEL_FUNCTION,
MEMBER_FUNCTION,
TOP_LEVEL_PROPERTY,
MEMBER_PROPERTY,
CONSTRUCTOR,
CLASS_ONLY,
OBJECT,
INTERFACE,
ENUM_CLASS,
ANNOTATION_CLASS,
TYPEALIAS
)
)
private val featureDependencies = mapOf(
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties),
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables)
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties),
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables)
)
private val featureDependenciesTargets = mapOf(
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY)
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY)
)
// NOTE: deprecated targets must be possible!
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
private val deprecatedModifierMap = mapOf(
HEADER_KEYWORD to EXPECT_KEYWORD,
IMPL_KEYWORD to ACTUAL_KEYWORD
HEADER_KEYWORD to EXPECT_KEYWORD,
IMPL_KEYWORD to ACTUAL_KEYWORD
)
// NOTE: redundant targets must be possible!
private val redundantTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
OPEN_KEYWORD to EnumSet.of(INTERFACE)
OPEN_KEYWORD to EnumSet.of(INTERFACE)
)
private val possibleParentTargetPredicateMap = mapOf<KtModifierKeywordToken, TargetAllowedPredicate>(
INNER_KEYWORD to or(always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)),
OVERRIDE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY),
PROTECTED_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
INTERNAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, FILE),
PRIVATE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
COMPANION_KEYWORD to always(CLASS_ONLY, ENUM_CLASS, INTERFACE),
FINAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, ANNOTATION_CLASS, FILE),
VARARG_KEYWORD to always(CONSTRUCTOR, FUNCTION, CLASS)
INNER_KEYWORD to or(
always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)
),
OVERRIDE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY),
PROTECTED_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
INTERNAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, FILE),
PRIVATE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
COMPANION_KEYWORD to always(CLASS_ONLY, ENUM_CLASS, INTERFACE),
FINAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, ANNOTATION_CLASS, FILE),
VARARG_KEYWORD to always(CONSTRUCTOR, FUNCTION, CLASS)
)
private val deprecatedParentTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
fun isPossibleParentTarget(
modifier: KtModifierKeywordToken,
parentTarget: KotlinTarget,
languageVersionSettings: LanguageVersionSettings
modifier: KtModifierKeywordToken,
parentTarget: KotlinTarget,
languageVersionSettings: LanguageVersionSettings
): Boolean {
deprecatedParentTargetMap[modifier]?.let {
if (parentTarget in it) return false
@@ -198,15 +228,17 @@ object ModifierCheckerCore {
}
private fun redundantRegister(
sufficient: KtModifierKeywordToken,
redundant: KtModifierKeywordToken
sufficient: KtModifierKeywordToken,
redundant: KtModifierKeywordToken
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
return mapOf(Pair(sufficient, redundant) to Compatibility.REDUNDANT,
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT)
return mapOf(
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
)
}
private fun compatibilityRegister(
compatibility: Compatibility, vararg list: KtModifierKeywordToken
compatibility: Compatibility, vararg list: KtModifierKeywordToken
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
val result = hashMapOf<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility>()
for (first in list) {
@@ -220,7 +252,7 @@ object ModifierCheckerCore {
}
private fun compatibilityForClassesRegister(vararg list: KtModifierKeywordToken) =
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
private fun incompatibilityRegister(vararg list: KtModifierKeywordToken) = compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
@@ -229,29 +261,31 @@ object ModifierCheckerCore {
private fun compatibility(first: KtModifierKeywordToken, second: KtModifierKeywordToken): Compatibility {
return if (first == second) {
Compatibility.REPEATED
}
else {
} else {
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
}
}
private fun checkCompatibility(trace: BindingTrace,
firstNode: ASTNode,
secondNode: ASTNode,
owner: PsiElement,
incorrectNodes: MutableSet<ASTNode>) {
private fun checkCompatibility(
trace: BindingTrace,
firstNode: ASTNode,
secondNode: ASTNode,
owner: PsiElement,
incorrectNodes: MutableSet<ASTNode>
) {
val first = firstNode.elementType as KtModifierKeywordToken
val second = secondNode.elementType as KtModifierKeywordToken
val compatibility = compatibility(first, second)
when (compatibility) {
Compatibility.COMPATIBLE -> {}
Compatibility.COMPATIBLE -> {
}
Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) {
trace.report(Errors.REPEATED_MODIFIER.on (secondNode.psi, first))
trace.report(Errors.REPEATED_MODIFIER.on(secondNode.psi, first))
}
Compatibility.REDUNDANT ->
trace.report(Errors.REDUNDANT_MODIFIER.on(secondNode.psi, second, first))
Compatibility.REVERSE_REDUNDANT ->
trace.report(Errors.REDUNDANT_MODIFIER.on(firstNode.psi, first, second))
trace.report(Errors.REDUNDANT_MODIFIER.on(firstNode.psi, first, second))
Compatibility.DEPRECATED -> {
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(firstNode.psi, first, second))
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(secondNode.psi, second, first))
@@ -285,18 +319,30 @@ object ModifierCheckerCore {
deprecatedModifierReplacement != null ->
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
actualTargets.any { it in deprecatedTargets } ->
trace.report(Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
trace.report(
Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(
node.psi,
modifier,
actualTargets.firstOrNull()?.description ?: "this"
)
)
actualTargets.any { it in redundantTargets } ->
trace.report(Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
trace.report(
Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(
node.psi,
modifier,
actualTargets.firstOrNull()?.description ?: "this"
)
)
}
return true
}
private fun checkLanguageLevelSupport(
trace: BindingTrace,
node: ASTNode,
languageVersionSettings: LanguageVersionSettings,
actualTargets: List<KotlinTarget>
trace: BindingTrace,
node: ASTNode,
languageVersionSettings: LanguageVersionSettings,
actualTargets: List<KotlinTarget>
): Boolean {
val modifier = node.elementType as KtModifierKeywordToken
@@ -313,8 +359,7 @@ object ModifierCheckerCore {
if (featureSupport == LanguageFeature.State.DISABLED) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData))
}
else {
} else {
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData))
}
return false
@@ -330,7 +375,12 @@ object ModifierCheckerCore {
// Should return false if error is reported, true otherwise
private fun checkParent(trace: BindingTrace, node: ASTNode, parentDescriptor: DeclarationDescriptor?, languageVersionSettings: LanguageVersionSettings): Boolean {
private fun checkParent(
trace: BindingTrace,
node: ASTNode,
parentDescriptor: DeclarationDescriptor?,
languageVersionSettings: LanguageVersionSettings
): Boolean {
val modifier = node.elementType as KtModifierKeywordToken
val actualParents: List<KotlinTarget> = when (parentDescriptor) {
is ClassDescriptor -> KotlinTarget.classActualTargets(parentDescriptor)
@@ -341,23 +391,35 @@ object ModifierCheckerCore {
}
val deprecatedParents = deprecatedParentTargetMap[modifier]
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
trace.report(Errors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION.on(node.psi, modifier, actualParents.firstOrNull()?.description ?: "this scope"))
trace.report(
Errors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION.on(
node.psi,
modifier,
actualParents.firstOrNull()?.description ?: "this scope"
)
)
return true
}
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
trace.report(Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(node.psi, modifier, actualParents.firstOrNull()?.description ?: "this scope"))
trace.report(
Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(
node.psi,
modifier,
actualParents.firstOrNull()?.description ?: "this scope"
)
)
return false
}
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
private fun checkModifierList(
list: KtModifierList,
trace: BindingTrace,
parentDescriptor: DeclarationDescriptor?,
actualTargets: List<KotlinTarget>,
languageVersionSettings: LanguageVersionSettings
list: KtModifierList,
trace: BindingTrace,
parentDescriptor: DeclarationDescriptor?,
actualTargets: List<KotlinTarget>,
languageVersionSettings: LanguageVersionSettings
) {
// It's a list of all nodes with error already reported
// General strategy: report no more than one error but any number of warnings
@@ -381,10 +443,10 @@ object ModifierCheckerCore {
}
fun check(
listOwner: KtModifierListOwner,
trace: BindingTrace,
descriptor: DeclarationDescriptor?,
languageVersionSettings: LanguageVersionSettings
listOwner: KtModifierListOwner,
trace: BindingTrace,
descriptor: DeclarationDescriptor?,
languageVersionSettings: LanguageVersionSettings
) {
if (listOwner is KtDeclarationWithBody) {
// JetFunction or JetPropertyAccessor
@@ -410,18 +472,19 @@ private fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object
private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
target in targetSet
target in targetSet
}
private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets)
private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
}
}
private fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
p1.isAllowed(target, languageVersionSettings) ||
p2.isAllowed(target, languageVersionSettings)
p1.isAllowed(target, languageVersionSettings) ||
p2.isAllowed(target, languageVersionSettings)
}
@@ -31,9 +31,9 @@ import org.jetbrains.kotlin.utils.DFS
object NonExpansiveInheritanceRestrictionChecker {
@JvmStatic
fun check(
declaration: KtClass,
classDescriptor: ClassDescriptor,
diagnosticHolder: DiagnosticSink
declaration: KtClass,
classDescriptor: ClassDescriptor,
diagnosticHolder: DiagnosticSink
) {
val typeConstructor = classDescriptor.typeConstructor
if (typeConstructor.parameters.isEmpty()) return
@@ -104,11 +104,14 @@ object NonExpansiveInheritanceRestrictionChecker {
for (typeParameter in typeParameters) {
if (typeParameter.defaultType in constituents || typeParameter.defaultType.makeNullableAsSpecified(true) in constituents) {
addEdge(typeParameter, constituentTypeConstructor.parameters[i], !TypeUtils.isTypeParameter(typeProjection.type))
addEdge(
typeParameter,
constituentTypeConstructor.parameters[i],
!TypeUtils.isTypeParameter(typeProjection.type)
)
}
}
}
else {
} else {
// Furthermore, if T appears as a constituent type of an element of the B-closure of the set of lower and
// upper bounds of a skolem type variable Q in a skolemization of a projected generic type in ST, add an
// expanding edge from T to V, where V is the type parameter corresponding to Q.
@@ -116,7 +119,8 @@ object NonExpansiveInheritanceRestrictionChecker {
val bounds = hashSetOf<KotlinType>()
val substitutor = TypeConstructorSubstitution.create(constituentType).buildSubstitutor()
val adaptedUpperBounds = originalTypeParameter.upperBounds.mapNotNull { substitutor.substitute(it, Variance.INVARIANT) }
val adaptedUpperBounds =
originalTypeParameter.upperBounds.mapNotNull { substitutor.substitute(it, Variance.INVARIANT) }
bounds.addAll(adaptedUpperBounds)
if (!typeProjection.isStarProjection) {
@@ -138,7 +142,7 @@ object NonExpansiveInheritanceRestrictionChecker {
private data class ExpansiveEdge<out T>(val from: T, val to: T)
private interface Graph<T> {
private interface Graph<T> {
fun getNeighbors(node: T): Collection<T>
val expansiveEdges: Set<ExpansiveEdge<T>>
}
@@ -42,9 +42,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
import java.util.*
class OverrideResolver(
private val trace: BindingTrace,
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
private val languageVersionSettings: LanguageVersionSettings
private val trace: BindingTrace,
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
private val languageVersionSettings: LanguageVersionSettings
) {
fun check(c: TopDownAnalysisContext) {
@@ -106,14 +106,17 @@ class OverrideResolver(
// don't care
}
override fun abstractMemberWithMoreSpecificType(abstractMember: CallableMemberDescriptor, concreteMember: CallableMemberDescriptor) {
override fun abstractMemberWithMoreSpecificType(
abstractMember: CallableMemberDescriptor,
concreteMember: CallableMemberDescriptor
) {
shouldImplement.add(abstractMember)
}
}
private inner class CollectErrorInformationForInheritedMembersStrategy(
private val klass: KtClassOrObject,
private val classDescriptor: ClassDescriptor
private val klass: KtClassOrObject,
private val classDescriptor: ClassDescriptor
) : CheckInheritedSignaturesReportStrategy, CheckOverrideReportStrategy {
private val abstractNoImpl = linkedSetOf<CallableMemberDescriptor>()
@@ -147,24 +150,25 @@ class OverrideResolver(
if (descriptor1 is PropertyDescriptor && descriptor2 is PropertyDescriptor) {
if (descriptor1.isVar || descriptor2.isVar) {
reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
}
else {
} else {
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
}
}
else {
} else {
reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
}
}
override fun abstractMemberWithMoreSpecificType(abstractMember: CallableMemberDescriptor, concreteMember: CallableMemberDescriptor) {
override fun abstractMemberWithMoreSpecificType(
abstractMember: CallableMemberDescriptor,
concreteMember: CallableMemberDescriptor
) {
typeMismatchOnInheritance(abstractMember, concreteMember)
}
private fun reportInheritanceConflictIfRequired(
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
descriptor1: CallableMemberDescriptor,
descriptor2: CallableMemberDescriptor
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
descriptor1: CallableMemberDescriptor,
descriptor2: CallableMemberDescriptor
) {
if (!onceErrorsReported.contains(diagnosticFactory)) {
onceErrorsReported.add(diagnosticFactory)
@@ -177,19 +181,21 @@ class OverrideResolver(
}
override fun returnTypeMismatchOnOverride(
overriding: CallableMemberDescriptor,
overridden: CallableMemberDescriptor
overriding: CallableMemberDescriptor,
overridden: CallableMemberDescriptor
) {
reportDelegationProblemIfRequired(
RETURN_TYPE_MISMATCH_BY_DELEGATION, RETURN_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden)
RETURN_TYPE_MISMATCH_BY_DELEGATION, RETURN_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden
)
}
override fun propertyTypeMismatchOnOverride(
overriding: PropertyDescriptor,
overridden: PropertyDescriptor
overriding: PropertyDescriptor,
overridden: PropertyDescriptor
) {
reportDelegationProblemIfRequired(
PROPERTY_TYPE_MISMATCH_BY_DELEGATION, PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden)
PROPERTY_TYPE_MISMATCH_BY_DELEGATION, PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden
)
}
override fun varOverriddenByVal(overriding: CallableMemberDescriptor, overridden: CallableMemberDescriptor) {
@@ -197,14 +203,16 @@ class OverrideResolver(
}
private fun reportDelegationProblemIfRequired(
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
relevantDiagnosticFromInheritance: DiagnosticFactoryWithPsiElement<*, *>?,
delegate: CallableMemberDescriptor,
overridden: CallableMemberDescriptor
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
relevantDiagnosticFromInheritance: DiagnosticFactoryWithPsiElement<*, *>?,
delegate: CallableMemberDescriptor,
overridden: CallableMemberDescriptor
) {
assert(delegate.kind == DELEGATION) { "Delegate expected, got " + delegate + " of kind " + delegate.kind }
if (!onceErrorsReported.contains(diagnosticFactory) && (relevantDiagnosticFromInheritance == null || !onceErrorsReported.contains(relevantDiagnosticFromInheritance))) {
if (!onceErrorsReported.contains(diagnosticFactory) && (relevantDiagnosticFromInheritance == null || !onceErrorsReported.contains(
relevantDiagnosticFromInheritance
))) {
onceErrorsReported.add(diagnosticFactory)
trace.report(diagnosticFactory.on(klass, delegate, overridden))
}
@@ -214,8 +222,7 @@ class OverrideResolver(
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.first()))
}
else if (abstractNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
} else if (abstractNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.first()))
}
@@ -223,8 +230,7 @@ class OverrideResolver(
multipleImplementations.removeAll(conflictingReturnTypes)
if (!conflictingInterfaceMembers.isEmpty()) {
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next()))
}
else if (!multipleImplementations.isEmpty()) {
} else if (!multipleImplementations.isEmpty()) {
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, multipleImplementations.iterator().next()))
}
}
@@ -246,8 +252,7 @@ class OverrideResolver(
if (declared.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) {
if (DataClassDescriptorResolver.isComponentLike(declared.name)) {
checkOverrideForComponentFunction(declared)
}
else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
} else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
checkOverrideForCopyFunction(declared)
}
return
@@ -257,7 +262,8 @@ class OverrideResolver(
return
}
val member = DescriptorToSourceUtils.descriptorToDeclaration(declared) as KtNamedDeclaration? ?: throw IllegalStateException("declared descriptor is not resolved to declaration: " + declared)
val member = DescriptorToSourceUtils.descriptorToDeclaration(declared) as KtNamedDeclaration?
?: throw IllegalStateException("declared descriptor is not resolved to declaration: " + declared)
val modifierList = member.modifierList
val hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
@@ -288,8 +294,7 @@ class OverrideResolver(
typeMismatchError = true
if (overridden.isVar) {
trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
}
else {
} else {
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
}
}
@@ -302,7 +307,10 @@ class OverrideResolver(
}
}
override fun cannotOverrideInvisibleMember(overriding: CallableMemberDescriptor, invisibleOverridden: CallableMemberDescriptor) {
override fun cannotOverrideInvisibleMember(
overriding: CallableMemberDescriptor,
invisibleOverridden: CallableMemberDescriptor
) {
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden))
}
@@ -310,8 +318,7 @@ class OverrideResolver(
trace.report(NOTHING_TO_OVERRIDE.on(member, declared))
}
})
}
else if (!overriddenDescriptors.isEmpty() && !overridesBackwardCompatibilityHelper.overrideCanBeOmitted(declared)) {
} else if (!overriddenDescriptors.isEmpty() && !overridesBackwardCompatibilityHelper.overrideCanBeOmitted(declared)) {
val overridden = overriddenDescriptors.iterator().next()
trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.containingDeclaration))
}
@@ -354,8 +361,7 @@ class OverrideResolver(
val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration)
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) {
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR.on(dataModifier, copyFunction, baseClassifier))
}
else {
} else {
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING.on(dataModifier, copyFunction, baseClassifier))
}
}
@@ -397,15 +403,15 @@ class OverrideResolver(
if (isDeclaration) {
checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper)
}
else {
} else {
checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper)
}
}
}
private fun checkNameAndDefaultForDeclaredParameter(descriptor: ValueParameterDescriptor, multipleDefaultsInSuper: Boolean) {
val parameter = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtParameter ?: error("Declaration not found for parameter: " + descriptor)
val parameter = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtParameter
?: error("Declaration not found for parameter: " + descriptor)
if (descriptor.declaresDefaultValue()) {
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter))
@@ -418,22 +424,25 @@ class OverrideResolver(
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
trace.report(PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
trace.report(
PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
parameter,
parameterFromSuperclass.containingDeclaration.containingDeclaration as ClassDescriptor,
parameterFromSuperclass)
parameterFromSuperclass
)
)
}
}
}
private fun checkNameAndDefaultForFakeOverrideParameter(
containingFunction: CallableMemberDescriptor,
descriptor: ValueParameterDescriptor,
multipleDefaultsInSuper: Boolean
containingFunction: CallableMemberDescriptor,
descriptor: ValueParameterDescriptor,
multipleDefaultsInSuper: Boolean
) {
val containingClass = containingFunction.containingDeclaration
val classElement = DescriptorToSourceUtils.descriptorToDeclaration(containingClass) as KtClassOrObject? ?: error("Declaration not found for class: " + containingClass)
val classElement = DescriptorToSourceUtils.descriptorToDeclaration(containingClass) as KtClassOrObject?
?: error("Declaration not found for class: " + containingClass)
if (multipleDefaultsInSuper) {
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, descriptor))
@@ -441,10 +450,12 @@ class OverrideResolver(
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
trace.report(DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES.on(
trace.report(
DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES.on(
classElement,
containingFunction.overriddenDescriptors,
parameterFromSuperclass.index + 1)
parameterFromSuperclass.index + 1
)
)
}
}
@@ -468,11 +479,24 @@ class OverrideResolver(
for (descriptor in memberDescriptor.overriddenDescriptors) {
val compare = Visibilities.compare(visibility, descriptor.visibility)
if (compare == null) {
trace.report(CANNOT_CHANGE_ACCESS_PRIVILEGE.on(declaration, descriptor.visibility, descriptor, descriptor.containingDeclaration))
trace.report(
CANNOT_CHANGE_ACCESS_PRIVILEGE.on(
declaration,
descriptor.visibility,
descriptor,
descriptor.containingDeclaration
)
)
return
}
else if (compare < 0) {
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(declaration, descriptor.visibility, descriptor, descriptor.containingDeclaration))
} else if (compare < 0) {
trace.report(
CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(
declaration,
descriptor.visibility,
descriptor,
descriptor.containingDeclaration
)
)
return
}
}
@@ -481,8 +505,8 @@ class OverrideResolver(
companion object {
fun resolveUnknownVisibilities(
descriptors: Collection<CallableMemberDescriptor>,
trace: BindingTrace
descriptors: Collection<CallableMemberDescriptor>,
trace: BindingTrace
) {
for (descriptor in descriptors) {
OverridingUtil.resolveUnknownVisibilityForMember(descriptor, createCannotInferVisibilityReporter(trace))
@@ -515,9 +539,9 @@ class OverrideResolver(
}
private fun checkInheritedAndDelegatedSignatures(
classDescriptor: ClassDescriptor,
inheritedReportStrategy: CheckInheritedSignaturesReportStrategy,
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
classDescriptor: ClassDescriptor,
inheritedReportStrategy: CheckInheritedSignaturesReportStrategy,
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
) {
for (member in DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)) {
if (member is CallableMemberDescriptor) {
@@ -527,9 +551,9 @@ class OverrideResolver(
}
private fun checkInheritedAndDelegatedSignatures(
descriptor: CallableMemberDescriptor,
reportingStrategy: CheckInheritedSignaturesReportStrategy,
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
descriptor: CallableMemberDescriptor,
reportingStrategy: CheckInheritedSignaturesReportStrategy,
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
) {
val kind = descriptor.kind
if (kind != FAKE_OVERRIDE && kind != DELEGATION) return
@@ -545,9 +569,11 @@ class OverrideResolver(
val allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values)
val allFilteredOverriddenDeclarations = OverridingUtil.filterOutOverridden(
Sets.newLinkedHashSet(allOverriddenDeclarations))
Sets.newLinkedHashSet(allOverriddenDeclarations)
)
val relevantDirectlyOverridden = getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
val relevantDirectlyOverridden =
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
checkInheritedDescriptorsGroup(descriptor, relevantDirectlyOverridden, reportingStrategy)
@@ -560,8 +586,8 @@ class OverrideResolver(
}
val (concreteOverridden, abstractOverridden) = relevantDirectlyOverridden
.filter { !isOrOverridesSynthesized(it) }
.partition { it.modality != Modality.ABSTRACT }
.filter { !isOrOverridesSynthesized(it) }
.partition { it.modality != Modality.ABSTRACT }
val numImplementations = concreteOverridden.size
@@ -587,8 +613,8 @@ class OverrideResolver(
}
private fun checkMissingOverridesByJava8Restrictions(
relevantDirectlyOverridden: Set<CallableMemberDescriptor>,
reportingStrategy: CheckInheritedSignaturesReportStrategy
relevantDirectlyOverridden: Set<CallableMemberDescriptor>,
reportingStrategy: CheckInheritedSignaturesReportStrategy
) {
// Java 8:
// -- class should implement an abstract member of a super-class,
@@ -608,8 +634,7 @@ class OverrideResolver(
if (overridden.modality === Modality.ABSTRACT) {
overridesAbstractInBaseClass = overridden
}
}
else if (containingDeclaration.kind == ClassKind.INTERFACE) {
} else if (containingDeclaration.kind == ClassKind.INTERFACE) {
overriddenInterfaceMembers.add(overridden)
if (overridden.modality !== Modality.ABSTRACT) {
overridesNonAbstractInterfaceMember = true
@@ -629,14 +654,14 @@ class OverrideResolver(
}
private fun collectAbstractMethodsWithMoreSpecificReturnType(
abstractOverridden: List<CallableMemberDescriptor>,
implementation: CallableMemberDescriptor
abstractOverridden: List<CallableMemberDescriptor>,
implementation: CallableMemberDescriptor
): List<CallableMemberDescriptor> =
abstractOverridden.filter { abstractMember -> !isReturnTypeOkForOverride(abstractMember, implementation) }
abstractOverridden.filter { abstractMember -> !isReturnTypeOkForOverride(abstractMember, implementation) }
private fun getRelevantDirectlyOverridden(
overriddenByParent: MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>,
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
overriddenByParent: MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>,
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
): Set<CallableMemberDescriptor> {
/* Let the following class hierarchy is declared:
@@ -678,9 +703,9 @@ class OverrideResolver(
}
private fun isRelevant(
declarationSet: Set<CallableMemberDescriptor>,
allDeclarationSets: Collection<Set<CallableMemberDescriptor>>,
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
declarationSet: Set<CallableMemberDescriptor>,
allDeclarationSets: Collection<Set<CallableMemberDescriptor>>,
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
): Boolean {
for (otherSet in allDeclarationSets) {
if (otherSet === declarationSet) continue
@@ -691,7 +716,7 @@ class OverrideResolver(
}
private fun collectOverriddenDeclarations(
directOverriddenDescriptors: Collection<CallableMemberDescriptor>
directOverriddenDescriptors: Collection<CallableMemberDescriptor>
): MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>> {
val overriddenDeclarationsByDirectParent = Maps.newLinkedHashMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>()
for (descriptor in directOverriddenDescriptors) {
@@ -703,9 +728,9 @@ class OverrideResolver(
}
private fun checkInheritedDescriptorsGroup(
descriptor: CallableMemberDescriptor,
overriddenDescriptors: Collection<CallableMemberDescriptor>,
reportingStrategy: CheckInheritedSignaturesReportStrategy
descriptor: CallableMemberDescriptor,
overriddenDescriptors: Collection<CallableMemberDescriptor>,
reportingStrategy: CheckInheritedSignaturesReportStrategy
) {
if (overriddenDescriptors.size <= 1) return
@@ -713,12 +738,12 @@ class OverrideResolver(
for (overriddenDescriptor in overriddenDescriptors) {
if (propertyDescriptor != null) {
val overriddenPropertyDescriptor = overriddenDescriptor.assertedCast<PropertyDescriptor> { "$overriddenDescriptor is not a property" }
val overriddenPropertyDescriptor =
overriddenDescriptor.assertedCast<PropertyDescriptor> { "$overriddenDescriptor is not a property" }
if (!isPropertyTypeOkForOverride(overriddenPropertyDescriptor, propertyDescriptor)) {
reportingStrategy.typeMismatchOnInheritance(propertyDescriptor, overriddenPropertyDescriptor)
}
}
else {
} else {
if (!isReturnTypeOkForOverride(overriddenDescriptor, descriptor)) {
reportingStrategy.typeMismatchOnInheritance(descriptor, overriddenDescriptor)
}
@@ -727,8 +752,8 @@ class OverrideResolver(
}
private fun checkOverridesForMemberMarkedOverride(
declared: CallableMemberDescriptor,
reportError: CheckOverrideReportForDeclaredMemberStrategy
declared: CallableMemberDescriptor,
reportError: CheckOverrideReportForDeclaredMemberStrategy
) {
val overriddenDescriptors = declared.overriddenDescriptors
@@ -743,17 +768,16 @@ class OverrideResolver(
val invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass)
if (invisibleOverriddenDescriptor != null) {
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor)
}
else {
} else {
reportError.nothingToOverride(declared)
}
}
}
private fun checkOverridesForMember(
memberDescriptor: CallableMemberDescriptor,
overriddenDescriptors: Collection<CallableMemberDescriptor>,
reportError: CheckOverrideReportStrategy
memberDescriptor: CallableMemberDescriptor,
overriddenDescriptors: Collection<CallableMemberDescriptor>,
reportError: CheckOverrideReportStrategy
) {
val propertyMemberDescriptor = if (memberDescriptor is PropertyDescriptor) memberDescriptor else null
@@ -769,8 +793,7 @@ class OverrideResolver(
if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) {
reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty)
}
}
else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
} else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden)
}
@@ -781,8 +804,8 @@ class OverrideResolver(
}
private fun isReturnTypeOkForOverride(
superDescriptor: CallableDescriptor,
subDescriptor: CallableDescriptor
superDescriptor: CallableDescriptor,
subDescriptor: CallableDescriptor
): Boolean {
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
@@ -796,8 +819,8 @@ class OverrideResolver(
}
private fun prepareTypeSubstitutor(
superDescriptor: CallableDescriptor,
subDescriptor: CallableDescriptor
superDescriptor: CallableDescriptor,
subDescriptor: CallableDescriptor
): TypeSubstitutor? {
val superTypeParameters = superDescriptor.typeParameters
val subTypeParameters = subDescriptor.typeParameters
@@ -812,8 +835,8 @@ class OverrideResolver(
}
private fun isPropertyTypeOkForOverride(
superDescriptor: PropertyDescriptor,
subDescriptor: PropertyDescriptor
superDescriptor: PropertyDescriptor,
subDescriptor: PropertyDescriptor
): Boolean {
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
@@ -821,8 +844,7 @@ class OverrideResolver(
return if (superDescriptor.isVar) {
KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.type, substitutedSuperReturnType)
}
else {
} else {
KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.type, substitutedSuperReturnType)
}
}
@@ -840,8 +862,8 @@ class OverrideResolver(
}
private fun findInvisibleOverriddenDescriptor(
declared: CallableMemberDescriptor,
declaringClass: ClassDescriptor
declared: CallableMemberDescriptor,
declaringClass: ClassDescriptor
): CallableMemberDescriptor? {
for (supertype in declaringClass.typeConstructor.supertypes) {
val all = Sets.newLinkedHashSet<CallableMemberDescriptor>()
@@ -850,8 +872,10 @@ class OverrideResolver(
for (fromSuper in all) {
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null).result == OVERRIDABLE) {
if (OverridingUtil.isVisibleForOverride(declared, fromSuper)) {
throw IllegalStateException("Descriptor " + fromSuper + " is overridable by " + declared +
" and visible but does not appear in its getOverriddenDescriptors()")
throw IllegalStateException(
"Descriptor " + fromSuper + " is overridable by " + declared +
" and visible but does not appear in its getOverriddenDescriptors()"
)
}
return fromSuper
}
@@ -861,12 +885,12 @@ class OverrideResolver(
}
fun shouldReportParameterNameOverrideWarning(
parameterFromSubclass: ValueParameterDescriptor,
parameterFromSuperclass: ValueParameterDescriptor
parameterFromSubclass: ValueParameterDescriptor,
parameterFromSuperclass: ValueParameterDescriptor
): Boolean {
return parameterFromSubclass.containingDeclaration.hasStableParameterNames() &&
parameterFromSuperclass.containingDeclaration.hasStableParameterNames() &&
parameterFromSuperclass.name != parameterFromSubclass.name
parameterFromSuperclass.containingDeclaration.hasStableParameterNames() &&
parameterFromSuperclass.name != parameterFromSubclass.name
}
private fun checkPropertyKind(descriptor: CallableMemberDescriptor, isVar: Boolean): Boolean {
@@ -32,7 +32,7 @@ interface TypeBinding<out P : PsiElement> : TypeHolder<TypeBinding<P>> {
override val arguments: List<TypeArgumentBinding<P>?>
}
interface TypeArgumentBinding<out P: PsiElement> : TypeHolderArgument<TypeBinding<P>>
interface TypeArgumentBinding<out P : PsiElement> : TypeHolderArgument<TypeBinding<P>>
fun KtTypeReference.createTypeBinding(trace: BindingContext): TypeBinding<KtTypeElement>? {
val type = trace[BindingContext.TYPE, this]
@@ -51,7 +51,7 @@ private fun createTypeBindingFromPsi(trace: BindingContext, psiElement: KtTypeEl
ExplicitTypeBinding(trace, psiElement, type)
}
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
val jetTypeReference = typeReference
if (jetTypeReference != null) return jetTypeReference.createTypeBinding(trace)
@@ -61,16 +61,16 @@ fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext):
return descriptor.returnType?.let { NoTypeElementBinding(trace, this, it) }
}
private class TypeArgumentBindingImpl<out P: PsiElement>(
override val projection: TypeProjection,
override val typeParameter: TypeParameterDescriptor?,
override val holder: TypeBinding<P>
private class TypeArgumentBindingImpl<out P : PsiElement>(
override val projection: TypeProjection,
override val typeParameter: TypeParameterDescriptor?,
override val holder: TypeBinding<P>
) : TypeArgumentBinding<P>
private class ExplicitTypeBinding(
private val trace: BindingContext,
override val psiElement: KtTypeElement,
override val type: KotlinType
private val trace: BindingContext,
override val psiElement: KtTypeElement,
override val type: KotlinType
) : TypeBinding<KtTypeElement> {
override val isInAbbreviation: Boolean get() = false
@@ -80,7 +80,7 @@ private class ExplicitTypeBinding(
assert(type.getAbbreviatedType() == null) { "Non-abbreviated type expected: $type" }
val isErrorBinding = run {
val sizeIsEqual = psiTypeArguments.size == type.arguments.size
&& psiTypeArguments.size == type.constructor.parameters.size
&& psiTypeArguments.size == type.constructor.parameters.size
type.isError || !sizeIsEqual
}
@@ -93,59 +93,57 @@ private class ExplicitTypeBinding(
val nextJetType = trace[BindingContext.TYPE, jetTypeReference] ?: return@map null
return@map TypeArgumentBindingImpl(
TypeProjectionImpl(nextJetType),
null,
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
TypeProjectionImpl(nextJetType),
null,
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
)
}
val typeProjection = type.arguments[index]
return@map TypeArgumentBindingImpl(
typeProjection,
type.constructor.parameters[index],
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
typeProjection,
type.constructor.parameters[index],
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
)
}
}
}
private class AbbreviatedTypeBinding(
override val type: KotlinType,
override val psiElement: KtTypeElement
): TypeBinding<KtTypeElement> {
override val type: KotlinType,
override val psiElement: KtTypeElement
) : TypeBinding<KtTypeElement> {
override val isInAbbreviation: Boolean get() = true
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
get() = createTypeArgumentBindingsWithSinglePsiElement(type) {
argumentType ->
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
AbbreviatedTypeBinding(argumentType, psiElement)
}
}
private class NoTypeElementBinding<out P : PsiElement>(
private val trace: BindingContext,
override val psiElement: P,
override val type: KotlinType
): TypeBinding<P> {
private val trace: BindingContext,
override val psiElement: P,
override val type: KotlinType
) : TypeBinding<P> {
override val isInAbbreviation: Boolean get() = false
override val arguments: List<TypeArgumentBinding<P>?>
get() = createTypeArgumentBindingsWithSinglePsiElement(type) {
argumentType ->
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
NoTypeElementBinding(trace, psiElement, argumentType)
}
}
internal fun <P : PsiElement> createTypeArgumentBindingsWithSinglePsiElement(
type: KotlinType,
createBinding: (KotlinType) -> TypeBinding<P>
) : List<TypeArgumentBinding<P>> {
type: KotlinType,
createBinding: (KotlinType) -> TypeBinding<P>
): List<TypeArgumentBinding<P>> {
val isErrorBinding = type.isError || type.constructor.parameters.size != type.arguments.size
return type.arguments.mapIndexed { index, typeProjection ->
TypeArgumentBindingImpl(
typeProjection,
if (isErrorBinding) null else type.constructor.parameters[index],
createBinding(typeProjection.type)
typeProjection,
if (isErrorBinding) null else type.constructor.parameters[index],
createBinding(typeProjection.type)
)
}
}
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.types.KotlinType
class VariableAsPropertyInfo(
val propertyGetter: KtPropertyAccessor?,
val propertySetter: KtPropertyAccessor?,
val variableType: KotlinType?,
val hasBody: Boolean,
val hasDelegate: Boolean
val propertyGetter: KtPropertyAccessor?,
val propertySetter: KtPropertyAccessor?,
val variableType: KotlinType?,
val hasBody: Boolean,
val hasDelegate: Boolean
) {
companion object {
fun createFromDestructuringDeclarationEntry(type: KotlinType): VariableAsPropertyInfo {
@@ -114,7 +114,7 @@ class VariableTypeAndInitializerResolver(
if (!variable.hasInitializer() || variable.isVar) return
variableDescriptor.setCompileTimeInitializer(
storageManager.createRecursionTolerantNullableLazyValue(
computeInitializer@{
computeInitializer@ {
if (!DescriptorUtils.shouldRecordInitializerForProperty(
variableDescriptor,
variableType
@@ -57,19 +57,19 @@ import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
import java.util.*
class CallCompleter(
private val argumentTypeResolver: ArgumentTypeResolver,
private val candidateResolver: CandidateResolver,
private val dataFlowAnalyzer: DataFlowAnalyzer,
private val callCheckers: Iterable<CallChecker>,
private val builtIns: KotlinBuiltIns,
private val languageVersionSettings: LanguageVersionSettings,
private val deprecationResolver: DeprecationResolver,
private val effectSystem: EffectSystem
private val argumentTypeResolver: ArgumentTypeResolver,
private val candidateResolver: CandidateResolver,
private val dataFlowAnalyzer: DataFlowAnalyzer,
private val callCheckers: Iterable<CallChecker>,
private val builtIns: KotlinBuiltIns,
private val languageVersionSettings: LanguageVersionSettings,
private val deprecationResolver: DeprecationResolver,
private val effectSystem: EffectSystem
) {
fun <D : CallableDescriptor> completeCall(
context: BasicCallResolutionContext,
results: OverloadResolutionResultsImpl<D>,
tracing: TracingStrategy
context: BasicCallResolutionContext,
results: OverloadResolutionResultsImpl<D>,
tracing: TracingStrategy
): OverloadResolutionResultsImpl<D> {
val resolvedCall = if (results.isSingleResult) results.resultingCall else null
@@ -87,8 +87,8 @@ class CallCompleter(
else
resolvedCall.call.calleeExpression
val reportOn =
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
else resolvedCall.call.callElement
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
else resolvedCall.call.callElement
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, deprecationResolver)
for (callChecker in callCheckers) {
@@ -107,30 +107,34 @@ class CallCompleter(
}
private fun <D : CallableDescriptor> completeAllCandidates(
context: BasicCallResolutionContext,
results: OverloadResolutionResultsImpl<D>
context: BasicCallResolutionContext,
results: OverloadResolutionResultsImpl<D>
) {
@Suppress("UNCHECKED_CAST")
val candidates = (if (context.collectAllCandidates) {
results.allCandidates!!
}
else {
} else {
results.resultingCalls
}) as Collection<MutableResolvedCall<D>>
val temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach {
resolvedCall ->
val temporaryBindingTrace =
TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach { resolvedCall ->
completeResolvedCallAndArguments(resolvedCall, results, context.replaceBindingTrace(temporaryBindingTrace), TracingStrategy.EMPTY)
completeResolvedCallAndArguments(
resolvedCall,
results,
context.replaceBindingTrace(temporaryBindingTrace),
TracingStrategy.EMPTY
)
}
}
private fun <D : CallableDescriptor> completeResolvedCallAndArguments(
resolvedCall: MutableResolvedCall<D>?,
results: OverloadResolutionResultsImpl<D>,
context: BasicCallResolutionContext,
tracing: TracingStrategy
resolvedCall: MutableResolvedCall<D>?,
results: OverloadResolutionResultsImpl<D>,
context: BasicCallResolutionContext,
tracing: TracingStrategy
) {
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
completeArguments(context, results)
@@ -149,24 +153,23 @@ class CallCompleter(
}
private fun <D : CallableDescriptor> MutableResolvedCall<D>.completeConstraintSystem(
expectedType: KotlinType,
trace: BindingTrace
expectedType: KotlinType,
trace: BindingTrace
) {
val returnType = candidateDescriptor.returnType
val expectedReturnType =
if (call.isCallableReference()) {
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
else TypeUtils.NO_EXPECTED_TYPE
}
else expectedType
if (call.isCallableReference()) {
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
else TypeUtils.NO_EXPECTED_TYPE
} else expectedType
fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? =
type?.let {
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
substitutor.substitute(it, Variance.INVARIANT)
}
type?.let {
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
substitutor.substitute(it, Variance.INVARIANT)
}
fun updateSystemIfNeeded(buildSystemWithAdditionalConstraints: (ConstraintSystem.Builder) -> ConstraintSystem?) {
val system = buildSystemWithAdditionalConstraints(constraintSystem!!.toBuilder())
@@ -181,8 +184,7 @@ class CallCompleter(
if (returnTypeInSystem != null) {
builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position())
builder.build()
}
else null
} else null
}
}
@@ -206,17 +208,21 @@ class CallCompleter(
builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position())
val system = builder.build()
if (system.status.isSuccessful()) system else null
}
else null
} else null
}
}
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
updateSystemIfNeeded { builder ->
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType()).forEach { (parameter, argument) ->
val valueParameterInSystem = builder.typeInSystem(parameter.type)
builder.addSubtypeConstraint(valueParameterInSystem, argument.type, VALUE_PARAMETER_POSITION.position(parameter.index))
}
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType())
.forEach { (parameter, argument) ->
val valueParameterInSystem = builder.typeInSystem(parameter.type)
builder.addSubtypeConstraint(
valueParameterInSystem,
argument.type,
VALUE_PARAMETER_POSITION.position(parameter.index)
)
}
builder.build()
}
@@ -231,8 +237,8 @@ class CallCompleter(
}
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
context: BasicCallResolutionContext,
tracing: TracingStrategy
context: BasicCallResolutionContext,
tracing: TracingStrategy
) {
val contextWithResolvedCall = CallCandidateResolutionContext.createForCallBeingAnalyzed(this, context, tracing)
val valueArgumentsCheckingResult = candidateResolver.checkAllValueArguments(contextWithResolvedCall, RESOLVE_FUNCTION_ARGUMENTS)
@@ -248,8 +254,8 @@ class CallCompleter(
val receiverType = extensionReceiver?.type
val errorData = InferenceErrorData.create(
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
receiverType, context.expectedType, context.call
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
receiverType, context.expectedType, context.call
)
tracing.typeInferenceFailed(context, errorData)
@@ -257,8 +263,8 @@ class CallCompleter(
}
private fun <D : CallableDescriptor> completeArguments(
context: BasicCallResolutionContext,
results: OverloadResolutionResultsImpl<D>
context: BasicCallResolutionContext,
results: OverloadResolutionResultsImpl<D>
) {
if (context.checkArguments != CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) return
@@ -268,8 +274,7 @@ class CallCompleter(
val resolvedCall = results.resultingCall
getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) }
getDataFlowInfoForArgument = { argument -> resolvedCall.dataFlowInfoForArguments.getInfo(argument) }
}
else {
} else {
getArgumentMapping = { ArgumentUnmapped }
getDataFlowInfoForArgument = { context.dataFlowInfo }
}
@@ -278,21 +283,22 @@ class CallCompleter(
val argumentMapping = getArgumentMapping(valueArgument!!)
val (expectedType, callPosition) = when (argumentMapping) {
is ArgumentMatch -> Pair(
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument))
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument)
)
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
}
val newContext =
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
.replaceExpectedType(expectedType)
.replaceCallPosition(callPosition)
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
.replaceExpectedType(expectedType)
.replaceCallPosition(callPosition)
completeOneArgument(valueArgument, newContext)
}
}
private fun completeOneArgument(
valueArgument: ValueArgument,
context: BasicCallResolutionContext
valueArgument: ValueArgument,
context: BasicCallResolutionContext
) {
if (valueArgument.isExternal()) return
@@ -307,8 +313,7 @@ class CallCompleter(
val resolvedCall = results.resultingCall
updatedType = if (resolvedCall.hasInferredReturnType()) {
resolvedCall.makeNullableTypeIfSafeReceiver(resolvedCall.resultingDescriptor?.returnType, context)
}
else null
} else null
}
// For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.),
@@ -336,24 +341,24 @@ class CallCompleter(
}
private fun completeCallForArgument(
expression: KtExpression,
context: BasicCallResolutionContext
expression: KtExpression,
context: BasicCallResolutionContext
): OverloadResolutionResultsImpl<*>? {
val cachedData = getResolutionResultsCachedData(expression, context) ?: return null
val (cachedResolutionResults, cachedContext, tracing) = cachedData
val contextForArgument = cachedContext.replaceBindingTrace(context.trace)
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false).replaceCallPosition(context.callPosition)
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false).replaceCallPosition(context.callPosition)
return completeCall(contextForArgument, cachedResolutionResults, tracing)
}
private fun updateRecordedTypeForArgument(
updatedType: KotlinType?,
recordedType: KotlinType?,
argumentExpression: KtExpression,
statementFilter: StatementFilter,
trace: BindingTrace
updatedType: KotlinType?,
recordedType: KotlinType?,
argumentExpression: KtExpression,
statementFilter: StatementFilter,
trace: BindingTrace
): KotlinType? {
//workaround for KT-8218
if ((!ErrorUtils.containsErrorType(recordedType) && recordedType == updatedType) || updatedType == null) return updatedType
@@ -67,13 +67,13 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
import javax.inject.Inject
class CallExpressionResolver(
private val callResolver: CallResolver,
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
private val argumentTypeResolver: ArgumentTypeResolver,
private val dataFlowAnalyzer: DataFlowAnalyzer,
private val builtIns: KotlinBuiltIns,
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
private val languageVersionSettings: LanguageVersionSettings
private val callResolver: CallResolver,
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
private val argumentTypeResolver: ArgumentTypeResolver,
private val dataFlowAnalyzer: DataFlowAnalyzer,
private val builtIns: KotlinBuiltIns,
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
private val languageVersionSettings: LanguageVersionSettings
) {
private lateinit var expressionTypingServices: ExpressionTypingServices
@@ -84,13 +84,16 @@ class CallExpressionResolver(
}
private fun getResolvedCallForFunction(
call: Call,
context: ResolutionContext<*>,
checkArguments: CheckArgumentTypesMode,
initialDataFlowInfoForArguments: DataFlowInfo
call: Call,
context: ResolutionContext<*>,
checkArguments: CheckArgumentTypesMode,
initialDataFlowInfoForArguments: DataFlowInfo
): Pair<Boolean, ResolvedCall<FunctionDescriptor>?> {
val results = callResolver.resolveFunctionCall(BasicCallResolutionContext.create(
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)))
val results = callResolver.resolveFunctionCall(
BasicCallResolutionContext.create(
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
)
)
return if (!results.isNothing)
Pair(true, OverloadResolutionResultsUtil.getResultingCall(results, context))
else
@@ -98,23 +101,25 @@ class CallExpressionResolver(
}
private fun getVariableType(
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext
): Pair<Boolean, KotlinType?> {
val temporaryForVariable = TemporaryTraceAndCache.create(
context, "trace to resolve as local variable or property", nameExpression)
context, "trace to resolve as local variable or property", nameExpression
)
val call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression)
val contextForVariable = BasicCallResolutionContext.create(
context.replaceTraceAndCache(temporaryForVariable),
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS)
context.replaceTraceAndCache(temporaryForVariable),
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
)
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
// if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
val isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression)
if (!resolutionResult.isNothing && resolutionResult.resultCode != CANDIDATES_WITH_WRONG_RECEIVER) {
val isQualifier = isLHSOfDot &&
resolutionResult.isSingleResult &&
resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject
resolutionResult.isSingleResult &&
resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject
if (!isQualifier) {
temporaryForVariable.commit()
return Pair(true, if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
@@ -122,25 +127,30 @@ class CallExpressionResolver(
}
temporaryForVariable.commit()
return Pair(!resolutionResult.isNothing,
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
return Pair(
!resolutionResult.isNothing,
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null
)
}
fun getSimpleNameExpressionTypeInfo(
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext
) = getSimpleNameExpressionTypeInfo(nameExpression, receiver, callOperationNode, context, context.dataFlowInfo)
private fun getSimpleNameExpressionTypeInfo(
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext,
initialDataFlowInfoForArguments: DataFlowInfo
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext,
initialDataFlowInfoForArguments: DataFlowInfo
): KotlinTypeInfo {
val temporaryForVariable = TemporaryTraceAndCache.create(
context, "trace to resolve as variable", nameExpression)
val (notNothing, type) = getVariableType(nameExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable))
context, "trace to resolve as variable", nameExpression
)
val (notNothing, type) = getVariableType(
nameExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable)
)
if (notNothing) {
temporaryForVariable.commit()
@@ -149,10 +159,12 @@ class CallExpressionResolver(
val call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, emptyList())
val temporaryForFunction = TemporaryTraceAndCache.create(
context, "trace to resolve as function", nameExpression)
context, "trace to resolve as function", nameExpression
)
val newContext = context.replaceTraceAndCache(temporaryForFunction)
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments)
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments
)
if (resolveResult) {
val functionDescriptor = resolvedCall?.resultingDescriptor
if (functionDescriptor !is ConstructorDescriptor) {
@@ -173,11 +185,12 @@ class CallExpressionResolver(
}
fun getCallExpressionTypeInfo(
callExpression: KtCallExpression, receiver: ReceiverValue?,
callOperationNode: ASTNode?, context: ExpressionTypingContext
callExpression: KtCallExpression, receiver: ReceiverValue?,
callOperationNode: ASTNode?, context: ExpressionTypingContext
): KotlinTypeInfo {
val typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
callExpression, receiver, callOperationNode, context, context.dataFlowInfo)
callExpression, receiver, callOperationNode, context, context.dataFlowInfo
)
if (context.contextDependency == INDEPENDENT) {
dataFlowAnalyzer.checkType(typeInfo.type, callExpression, context)
}
@@ -189,19 +202,21 @@ class CallExpressionResolver(
* Determines the result type and data flow information after the call.
*/
private fun getCallExpressionTypeInfoWithoutFinalTypeCheck(
callExpression: KtCallExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext,
initialDataFlowInfoForArguments: DataFlowInfo
callExpression: KtCallExpression, receiver: Receiver?,
callOperationNode: ASTNode?, context: ExpressionTypingContext,
initialDataFlowInfoForArguments: DataFlowInfo
): KotlinTypeInfo {
val call = CallMaker.makeCall(receiver, callOperationNode, callExpression)
val temporaryForFunction = TemporaryTraceAndCache.create(
context, "trace to resolve as function call", callExpression)
context, "trace to resolve as function call", callExpression
)
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
call,
context.replaceTraceAndCache(temporaryForFunction),
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
initialDataFlowInfoForArguments)
call,
context.replaceTraceAndCache(temporaryForFunction),
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
initialDataFlowInfoForArguments
)
if (resolveResult) {
val functionDescriptor = resolvedCall?.resultingDescriptor
temporaryForFunction.commit()
@@ -246,9 +261,12 @@ class CallExpressionResolver(
val calleeExpression = callExpression.calleeExpression
if (calleeExpression is KtSimpleNameExpression && callExpression.typeArgumentList == null) {
val temporaryForVariable = TemporaryTraceAndCache.create(
context, "trace to resolve as variable with 'invoke' call", callExpression)
val (notNothing, type) = getVariableType(calleeExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable))
context, "trace to resolve as variable with 'invoke' call", callExpression
)
val (notNothing, type) = getVariableType(
calleeExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable)
)
val qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression)
if (notNothing && (qualifier == null || qualifier !is PackageQualifier)) {
@@ -258,14 +276,18 @@ class CallExpressionResolver(
}
temporaryForVariable.commit()
context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
type ?: ErrorUtils.createErrorType("")))
context.trace.report(
FUNCTION_EXPECTED.on(
calleeExpression, calleeExpression,
type ?: ErrorUtils.createErrorType("")
)
)
argumentTypeResolver.analyzeArgumentsAndRecordTypes(
BasicCallResolutionContext.create(
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
),
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
BasicCallResolutionContext.create(
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
),
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
)
return noTypeInfo(context)
}
@@ -275,41 +297,41 @@ class CallExpressionResolver(
}
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
nameExpression ->
val resolutionResult = resolveSimpleName(context, nameExpression)
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) { nameExpression ->
val resolutionResult = resolveSimpleName(context, nameExpression)
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
false
}
else when (resolutionResult.resultCode) {
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
}
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
false
} else when (resolutionResult.resultCode) {
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
}
}
private fun resolveSimpleName(
context: ExpressionTypingContext, expression: KtSimpleNameExpression
context: ExpressionTypingContext, expression: KtSimpleNameExpression
): OverloadResolutionResults<VariableDescriptor> {
val temporaryForVariable = TemporaryTraceAndCache.create(context, "trace to resolve as local variable or property", expression)
val call = CallMaker.makePropertyCall(null, null, expression)
val contextForVariable = BasicCallResolutionContext.create(
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
)
return callResolver.resolveSimpleProperty(contextForVariable)
}
private fun getUnsafeSelectorTypeInfo(
receiver: Receiver,
callOperationNode: ASTNode?,
selectorExpression: KtExpression?,
context: ExpressionTypingContext,
initialDataFlowInfoForArguments: DataFlowInfo
receiver: Receiver,
callOperationNode: ASTNode?,
selectorExpression: KtExpression?,
context: ExpressionTypingContext,
initialDataFlowInfoForArguments: DataFlowInfo
): KotlinTypeInfo = when (selectorExpression) {
is KtCallExpression -> getCallExpressionTypeInfoWithoutFinalTypeCheck(
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments)
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
)
is KtSimpleNameExpression -> getSimpleNameExpressionTypeInfo(
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments)
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
)
is KtExpression -> {
expressionTypingServices.getTypeInfo(selectorExpression, context)
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression))
@@ -323,14 +345,14 @@ class CallExpressionResolver(
var initialDataFlowInfoForArguments = context.dataFlowInfo
val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) }
val receiverCanBeNull = receiverDataFlowValue != null &&
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
if (receiverDataFlowValue != null && element.safe) {
// Additional "receiver != null" information should be applied if we consider a safe call
if (receiverCanBeNull) {
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings)
}
else if (receiver is ReceiverValue) {
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings
)
} else if (receiver is ReceiverValue) {
reportUnnecessarySafeCall(context.trace, receiver.type, element.node, receiver)
}
}
@@ -361,8 +383,7 @@ class CallExpressionResolver(
val value = constantExpressionEvaluator.evaluateExpression(qualified, context.trace, context.expectedType)
return if (value != null && value.isPure) {
dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, qualified, context)
}
else {
} else {
if (context.contextDependency == INDEPENDENT) {
dataFlowAnalyzer.checkType(selectorTypeInfo.type, qualified, context)
}
@@ -409,20 +430,19 @@ class CallExpressionResolver(
val receiverType = receiverTypeInfo.type ?: ErrorUtils.createErrorType("Type for " + element.receiver.text)
val receiver = trace.get(BindingContext.QUALIFIER, element.receiver)
?: ExpressionReceiver.create(element.receiver, receiverType, trace.bindingContext)
?: ExpressionReceiver.create(element.receiver, receiverType, trace.bindingContext)
val qualifiedExpression = element.qualified
val lastStage = qualifiedExpression === expression
// Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage
val contextForSelector = (if (lastStage) context else currentContext).replaceDataFlowInfo(
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
// Call with nullable receiver: take data flow info from branch point
branchPointDataFlowInfo
}
else {
// Take data flow info from the current receiver
receiverTypeInfo.dataFlowInfo
}
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
// Call with nullable receiver: take data flow info from branch point
branchPointDataFlowInfo
} else {
// Take data flow info from the current receiver
receiverTypeInfo.dataFlowInfo
}
)
val selectorTypeInfo = getSafeOrUnsafeSelectorTypeInfo(receiver, element, contextForSelector)
@@ -432,8 +452,9 @@ class CallExpressionResolver(
branchPointDataFlowInfo = selectorTypeInfo.dataFlowInfo
}
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).
replaceDataFlowInfo(branchPointDataFlowInfo)
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).replaceDataFlowInfo(
branchPointDataFlowInfo
)
if (!lastStage) {
recordResultTypeInfo(qualifiedExpression, resultTypeInfo, contextForSelector)
}
@@ -444,9 +465,9 @@ class CallExpressionResolver(
}
private fun resolveDeferredReceiverInQualifiedExpression(
qualifier: Qualifier,
selectorExpression: KtExpression?,
context: ExpressionTypingContext
qualifier: Qualifier,
selectorExpression: KtExpression?,
context: ExpressionTypingContext
) {
val calleeExpression = KtPsiUtil.deparenthesize(selectorExpression.getCalleeExpressionIfAny())
val selectorDescriptor = (calleeExpression as? KtReferenceExpression)?.let {
@@ -469,33 +490,31 @@ class CallExpressionResolver(
if (parent != null) {
return isUnderAnnotationClassDeclaration(trace, parent)
}
}
else if (parent is KtParameter) {
} else if (parent is KtParameter) {
return isUnderAnnotationClassDeclaration(trace, parent)
}
return false
}
private fun isUnderAnnotationClassDeclaration(trace: BindingTrace, parent: PsiElement) =
parent.getParentOfType<KtClass>(true)?.let {
DescriptorUtils.isAnnotationClass(trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, it))
} ?: false
parent.getParentOfType<KtClass>(true)?.let {
DescriptorUtils.isAnnotationClass(trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, it))
} ?: false
fun reportUnnecessarySafeCall(
trace: BindingTrace, type: KotlinType,
callOperationNode: ASTNode, explicitReceiver: Receiver?
trace: BindingTrace, type: KotlinType,
callOperationNode: ASTNode, explicitReceiver: Receiver?
) = trace.report(
if (explicitReceiver is ExpressionReceiver && explicitReceiver.expression is KtSuperExpression) {
UNEXPECTED_SAFE_CALL.on(callOperationNode.psi)
}
else {
} else {
UNNECESSARY_SAFE_CALL.on(callOperationNode.psi, type)
}
)
private fun checkNestedClassAccess(
expression: KtQualifiedExpression,
context: ExpressionTypingContext
expression: KtQualifiedExpression,
context: ExpressionTypingContext
) {
val selectorExpression = expression.selectorExpression ?: return
@@ -80,13 +80,13 @@ fun replaceReturnTypeForCallable(type: KotlinType, given: KotlinType): KotlinTyp
fun replaceReturnTypeByUnknown(type: KotlinType) = replaceReturnTypeForCallable(type, DONT_CARE)
private fun replaceTypeArguments(type: KotlinType, newArguments: List<TypeProjection>) =
KotlinTypeFactory.simpleType(type.annotations, type.constructor, newArguments, type.isMarkedNullable)
KotlinTypeFactory.simpleType(type.annotations, type.constructor, newArguments, type.isMarkedNullable)
private fun getParameterArgumentsOfCallableType(type: KotlinType) =
type.arguments.dropLast(1)
type.arguments.dropLast(1)
fun getReturnTypeForCallable(type: KotlinType) =
type.arguments.last().type
type.arguments.last().type
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
val returnType = returnType ?: return false
@@ -125,8 +125,10 @@ fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescript
receiverType.constructor
}
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true))
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true)
)
}
fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boolean {
@@ -163,7 +165,7 @@ fun isInfixCall(call: Call): Boolean {
}
fun isSuperOrDelegatingConstructorCall(call: Call): Boolean =
call.calleeExpression.let { it is KtConstructorCalleeExpression || it is KtConstructorDelegationReferenceExpression }
call.calleeExpression.let { it is KtConstructorCalleeExpression || it is KtConstructorDelegationReferenceExpression }
fun isInvokeCallOnVariable(call: Call): Boolean {
if (call.callType !== Call.CallType.INVOKE) return false
@@ -183,9 +185,9 @@ fun getSuperCallExpression(call: Call): KtSuperExpression? {
}
fun getEffectiveExpectedType(
parameterDescriptor: ValueParameterDescriptor,
argument: ValueArgument,
context: ResolutionContext<*>
parameterDescriptor: ValueParameterDescriptor,
argument: ValueArgument,
context: ResolutionContext<*>
): KotlinType {
if (argument.getSpreadElement() != null || shouldCheckAsArray(parameterDescriptor, argument, context)) {
if (parameterDescriptor.varargElementType == null) {
@@ -203,9 +205,9 @@ fun getEffectiveExpectedType(
}
private fun shouldCheckAsArray(
parameterDescriptor: ValueParameterDescriptor,
argument: ValueArgument,
context: ResolutionContext<*>
parameterDescriptor: ValueParameterDescriptor,
argument: ValueArgument,
context: ResolutionContext<*>
): Boolean {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
@@ -223,29 +225,30 @@ fun isArrayOrArrayLiteral(argument: ValueArgument, context: ResolutionContext<*>
}
fun createResolutionCandidatesForConstructors(
lexicalScope: LexicalScope,
call: Call,
typeWithConstructors: KotlinType,
useKnownTypeSubstitutor: Boolean,
syntheticScopes: SyntheticScopes
lexicalScope: LexicalScope,
call: Call,
typeWithConstructors: KotlinType,
useKnownTypeSubstitutor: Boolean,
syntheticScopes: SyntheticScopes
): List<ResolutionCandidate<ConstructorDescriptor>> {
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
val unwrappedType = typeWithConstructors.unwrap()
val knownSubstitutor =
if (useKnownTypeSubstitutor)
TypeSubstitutor.create(
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
)
else null
if (useKnownTypeSubstitutor)
TypeSubstitutor.create(
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
)
else null
val typeAliasDescriptor =
if (unwrappedType is AbbreviatedType)
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
else
null
if (unwrappedType is AbbreviatedType)
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
else
null
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver) ?: classWithConstructors.constructors
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver)
?: classWithConstructors.constructors
if (constructors.isEmpty()) return emptyList()
@@ -262,8 +265,7 @@ fun createResolutionCandidatesForConstructors(
receiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
dispatchReceiver = receiver.value
}
else {
} else {
receiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
dispatchReceiver = null
}
@@ -276,12 +278,12 @@ fun createResolutionCandidatesForConstructors(
}
fun KtLambdaExpression.getCorrespondingParameterForFunctionArgument(
bindingContext: BindingContext
bindingContext: BindingContext
): ValueParameterDescriptor? {
val resolvedCall = KtPsiUtil.getParentCallIfPresent(this)?.getResolvedCall(bindingContext) ?: return null
val valueArgument =
resolvedCall.call.getValueArgumentForExpression(this)
?: return null
resolvedCall.call.getValueArgumentForExpression(this)
?: return null
val mapping = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return null
return mapping.valueParameter
@@ -57,15 +57,15 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import java.util.*
class CandidateResolver(
private val argumentTypeResolver: ArgumentTypeResolver,
private val genericCandidateResolver: GenericCandidateResolver,
private val reflectionTypes: ReflectionTypes,
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
private val smartCastManager: SmartCastManager
private val argumentTypeResolver: ArgumentTypeResolver,
private val genericCandidateResolver: GenericCandidateResolver,
private val reflectionTypes: ReflectionTypes,
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
private val smartCastManager: SmartCastManager
) {
fun <D : CallableDescriptor> performResolutionForCandidateCall(
context: CallCandidateResolutionContext<D>,
checkArguments: CheckArgumentTypesMode
context: CallCandidateResolutionContext<D>,
checkArguments: CheckArgumentTypesMode
): Unit = with(context) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
@@ -107,8 +107,7 @@ class CandidateResolver(
&& candidateCall.knownTypeParametersSubstitutor == null
) {
genericCandidateResolver.inferTypeArguments(this)
}
else {
} else {
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
}
}
@@ -117,8 +116,7 @@ class CandidateResolver(
val ktTypeArguments = call.typeArguments
if (candidateCall.knownTypeParametersSubstitutor != null) {
candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
}
else if (ktTypeArguments.isNotEmpty()) {
} else if (ktTypeArguments.isNotEmpty()) {
// Explicit type arguments passed
val typeArguments = ArrayList<KotlinType>()
@@ -130,9 +128,11 @@ class CandidateResolver(
val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size
for (index in ktTypeArguments.size..expectedTypeArgumentCount - 1) {
typeArguments.add(ErrorUtils.createErrorType(
typeArguments.add(
ErrorUtils.createErrorType(
"Explicit type argument expected for " + candidateDescriptor.typeParameters[index].name
))
)
)
}
val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments)
val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution))
@@ -140,8 +140,7 @@ class CandidateResolver(
if (expectedTypeArgumentCount != ktTypeArguments.size) {
candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR)
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor)
}
else {
} else {
checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
}
@@ -149,31 +148,30 @@ class CandidateResolver(
}
}
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments()
= check {
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
call, tracing, candidateCall)
if (!argumentMappingStatus.isSuccess) {
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
}
}
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments() = check {
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
call, tracing, candidateCall
)
if (!argumentMappingStatus.isSuccess) {
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
}
}
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType()
= check {
if (!noExpectedType(expectedType)) {
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
candidateCall.candidateDescriptor,
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
},
reflectionTypes, scope.ownerDescriptor
)
if (candidateKCallableType == null ||
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
candidateCall.addStatus(OTHER_ERROR)
}
}
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType() = check {
if (!noExpectedType(expectedType)) {
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
candidateCall.candidateDescriptor,
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
},
reflectionTypes, scope.ownerDescriptor
)
if (candidateKCallableType == null ||
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
candidateCall.addStatus(OTHER_ERROR)
}
}
}
private fun canBeSubtype(subType: KotlinType, superType: KotlinType, candidateTypeParameters: List<TypeParameterDescriptor>): Boolean {
// Here we need to check that there exists a substitution from type parameters (used in types in candidate signature)
@@ -191,11 +189,12 @@ class CandidateResolver(
}
private fun CallCandidateResolutionContext<*>.checkVisibilityWithDispatchReceiver(
receiverArgument: ReceiverValue?,
smartCastType: KotlinType?
receiverArgument: ReceiverValue?,
smartCastType: KotlinType?
): ResolutionStatus {
val invisibleMember = Visibilities.findInvisibleMember(
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor)
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor
)
return if (invisibleMember != null) {
tracing.invisibleMember(trace, invisibleMember)
INVISIBLE_MEMBER_ERROR
@@ -205,17 +204,17 @@ class CandidateResolver(
}
private fun CallCandidateResolutionContext<*>.isCandidateVisibleOrExtensionReceiver(
receiverArgument: ReceiverValue?,
smartCastType: KotlinType?,
isDispatchReceiver: Boolean
receiverArgument: ReceiverValue?,
smartCastType: KotlinType?,
isDispatchReceiver: Boolean
) = !isDispatchReceiver || isCandidateVisible(receiverArgument, smartCastType)
private fun CallCandidateResolutionContext<*>.isCandidateVisible(
receiverArgument: ReceiverValue?,
smartCastType: KotlinType?
receiverArgument: ReceiverValue?,
smartCastType: KotlinType?
) = Visibilities.findInvisibleMember(
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
candidateDescriptor, scope.ownerDescriptor
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
candidateDescriptor, scope.ownerDescriptor
) == null
private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport {
@@ -224,17 +223,14 @@ class CandidateResolver(
if (receiverParameter != null && receiverArgument == null) {
tracing.missingReceiver(candidateCall.trace, receiverParameter)
OTHER_ERROR
}
else if (receiverParameter == null && receiverArgument != null) {
} else if (receiverParameter == null && receiverArgument != null) {
tracing.noReceiverAllowed(candidateCall.trace)
if (call.calleeExpression is KtSimpleNameExpression) {
RECEIVER_PRESENCE_ERROR
}
else {
} else {
OTHER_ERROR
}
}
else {
} else {
SUCCESS
}
}
@@ -248,8 +244,7 @@ class CandidateResolver(
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration)
) {
nestedClass = candidateDescriptor.containingDeclaration
}
else if (candidateDescriptor is FakeCallableDescriptorForObject) {
} else if (candidateDescriptor is FakeCallableDescriptorForObject) {
nestedClass = candidateDescriptor.getReferencedObject()
}
if (nestedClass != null) {
@@ -341,8 +336,9 @@ class CandidateResolver(
}
fun <D : CallableDescriptor> checkAllValueArguments(
context: CallCandidateResolutionContext<D>,
resolveFunctionArgumentBodies: ResolveArgumentsMode): ValueArgumentsCheckingResult {
context: CallCandidateResolutionContext<D>,
resolveFunctionArgumentBodies: ResolveArgumentsMode
): ValueArgumentsCheckingResult {
val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies)
var resultStatus = checkingResult.status
resultStatus = resultStatus.combine(checkReceivers(context))
@@ -351,9 +347,9 @@ class CandidateResolver(
}
private fun <D : CallableDescriptor, C : CallResolutionContext<C>> checkValueArgumentTypes(
context: CallResolutionContext<C>,
candidateCall: MutableResolvedCall<D>,
resolveFunctionArgumentBodies: ResolveArgumentsMode
context: CallResolutionContext<C>,
candidateCall: MutableResolvedCall<D>,
resolveFunctionArgumentBodies: ResolveArgumentsMode
): ValueArgumentsCheckingResult {
var resultStatus = SUCCESS
val argumentTypes = Lists.newArrayList<KotlinType>()
@@ -373,27 +369,26 @@ class CandidateResolver(
var resultingType: KotlinType? = type
if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
}
else if (!noExpectedType(expectedType)) {
} else if (!noExpectedType(expectedType)) {
if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
if (smartCast == null) {
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
}
else {
} else {
resultingType = smartCast
}
}
else if (ErrorUtils.containsUninferredParameter(expectedType)) {
} else if (ErrorUtils.containsUninferredParameter(expectedType)) {
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
}
val spreadElement = argument.getSpreadElement()
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context,
call = null, recordExpressionType = false)
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, expectedType, expression, context,
call = null, recordExpressionType = false
)
if (smartCastResult == null || !smartCastResult.isCorrect) {
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
}
@@ -407,10 +402,10 @@ class CandidateResolver(
}
private fun smartCastValueArgumentTypeIfPossible(
expression: KtExpression,
expectedType: KotlinType,
actualType: KotlinType,
context: ResolutionContext<*>
expression: KtExpression,
expectedType: KotlinType,
actualType: KotlinType,
context: ResolutionContext<*>
): KotlinType? {
val receiverToCast = ExpressionReceiver.create(KtPsiUtil.safeDeparenthesize(expression), actualType, context.trace.bindingContext)
val variants = smartCastManager.getSmartCastVariantsExcludingReceiver(context, receiverToCast)
@@ -440,8 +435,8 @@ class CandidateResolver(
}
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(
receiverParameterDescriptor: ReceiverParameterDescriptor?,
receiverArgument: ReceiverValue?
receiverParameterDescriptor: ReceiverParameterDescriptor?,
receiverArgument: ReceiverValue?
) = checkAndReport {
if (receiverParameterDescriptor == null || receiverArgument == null) return@checkAndReport SUCCESS
@@ -463,42 +458,48 @@ class CandidateResolver(
// both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
// Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
resultStatus = resultStatus.combine(context.checkReceiver(
resultStatus = resultStatus.combine(
context.checkReceiver(
candidateCall,
candidateCall.resultingDescriptor.extensionReceiverParameter,
candidateCall.extensionReceiver,
candidateCall.explicitReceiverKind.isExtensionReceiver,
implicitInvokeCheck = false, isDispatchReceiver = false
))
)
)
resultStatus = resultStatus.combine(context.checkReceiver(
resultStatus = resultStatus.combine(
context.checkReceiver(
candidateCall,
candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver,
candidateCall.explicitReceiverKind.isDispatchReceiver,
// for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
implicitInvokeCheck = context.call is CallForImplicitInvoke,
isDispatchReceiver = true
))
)
)
if (!context.isDebuggerContext
&& candidateCall.dispatchReceiver != null
// Do not report error if it's already reported when checked without receiver
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
&& candidateCall.dispatchReceiver != null
// Do not report error if it's already reported when checked without receiver
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
resultStatus = resultStatus.combine(
context.checkVisibilityWithDispatchReceiver(
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType))
context.checkVisibilityWithDispatchReceiver(
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType
)
)
}
return resultStatus
}
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkReceiver(
candidateCall: MutableResolvedCall<D>,
receiverParameter: ReceiverParameterDescriptor?,
receiverArgument: ReceiverValue?,
isExplicitReceiver: Boolean,
implicitInvokeCheck: Boolean,
isDispatchReceiver: Boolean
candidateCall: MutableResolvedCall<D>,
receiverParameter: ReceiverParameterDescriptor?,
receiverArgument: ReceiverValue?,
isExplicitReceiver: Boolean,
implicitInvokeCheck: Boolean,
isDispatchReceiver: Boolean
): ResolutionStatus {
if (receiverParameter == null || receiverArgument == null) return SUCCESS
val candidateDescriptor = candidateCall.candidateDescriptor
@@ -513,14 +514,15 @@ class CandidateResolver(
val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
if (smartCastSubtypingResult == null) {
tracing.wrongReceiverType(
trace, receiverParameter, receiverArgument,
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall)))
trace, receiverParameter, receiverArgument,
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))
)
return OTHER_ERROR
}
val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK
val smartCastNeeded =
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
var reportUnsafeCall = false
var nullableImplicitInvokeReceiver = false
@@ -547,26 +549,23 @@ class CandidateResolver(
if (dataFlowValue.immanentNullability.canBeNonNull()) {
expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) }
}
}
else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
} else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
// Look if smart cast has some useful nullability info
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, expectedReceiverParameterType,
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
expression, this, candidateCall.call, recordExpressionType = true
dataFlowValue, expectedReceiverParameterType,
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
expression, this, candidateCall.call, recordExpressionType = true
)
if (smartCastResult == null) {
if (notNullReceiverExpected) {
reportUnsafeCall = true
}
}
else {
} else {
if (isDispatchReceiver) {
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
}
else {
} else {
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
}
if (!smartCastResult.isCorrect) {
@@ -589,11 +588,11 @@ class CandidateResolver(
inner class ValueArgumentsCheckingResult(val status: ResolutionStatus, val argumentTypes: List<KotlinType>)
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInAFunctionCall(
ktTypeArguments: List<KtTypeProjection>,
typeArguments: List<KotlinType>,
functionDescriptor: CallableDescriptor,
substitutor: TypeSubstitutor,
trace: BindingTrace
ktTypeArguments: List<KtTypeProjection>,
typeArguments: List<KotlinType>,
functionDescriptor: CallableDescriptor,
substitutor: TypeSubstitutor,
trace: BindingTrace
) {
if (functionDescriptor is TypeAliasConstructorDescriptor) {
checkGenericBoundsInTypeAliasConstructorCall(ktTypeArguments, functionDescriptor, substitutor, trace)
@@ -612,10 +611,10 @@ class CandidateResolver(
}
private class TypeAliasSingleStepExpansionReportStrategy(
private val callElement: KtElement,
typeAlias: TypeAliasDescriptor,
ktTypeArguments: List<KtTypeProjection>,
private val trace: BindingTrace
private val callElement: KtElement,
typeAlias: TypeAliasDescriptor,
ktTypeArguments: List<KtTypeProjection>,
private val trace: BindingTrace
) : TypeAliasExpansionReportStrategy {
init {
assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" }
@@ -627,7 +626,11 @@ class CandidateResolver(
// can't happen in single-step expansion
}
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
override fun conflictingProjection(
typeAlias: TypeAliasDescriptor,
typeParameter: TypeParameterDescriptor?,
substitutedArgument: KotlinType
) {
// can't happen in single-step expansion
}
@@ -639,24 +642,28 @@ class CandidateResolver(
// can't happen in single-step expansion
}
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
override fun boundsViolationInSubstitution(
bound: KotlinType,
unsubstitutedArgument: KotlinType,
argument: KotlinType,
typeParameter: TypeParameterDescriptor
) {
val descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor
val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument]
val argumentTypeReferenceElement = argumentElement?.typeReference
if (argumentTypeReferenceElement != null) {
trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument))
}
else {
} else {
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(callElement, bound, argument, typeParameter))
}
}
}
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInTypeAliasConstructorCall(
ktTypeArguments: List<KtTypeProjection>,
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
typeAliasParametersSubstitutor: TypeSubstitutor,
trace: BindingTrace
ktTypeArguments: List<KtTypeProjection>,
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
typeAliasParametersSubstitutor: TypeSubstitutor,
trace: BindingTrace
) {
val substitutedType = typeAliasParametersSubstitutor.substitute(typeAliasConstructorDescriptor.returnType, Variance.INVARIANT)!!
val boundsSubstitutor = TypeSubstitutor.create(substitutedType)
@@ -677,10 +684,10 @@ class CandidateResolver(
private fun checkTypeInTypeAliasSubstitutionRec(
reportStrategy: TypeAliasExpansionReportStrategy,
unsubstitutedType: KotlinType,
typeAliasParametersSubstitutor: TypeSubstitutor,
boundsSubstitutor: TypeSubstitutor
reportStrategy: TypeAliasExpansionReportStrategy,
unsubstitutedType: KotlinType,
typeAliasParametersSubstitutor: TypeSubstitutor,
boundsSubstitutor: TypeSubstitutor
) {
// TODO refactor TypeResolver
val typeParameters = unsubstitutedType.constructor.parameters
@@ -688,30 +695,41 @@ class CandidateResolver(
// TODO do not perform substitution for type arguments multiple times
val substitutedTypeArguments = typeAliasParametersSubstitutor.safeSubstitute(unsubstitutedType, Variance.INVARIANT).arguments
for (i in 0 ..Math.min(typeParameters.size, substitutedTypeArguments.size) - 1) {
for (i in 0..Math.min(typeParameters.size, substitutedTypeArguments.size) - 1) {
val substitutedTypeProjection = substitutedTypeArguments[i]
if (substitutedTypeProjection.isStarProjection) continue
val typeParameter = typeParameters[i]
val substitutedTypeArgument = substitutedTypeProjection.type
val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].type
DescriptorResolver.checkBoundsInTypeAlias(reportStrategy, unsubstitutedTypeArgument, substitutedTypeArgument, typeParameter, boundsSubstitutor)
DescriptorResolver.checkBoundsInTypeAlias(
reportStrategy,
unsubstitutedTypeArgument,
substitutedTypeArgument,
typeParameter,
boundsSubstitutor
)
checkTypeInTypeAliasSubstitutionRec(reportStrategy, unsubstitutedTypeArgument, typeAliasParametersSubstitutor, boundsSubstitutor)
checkTypeInTypeAliasSubstitutionRec(
reportStrategy,
unsubstitutedTypeArgument,
typeAliasParametersSubstitutor,
boundsSubstitutor
)
}
}
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.shouldContinue() =
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.check(
crossinline checker: CallCandidateResolutionContext<D>.() -> Unit
crossinline checker: CallCandidateResolutionContext<D>.() -> Unit
) {
if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() }
}
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
) {
check {
candidateCall.addStatus(checker())
@@ -38,10 +38,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class DiagnosticReporterByTrackingStrategy(
val constantExpressionEvaluator: ConstantExpressionEvaluator,
val context: BasicCallResolutionContext,
val psiKotlinCall: PSIKotlinCall
): DiagnosticReporter {
val constantExpressionEvaluator: ConstantExpressionEvaluator,
val context: BasicCallResolutionContext,
val psiKotlinCall: PSIKotlinCall
) : DiagnosticReporter {
private val trace = context.trace as TrackingBindingTrace
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
private val call: Call get() = psiKotlinCall.psiCall
@@ -53,7 +53,10 @@ class DiagnosticReporterByTrackingStrategy(
override fun onCall(diagnostic: KotlinCallDiagnostic) {
when (diagnostic.javaClass) {
VisibilityError::class.java -> tracingStrategy.invisibleMember(trace, (diagnostic as VisibilityError).invisibleMember)
NoValueForParameter::class.java -> tracingStrategy.noValueForParameter(trace, (diagnostic as NoValueForParameter).parameterDescriptor)
NoValueForParameter::class.java -> tracingStrategy.noValueForParameter(
trace,
(diagnostic as NoValueForParameter).parameterDescriptor
)
InstantiationOfAbstractClass::class.java -> tracingStrategy.instantiationOfAbstractClass(trace)
AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace)
}
@@ -62,10 +65,10 @@ class DiagnosticReporterByTrackingStrategy(
override fun onTypeArguments(diagnostic: KotlinCallDiagnostic) {
val psiCallElement = psiKotlinCall.psiCall.callElement
val reportElement =
if (psiCallElement is KtCallExpression)
psiCallElement.typeArgumentList ?: psiCallElement.calleeExpression ?: psiCallElement
else
psiCallElement
if (psiCallElement is KtCallExpression)
psiCallElement.typeArgumentList ?: psiCallElement.calleeExpression ?: psiCallElement
else
psiCallElement
when (diagnostic) {
is WrongCountOfTypeArguments -> {
@@ -123,8 +126,8 @@ class DiagnosticReporterByTrackingStrategy(
}
override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression ?:
error("Argument name should be not null for argument: $callArgument")
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression
?: error("Argument name should be not null for argument: $callArgument")
when (diagnostic.javaClass) {
NamedArgumentReference::class.java -> {
trace.record(BindingContext.REFERENCE_TARGET, nameReference, (diagnostic as NamedArgumentReference).parameterDescriptor)
@@ -133,10 +136,12 @@ class DiagnosticReporterByTrackingStrategy(
NameForAmbiguousParameter::class.java -> trace.report(NAME_FOR_AMBIGUOUS_PARAMETER.on(nameReference))
NameNotFound::class.java -> trace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference, nameReference))
NamedArgumentNotAllowed::class.java -> trace.report(NAMED_ARGUMENTS_NOT_ALLOWED.on(
NamedArgumentNotAllowed::class.java -> trace.report(
NAMED_ARGUMENTS_NOT_ALLOWED.on(
nameReference,
if ((diagnostic as NamedArgumentNotAllowed).descriptor is FunctionInvokeDescriptor) INVOKE_ON_FUNCTION_TYPE else NON_KOTLIN_FUNCTION
))
)
)
ArgumentPassedTwice::class.java -> trace.report(ARGUMENT_PASSED_TWICE.on(nameReference))
}
}
@@ -156,23 +161,29 @@ class DiagnosticReporterByTrackingStrategy(
is ExpressionKotlinCallArgumentImpl -> {
trace.markAsReported()
val context = context.replaceDataFlowInfo(expressionArgument.dataFlowInfoBeforeThisArgument)
val argumentExpression = KtPsiUtil.getLastElementDeparenthesized(expressionArgument.valueArgument.getArgumentExpression (), context.statementFilter)
val argumentExpression = KtPsiUtil.getLastElementDeparenthesized(
expressionArgument.valueArgument.getArgumentExpression(),
context.statementFilter
)
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
recordExpressionType = true)
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
recordExpressionType = true
)
}
is ReceiverExpressionKotlinCallArgument -> {
trace.markAsReported()
val receiverValue = expressionArgument.receiver.receiverValue
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
recordExpressionType = true)
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
recordExpressionType = true
)
}
else -> null
}
val resolvedCall = smartCastDiagnostic.kotlinCall?.psiKotlinCall?.psiCall?.getResolvedCall(trace.bindingContext) as? NewResolvedCallImpl<*>
val resolvedCall =
smartCastDiagnostic.kotlinCall?.psiKotlinCall?.psiCall?.getResolvedCall(trace.bindingContext) as? NewResolvedCallImpl<*>
if (resolvedCall != null && smartCastResult != null) {
if (resolvedCall.extensionReceiver == expressionArgument.receiver.receiverValue) {
resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
@@ -194,7 +205,7 @@ class DiagnosticReporterByTrackingStrategy(
val constraintError = diagnostic as NewConstraintError
val position = constraintError.position.from
val argument = (position as? ArgumentConstraintPosition)?.argument
?: (position as? ReceiverConstraintPosition)?.argument
?: (position as? ReceiverConstraintPosition)?.argument
argument?.let {
val expression = it.psiExpression ?: return
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
@@ -218,7 +229,12 @@ class DiagnosticReporterByTrackingStrategy(
val capturedError = diagnostic as CapturedTypeFromSubtyping
(capturedError.position as? ArgumentConstraintPosition)?.let {
val expression = it.argument.psiExpression ?: return
trace.report(NEW_INFERENCE_ERROR.on(expression, "Capture type from subtyping ${capturedError.constraintType} for variable ${capturedError.typeVariable}"))
trace.report(
NEW_INFERENCE_ERROR.on(
expression,
"Capture type from subtyping ${capturedError.constraintType} for variable ${capturedError.typeVariable}"
)
)
}
}
}
@@ -229,7 +245,7 @@ class DiagnosticReporterByTrackingStrategy(
val builtIns = context.scope.ownerDescriptor.builtIns
val constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, trace, context.expectedType)
val hasConstantTypeError = CompileTimeConstantChecker(context, builtIns, true)
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
if (hasConstantTypeError) return true
}
return false
@@ -66,9 +66,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
private val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialFunctionName }.toSet()
class GenericCandidateResolver(
private val argumentTypeResolver: ArgumentTypeResolver,
private val coroutineInferenceSupport: CoroutineInferenceSupport,
private val languageVersionSettings: LanguageVersionSettings
private val argumentTypeResolver: ArgumentTypeResolver,
private val coroutineInferenceSupport: CoroutineInferenceSupport,
private val languageVersionSettings: LanguageVersionSettings
) {
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
val candidateCall = context.candidateCall
@@ -90,7 +90,7 @@ class GenericCandidateResolver(
// and throw the results away
// We'll type check the arguments later, with the inferred types expected
addConstraintForValueArgument(
valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS
valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS
)
}
}
@@ -114,9 +114,9 @@ class GenericCandidateResolver(
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
}
builder.addSubtypeConstraint(
receiverType,
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
RECEIVER_POSITION.position()
receiverType,
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
RECEIVER_POSITION.position()
)
}
@@ -133,9 +133,9 @@ class GenericCandidateResolver(
}
private fun ConstraintSystem.Builder.typeInSystem(call: Call, type: KotlinType?): KotlinType? =
type?.let {
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
}
type?.let {
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
}
private fun FunctionDescriptor.isFunctionForExpectTypeFromCastFeature(): Boolean {
val typeParameter = typeParameters.singleOrNull() ?: return false
@@ -153,8 +153,8 @@ class GenericCandidateResolver(
}
private fun addExpectedTypeForExplicitCast(
context: CallCandidateResolutionContext<*>,
builder: ConstraintSystem.Builder
context: CallCandidateResolutionContext<*>,
builder: ConstraintSystem.Builder
) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return
@@ -185,8 +185,7 @@ class GenericCandidateResolver(
val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) {
if (possibleQualifiedExpression.selectorExpression != callExpression) return null
possibleQualifiedExpression
}
else {
} else {
callExpression
}
@@ -207,7 +206,7 @@ class GenericCandidateResolver(
val boundsSubstitutor = TypeSubstitutor.create(type)
type.arguments.forEachIndexed forEachArgument@{ i, typeProjection ->
type.arguments.forEachIndexed forEachArgument@ { i, typeProjection ->
if (typeProjection.isStarProjection) return@forEachArgument // continue
val typeParameter = typeConstructor.parameters[i]
@@ -218,10 +217,10 @@ class GenericCandidateResolver(
}
private fun addValidityConstraintsForTypeArgument(
builder: ConstraintSystem.Builder,
substitutedArgument: TypeProjection,
typeParameter: TypeParameterDescriptor,
boundsSubstitutor: TypeSubstitutor
builder: ConstraintSystem.Builder,
substitutedArgument: TypeProjection,
typeParameter: TypeParameterDescriptor,
boundsSubstitutor: TypeSubstitutor
) {
val substitutedType = substitutedArgument.type
for (upperBound in typeParameter.upperBounds) {
@@ -247,12 +246,12 @@ class GenericCandidateResolver(
}
private fun addConstraintForValueArgument(
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
substitutor: TypeSubstitutor,
builder: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<*>,
resolveFunctionArgumentBodies: ResolveArgumentsMode
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
substitutor: TypeSubstitutor,
builder: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<*>,
resolveFunctionArgumentBodies: ResolveArgumentsMode
) {
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
val argumentExpression = valueArgument.getArgumentExpression()
@@ -268,23 +267,24 @@ class GenericCandidateResolver(
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return
val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
val type =
updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
if (argumentExpression is KtCallableReferenceExpression && type == null) return
builder.addSubtypeConstraint(
type,
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
constraintPosition
type,
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
constraintPosition
)
}
private fun addConstraintForNestedCall(
argumentExpression: KtExpression?,
constraintPosition: ConstraintPosition,
builder: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<*>,
effectiveExpectedType: KotlinType
argumentExpression: KtExpression?,
constraintPosition: ConstraintPosition,
builder: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<*>,
effectiveExpectedType: KotlinType
): Boolean {
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
if (resolutionResults == null || !resolutionResults.isSingleResult) return false
@@ -312,18 +312,18 @@ class GenericCandidateResolver(
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
builder.addSubtypeConstraint(
argumentExpressionType,
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
constraintPosition
argumentExpressionType,
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
constraintPosition
)
return true
}
private fun updateResultTypeForSmartCasts(
type: KotlinType?,
argumentExpression: KtExpression?,
context: ResolutionContext<*>
type: KotlinType?,
argumentExpression: KtExpression?,
context: ResolutionContext<*>
): KotlinType? {
val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
if (deparenthesizedArgument == null || type == null) return type
@@ -345,7 +345,8 @@ class GenericCandidateResolver(
// to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument`
val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) {
CallCandidateResolutionContext.create(
resolvedCall, context, context.trace, context.tracing, resolvedCall.functionCall.call, context.candidateResolveMode)
resolvedCall, context, context.trace, context.tracing, resolvedCall.functionCall.call, context.candidateResolveMode
)
} else {
context
}
@@ -356,8 +357,10 @@ class GenericCandidateResolver(
for (valueArgument in resolvedValueArgument.arguments) {
valueArgument.getArgumentExpression()?.let { argumentExpression ->
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral ->
addConstraintForFunctionLiteralArgument(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
resolvedCall.candidateDescriptor.returnType)
addConstraintForFunctionLiteralArgument(
functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
resolvedCall.candidateDescriptor.returnType
)
}
// as inference for callable references depends on expected type,
@@ -367,20 +370,21 @@ class GenericCandidateResolver(
// For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression)
val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
newContext
}
else {
} else {
val temporaryBindingTrace = TemporaryBindingTrace.create(
newContext.trace, "Trace to complete argument for call that might be not resulting call")
newContext.trace, "Trace to complete argument for call that might be not resulting call"
)
newContext.replaceBindingTrace(temporaryBindingTrace)
}
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference ->
addConstraintForCallableReference(
callableReference,
valueArgument,
valueParameterDescriptor,
constraintSystem,
temporaryContextForCall)
callableReference,
valueArgument,
valueParameterDescriptor,
constraintSystem,
temporaryContextForCall
)
}
}
}
@@ -395,24 +399,24 @@ class GenericCandidateResolver(
// and we have some expected type Type, we can expected from literal to return Type
// Otherwise we do not care about literal's exact return type
private fun estimateLiteralReturnType(
context: CallCandidateResolutionContext<*>,
literalExpectedType: KotlinType,
ownerReturnType: KotlinType?
context: CallCandidateResolutionContext<*>,
literalExpectedType: KotlinType,
ownerReturnType: KotlinType?
) = if (!TypeUtils.noExpectedType(context.expectedType) &&
ownerReturnType != null &&
TypeUtils.isTypeParameter(ownerReturnType) &&
literalExpectedType.isFunctionTypeOrSubtype &&
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
ownerReturnType != null &&
TypeUtils.isTypeParameter(ownerReturnType) &&
literalExpectedType.isFunctionTypeOrSubtype &&
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
context.expectedType
else DONT_CARE
private fun <D : CallableDescriptor> addConstraintForFunctionLiteralArgument(
functionLiteral: KtFunction,
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>,
argumentOwnerReturnType: KotlinType?
functionLiteral: KtFunction,
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>,
argumentOwnerReturnType: KotlinType?
) {
val argumentExpression = valueArgument.getArgumentExpression() ?: return
@@ -439,24 +443,27 @@ class GenericCandidateResolver(
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
val effectiveExpectedTypeInSystem =
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT)
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT)
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
val hasExpectedReturnType = !hasUnknownReturnType(expectedType)
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
if (hasExpectedReturnType) {
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
context, "trace to resolve function literal with expected return type", argumentExpression)
context, "trace to resolve function literal with expected return type", argumentExpression
)
val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return
val mismatch = BooleanArray(1)
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch)
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch
)
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
.replaceContextDependency(INDEPENDENT)
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
.replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS
).type
if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
temporaryToResolveFunctionLiteral.commit()
@@ -466,36 +473,38 @@ class GenericCandidateResolver(
val estimatedReturnType = estimateLiteralReturnType(context, effectiveExpectedType, argumentOwnerReturnType)
val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType)
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
.replaceContextDependency(INDEPENDENT)
val type =
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
.type
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
}
private fun <D : CallableDescriptor> addConstraintForCallableReference(
callableReference: KtCallableReferenceExpression,
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>
callableReference: KtCallableReferenceExpression,
valueArgument: ValueArgument,
valueParameterDescriptor: ValueParameterDescriptor,
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>
) {
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
?: return
?: return
if (!ReflectionTypes.isCallableType(expectedType)) return
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
constraintSystem.addSubtypeConstraint(
resolvedType,
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
position
resolvedType,
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
position
)
}
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
callableReference: KtCallableReferenceExpression,
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>,
effectiveExpectedType: KotlinType
callableReference: KtCallableReferenceExpression,
constraintSystem: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<D>,
effectiveExpectedType: KotlinType
): KotlinType? {
val substitutedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
@@ -509,19 +518,20 @@ class GenericCandidateResolver(
}
private fun <D : CallableDescriptor> getResolvedTypeForCallableReference(
callableReference: KtCallableReferenceExpression,
context: CallCandidateResolutionContext<D>,
expectedType: KotlinType,
valueArgument: ValueArgument
callableReference: KtCallableReferenceExpression,
context: CallCandidateResolutionContext<D>,
expectedType: KotlinType,
valueArgument: ValueArgument
): KotlinType? {
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
val expectedTypeWithoutReturnType = if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
val expectedTypeWithoutReturnType =
if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
val newContext = context
.replaceExpectedType(expectedTypeWithoutReturnType)
.replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT)
.replaceExpectedType(expectedTypeWithoutReturnType)
.replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT)
return argumentTypeResolver.getCallableReferenceTypeInfo(
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
).type
}
}
@@ -539,7 +549,7 @@ fun makeConstantSubstitutor(typeParameterDescriptors: Collection<TypeParameterDe
return TypeSubstitutor.create(object : TypeConstructorSubstitution() {
override operator fun get(key: TypeConstructor) =
if (key in constructors) projection else null
if (key in constructors) projection else null
override fun isEmpty() = false
})
@@ -33,6 +33,6 @@ class CallReturnsArrayOfNothingChecker : CallChecker {
if (this == null || isComputingDeferredType(this)) return false
return isArrayOfNothing() ||
arguments.any { !it.isStarProjection && it.type.containsArrayOfNothing() }
arguments.any { !it.isStarProjection && it.type.containsArrayOfNothing() }
}
}
@@ -32,11 +32,16 @@ class CallableReferenceCompatibilityChecker : CallChecker {
for ((_, resolvedArgument) in resolvedCall.valueArguments) {
inner@ for (argument in resolvedArgument.arguments) {
val argumentExpression = argument.getArgumentExpression() as? KtCallableReferenceExpression ?: continue@inner
val callableReferenceResolvedCall = argumentExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue@inner
val callableReferenceResolvedCall =
argumentExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue@inner
if (callableReferenceResolvedCall.call.isCallableReference() &&
callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) {
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression,
typeInferenceForCallableReferencesFeature to context.languageVersionSettings))
context.trace.report(
Errors.UNSUPPORTED_FEATURE.on(
argumentExpression,
typeInferenceForCallableReferencesFeature to context.languageVersionSettings
)
)
}
}
}
@@ -62,7 +62,7 @@ class CapturingInClosureChecker : CallChecker {
}
private fun isCapturedInInline(
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
): Boolean {
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
@@ -70,7 +70,7 @@ class CapturingInClosureChecker : CallChecker {
if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) {
val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer")
return !isCapturedVariable(variableParent, scopeContainerParent) ||
isCapturedInInline(context, scopeContainerParent, variableParent)
isCapturedInInline(context, scopeContainerParent, variableParent)
}
return false
}
@@ -40,9 +40,9 @@ object DeprecatedCallChecker : CallChecker {
}
private fun check(
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
) {
// Objects will be checked by DeprecatedClassifierUsageChecker
if (targetDescriptor is FakeCallableDescriptorForObject) return
@@ -58,8 +58,7 @@ object DeprecatedCallChecker : CallChecker {
for (deprecation in deprecations) {
trace.report(createDeprecationDiagnostic(element, deprecation, languageVersionSettings))
}
}
else if (targetDescriptor is PropertyDescriptor && shouldCheckPropertyGetter(element)) {
} else if (targetDescriptor is PropertyDescriptor && shouldCheckPropertyGetter(element)) {
targetDescriptor.getter?.let { check(it, trace, element, languageVersionSettings, deprecationResolver) }
}
}
@@ -46,15 +46,15 @@ object DslScopeViolationCallChecker : CallChecker {
}
private fun checkCallImplicitReceiver(
callImplicitReceiver: ReceiverValue,
resolvedCall: ResolvedCall<*>,
reportOn: PsiElement,
context: CallCheckerContext
callImplicitReceiver: ReceiverValue,
resolvedCall: ResolvedCall<*>,
reportOn: PsiElement,
context: CallCheckerContext
) {
val receiversUntilOneFromTheCall =
context.scope.parentsWithSelf
.mapNotNull { (it as? LexicalScope)?.implicitReceiver?.value }
.takeWhile { it != callImplicitReceiver }.toList()
context.scope.parentsWithSelf
.mapNotNull { (it as? LexicalScope)?.implicitReceiver?.value }
.takeWhile { it != callImplicitReceiver }.toList()
if (receiversUntilOneFromTheCall.isEmpty()) return
@@ -62,7 +62,7 @@ object DslScopeViolationCallChecker : CallChecker {
if (callDslMarkers.isEmpty()) return
val closestAnotherReceiverWithSameDslMarker =
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
if (closestAnotherReceiverWithSameDslMarker != null) {
// TODO: report receivers configuration (what's one is used and what's one is the closest)
@@ -83,7 +83,7 @@ object DslScopeViolationCallChecker : CallChecker {
}
constructor.declarationDescriptor?.getAllSuperClassifiers()?.asIterable()
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
return result
}
@@ -91,7 +91,7 @@ object DslScopeViolationCallChecker : CallChecker {
}
private fun Annotations.extractDslMarkerFqNames() =
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
private fun AnnotationDescriptor.isDslMarker(): Boolean {
val classDescriptor = annotationClass ?: return false
@@ -49,9 +49,11 @@ class OperatorCallChecker : CallChecker {
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
val outerCall = call.outerCall
if (isConventionCall(outerCall) || isWrongCallWithExplicitTypeArguments(resolvedCall, outerCall)) {
throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. " +
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}")
throw AssertionError(
"Illegal resolved call to variable with invoke for $outerCall. " +
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}"
)
}
}
@@ -89,11 +91,11 @@ class OperatorCallChecker : CallChecker {
}
private fun isWrongCallWithExplicitTypeArguments(
resolvedCall: VariableAsFunctionResolvedCall,
outerCall: Call
resolvedCall: VariableAsFunctionResolvedCall,
outerCall: Call
): Boolean {
val passedTypeArgumentsToInvoke = outerCall.typeArguments.isNotEmpty() &&
resolvedCall.functionCall.candidateDescriptor.typeParameters.isNotEmpty()
resolvedCall.functionCall.candidateDescriptor.typeParameters.isNotEmpty()
return passedTypeArgumentsToInvoke && resolvedCall.variableCall.candidateDescriptor.typeParameters.isNotEmpty()
}
}
@@ -108,8 +110,8 @@ fun shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings: LanguageVe
}
private fun checkModConvention(
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
diagnosticHolder: DiagnosticSink, modifier: PsiElement
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
diagnosticHolder: DiagnosticSink, modifier: PsiElement
) {
if (!descriptor.isOperatorMod()) return
@@ -117,8 +119,7 @@ private fun checkModConvention(
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
}
}
else {
} else {
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
}
@@ -33,8 +33,8 @@ enum class RttiOperation {
}
class RttiExpressionInformation(
val subject: KtExpression,
val sourceType: KotlinType?,
val targetType: KotlinType?,
val operation: RttiOperation
val subject: KtExpression,
val sourceType: KotlinType?,
val targetType: KotlinType?,
val operation: RttiOperation
)
@@ -56,9 +56,9 @@ object CoroutineSuspendCallChecker : CallChecker {
}
val enclosingSuspendFunction = context.scope
.parentsWithSelf.firstOrNull {
.parentsWithSelf.firstOrNull {
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
when {
@@ -67,19 +67,32 @@ object CoroutineSuspendCallChecker : CallChecker {
if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) {
context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn))
}
else if (context.scope.parentsWithSelf.any { it.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction) }) {
} else if (context.scope.parentsWithSelf.any { it.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction) }) {
context.trace.report(Errors.UNSUPPORTED.on(reportOn, "suspend function calls in a context of default parameter value"))
}
context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction)
context.trace.record(
BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL,
resolvedCall.call,
enclosingSuspendFunction
)
checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
}
else -> {
when (descriptor) {
is FunctionDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn, resolvedCall.candidateDescriptor))
is PropertyDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(reportOn, resolvedCall.candidateDescriptor))
is FunctionDescriptor -> context.trace.report(
Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(
reportOn,
resolvedCall.candidateDescriptor
)
)
is PropertyDescriptor -> context.trace.report(
Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(
reportOn,
resolvedCall.candidateDescriptor
)
)
}
}
}
@@ -87,7 +100,7 @@ object CoroutineSuspendCallChecker : CallChecker {
}
private fun HierarchicalScope.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction: FunctionDescriptor) =
this is LexicalScope && this.kind == LexicalScopeKind.DEFAULT_VALUE && this.ownerDescriptor == enclosingSuspendFunction
this is LexicalScope && this.kind == LexicalScopeKind.DEFAULT_VALUE && this.ownerDescriptor == enclosingSuspendFunction
object BuilderFunctionsCallChecker : CallChecker {
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
@@ -116,10 +129,10 @@ fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, dia
}
private fun checkRestrictsSuspension(
enclosingCallableDescriptor: CallableDescriptor,
resolvedCall: ResolvedCall<*>,
reportOn: PsiElement,
context: CallCheckerContext
enclosingCallableDescriptor: CallableDescriptor,
resolvedCall: ResolvedCall<*>,
reportOn: PsiElement,
context: CallCheckerContext
) {
val enclosingSuspendReceiverValue = enclosingCallableDescriptor.extensionReceiverParameter?.value ?: return
@@ -50,7 +50,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
internal data class Constraint(
val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition
val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition
)
enum class ConstraintKind(val bound: TypeBounds.BoundKind) {
@@ -74,7 +74,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
override fun registerTypeVariables(
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
): TypeSubstitutor {
if (typeParameters.isEmpty()) return storeSubstitutor(call, TypeSubstitutor.EMPTY)
@@ -82,11 +82,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
typeParameters.map {
TypeVariable(call, it, it, true)
}
}
else {
} else {
val freshTypeParameters = ArrayList<TypeParameterDescriptor>(typeParameters.size)
DescriptorSubstitutor.substituteTypeParameters(
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
)
freshTypeParameters.zip(typeParameters).map {
val (fresh, original) = it
@@ -106,33 +105,44 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
}
return storeSubstitutor(call, TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap(
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
)))
return storeSubstitutor(
call, TypeSubstitutor.create(
TypeConstructorSubstitution.createByParametersMap(
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
)
)
)
}
private fun KotlinType.isProper() = !TypeUtils.contains(this) {
type -> type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
private fun KotlinType.isProper() = !TypeUtils.contains(this) { type ->
type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
}
internal fun getNestedTypeVariables(type: KotlinType): List<TypeVariable> =
type.getNestedTypeParameters().mapNotNull { getMyTypeVariable(it) }
type.getNestedTypeParameters().mapNotNull { getMyTypeVariable(it) }
override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType?, constraintPosition: ConstraintPosition) {
addConstraint(SUB_TYPE, constrainingType, subjectType, ConstraintContext(constraintPosition, initial = true, initialReduction = true))
addConstraint(
SUB_TYPE,
constrainingType,
subjectType,
ConstraintContext(constraintPosition, initial = true, initialReduction = true)
)
}
fun addConstraint(
constraintKind: ConstraintKind,
subType: KotlinType?,
superType: KotlinType?,
constraintContext: ConstraintContext
constraintKind: ConstraintKind,
subType: KotlinType?,
superType: KotlinType?,
constraintContext: ConstraintContext
) {
val constraintPosition = constraintContext.position
// when processing nested constraints, `derivedFrom` information should be reset
val newConstraintContext = ConstraintContext(constraintContext.position, derivedFrom = null, initial = false,
initialReduction = constraintContext.initialReduction)
val newConstraintContext = ConstraintContext(
constraintContext.position, derivedFrom = null, initial = false,
initialReduction = constraintContext.initialReduction
)
val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks {
private var depth = 0
@@ -187,11 +197,11 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
private fun doAddConstraint(
constraintKind: ConstraintKind,
subType: KotlinType?,
superType: KotlinType?,
constraintContext: ConstraintContext,
typeCheckingProcedure: TypeCheckingProcedure
constraintKind: ConstraintKind,
subType: KotlinType?,
superType: KotlinType?,
constraintContext: ConstraintContext,
typeCheckingProcedure: TypeCheckingProcedure
) {
val constraintPosition = constraintContext.position
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
@@ -212,8 +222,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
return
}
createTypeForFunctionPlaceholder(subType, superType)
}
else {
} else {
subType
}
@@ -230,8 +239,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
val superType2 = simplifyType(superType, constraintContext.initial)
val result = if (constraintKind == EQUAL) {
typeCheckingProcedure.equalTypes(subType2, superType2)
}
else {
} else {
typeCheckingProcedure.isSubtypeOf(subType2, superType)
}
if (!result) errors.add(newTypeInferenceOrParameterConstraintError(constraintPosition))
@@ -245,22 +253,24 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
private fun simplifyType(type: KotlinType, isInitialConstraint: Boolean): KotlinType =
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
type
else {
// if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
// but constraint system should be solved anyway
TypeUtils.makeNotNullable(type)
}
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
type
else {
// if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
// but constraint system should be solved anyway
TypeUtils.makeNotNullable(type)
}
internal fun addBound(
typeVariable: TypeVariable,
constrainingType: KotlinType,
kind: TypeBounds.BoundKind,
constraintContext: ConstraintContext
typeVariable: TypeVariable,
constrainingType: KotlinType,
kind: TypeBounds.BoundKind,
constraintContext: ConstraintContext
) {
val bound = Bound(typeVariable, constrainingType, kind, constraintContext.position,
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet())
val bound = Bound(
typeVariable, constrainingType, kind, constraintContext.position,
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet()
)
val typeBounds = getTypeBounds(typeVariable)
if (typeBounds.bounds.contains(bound)) return
@@ -277,10 +287,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
private fun generateTypeParameterBound(
parameterType: KotlinType,
constrainingType: KotlinType,
boundKind: TypeBounds.BoundKind,
constraintContext: ConstraintContext
parameterType: KotlinType,
constrainingType: KotlinType,
boundKind: TypeBounds.BoundKind,
constraintContext: ConstraintContext
) {
val typeVariable = getMyTypeVariable(parameterType)!!
@@ -321,10 +331,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
private fun generateTypeParameterCaptureConstraint(
typeVariable: TypeVariable,
constrainingTypeProjection: TypeProjection,
constraintContext: ConstraintContext,
isTypeMarkedNullable: Boolean
typeVariable: TypeVariable,
constrainingTypeProjection: TypeProjection,
constraintContext: ConstraintContext,
isTypeMarkedNullable: Boolean
) {
if (!typeVariable.originalTypeParameter.upperBounds.let { it.size == 1 && it.single().isDefaultBound() } &&
constrainingTypeProjection.projectionKind == Variance.IN_VARIANCE) {
@@ -332,8 +342,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
val typeProjection = if (isTypeMarkedNullable) {
TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type))
}
else {
} else {
constrainingTypeProjection
}
val capturedType = createCapturedType(typeProjection)
@@ -341,24 +350,29 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
internal fun getTypeBounds(variable: TypeVariable): TypeBoundsImpl {
return allTypeParameterBounds[variable] ?:
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
return allTypeParameterBounds[variable]
?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
}
private fun isMyTypeVariable(typeParameter: TypeParameterDescriptor) =
getMyTypeVariable(typeParameter) != null
getMyTypeVariable(typeParameter) != null
internal fun isMyTypeVariable(type: KotlinType): Boolean =
getMyTypeVariable(type) != null
getMyTypeVariable(type) != null
internal fun getMyTypeVariable(type: KotlinType): TypeVariable? {
return getMyTypeVariable(type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return null)
}
private fun getMyTypeVariable(typeParameter: TypeParameterDescriptor): TypeVariable? =
allTypeParameterBounds.keys.find { it.freshTypeParameter == typeParameter }
allTypeParameterBounds.keys.find { it.freshTypeParameter == typeParameter }
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: KotlinType, superType: KotlinType, position: ConstraintPosition) {
private fun storeInitialConstraint(
constraintKind: ConstraintKind,
subType: KotlinType,
superType: KotlinType,
position: ConstraintPosition
) {
initialConstraints.add(Constraint(constraintKind, subType, superType, position))
}
@@ -381,14 +395,14 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
if (!Collections.disjoint(typeVariableSubstitutors.keys, other.typeVariableSubstitutors.keys)) {
throw IllegalArgumentException(
"Combining two constraint systems only makes sense when they were created for different calls. " +
"Calls of the first system: ${typeVariableSubstitutors.keys}, second: ${other.typeVariableSubstitutors.keys}"
"Combining two constraint systems only makes sense when they were created for different calls. " +
"Calls of the first system: ${typeVariableSubstitutors.keys}, second: ${other.typeVariableSubstitutors.keys}"
)
}
if (!Collections.disjoint(other.allTypeParameterBounds.keys, allTypeParameterBounds.keys)) {
throw IllegalArgumentException(
"Combining two constraint systems only makes sense when they have no common variables. " +
"First system variables: ${allTypeParameterBounds.keys}, second: ${other.allTypeParameterBounds.keys}"
"Combining two constraint systems only makes sense when they have no common variables. " +
"First system variables: ${allTypeParameterBounds.keys}, second: ${other.allTypeParameterBounds.keys}"
)
}
@@ -415,10 +429,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
var counter = 0
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>) =
registerTypeVariables(CallHandle.NONE, typeParameters)
registerTypeVariables(CallHandle.NONE, typeParameters)
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType) =
addSubtypeConstraint(subType, superType, ConstraintPositionKind.VALUE_PARAMETER_POSITION.position(counter++))
addSubtypeConstraint(subType, superType, ConstraintPositionKind.VALUE_PARAMETER_POSITION.position(counter++))
override fun hasContradiction(): Boolean {
fixVariables()
@@ -429,8 +443,8 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
}
internal fun createTypeForFunctionPlaceholder(
functionPlaceholder: KotlinType,
expectedType: KotlinType
functionPlaceholder: KotlinType,
expectedType: KotlinType
): KotlinType {
if (!functionPlaceholder.isFunctionPlaceholder) return functionPlaceholder
@@ -445,11 +459,12 @@ internal fun createTypeForFunctionPlaceholder(
val result = arrayListOf<KotlinType>()
(1..functionArgumentsSize).forEach { result.add(DONT_CARE) }
result
}
else {
} else {
functionPlaceholderTypeConstructor.argumentTypes
}
val receiverType = if (isExtension) DONT_CARE else null
return createFunctionType(functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
suspendFunction = expectedType.isSuspendFunctionType)
return createFunctionType(
functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
suspendFunction = expectedType.isSuspendFunctionType
)
}
@@ -33,11 +33,11 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import java.util.*
internal class ConstraintSystemImpl(
private val allTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
private val errors: List<ConstraintError>,
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
private val allTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
private val errors: List<ConstraintError>,
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
) : ConstraintSystem {
private val localTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>
get() = allTypeParameterBounds.filterNot { it.key.isExternal }
@@ -48,7 +48,7 @@ internal class ConstraintSystemImpl(
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters() && satisfyInitialConstraints()
override fun hasContradiction() = hasParameterConstraintError() || hasConflictingConstraints()
|| hasCannotCaptureTypesError() || errors.any { it is TypeInferenceError }
|| hasCannotCaptureTypesError() || errors.any { it is TypeInferenceError }
/**
* All hacks were removed. This comment is left for information.
@@ -84,7 +84,7 @@ internal class ConstraintSystemImpl(
override fun hasConflictingConstraints() = localTypeParameterBounds.values.any { it.values.size > 1 }
override fun hasUnknownParameters() =
localTypeParameterBounds.values.any { it.values.isEmpty() } || hasTypeParameterWithUnsatisfiedOnlyInputTypesError()
localTypeParameterBounds.values.any { it.values.isEmpty() } || hasTypeParameterWithUnsatisfiedOnlyInputTypesError()
override fun hasParameterConstraintError() = errors.any { it is ParameterConstraintError }
@@ -101,26 +101,26 @@ internal class ConstraintSystemImpl(
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
override fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError() =
localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null }
localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null }
override val constraintErrors: List<ConstraintError>
get() = errors
}
private fun getParameterToInferredValueMap(
typeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
getDefaultType: (TypeVariable) -> KotlinType,
substituteOriginal: Boolean
typeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
getDefaultType: (TypeVariable) -> KotlinType,
substituteOriginal: Boolean
): Map<TypeConstructor, TypeProjection> {
val substitutionContext = HashMap<TypeConstructor, TypeProjection>()
for ((variable, typeBounds) in typeParameterBounds) {
val value = typeBounds.value
val typeConstructor =
if (substituteOriginal) variable.originalTypeParameter.typeConstructor
else variable.type.constructor
if (substituteOriginal) variable.originalTypeParameter.typeConstructor
else variable.type.constructor
val type =
if (value != null && !TypeUtils.contains(value, DONT_CARE)) value
else getDefaultType(variable)
if (value != null && !TypeUtils.contains(value, DONT_CARE)) value
else getDefaultType(variable)
substitutionContext.put(typeConstructor, TypeProjectionImpl(type))
}
return substitutionContext
@@ -130,8 +130,8 @@ internal class ConstraintSystemImpl(
get() = allTypeParameterBounds.keys
override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl {
return allTypeParameterBounds[typeVariable] ?:
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
return allTypeParameterBounds[typeVariable]
?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
}
override val resultingSubstitutor: TypeSubstitutor
@@ -143,11 +143,11 @@ internal class ConstraintSystemImpl(
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeVariable) -> KotlinType): TypeSubstitutor {
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
return TypeSubstitutor.create(
SubstitutionWithCapturedTypeApproximation(
SubstitutionFilteringInternalResolveAnnotations(
TypeConstructorSubstitution.createByConstructorsMap(parameterToInferredValueMap)
)
SubstitutionWithCapturedTypeApproximation(
SubstitutionFilteringInternalResolveAnnotations(
TypeConstructorSubstitution.createByConstructorsMap(parameterToInferredValueMap)
)
)
)
}
@@ -159,8 +159,7 @@ internal class ConstraintSystemImpl(
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
return initialConstraints.all {
(kind, subtype, superType, position) ->
return initialConstraints.all { (kind, subtype, superType, position) ->
val resultSubType = subtype.substitute()?.let {
// the call might be done via safe access, so we check for notNullable receiver type;
// 'unsafe call' error is reported otherwise later
@@ -181,7 +180,7 @@ internal class ConstraintSystemImpl(
}
result.usedInBounds.putAll(usedInBounds.map {
val (variable, bounds) = it
variable to bounds.filterTo(arrayListOf<TypeBounds.Bound>()) { filterConstraintPosition(it.position )}
variable to bounds.filterTo(arrayListOf<TypeBounds.Bound>()) { filterConstraintPosition(it.position) }
}.toMap())
result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
@@ -55,12 +55,12 @@ import org.jetbrains.kotlin.types.typeUtil.contains
import javax.inject.Inject
class TypeTemplate(
val typeVariable: TypeVariable,
val coroutineInferenceData: CoroutineInferenceData,
nullable: Boolean = true
val typeVariable: TypeVariable,
val coroutineInferenceData: CoroutineInferenceData,
nullable: Boolean = true
) : FlexibleType(
typeVariable.originalTypeParameter.builtIns.nothingType,
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
typeVariable.originalTypeParameter.builtIns.nothingType,
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
) {
override fun replaceAnnotations(newAnnotations: Annotations) = this
@@ -79,9 +79,9 @@ class CoroutineInferenceData {
private var hereIsBadCall = false
fun getTypeTemplate(typeVariable: TypeVariable) =
typeTemplates.getOrPut(typeVariable) {
TypeTemplate(typeVariable, this)
}
typeTemplates.getOrPut(typeVariable) {
TypeTemplate(typeVariable, this)
}
fun initSystem() {
csBuilder.registerTypeVariables(CallHandle.NONE, typeTemplates.keys.map { it.freshTypeParameter })
@@ -115,18 +115,18 @@ class CoroutineInferenceData {
}
class CoroutineInferenceSupport(
val argumentTypeResolver: ArgumentTypeResolver,
val expressionTypingServices: ExpressionTypingServices
val argumentTypeResolver: ArgumentTypeResolver,
val expressionTypingServices: ExpressionTypingServices
) {
@set:Inject
lateinit var callCompleter: CallCompleter
fun analyzeCoroutine(
functionLiteral: KtFunction,
valueArgument: ValueArgument,
csBuilder: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<*>,
lambdaExpectedType: KotlinType
functionLiteral: KtFunction,
valueArgument: ValueArgument,
csBuilder: ConstraintSystem.Builder,
context: CallCandidateResolutionContext<*>,
lambdaExpectedType: KotlinType
) {
val argumentExpression = valueArgument.getArgumentExpression() ?: return
if (!lambdaExpectedType.isSuspendFunctionType) return
@@ -155,13 +155,16 @@ class CoroutineInferenceSupport(
val approximationSubstitutor = object : DelegatedTypeSubstitution(constraintSystem.currentSubstitutor.substitution) {
override fun approximateContravariantCapturedTypes() = true
}
val approximatedLambdaType = approximationSubstitutor.buildSubstitutor().substitute(lambdaExpectedType, Variance.IN_VARIANCE) ?: return
val approximatedLambdaType =
approximationSubstitutor.buildSubstitutor().substitute(lambdaExpectedType, Variance.IN_VARIANCE) ?: return
val newExpectedType = createFunctionType(newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType,
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
parameterNames = null, // TODO: parameterNames
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
suspendFunction = true)
val newExpectedType = createFunctionType(
newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType,
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
parameterNames = null, // TODO: parameterNames
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
suspendFunction = true
)
if (hasUnknownFunctionParameter(newExpectedType)) return
@@ -169,20 +172,21 @@ class CoroutineInferenceSupport(
// this trace shouldn't be committed
val temporaryForCoroutine = TemporaryTraceAndCache.create(
context, "trace for type argument inference for coroutine", functionLiteral)
context, "trace for type argument inference for coroutine", functionLiteral
)
val newContext = context.replaceExpectedType(newExpectedType)
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
inferenceData.reportInferenceResult(csBuilder)
}
fun checkCoroutineCalls(
context: BasicCallResolutionContext,
tracingStrategy: TracingStrategy,
overloadResults: OverloadResolutionResultsImpl<*>
context: BasicCallResolutionContext,
tracingStrategy: TracingStrategy,
overloadResults: OverloadResolutionResultsImpl<*>
) {
val inferenceData = overloadResults.getCoroutineInferenceData() ?: return
@@ -197,10 +201,9 @@ class CoroutineInferenceSupport(
inferenceData.badCallHappened()
}
forceInferenceForArguments(context) {
valueArgument: ValueArgument, kotlinType: KotlinType ->
forceInferenceForArguments(context) { valueArgument: ValueArgument, kotlinType: KotlinType ->
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch
?: return@forceInferenceForArguments
?: return@forceInferenceForArguments
with(NewKotlinTypeChecker) {
val parameterType = getEffectiveExpectedType(argumentMatch.valueParameter, valueArgument, context)
@@ -237,7 +240,10 @@ class CoroutineInferenceSupport(
}
}
private fun forceInferenceForArguments(context: CallResolutionContext<*>, callback: (argument: ValueArgument, argumentType: KotlinType) -> Unit) {
private fun forceInferenceForArguments(
context: CallResolutionContext<*>,
callback: (argument: ValueArgument, argumentType: KotlinType) -> Unit
) {
val infoForArguments = context.dataFlowInfoForArguments
val call = context.call
val baseContext = context.replaceContextDependency(ContextDependency.INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)
@@ -250,8 +256,8 @@ class CoroutineInferenceSupport(
}
private fun getArgumentTypeInfo(
expression: KtExpression,
context: CallResolutionContext<*>
expression: KtExpression,
context: CallResolutionContext<*>
): KotlinTypeInfo {
getFunctionLiteralArgumentIfAny(expression, context)?.let {
return argumentTypeResolver.getFunctionLiteralTypeInfo(expression, it, context, RESOLVE_FUNCTION_ARGUMENTS)
@@ -266,9 +272,9 @@ class CoroutineInferenceSupport(
}
fun isCoroutineCallWithAdditionalInference(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument) =
parameterDescriptor.hasSuspendFunctionType &&
argument.getArgumentExpression() is KtLambdaExpression &&
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
parameterDescriptor.hasSuspendFunctionType &&
argument.getArgumentExpression() is KtLambdaExpression &&
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
@@ -23,32 +23,32 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation
import org.jetbrains.kotlin.types.KotlinType
class TypeVariable(
val call: CallHandle,
internal val freshTypeParameter: TypeParameterDescriptor,
val originalTypeParameter: TypeParameterDescriptor,
val isExternal: Boolean
val call: CallHandle,
internal val freshTypeParameter: TypeParameterDescriptor,
val originalTypeParameter: TypeParameterDescriptor,
val isExternal: Boolean
) {
val name: Name get() = originalTypeParameter.name
val type: KotlinType get() = freshTypeParameter.defaultType
fun hasOnlyInputTypesAnnotation(): Boolean =
originalTypeParameter.hasOnlyInputTypesAnnotation()
originalTypeParameter.hasOnlyInputTypesAnnotation()
}
interface CallHandle {
object NONE : CallHandle
}
class CallBasedCallHandle(val call: Call): CallHandle {
class CallBasedCallHandle(val call: Call) : CallHandle {
override fun equals(other: Any?) =
other is CallBasedCallHandle && call === other.call
other is CallBasedCallHandle && call === other.call
override fun hashCode() =
System.identityHashCode(call)
System.identityHashCode(call)
override fun toString() =
call.toString()
call.toString()
}
fun Call.toHandle(): CallHandle = CallBasedCallHandle(this)
@@ -32,11 +32,12 @@ import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
import java.util.*
data class ConstraintContext(
val position: ConstraintPosition,
// see TypeBounds.Bound.derivedFrom
val derivedFrom: Set<TypeVariable>? = null,
val initial: Boolean = false,
val initialReduction: Boolean = false)
val position: ConstraintPosition,
// see TypeBounds.Bound.derivedFrom
val derivedFrom: Set<TypeVariable>? = null,
val initial: Boolean = false,
val initialReduction: Boolean = false
)
fun ConstraintSystemBuilderImpl.incorporateBound(newBound: Bound) {
val typeVariable = newBound.typeVariable
@@ -23,7 +23,7 @@ interface ArgumentMapping {
fun isError(): Boolean
}
object ArgumentUnmapped: ArgumentMapping {
object ArgumentUnmapped : ArgumentMapping {
override fun isError(): Boolean = true
}
@@ -46,7 +46,7 @@ interface ArgumentMatch : ArgumentMapping {
override fun isError(): Boolean = status.isError
}
class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor): ArgumentMatch {
class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor) : ArgumentMatch {
private var _status: ArgumentMatchStatus? = null
override val status: ArgumentMatchStatus
@@ -64,5 +64,4 @@ class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor):
}
//TODO: temporary hack until status.isSuccess is not always correct
fun ResolvedCall<*>.isReallySuccess(): Boolean
= status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
fun ResolvedCall<*>.isReallySuccess(): Boolean = status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
@@ -32,8 +32,8 @@ interface VariableAsFunctionMutableResolvedCall : VariableAsFunctionResolvedCall
}
class VariableAsFunctionResolvedCallImpl(
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
override val variableCall: MutableResolvedCall<VariableDescriptor>
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
override val variableCall: MutableResolvedCall<VariableDescriptor>
) : VariableAsFunctionMutableResolvedCall, MutableResolvedCall<FunctionDescriptor> by functionCall {
override fun markCallAsCompleted() {
@@ -28,9 +28,11 @@ private val KotlinType.immanentNullability: Nullability
* This class describes an arbitrary object which has some value in data flow analysis.
* In general case it's some r-value.
*/
class DataFlowValue(val identifierInfo: IdentifierInfo,
val type: KotlinType,
val immanentNullability: Nullability = type.immanentNullability) {
class DataFlowValue(
val identifierInfo: IdentifierInfo,
val type: KotlinType,
val immanentNullability: Nullability = type.immanentNullability
) {
val kind: Kind get() = identifierInfo.kind
@@ -379,7 +379,7 @@ object DataFlowValueFactory {
// Local variable classification: STABLE or CAPTURED
val preliminaryVisitor = PreliminaryDeclarationVisitor.getVisitorByVariable(variableDescriptor, bindingContext)
// A case when we just analyse an expression alone: counts as captured
// A case when we just analyse an expression alone: counts as captured
?: return CAPTURED_VARIABLE
// Analyze who writes variable
@@ -30,18 +30,18 @@ import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
import java.util.*
internal class DelegatingDataFlowInfo private constructor(
private val parent: DataFlowInfo?,
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
// Also immutable
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
/**
* Value for which type info was cleared or reassigned at this point
* so parent type info should not be in use
*/
private val valueWithGivenTypeInfo: DataFlowValue?
private val parent: DataFlowInfo?,
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
// Also immutable
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
/**
* Value for which type info was cleared or reassigned at this point
* so parent type info should not be in use
*/
private val valueWithGivenTypeInfo: DataFlowValue?
) : DataFlowInfo {
constructor(): this(null, emptyMap(), newTypeInfo(), null)
constructor() : this(null, emptyMap(), newTypeInfo(), null)
override val completeNullabilityInfo: Map<DataFlowValue, Nullability>
get() {
@@ -80,23 +80,22 @@ internal class DelegatingDataFlowInfo private constructor(
override fun getStableNullability(key: DataFlowValue) = getNullability(key, true)
private fun getNullability(key: DataFlowValue, stableOnly: Boolean) =
if (stableOnly && !key.isStable) {
key.immanentNullability
}
else {
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
}
if (stableOnly && !key.isStable) {
key.immanentNullability
} else {
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
}
private fun putNullabilityAndTypeInfo(
map: MutableMap<DataFlowValue, Nullability>,
value: DataFlowValue,
nullability: Nullability,
languageVersionSettings: LanguageVersionSettings,
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
affectReceiver: Boolean = true,
// TODO: remove me in version 1.3! I'm very dirty hack!
// In normal circumstances this should be always true
recordUnstable: Boolean = true
map: MutableMap<DataFlowValue, Nullability>,
value: DataFlowValue,
nullability: Nullability,
languageVersionSettings: LanguageVersionSettings,
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
affectReceiver: Boolean = true,
// TODO: remove me in version 1.3! I'm very dirty hack!
// In normal circumstances this should be always true
recordUnstable: Boolean = true
): Boolean {
if (value.isStable || recordUnstable) {
map.put(value, nullability)
@@ -110,8 +109,10 @@ internal class DelegatingDataFlowInfo private constructor(
val receiverType = identifierInfo.receiverType
if (identifierInfo.safe && receiverType != null) {
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
putNullabilityAndTypeInfo(map, receiverValue, nullability,
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
putNullabilityAndTypeInfo(
map, receiverValue, nullability,
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
)
}
}
is IdentifierInfo.SafeCast -> {
@@ -121,16 +122,20 @@ internal class DelegatingDataFlowInfo private constructor(
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
putNullabilityAndTypeInfo(map, subjectValue, nullability,
languageVersionSettings, typeInfo, recordUnstable = false)
putNullabilityAndTypeInfo(
map, subjectValue, nullability,
languageVersionSettings, typeInfo, recordUnstable = false
)
if (subjectValue.isStable) {
typeInfo?.put(subjectValue, targetType)
}
}
}
is IdentifierInfo.Variable -> identifierInfo.bound?.let {
putNullabilityAndTypeInfo(map, it, nullability,
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
putNullabilityAndTypeInfo(
map, it, nullability,
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
)
}
}
}
@@ -139,12 +144,12 @@ internal class DelegatingDataFlowInfo private constructor(
}
override fun getCollectedTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
getCollectedTypes(key, true, languageVersionSettings)
getCollectedTypes(key, true, languageVersionSettings)
private fun getCollectedTypes(
key: DataFlowValue,
enrichWithNotNull: Boolean,
languageVersionSettings: LanguageVersionSettings
key: DataFlowValue,
enrichWithNotNull: Boolean,
languageVersionSettings: LanguageVersionSettings
): Set<KotlinType> {
val types = collectTypesFromMeAndParents(key, languageVersionSettings)
if (!enrichWithNotNull || getCollectedNullability(key).canBeNull()) {
@@ -164,10 +169,10 @@ internal class DelegatingDataFlowInfo private constructor(
}
override fun getStableTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
getStableTypes(key, true, languageVersionSettings)
getStableTypes(key, true, languageVersionSettings)
private fun getStableTypes(key: DataFlowValue, enrichWithNotNull: Boolean, languageVersionSettings: LanguageVersionSettings) =
if (!key.isStable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull, languageVersionSettings)
if (!key.isStable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull, languageVersionSettings)
private fun KotlinType.canBeDefinitelyNotNullOrNotNull(settings: LanguageVersionSettings): Boolean {
return if (settings.supportsFeature(LanguageFeature.NewInference))
@@ -182,6 +187,7 @@ internal class DelegatingDataFlowInfo private constructor(
else
TypeUtils.makeNotNullable(this)
}
/**
* Call this function to clear all data flow information about
* the given data flow value.
@@ -214,7 +220,7 @@ internal class DelegatingDataFlowInfo private constructor(
}
override fun equate(
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
): DataFlowInfo {
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
val nullabilityOfA = getStableNullability(a)
@@ -222,8 +228,20 @@ internal class DelegatingDataFlowInfo private constructor(
val newTypeInfo = newTypeInfo()
var changed =
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB), languageVersionSettings, newTypeInfo) or
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA), languageVersionSettings, newTypeInfo)
putNullabilityAndTypeInfo(
resultNullabilityInfo,
a,
nullabilityOfA.refine(nullabilityOfB),
languageVersionSettings,
newTypeInfo
) or
putNullabilityAndTypeInfo(
resultNullabilityInfo,
b,
nullabilityOfB.refine(nullabilityOfA),
languageVersionSettings,
newTypeInfo
)
// NB: == has no guarantees of type equality, see KT-11280 for the example
if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) {
@@ -252,8 +270,7 @@ internal class DelegatingDataFlowInfo private constructor(
if (current is DelegatingDataFlowInfo) {
types.addAll(current.typeInfo.get(value))
current = if (value == current.valueWithGivenTypeInfo) null else current.parent
}
else {
} else {
types.addAll(current.getCollectedTypes(value, languageVersionSettings))
break
}
@@ -263,7 +280,7 @@ internal class DelegatingDataFlowInfo private constructor(
}
override fun disequate(
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
): DataFlowInfo {
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
val nullabilityOfA = getStableNullability(a)
@@ -271,15 +288,27 @@ internal class DelegatingDataFlowInfo private constructor(
val newTypeInfo = newTypeInfo()
val changed =
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB.invert()), languageVersionSettings, newTypeInfo) or
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA.invert()), languageVersionSettings, newTypeInfo)
putNullabilityAndTypeInfo(
resultNullabilityInfo,
a,
nullabilityOfA.refine(nullabilityOfB.invert()),
languageVersionSettings,
newTypeInfo
) or
putNullabilityAndTypeInfo(
resultNullabilityInfo,
b,
nullabilityOfB.refine(nullabilityOfA.invert()),
languageVersionSettings,
newTypeInfo
)
return if (changed) create(this, resultNullabilityInfo, if (newTypeInfo.isEmpty) EMPTY_TYPE_INFO else newTypeInfo) else this
}
override fun establishSubtyping(
value: DataFlowValue, type: KotlinType, languageVersionSettings: LanguageVersionSettings
value: DataFlowValue, type: KotlinType, languageVersionSettings: LanguageVersionSettings
): DataFlowInfo {
if (value.type == type) return this
if (getCollectedTypes(value, languageVersionSettings).contains(type)) return this
@@ -321,11 +350,11 @@ internal class DelegatingDataFlowInfo private constructor(
private fun Set<KotlinType>.containsNothing() = any { KotlinBuiltIns.isNothing(it) }
private fun Set<KotlinType>.intersectConsideringNothing(other: Set<KotlinType>) =
when {
other.containsNothing() -> this
this.containsNothing() -> other
else -> this.intersect(other)
}
when {
other.containsNothing() -> this
this.containsNothing() -> other
else -> this.intersect(other)
}
override fun or(other: DataFlowInfo): DataFlowInfo {
if (other === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY
@@ -358,15 +387,16 @@ internal class DelegatingDataFlowInfo private constructor(
private val EMPTY_TYPE_INFO = newTypeInfo()
private fun containsAll(first: SetMultimap<DataFlowValue, KotlinType>, second: SetMultimap<DataFlowValue, KotlinType>) =
first.entries().containsAll(second.entries())
first.entries().containsAll(second.entries())
fun newTypeInfo(): SetMultimap<DataFlowValue, KotlinType> = LinkedHashMultimap.create<DataFlowValue, KotlinType>()
private fun create(parent: DataFlowInfo?,
nullabilityInfo: Map<DataFlowValue, Nullability>,
// NB: typeInfo must be mutable here!
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
valueWithGivenTypeInfo: DataFlowValue? = null
private fun create(
parent: DataFlowInfo?,
nullabilityInfo: Map<DataFlowValue, Nullability>,
// NB: typeInfo must be mutable here!
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
valueWithGivenTypeInfo: DataFlowValue? = null
): DataFlowInfo {
val toDelete = newTypeInfo()
for (value in typeInfo.keys()) {
@@ -81,33 +81,32 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
return if (call.valueArgumentList == null && call.valueArguments.isEmpty()) {
listOf(createDynamicProperty(owner, name, call))
}
else listOf()
} else listOf()
}
}
private fun createDynamicProperty(owner: DeclarationDescriptor, name: Name, call: Call): PropertyDescriptorImpl {
val propertyDescriptor = PropertyDescriptorImpl.create(
owner,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PUBLIC,
true,
name,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false
owner,
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PUBLIC,
true,
name,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false
)
propertyDescriptor.setType(
dynamicType,
createTypeParameters(propertyDescriptor, call),
createDynamicDispatchReceiverParameter(propertyDescriptor),
null as KotlinType?
dynamicType,
createTypeParameters(propertyDescriptor, call),
createDynamicDispatchReceiverParameter(propertyDescriptor),
null as KotlinType?
)
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
@@ -121,20 +120,20 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
private fun createDynamicFunction(owner: DeclarationDescriptor, name: Name, call: Call): SimpleFunctionDescriptorImpl {
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
owner,
Annotations.EMPTY,
name,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
owner,
Annotations.EMPTY,
name,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
functionDescriptor.initialize(
null,
createDynamicDispatchReceiverParameter(functionDescriptor),
createTypeParameters(functionDescriptor, call),
createValueParameters(functionDescriptor, call),
dynamicType,
Modality.FINAL,
Visibilities.PUBLIC
null,
createDynamicDispatchReceiverParameter(functionDescriptor),
createTypeParameters(functionDescriptor, call),
createValueParameters(functionDescriptor, call),
dynamicType,
Modality.FINAL,
Visibilities.PUBLIC
)
functionDescriptor.setHasSynthesizedParameterNames(true)
return functionDescriptor
@@ -144,26 +143,27 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
return ReceiverParameterDescriptorImpl(owner, TransientReceiver(dynamicType))
}
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> = call.typeArguments.indices.map {
index
->
TypeParameterDescriptorImpl.createWithDefaultBound(
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> =
call.typeArguments.indices.map { index
->
TypeParameterDescriptorImpl.createWithDefaultBound(
owner,
Annotations.EMPTY,
false,
Variance.INVARIANT,
Name.identifier("T$index"),
index
)
}
)
}
private fun createValueParameters(owner: FunctionDescriptor, call: Call): List<ValueParameterDescriptor> {
val parameters = ArrayList<ValueParameterDescriptor>()
fun addParameter(arg : ValueArgument, outType: KotlinType, varargElementType: KotlinType?) {
fun addParameter(arg: ValueArgument, outType: KotlinType, varargElementType: KotlinType?) {
val index = parameters.size
parameters.add(ValueParameterDescriptorImpl(
parameters.add(
ValueParameterDescriptorImpl(
owner,
null,
index,
@@ -175,7 +175,8 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
/* isNoinline = */ false,
varargElementType,
SourceElement.NO_SOURCE
))
)
)
}
fun getFunctionType(funLiteralExpr: KtLambdaExpression): KotlinType {
@@ -55,14 +55,14 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinResolutionCallbacksImpl(
topLevelCallContext: BasicCallResolutionContext,
val expressionTypingServices: ExpressionTypingServices,
val typeApproximator: TypeApproximator,
val argumentTypeResolver: ArgumentTypeResolver,
val languageVersionSettings: LanguageVersionSettings,
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
val constantExpressionEvaluator: ConstantExpressionEvaluator
): KotlinResolutionCallbacks {
topLevelCallContext: BasicCallResolutionContext,
val expressionTypingServices: ExpressionTypingServices,
val typeApproximator: TypeApproximator,
val argumentTypeResolver: ArgumentTypeResolver,
val languageVersionSettings: LanguageVersionSettings,
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
val constantExpressionEvaluator: ConstantExpressionEvaluator
) : KotlinResolutionCallbacks {
val trace: BindingTrace = topLevelCallContext.trace
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
@@ -75,35 +75,42 @@ class KotlinResolutionCallbacksImpl(
}
override fun analyzeAndGetLambdaReturnArguments(
lambdaArgument: LambdaKotlinCallArgument,
isSuspend: Boolean,
receiverType: UnwrappedType?,
parameters: List<UnwrappedType>,
expectedReturnType: UnwrappedType?
lambdaArgument: LambdaKotlinCallArgument,
isSuspend: Boolean,
receiverType: UnwrappedType?,
parameters: List<UnwrappedType>,
expectedReturnType: UnwrappedType?
): List<SimpleKotlinCallArgument> {
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
val outerCallContext = psiCallArgument.outerCallContext
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings)
createSimplePSICallArgument(
trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings
)
val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT)
val lambdaInfo = LambdaInfo(
expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT
)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
lambdaInfo.expectedType, isSuspend)
val expectedType = createFunctionType(
builtIns, Annotations.EMPTY, receiverType, parameters, null,
lambdaInfo.expectedType, isSuspend
)
val approximatesExpectedType = typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType
val approximatesExpectedType =
typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType
val actualContext = outerCallContext
.replaceBindingTrace(trace)
.replaceContextDependency(lambdaInfo.contextDependency)
.replaceExpectedType(approximatesExpectedType)
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
.replaceBindingTrace(trace)
.replaceContextDependency(lambdaInfo.contextDependency)
.replaceExpectedType(approximatesExpectedType)
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
@@ -113,11 +120,10 @@ class KotlinResolutionCallbacksImpl(
val returnedExpression = expression.returnedExpression
if (returnedExpression != null) {
createCallArgument(
returnedExpression,
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
returnedExpression,
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
)
}
else {
} else {
hasReturnWithoutExpression = true
EmptyLabeledReturn(expression, builtIns)
}
@@ -141,8 +147,7 @@ class KotlinResolutionCallbacksImpl(
val lastExpression: KtExpression?
if (psiCallArgument is LambdaKotlinCallArgumentImpl) {
lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull()
}
else {
} else {
lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis()
}
@@ -159,11 +164,11 @@ class KotlinResolutionCallbacksImpl(
val expression = psiKotlinCall.psiCall.callElement.safeAs<KtExpression>() ?: return null
return transformToReceiverWithSmartCastInfo(
resolvedAtom.candidateDescriptor,
trace.bindingContext,
psiKotlinCall.resultDataFlowInfo,
ExpressionReceiver.create(expression, returnType, trace.bindingContext),
languageVersionSettings
resolvedAtom.candidateDescriptor,
trace.bindingContext,
psiKotlinCall.resultDataFlowInfo,
ExpressionReceiver.create(expression, returnType, trace.bindingContext),
languageVersionSettings
)
}
@@ -179,8 +184,8 @@ class KotlinResolutionCallbacksImpl(
val expression = findCommonParent(callElement, resolvedAtom.atom.psiKotlinCall.explicitReceiver)
val temporaryBindingTrace = TemporaryBindingTrace.create(
trace,
"Trace to check if some expression is constant, we have to avoid writing probably wrong COMPILE_TIME_VALUE slice"
trace,
"Trace to check if some expression is constant, we have to avoid writing probably wrong COMPILE_TIME_VALUE slice"
)
return constantExpressionEvaluator.evaluateExpression(expression, temporaryBindingTrace, expectedType) != null
}
@@ -61,39 +61,45 @@ import java.lang.IllegalStateException
import java.util.*
class NewResolutionOldInference(
private val candidateResolver: CandidateResolver,
private val towerResolver: TowerResolver,
private val resolutionResultsHandler: ResolutionResultsHandler,
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
private val syntheticScopes: SyntheticScopes,
private val languageVersionSettings: LanguageVersionSettings,
private val coroutineInferenceSupport: CoroutineInferenceSupport,
private val deprecationResolver: DeprecationResolver
private val candidateResolver: CandidateResolver,
private val towerResolver: TowerResolver,
private val resolutionResultsHandler: ResolutionResultsHandler,
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
private val syntheticScopes: SyntheticScopes,
private val languageVersionSettings: LanguageVersionSettings,
private val coroutineInferenceSupport: CoroutineInferenceSupport,
private val deprecationResolver: DeprecationResolver
) {
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
abstract internal fun createTowerProcessor(
outer: NewResolutionOldInference,
name: Name,
tracing: TracingStrategy,
scopeTower: ImplicitScopeTower,
explicitReceiver: DetailedReceiver?,
context: BasicCallResolutionContext
outer: NewResolutionOldInference,
name: Name,
tracing: TracingStrategy,
scopeTower: ImplicitScopeTower,
explicitReceiver: DetailedReceiver?,
context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate>
object Function : ResolutionKind<FunctionDescriptor>(KotlinCallKind.FUNCTION) {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate> {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
return createFunctionProcessor(scopeTower, name, functionFactory, outer.CandidateFactoryProviderForInvokeImpl(functionFactory), explicitReceiver)
return createFunctionProcessor(
scopeTower,
name,
functionFactory,
outer.CandidateFactoryProviderForInvokeImpl(functionFactory),
explicitReceiver
)
}
}
object Variable : ResolutionKind<VariableDescriptor>(KotlinCallKind.VARIABLE) {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate> {
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
return createVariableAndObjectProcessor(scopeTower, name, variableFactory, explicitReceiver)
@@ -102,22 +108,22 @@ class NewResolutionOldInference(
object CallableReference : ResolutionKind<CallableDescriptor>() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate> {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
return PrioritizedCompositeScopeTowerProcessor(
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
)
}
}
object Invoke : ResolutionKind<FunctionDescriptor>() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate> {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
// todo
@@ -125,7 +131,12 @@ class NewResolutionOldInference(
"Call should be CallForImplicitInvoke, but it is: ${context.call}"
}
return createProcessorWithReceiverValueOrEmpty(explicitReceiver) {
createCallTowerProcessorForExplicitInvoke(scopeTower, functionFactory, context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver), it)
createCallTowerProcessorForExplicitInvoke(
scopeTower,
functionFactory,
context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver),
it
)
}
}
@@ -133,8 +144,8 @@ class NewResolutionOldInference(
class GivenCandidates<D : CallableDescriptor> : ResolutionKind<D>() {
override fun createTowerProcessor(
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate> {
throw IllegalStateException("Should be not called")
}
@@ -142,16 +153,15 @@ class NewResolutionOldInference(
}
fun <D : CallableDescriptor> runResolution(
context: BasicCallResolutionContext,
name: Name,
kind: ResolutionKind<D>,
tracing: TracingStrategy
context: BasicCallResolutionContext,
name: Name,
kind: ResolutionKind<D>,
tracing: TracingStrategy
): OverloadResolutionResultsImpl<D> {
val explicitReceiver = context.call.explicitReceiver
val detailedReceiver = if (explicitReceiver is QualifierReceiver?) {
explicitReceiver
}
else {
} else {
context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue)
}
@@ -171,15 +181,22 @@ class NewResolutionOldInference(
return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor, nameToResolve))
}
var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference, name = nameToResolve)
var candidates =
towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference, name = nameToResolve)
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
candidates.all { it.resultingApplicability.isInapplicable }
candidates.all { it.resultingApplicability.isInapplicable }
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference, name = deprecatedName)
val processorForDeprecatedName =
kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
candidates = towerResolver.runResolve(
scopeTower,
processorForDeprecatedName,
useOrder = kind != ResolutionKind.CallableReference,
name = deprecatedName
)
}
if (candidates.isEmpty()) {
@@ -194,9 +211,9 @@ class NewResolutionOldInference(
}
fun <D : CallableDescriptor> runResolutionForGivenCandidates(
basicCallContext: BasicCallResolutionContext,
tracing: TracingStrategy,
candidates: Collection<ResolutionCandidate<D>>
basicCallContext: BasicCallResolutionContext,
tracing: TracingStrategy,
candidates: Collection<ResolutionCandidate<D>>
): OverloadResolutionResultsImpl<D> {
val resolvedCandidates = candidates.map { candidate ->
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
@@ -207,8 +224,8 @@ class NewResolutionOldInference(
}
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
CandidateResolveMode.EXIT_ON_FIRST_ERROR
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
CandidateResolveMode.EXIT_ON_FIRST_ERROR
)
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
@@ -219,27 +236,31 @@ class NewResolutionOldInference(
}
}
if (basicCallContext.collectAllCandidates) {
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
TowerResolver.AllCandidatesCollector(), useOrder = false)
val allCandidates = towerResolver.runWithEmptyTowerData(
KnownResultProcessor(resolvedCandidates),
TowerResolver.AllCandidatesCollector(), useOrder = false
)
return allCandidatesResult(allCandidates)
}
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
TowerResolver.SuccessfulResultCollector(), useOrder = true)
val processedCandidates = towerResolver.runWithEmptyTowerData(
KnownResultProcessor(resolvedCandidates),
TowerResolver.SuccessfulResultCollector(), useOrder = true
)
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
}
private fun <D: CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>)
= OverloadResolutionResultsImpl.nameNotFound<D>().apply {
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
}
private fun <D : CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>) =
OverloadResolutionResultsImpl.nameNotFound<D>().apply {
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
}
private fun <D : CallableDescriptor> convertToOverloadResults(
candidates: Collection<MyCandidate>,
tracing: TracingStrategy,
basicCallContext: BasicCallResolutionContext,
languageVersionSettings: LanguageVersionSettings
candidates: Collection<MyCandidate>,
tracing: TracingStrategy,
basicCallContext: BasicCallResolutionContext,
languageVersionSettings: LanguageVersionSettings
): OverloadResolutionResultsImpl<D> {
val resolvedCalls = candidates.map {
val (diagnostics, resolvedCall) = it
@@ -260,8 +281,17 @@ class NewResolutionOldInference(
if (resolvedCall.status.possibleTransformToSuccess()) {
for (error in diagnostics) {
when (error) {
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message))
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind)
is UnsupportedInnerClassCall -> resolvedCall.trace.report(
Errors.UNSUPPORTED.on(
resolvedCall.call.callElement,
error.message
)
)
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(
resolvedCall.trace,
error.classDescriptor,
resolvedCall.explicitReceiverKind
)
is ErrorDescriptorDiagnostic -> {
// todo
// return@map null
@@ -278,11 +308,11 @@ class NewResolutionOldInference(
// true if we found something
private fun reportAdditionalDiagnosticIfNoCandidates(
context: BasicCallResolutionContext,
name: Name,
kind: ResolutionKind<*>,
scopeTower: ImplicitScopeTower,
detailedReceiver: DetailedReceiver?
context: BasicCallResolutionContext,
name: Name,
kind: ResolutionKind<*>,
scopeTower: ImplicitScopeTower,
detailedReceiver: DetailedReceiver?
): Boolean {
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
@@ -301,17 +331,17 @@ class NewResolutionOldInference(
}
private class ImplicitScopeTowerImpl(
val resolutionContext: ResolutionContext<*>,
override val dynamicScope: MemberScope,
override val syntheticScopes: SyntheticScopes,
override val location: LookupLocation
): ImplicitScopeTower {
val resolutionContext: ResolutionContext<*>,
override val dynamicScope: MemberScope,
override val syntheticScopes: SyntheticScopes,
override val location: LookupLocation
) : ImplicitScopeTower {
private val cache = HashMap<ReceiverValue, ReceiverValueWithSmartCastInfo>()
override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? =
scope.implicitReceiver?.value?.let {
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
}
scope.implicitReceiver?.value?.let {
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
}
override val lexicalScope: LexicalScope get() = resolutionContext.scope
@@ -322,12 +352,12 @@ class NewResolutionOldInference(
}
internal class MyCandidate(
// Diagnostics that are already computed
// if resultingApplicability is successful they must be the same as `diagnostics`,
// otherwise they might be a bit different but result remains unsuccessful
val eagerDiagnostics: List<KotlinCallDiagnostic>,
val resolvedCall: MutableResolvedCall<*>,
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
// Diagnostics that are already computed
// if resultingApplicability is successful they must be the same as `diagnostics`,
// otherwise they might be a bit different but result remains unsuccessful
val eagerDiagnostics: List<KotlinCallDiagnostic>,
val resolvedCall: MutableResolvedCall<*>,
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
) : Candidate {
val diagnostics: List<KotlinCallDiagnostic> by lazy(LazyThreadSafetyMode.NONE) {
finalDiagnosticsComputation?.invoke() ?: eagerDiagnostics
@@ -344,22 +374,22 @@ class NewResolutionOldInference(
}
private inner class CandidateFactoryImpl(
val name: Name,
val basicCallContext: BasicCallResolutionContext,
val tracing: TracingStrategy
val name: Name,
val basicCallContext: BasicCallResolutionContext,
val tracing: TracingStrategy
) : CandidateFactory<MyCandidate> {
override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo?
towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo?
): MyCandidate {
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
val candidateCall = ResolvedCallImpl(
basicCallContext.call, towerCandidate.descriptor,
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
explicitReceiverKind, null, candidateTrace, tracing,
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
basicCallContext.call, towerCandidate.descriptor,
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
explicitReceiverKind, null, candidateTrace, tracing,
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
)
/**
@@ -385,8 +415,8 @@ class NewResolutionOldInference(
}
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
CandidateResolveMode.EXIT_ON_FIRST_ERROR
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
CandidateResolveMode.EXIT_ON_FIRST_ERROR
)
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
@@ -398,14 +428,14 @@ class NewResolutionOldInference(
}
private fun createDiagnosticsForCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver,
candidateCall: ResolvedCallImpl<CallableDescriptor>
towerCandidate: CandidateWithBoundDispatchReceiver,
candidateCall: ResolvedCallImpl<CallableDescriptor>
): List<ResolutionDiagnostic> =
mutableListOf<ResolutionDiagnostic>().apply {
addAll(towerCandidate.diagnostics)
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
addIfNotNull(createPreviousResolveError(candidateCall.status))
}
mutableListOf<ResolutionDiagnostic>().apply {
addAll(towerCandidate.diagnostics)
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
addIfNotNull(createPreviousResolveError(candidateCall.status))
}
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
@@ -421,16 +451,16 @@ class NewResolutionOldInference(
}
private inner class CandidateFactoryProviderForInvokeImpl(
val functionContext: CandidateFactoryImpl
val functionContext: CandidateFactoryImpl
) : CandidateFactoryProviderForInvoke<MyCandidate> {
override fun transformCandidate(
variable: MyCandidate,
invoke: MyCandidate
variable: MyCandidate,
invoke: MyCandidate
): MyCandidate {
val resolvedCallImpl = VariableAsFunctionResolvedCallImpl(
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
)
assert(variable.resultingApplicability.isSuccess) {
"Variable call must be success: $variable"
@@ -445,16 +475,20 @@ class NewResolutionOldInference(
val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let {
if (stripExplicitReceiver) CallTransformer.stripReceiver(it) else it
}
return CandidateFactoryImpl(functionContext.name, functionContext.basicCallContext.replaceCall(newCall), functionContext.tracing)
return CandidateFactoryImpl(
functionContext.name,
functionContext.basicCallContext.replaceCall(newCall),
functionContext.tracing
)
}
override fun factoryForInvoke(
variable: MyCandidate,
useExplicitReceiver: Boolean
variable: MyCandidate,
useExplicitReceiver: Boolean
): Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<MyCandidate>>? {
assert(variable.resolvedCall.status.possibleTransformToSuccess()) {
"Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " +
"and descriptor: ${variable.resolvedCall.candidateDescriptor}"
"and descriptor: ${variable.resolvedCall.candidateDescriptor}"
}
val calleeExpression = variable.resolvedCall.call.calleeExpression
val variableDescriptor = variable.resolvedCall.resultingDescriptor as VariableDescriptor
@@ -467,19 +501,22 @@ class NewResolutionOldInference(
return null // todo: create special check that there is no invoke on variable
}
val basicCallContext = functionContext.basicCallContext
val variableReceiver = ExpressionReceiver.create(calleeExpression!!,
variableType,
basicCallContext.trace.bindingContext)
val variableReceiver = ExpressionReceiver.create(
calleeExpression!!,
variableType,
basicCallContext.trace.bindingContext
)
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
// todo hacks
val functionCall = CallTransformer.CallForImplicitInvoke(
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
variableReceiver, basicCallContext.call, true)
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
variableReceiver, basicCallContext.call, true
)
val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type)
val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace)
.replaceCall(functionCall)
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
.replaceCall(functionCall)
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
val newContext = CandidateFactoryImpl(OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke)
@@ -491,25 +528,25 @@ class NewResolutionOldInference(
}
fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue) =
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings)
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings)
fun transformToReceiverWithSmartCastInfo(
containingDescriptor: DeclarationDescriptor,
bindingContext: BindingContext,
dataFlowInfo: DataFlowInfo,
receiver: ReceiverValue,
languageVersionSettings: LanguageVersionSettings
containingDescriptor: DeclarationDescriptor,
bindingContext: BindingContext,
dataFlowInfo: DataFlowInfo,
receiver: ReceiverValue,
languageVersionSettings: LanguageVersionSettings
): ReceiverValueWithSmartCastInfo {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, bindingContext, containingDescriptor)
return ReceiverValueWithSmartCastInfo(
receiver,
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
dataFlowValue.isStable
receiver,
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
dataFlowValue.isStable
)
}
@Deprecated("Temporary error")
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability): ResolutionDiagnostic(candidateLevel)
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability) : ResolutionDiagnostic(candidateLevel)
@Deprecated("Temporary error")
internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResolutionError? {
@@ -60,28 +60,28 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import java.util.*
class PSICallResolver(
private val typeResolver: TypeResolver,
private val expressionTypingServices: ExpressionTypingServices,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
private val languageVersionSettings: LanguageVersionSettings,
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
private val syntheticScopes: SyntheticScopes,
private val callComponents: KotlinCallComponents,
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
private val kotlinCallResolver: KotlinCallResolver,
private val typeApproximator: TypeApproximator,
private val argumentTypeResolver: ArgumentTypeResolver,
private val effectSystem: EffectSystem,
private val constantExpressionEvaluator: ConstantExpressionEvaluator
private val typeResolver: TypeResolver,
private val expressionTypingServices: ExpressionTypingServices,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
private val languageVersionSettings: LanguageVersionSettings,
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
private val syntheticScopes: SyntheticScopes,
private val callComponents: KotlinCallComponents,
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
private val kotlinCallResolver: KotlinCallResolver,
private val typeApproximator: TypeApproximator,
private val argumentTypeResolver: ArgumentTypeResolver,
private val effectSystem: EffectSystem,
private val constantExpressionEvaluator: ConstantExpressionEvaluator
) {
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
fun <D : CallableDescriptor> runResolutionAndInference(
context: BasicCallResolutionContext,
name: Name,
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
tracingStrategy: TracingStrategy
) : OverloadResolutionResults<D> {
context: BasicCallResolutionContext,
name: Name,
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
tracingStrategy: TracingStrategy
): OverloadResolutionResults<D> {
val isBinaryRemOperator = isBinaryRemOperator(context.call)
val refinedName = refineNameForRemOperator(isBinaryRemOperator, name)
@@ -93,7 +93,8 @@ class PSICallResolver(
val expectedType = calculateExpectedType(context)
var result = kotlinCallResolver.resolveCall(
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates)
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates
)
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
@@ -109,42 +110,48 @@ class PSICallResolver(
// actually, `D` is at least FunctionDescriptor, but right now because of CallResolver it isn't possible change upper bound for `D`
fun <D : CallableDescriptor> runResolutionAndInferenceForGivenCandidates(
context: BasicCallResolutionContext,
resolutionCandidates: Collection<ResolutionCandidate<D>>,
tracingStrategy: TracingStrategy
context: BasicCallResolutionContext,
resolutionCandidates: Collection<ResolutionCandidate<D>>,
tracingStrategy: TracingStrategy
): OverloadResolutionResults<D> {
val dispatchReceiver = resolutionCandidates.firstNotNullResult { it.dispatchReceiver }
val kotlinCall = toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
val kotlinCall =
toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
val scopeTower = ASTScopeTower(context)
val resolutionCallbacks = createResolutionCallbacks(context)
val givenCandidates = resolutionCandidates.map {
GivenCandidate(it.descriptor as FunctionDescriptor,
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
it.knownTypeParametersResultingSubstitutor)
GivenCandidate(
it.descriptor as FunctionDescriptor,
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
it.knownTypeParametersResultingSubstitutor
)
}
val result = kotlinCallResolver.resolveGivenCandidates(
scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates)
scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates
)
return convertToOverloadResolutionResults(context, result, tracingStrategy)
}
private fun <D : CallableDescriptor> resolveToDeprecatedMod(
remOperatorName: Name,
context: BasicCallResolutionContext,
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
tracingStrategy: TracingStrategy,
scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacksImpl,
expectedType: UnwrappedType?
remOperatorName: Name,
context: BasicCallResolutionContext,
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
tracingStrategy: TracingStrategy,
scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacksImpl,
expectedType: UnwrappedType?
): CallResolutionResult {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
refinedProviderForInvokeFactory, context.collectAllCandidates)
return kotlinCallResolver.resolveCall(
scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
refinedProviderForInvokeFactory, context.collectAllCandidates
)
}
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
@@ -153,9 +160,11 @@ class PSICallResolver(
}
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
constantExpressionEvaluator)
KotlinResolutionCallbacksImpl(
context, expressionTypingServices, typeApproximator,
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
constantExpressionEvaluator
)
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
val expectedType = context.expectedType.unwrap()
@@ -165,16 +174,15 @@ class PSICallResolver(
"Should have no expected type, got: $expectedType"
}
null
}
else {
} else {
if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType
}
}
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
context: BasicCallResolutionContext,
result: CallResolutionResult,
tracingStrategy: TracingStrategy
context: BasicCallResolutionContext,
result: CallResolutionResult,
tracingStrategy: TracingStrategy
): OverloadResolutionResults<D> {
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
val resolvedCalls = result.allCandidates?.map {
@@ -197,28 +205,26 @@ class PSICallResolver(
if (it.candidates.areAllFailed()) {
tracingStrategy.noneApplicable(trace, resolvedCalls)
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
}
else {
} else {
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
}
else {
} else {
tracingStrategy.ambiguity(trace, resolvedCalls)
}
}
return ManyCandidates(resolvedCalls)
}
val isInapplicableReceiver = getResultApplicability(result.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
val isInapplicableReceiver =
getResultApplicability(result.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
val resolvedCall = if (isInapplicableReceiver) {
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also {
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
}
}
else {
} else {
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
}
@@ -246,12 +252,12 @@ class PSICallResolver(
}
private fun CallResolutionResult.isEmpty(): Boolean =
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
private fun Collection<KotlinResolutionCandidate>.areAllFailed() =
all {
!it.resultingApplicability.isSuccess
}
all {
!it.resultingApplicability.isSuccess
}
private fun CallResolutionResult.areAllInapplicable(): Boolean {
val manyCandidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates
@@ -261,16 +267,16 @@ class PSICallResolver(
val applicability = getResultApplicability(diagnostics)
return applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
applicability == ResolutionCandidateApplicability.HIDDEN
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
applicability == ResolutionCandidateApplicability.HIDDEN
}
// true if we found something
private fun reportAdditionalDiagnosticIfNoCandidates(
context: BasicCallResolutionContext,
scopeTower: ImplicitScopeTower,
kind: KotlinCallKind,
kotlinCall: KotlinCall
context: BasicCallResolutionContext,
scopeTower: ImplicitScopeTower,
kind: KotlinCallKind,
kotlinCall: KotlinCall
): Boolean {
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
@@ -285,7 +291,14 @@ class PSICallResolver(
for (candidate in errorCandidates) {
if (candidate is ErrorCandidate.Classifier) {
context.trace.record(BindingContext.REFERENCE_TARGET, reference, candidate.descriptor)
context.trace.report(Errors.RESOLUTION_TO_CLASSIFIER.on(reference, candidate.descriptor, candidate.kind, candidate.errorMessage))
context.trace.report(
Errors.RESOLUTION_TO_CLASSIFIER.on(
reference,
candidate.descriptor,
candidate.kind,
candidate.errorMessage
)
)
return true
}
}
@@ -294,10 +307,11 @@ class PSICallResolver(
private inner class ASTScopeTower(
val context: BasicCallResolutionContext
): ImplicitScopeTower {
val context: BasicCallResolutionContext
) : ImplicitScopeTower {
// todo may be for invoke for case variable + invoke we should create separate dynamicScope(by newCall for invoke)
override val dynamicScope: MemberScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor)
override val dynamicScope: MemberScope =
dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor)
// same for location
override val location: LookupLocation = context.call.createLookupLocation()
@@ -317,9 +331,9 @@ class PSICallResolver(
}
private inner class FactoryProviderForInvoke(
val context: BasicCallResolutionContext,
val scopeTower: ImplicitScopeTower,
val kotlinCall: PSIKotlinCallImpl
val context: BasicCallResolutionContext,
val scopeTower: ImplicitScopeTower,
val kotlinCall: PSIKotlinCallImpl
) : CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> {
init {
@@ -327,8 +341,8 @@ class PSICallResolver(
}
override fun transformCandidate(
variable: KotlinResolutionCandidate,
invoke: KotlinResolutionCandidate
variable: KotlinResolutionCandidate,
invoke: KotlinResolutionCandidate
) = invoke
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
@@ -343,15 +357,14 @@ class PSICallResolver(
assert(variable.isSuccessful) {
"Variable call should be successful: $variable " +
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
}
val variableCallArgument = createReceiverCallArgument(variable)
val explicitReceiver = kotlinCall.explicitReceiver
val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) {
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
}
else {
} else {
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
}
@@ -369,22 +382,32 @@ class PSICallResolver(
variable.forceResolution()
val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
if (variableReceiver.possibleTypes.isNotEmpty()) {
return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true)
return ReceiverExpressionKotlinCallArgument(
createReceiverValueWithSmartCastInfo(variable),
isVariableReceiverForInvoke = true
)
}
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage())
return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
variableResult)
val variableResult = CallResolutionResult(
CallResolutionResult.Type.PARTIAL,
variable.resolvedCall,
listOf(),
variable.getSystem().asReadOnlyStorage()
)
return SubKotlinCallArgumentImpl(
CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
variableResult
)
}
// todo: decrease hacks count
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?:
error("Unexpected call : ${callForVariable.baseCall.psiCall}")
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression
?: error("Unexpected call : ${callForVariable.baseCall.psiCall}")
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
@@ -392,31 +415,32 @@ class PSICallResolver(
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor)
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
val dataFlowValue =
DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
return ReceiverValueWithSmartCastInfo(
variableReceiver,
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
dataFlowValue.isStable
variableReceiver,
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
dataFlowValue.isStable
)
}
}
private fun toKotlinCall(
context: BasicCallResolutionContext,
kotlinCallKind: KotlinCallKind,
oldCall: Call,
name: Name,
tracingStrategy: TracingStrategy,
forcedExplicitReceiver: Receiver? = null
context: BasicCallResolutionContext,
kotlinCallKind: KotlinCallKind,
oldCall: Call,
name: Name,
tracingStrategy: TracingStrategy,
forcedExplicitReceiver: Receiver? = null
): PSIKotlinCallImpl {
val resolvedExplicitReceiver = resolveExplicitReceiver(context, forcedExplicitReceiver?: oldCall.explicitReceiver, oldCall.isSafeCall())
val resolvedExplicitReceiver =
resolveExplicitReceiver(context, forcedExplicitReceiver ?: oldCall.explicitReceiver, oldCall.isSafeCall())
val resolvedTypeArguments = resolveTypeArguments(context, oldCall.typeArguments)
val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
oldCall.valueArguments
}
else {
} else {
oldCall.valueArguments.dropLast(1)
}
@@ -428,8 +452,7 @@ class PSICallResolver(
"Unexpected lambda parameters for call $oldCall"
}
oldCall.valueArguments.last()
}
else {
} else {
if (externalLambdaArguments.size > 2) {
externalLambdaArguments.drop(1).forEach {
context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression()))
@@ -440,10 +463,10 @@ class PSICallResolver(
}
val dataFlowInfoAfterArgumentsInParenthesis =
if (externalArgument != null && resolvedArgumentsInParenthesis.isNotEmpty())
resolvedArgumentsInParenthesis.last().psiCallArgument.dataFlowInfoAfterThisArgument
else
context.dataFlowInfoForArguments.resultInfo
if (externalArgument != null && resolvedArgumentsInParenthesis.isNotEmpty())
resolvedArgumentsInParenthesis.last().psiCallArgument.dataFlowInfoAfterThisArgument
else
context.dataFlowInfoForArguments.resultInfo
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
@@ -451,39 +474,47 @@ class PSICallResolver(
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments)
return PSIKotlinCallImpl(
kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments
)
}
private fun resolveExplicitReceiver(context: BasicCallResolutionContext, oldReceiver: Receiver?, isSafeCall: Boolean): ReceiverKotlinCallArgument? =
when(oldReceiver) {
null -> null
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
is ReceiverValue -> {
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
private fun resolveExplicitReceiver(
context: BasicCallResolutionContext,
oldReceiver: Receiver?,
isSafeCall: Boolean
): ReceiverKotlinCallArgument? =
when (oldReceiver) {
null -> null
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
is ReceiverValue -> {
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
var subCallArgument: ReceiverKotlinCallArgument? = null
if (oldReceiver is ExpressionReceiver) {
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
var subCallArgument: ReceiverKotlinCallArgument? = null
if (oldReceiver is ExpressionReceiver) {
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
val bindingContext = context.trace.bindingContext
val call = bindingContext[BindingContext.DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL, ktExpression]
?: ktExpression?.getCall(bindingContext)
val bindingContext = context.trace.bindingContext
val call = bindingContext[BindingContext.DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL, ktExpression]
?: ktExpression?.getCall(bindingContext)
val onlyResolvedCall = call?.let {
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
}
if (onlyResolvedCall != null) {
subCallArgument = SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument(oldReceiver.expression),
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall)
}
val onlyResolvedCall = call?.let {
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
}
if (onlyResolvedCall != null) {
subCallArgument = SubKotlinCallArgumentImpl(
CallMaker.makeExternalValueArgument(oldReceiver.expression),
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall
)
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
}
}
else -> error("Incorrect receiver: $oldReceiver")
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
}
else -> error("Incorrect receiver: $oldReceiver")
}
private fun resolveType(context: BasicCallResolutionContext, typeReference: KtTypeReference?): UnwrappedType? {
if (typeReference == null) return null
@@ -494,18 +525,19 @@ class PSICallResolver(
}
private fun resolveTypeArguments(context: BasicCallResolutionContext, typeArguments: List<KtTypeProjection>): List<TypeArgument> =
typeArguments.map { projection ->
if (projection.projectionKind != KtProjectionKind.NONE) {
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
}
ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings)
resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) } ?: TypeArgumentPlaceholder
typeArguments.map { projection ->
if (projection.projectionKind != KtProjectionKind.NONE) {
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
}
ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings)
resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) }
?: TypeArgumentPlaceholder
}
private fun resolveArgumentsInParenthesis(
context: BasicCallResolutionContext,
arguments: List<ValueArgument>
context: BasicCallResolutionContext,
arguments: List<ValueArgument>
): List<KotlinCallArgument> {
val dataFlowInfoForArguments = context.dataFlowInfoForArguments
return arguments.map { argument ->
@@ -516,9 +548,9 @@ class PSICallResolver(
}
private fun resolveValueArgument(
outerCallContext: BasicCallResolutionContext,
startDataFlowInfo: DataFlowInfo,
valueArgument: ValueArgument
outerCallContext: BasicCallResolutionContext,
startDataFlowInfo: DataFlowInfo,
valueArgument: ValueArgument
): PSIKotlinCallArgument {
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns)
@@ -534,17 +566,21 @@ class PSICallResolver(
if (ktExpression is KtCollectionLiteralExpression) {
return CollectionLiteralKotlinCallArgumentImpl(
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext)
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext
)
}
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
if (ktExpression is KtCallableReferenceExpression) {
checkNoSpread(outerCallContext, valueArgument)
val expressionTypingContext = ExpressionTypingContext.newContext(context)
val lhsResult = if (ktExpression.isEmptyLHS) null else doubleColonExpressionResolver.resolveDoubleColonLHS(ktExpression, expressionTypingContext)
val lhsResult = if (ktExpression.isEmptyLHS) null else doubleColonExpressionResolver.resolveDoubleColonLHS(
ktExpression,
expressionTypingContext
)
val newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo
val name = ktExpression.callableReference.getReferencedNameAsName()
@@ -556,12 +592,10 @@ class PSICallResolver(
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
}
else {
} else {
LHSResult.Error
}
}
else {
} else {
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
@@ -573,15 +607,16 @@ class PSICallResolver(
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
if (qualifier is ClassQualifier) {
LHSResult.Type(qualifier, lhsResult.type.unwrap())
}
else {
} else {
LHSResult.Error
}
}
}
return CallableReferenceKotlinCallArgumentImpl(ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
ktExpression, argumentName, lhsNewResult, name)
return CallableReferenceKotlinCallArgumentImpl(
ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
ktExpression, argumentName, lhsNewResult, name
)
}
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
@@ -590,29 +625,33 @@ class PSICallResolver(
}
private fun processFunctionalExpression(
outerCallContext: BasicCallResolutionContext,
argumentExpression: KtExpression,
startDataFlowInfo: DataFlowInfo,
valueArgument: ValueArgument,
argumentName: Name?,
builtIns: KotlinBuiltIns
outerCallContext: BasicCallResolutionContext,
argumentExpression: KtExpression,
startDataFlowInfo: DataFlowInfo,
valueArgument: ValueArgument,
argumentName: Name?,
builtIns: KotlinBuiltIns
): PSIKotlinCallArgument? {
val expression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: return null
val postponedExpression = if (expression is KtFunctionLiteral) expression.getParentOfType<KtLambdaExpression>(true) else expression
val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) {
is KtLambdaExpression ->
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral))
LambdaKotlinCallArgumentImpl(
outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral)
)
is KtNamedFunction -> {
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference)
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray()
val returnType = resolveType(outerCallContext, postponedExpression.typeReference) ?:
if (postponedExpression.hasBlockBody()) builtIns.unitType else null
val returnType = resolveType(outerCallContext, postponedExpression.typeReference)
?: if (postponedExpression.hasBlockBody()) builtIns.unitType else null
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName,
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType)
FunctionExpressionImpl(
outerCallContext, valueArgument, startDataFlowInfo, argumentName,
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType
)
}
else -> return null
@@ -47,16 +47,16 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
class ResolvedAtomCompleter(
private val resultSubstitutor: NewTypeSubstitutor,
private val trace: BindingTrace,
private val topLevelCallContext: BasicCallResolutionContext,
private val resultSubstitutor: NewTypeSubstitutor,
private val trace: BindingTrace,
private val topLevelCallContext: BasicCallResolutionContext,
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
private val expressionTypingServices: ExpressionTypingServices,
private val argumentTypeResolver: ArgumentTypeResolver,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
private val expressionTypingServices: ExpressionTypingServices,
private val argumentTypeResolver: ArgumentTypeResolver,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
) {
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings, deprecationResolver)
@@ -79,7 +79,12 @@ class ResolvedAtomCompleter(
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection<KotlinCallDiagnostic>): ResolvedCall<*>? {
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(resolvedCallAtom, trace, resultSubstitutor, diagnostics)
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(
resolvedCallAtom,
trace,
resultSubstitutor,
diagnostics
)
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall, diagnostics)
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
@@ -90,20 +95,20 @@ class ResolvedAtomCompleter(
}
private fun completeLambda(lambda: ResolvedLambdaAtom) {
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
updateTraceForLambdaReturnType(lambda, trace, returnType)
updateTraceForLambdaReturnType(lambda, trace, returnType)
for (lambdaResult in lambda.resultArguments) {
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
val newContext =
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
.replaceExpectedType(returnType)
.replaceBindingTrace(trace)
for (lambdaResult in lambda.resultArguments) {
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
val newContext =
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
.replaceExpectedType(returnType)
.replaceBindingTrace(trace)
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
}
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
}
}
private fun updateTraceForLambdaReturnType(lambda: ResolvedLambdaAtom, trace: BindingTrace, returnType: UnwrappedType) {
@@ -123,8 +128,8 @@ class ResolvedAtomCompleter(
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
}
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
throw AssertionError("No function descriptor for resolved lambda argument")
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl
?: throw AssertionError("No function descriptor for resolved lambda argument")
functionDescriptor.setReturnType(returnType)
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
@@ -132,26 +137,31 @@ class ResolvedAtomCompleter(
}
private fun completeCallableReference(
resolvedAtom: ResolvedCallableReferenceAtom
resolvedAtom: ResolvedCallableReferenceAtom
) {
val callableCandidate = resolvedAtom.candidate
if (callableCandidate == null) {
// todo report meanfull diagnostic here
return
}
val resultTypeParameters = callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) }
val resultTypeParameters =
callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) }
val psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
val resultSubstitutor = IndexedParametersSubstitution(
callableCandidate.candidate.typeParameters,
resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
// write down type for callable reference expression
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
resultType,
callableReferenceExpression)
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
trace, expressionTypingServices.statementFilter,
resultType,
callableReferenceExpression
)
val reference = callableReferenceExpression.callableReference
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
@@ -166,9 +176,11 @@ class ResolvedAtomCompleter(
val tracing = TracingStrategyImpl.create(reference, psiCall)
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
val resolvedCall = ResolvedCallImpl(
psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)
)
resolvedCall.setResultingSubstitutor(resultSubstitutor)
tracing.bindCall(trace, psiCall)
@@ -179,27 +191,40 @@ class ResolvedAtomCompleter(
resolvedCall.markCallAsCompleted()
when (callableCandidate.candidate) {
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(
callableReferenceExpression,
resultType,
topLevelCallContext
)
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(
callableReferenceExpression,
resultType,
topLevelCallContext
)
}
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
trace.recordType(callableReferenceExpression, resultType)
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(
callableCandidate.candidate,
topLevelCallContext.trace,
callableReferenceExpression
)
}
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
val context = psiCallArgument.outerCallContext
val expectedType = collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
val expectedType =
collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
val actualContext = context
.replaceBindingTrace(trace)
.replaceExpectedType(expectedType)
.replaceContextDependency(ContextDependency.INDEPENDENT)
.replaceBindingTrace(trace)
.replaceExpectedType(expectedType)
.replaceContextDependency(ContextDependency.INDEPENDENT)
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
}
@@ -49,8 +49,8 @@ fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedParameters(): Boolean {
return !parameterToArgumentMap.keys.containsAll(resultingDescriptor.valueParameters)
}
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped()
= call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped() =
call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
val resolvedValueArgument = valueArguments[parameter]
@@ -73,9 +73,9 @@ fun <D : CallableDescriptor> ResolvedCall<D>.usesDefaultArguments(): Boolean {
// call
fun <C: ResolutionContext<C>> Call.hasUnresolvedArguments(context: ResolutionContext<C>): Boolean {
fun <C : ResolutionContext<C>> Call.hasUnresolvedArguments(context: ResolutionContext<C>): Boolean {
val arguments = valueArguments.map { it.getArgumentExpression() }
return arguments.any (fun (argument: KtExpression?): Boolean {
return arguments.any(fun(argument: KtExpression?): Boolean {
if (argument == null || ArgumentTypeResolver.isFunctionLiteralOrCallableReference(argument, context)) return false
val resolvedCall = argument.getResolvedCall(context.trace.bindingContext) as MutableResolvedCall<*>?
@@ -91,12 +91,11 @@ fun Call.getValueArgumentsInParentheses(): List<ValueArgument> = valueArguments.
fun KtCallElement.getValueArgumentsInParentheses(): List<ValueArgument> = valueArguments.filterArgsInParentheses()
fun Call.getValueArgumentListOrElement(): KtElement =
if (this is CallTransformer.CallForImplicitInvoke) {
outerCall.getValueArgumentListOrElement()
}
else {
valueArgumentList ?: calleeExpression ?: callElement
}
if (this is CallTransformer.CallForImplicitInvoke) {
outerCall.getValueArgumentListOrElement()
} else {
valueArgumentList ?: calleeExpression ?: callElement
}
@Suppress("UNCHECKED_CAST")
private fun List<ValueArgument?>.filterArgsInParentheses() = filter { it !is KtLambdaArgument } as List<ValueArgument>
@@ -111,6 +110,7 @@ fun Call.getValueArgumentForExpression(expression: KtExpression): ValueArgument?
else -> null
}
}
fun KtElement.isParenthesizedExpression() = generateSequence(this) { it.deparenthesizeStructurally() }.any { it == expression }
return valueArguments.firstOrNull { it?.getArgumentExpression()?.isParenthesizedExpression() ?: false }
}
@@ -156,8 +156,9 @@ fun KtElement.getCall(context: BindingContext): Call? {
fun KtElement.getParentCall(context: BindingContext, strict: Boolean = true): Call? {
val callExpressionTypes = arrayOf<Class<out KtElement>?>(
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java)
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java
)
val parent = if (strict) {
PsiTreeUtil.getParentOfType(this, *callExpressionTypes)
@@ -248,20 +249,19 @@ fun Call.isSafeCall(): Boolean {
fun Call.isCallableReference(): Boolean {
val callElement = callElement
return callElement is KtNameReferenceExpression &&
(callElement.parent as? KtCallableReferenceExpression)?.callableReference == callElement
(callElement.parent as? KtCallableReferenceExpression)?.callableReference == callElement
}
fun Call.createLookupLocation(): KotlinLookupLocation {
val calleeExpression = calleeExpression
val element =
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
else callElement
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
else callElement
return KotlinLookupLocation(element)
}
fun ResolvedCall<*>.getFirstArgumentExpression(): KtExpression? =
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
fun ResolvedCall<*>.getReceiverExpression(): KtExpression? =
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?:
dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
@@ -26,11 +26,11 @@ import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
override fun check(
targetDescriptor: ClassifierDescriptor,
trace: BindingTrace,
element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
targetDescriptor: ClassifierDescriptor,
trace: BindingTrace,
element: PsiElement,
languageVersionSettings: LanguageVersionSettings,
deprecationResolver: DeprecationResolver
) {
targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version ->
trace.report(Errors.API_NOT_AVAILABLE.on(element, version.versionString, languageVersionSettings.apiVersion.versionString))
@@ -29,10 +29,10 @@ import org.jetbrains.kotlin.types.isError
object ConstModifierChecker : SimpleDeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor !is VariableDescriptor || !declaration.hasModifier(KtTokens.CONST_KEYWORD)) return
@@ -45,11 +45,13 @@ object ConstModifierChecker : SimpleDeclarationChecker {
}
fun canBeConst(declaration: KtDeclaration, constModifierPsiElement: PsiElement, descriptor: VariableDescriptor): Boolean =
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
private fun checkCanBeConst(declaration: KtDeclaration,
constModifierPsiElement: PsiElement,
descriptor: VariableDescriptor): ConstApplicability {
private fun checkCanBeConst(
declaration: KtDeclaration,
constModifierPsiElement: PsiElement,
descriptor: VariableDescriptor
): ConstApplicability {
if (descriptor.isVar) {
return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable()
}
@@ -34,12 +34,12 @@ import org.jetbrains.kotlin.resolve.OverridingUtil
class DelegationChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext,
languageVersionSettings: LanguageVersionSettings,
expectActualTracker: ExpectActualTracker
) {
if (descriptor !is ClassDescriptor) return
if (declaration !is KtClassOrObject) return
@@ -57,21 +57,27 @@ class DelegationChecker : DeclarationChecker {
}
private fun checkDescriptor(
classDeclaration: KtClassOrObject,
delegatedDescriptor: CallableMemberDescriptor,
delegatedToDescriptor: CallableMemberDescriptor,
diagnosticHolder: DiagnosticSink
classDeclaration: KtClassOrObject,
delegatedDescriptor: CallableMemberDescriptor,
delegatedToDescriptor: CallableMemberDescriptor,
diagnosticHolder: DiagnosticSink
) {
val reachableFromDelegated =
OverridingUtil.filterOutOverridden(
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
OverridingUtil.filterOutOverridden(
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
val nonAbstractReachable = reachableFromDelegated.filter { it.modality == Modality.OPEN }
if (nonAbstractReachable.isNotEmpty()) {
/*In case of MANY_IMPL_MEMBER_NOT_IMPLEMENTED error there could be several elements otherwise only one*/
diagnosticHolder.report(DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.on(classDeclaration, delegatedDescriptor, nonAbstractReachable))
diagnosticHolder.report(
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.on(
classDeclaration,
delegatedDescriptor,
nonAbstractReachable
)
)
}
}
}

Some files were not shown because too many files have changed in this diff Show More