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
@@ -70,7 +70,9 @@ class EmptyResolverForProject<M : ModuleInfo> : ResolverForProject<M>() {
get() = "Empty resolver" get() = "Empty resolver"
override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? = null 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 fun descriptorForModule(moduleInfo: M) = diagnoseUnknownModuleInfo(listOf(moduleInfo))
override val allModules: Collection<M> = listOf() 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")
@@ -117,16 +119,22 @@ class ResolverForProjectImpl<M : ModuleInfo>(
} }
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) { private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
moduleDescriptor.setDependencies(LazyModuleDependencies( moduleDescriptor.setDependencies(
LazyModuleDependencies(
projectContext.storageManager, projectContext.storageManager,
module, module,
firstDependency, firstDependency,
this)) this
)
)
val content = modulesContent(module) val content = modulesContent(module)
moduleDescriptor.initialize( moduleDescriptor.initialize(
DelegatingPackageFragmentProvider(this, moduleDescriptor, content, DelegatingPackageFragmentProvider(
packageOracleFactory.createOracle(module))) this, moduleDescriptor, content,
packageOracleFactory.createOracle(module)
)
)
} }
private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>() private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>()
@@ -156,7 +164,8 @@ class ResolverForProjectImpl<M : ModuleInfo>(
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module), module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
platformParameters, targetEnvironment, this@ResolverForProjectImpl, platformParameters, targetEnvironment, this@ResolverForProjectImpl,
languageSettingsProvider, languageSettingsProvider,
packagePartProviderFactory(module, modulesContent(module))) packagePartProviderFactory(module, modulesContent(module))
)
} }
} }
} }
@@ -204,12 +213,14 @@ class ResolverForProjectImpl<M : ModuleInfo>(
} }
private fun createModuleDescriptor(module: M): ModuleData { private fun createModuleDescriptor(module: M): ModuleData {
val moduleDescriptor = ModuleDescriptorImpl(module.name, val moduleDescriptor = ModuleDescriptorImpl(
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities) module.name,
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities
)
moduleInfoByDescriptor[moduleDescriptor] = module moduleInfoByDescriptor[moduleDescriptor] = module
setupModuleDescriptor(module, moduleDescriptor) setupModuleDescriptor(module, moduleDescriptor)
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker() ?: val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker()
(PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB }) ?: (PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
return ModuleData(moduleDescriptor, modificationTracker, modificationTracker?.modificationCount) return ModuleData(moduleDescriptor, modificationTracker, modificationTracker?.modificationCount)
} }
} }
@@ -366,6 +377,7 @@ interface ResolverForModuleComputationTracker {
fun onResolverComputed(moduleInfo: ModuleInfo) fun onResolverComputed(moduleInfo: ModuleInfo)
companion object { 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
} }
} }
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
interface ControlFlowBuilder { interface ControlFlowBuilder {
// Subroutines // Subroutines
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null) fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
val currentSubroutine: KtElement val currentSubroutine: KtElement
@@ -1544,8 +1544,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
//noinspection EnumSwitchStatementWhichMissesCases //noinspection EnumSwitchStatementWhichMissesCases
when (kind) { when (kind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver = resolvedCall.extensionReceiver ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver =
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {} resolvedCall.extensionReceiver
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {
}
} }
} }
@@ -74,9 +74,11 @@ class PseudocodeVariableDataCollector(
val variableDeclarationElement = instruction.variableDeclarationElement val variableDeclarationElement = instruction.variableDeclarationElement
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse
val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor) val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor)
?: throw AssertionError("Variable or class descriptor should correspond to " + ?: throw AssertionError(
"Variable or class descriptor should correspond to " +
"the instruction for ${instruction.element.text}.\n" + "the instruction for ${instruction.element.text}.\n" +
"Descriptor: $descriptor") "Descriptor: $descriptor"
)
blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope) blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope)
} }
}) })
@@ -113,8 +113,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) { if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) {
valsWithTrivialInitializer.add(descriptor) valsWithTrivialInitializer.add(descriptor)
} } else {
else {
nonTrivialVariables.add(descriptor) nonTrivialVariables.add(descriptor)
} }
} }
@@ -148,15 +147,17 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) { return pseudocodeVariableDataCollector.collectData(
instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> -> TraversalOrder.FORWARD,
InitControlFlowInfo()
) { instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
val enterInstructionData = mergeIncomingEdgesDataForInitializers(instruction, incomingEdgesData, blockScopeVariableInfo) val enterInstructionData = mergeIncomingEdgesDataForInitializers(instruction, incomingEdgesData, blockScopeVariableInfo)
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny( val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
instruction, enterInstructionData, blockScopeVariableInfo) instruction, enterInstructionData, blockScopeVariableInfo
)
Edges(enterInstructionData, exitInstructionData) Edges(enterInstructionData, exitInstructionData)
}.mapValues { }.mapValues { (instruction, edges) ->
(instruction, edges) ->
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!! val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing)) Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
} }
@@ -170,8 +171,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null) val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null)
when (instruction) { when (instruction) {
is VariableDeclarationInstruction -> is VariableDeclarationInstruction ->
extractValWithTrivialInitializer(instruction)?.let { extractValWithTrivialInitializer(instruction)?.let { variableDescriptor ->
variableDescriptor ->
declaredSet = declaredSet.add(variableDescriptor) declaredSet = declaredSet.add(variableDescriptor)
} }
is WriteValueInstruction -> { is WriteValueInstruction -> {
@@ -216,8 +216,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> { override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
val initial = delegate?.asMap() ?: ImmutableHashMap.empty() val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
return declaredSet.fold(initial) { return declaredSet.fold(initial) { acc, variableDescriptor ->
acc, variableDescriptor ->
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!) acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
} }
} }
@@ -246,15 +245,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
private fun addVariableInitStateFromCurrentInstructionIfAny( private fun addVariableInitStateFromCurrentInstructionIfAny(
instruction: Instruction, instruction: Instruction,
enterInstructionData: InitControlFlowInfo, enterInstructionData: InitControlFlowInfo,
blockScopeVariableInfo: BlockScopeVariableInfo): InitControlFlowInfo { blockScopeVariableInfo: BlockScopeVariableInfo
): InitControlFlowInfo {
if (instruction is MagicInstruction) { if (instruction is MagicInstruction) {
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) { if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
return enterInstructionData.iterator().fold(enterInstructionData) { return enterInstructionData.iterator().fold(enterInstructionData) { result, (key, value) ->
result, (key, value) ->
if (!value.definitelyInitialized()) { if (!value.definitelyInitialized()) {
result.put(key, VariableControlFlowState.createInitializedExhaustively(value.isDeclared)) result.put(key, VariableControlFlowState.createInitializedExhaustively(value.isDeclared))
} } else result
else result
} }
} }
} }
@@ -275,8 +273,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
val enterInitState = enterInstructionData.getOrNull(variable) val enterInitState = enterInstructionData.getOrNull(variable)
val initializationAtThisElement = VariableControlFlowState.create(instruction.element is KtProperty, enterInitState) val initializationAtThisElement = VariableControlFlowState.create(instruction.element is KtProperty, enterInitState)
exitInstructionData = exitInstructionData.put(variable, initializationAtThisElement, enterInitState) exitInstructionData = exitInstructionData.put(variable, initializationAtThisElement, enterInitState)
} } else {
else {
// instruction instanceof VariableDeclarationInstruction // instruction instanceof VariableDeclarationInstruction
val enterInitState = val enterInitState =
enterInstructionData.getOrNull(variable) enterInstructionData.getOrNull(variable)
@@ -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) { val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) {
incomingEdgesData.single() incomingEdgesData.single()
} } else {
else {
incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData -> incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) -> edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor))) subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
@@ -321,13 +320,11 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
?.takeIf { it in rootVariables.nonTrivialVariables } ?.takeIf { it in rootVariables.nonTrivialVariables }
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) { if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
Edges(enterResult, enterResult) Edges(enterResult, enterResult)
} } else {
else {
val exitResult = val exitResult =
if (instruction is ReadValueInstruction) { if (instruction is ReadValueInstruction) {
enterResult.put(variableDescriptor, VariableUseState.READ) enterResult.put(variableDescriptor, VariableUseState.READ)
} } else {
else {
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor) var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
if (variableUseState == null) { if (variableUseState == null) {
variableUseState = VariableUseState.UNUSED variableUseState = VariableUseState.UNUSED
@@ -341,8 +338,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
} }
Edges(enterResult, exitResult) Edges(enterResult, exitResult)
} }
}.mapValues { }.mapValues { (_, edges) ->
(_, edges) ->
Edges( Edges(
edgesForTrivialVals.incoming.replaceDelegate(edges.incoming), edgesForTrivialVals.incoming.replaceDelegate(edges.incoming),
@@ -387,8 +383,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> { override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
val initial = delegate?.asMap() ?: ImmutableHashMap.empty() val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
return used.fold(initial) { return used.fold(initial) { acc, variableDescriptor ->
acc, variableDescriptor ->
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!) acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
} }
} }
@@ -48,8 +48,7 @@ class UnreachableCodeImpl(
// element is dead but its only child is alive and has the same text range // 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 listOf(element.textRange.endOffset.let { TextRange(it, it) })
} }
} } else {
else {
listOf(element.textRange!!) listOf(element.textRange!!)
} }
} }
@@ -61,11 +60,11 @@ class UnreachableCodeImpl(
val children = ArrayList<PsiElement>() val children = ArrayList<PsiElement>()
acceptChildren(object : PsiElementVisitor() { acceptChildren(object : PsiElementVisitor() {
override fun visitElement(element: PsiElement) { 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()) { if (isReachable || element.children.isEmpty()) {
children.add(element) children.add(element)
} } else {
else {
element.acceptChildren(this) element.acceptChildren(this)
} }
} }
@@ -102,8 +101,7 @@ class UnreachableCodeImpl(
private fun List<PsiElement>.mergeAdjacentTextRanges(): List<TextRange> { private fun List<PsiElement>.mergeAdjacentTextRanges(): List<TextRange> {
val result = ArrayList<TextRange>() val result = ArrayList<TextRange>()
val lastRange = fold(null as TextRange?) { val lastRange = fold(null as TextRange?) { currentTextRange, element ->
currentTextRange, element ->
val elementRange = element.textRange!! val elementRange = element.textRange!!
when { when {
@@ -201,8 +201,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
if (checkedDescriptors.containsAll(checkedDescriptorSubclasses)) return listOf() if (checkedDescriptors.containsAll(checkedDescriptorSubclasses)) return listOf()
checkedDescriptors.addAll(subclasses) checkedDescriptors.addAll(subclasses)
checkedDescriptors.removeAll(checkedDescriptorSubclasses) checkedDescriptors.removeAll(checkedDescriptorSubclasses)
} } else {
else {
checkedDescriptors.addAll(checkedDescriptorSubclasses) checkedDescriptors.addAll(checkedDescriptorSubclasses)
} }
} }
@@ -258,9 +257,11 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
object WhenChecker { object WhenChecker {
private val exhaustivenessCheckers = listOf(WhenOnBooleanExhaustivenessChecker, private val exhaustivenessCheckers = listOf(
WhenOnBooleanExhaustivenessChecker,
WhenOnEnumExhaustivenessChecker, WhenOnEnumExhaustivenessChecker,
WhenOnSealedExhaustivenessChecker) WhenOnSealedExhaustivenessChecker
)
@JvmStatic @JvmStatic
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) = fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) =
@@ -276,8 +277,8 @@ object WhenChecker {
} }
@JvmStatic @JvmStatic
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor? fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor? =
= type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) } type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
@JvmStatic @JvmStatic
@@ -331,11 +332,11 @@ object WhenChecker {
is KtWhenConditionWithExpression -> { is KtWhenConditionWithExpression -> {
val constantExpression = condition.expression ?: continue@conditions val constantExpression = condition.expression ?: continue@conditions
val constant = ConstantExpressionEvaluator.getConstant( val constant = ConstantExpressionEvaluator.getConstant(
constantExpression, trace.bindingContext) ?: continue@conditions constantExpression, trace.bindingContext
) ?: continue@conditions
if (checkedConstants.contains(constant)) { if (checkedConstants.contains(constant)) {
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression)) trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression))
} } else {
else {
checkedConstants.add(constant) checkedConstants.add(constant)
} }
@@ -346,12 +347,12 @@ object WhenChecker {
val typeWithIsNegation = type to condition.isNegated val typeWithIsNegation = type to condition.isNegated
if (checkedTypes.contains(typeWithIsNegation)) { if (checkedTypes.contains(typeWithIsNegation)) {
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(typeReference)) trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(typeReference))
} } else {
else {
checkedTypes.add(typeWithIsNegation) checkedTypes.add(typeWithIsNegation)
} }
} }
else -> {} else -> {
}
} }
} }
} }
@@ -58,8 +58,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val worker = builders.pop() val worker = builders.pop()
builder = if (!builders.isEmpty()) { builder = if (!builders.isEmpty()) {
builders.peek() builders.peek()
} } else {
else {
null null
} }
return worker return worker
@@ -70,8 +69,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val shouldInlnie = invocationKind != null val shouldInlnie = invocationKind != null
if (builder != null && subroutine is KtFunctionLiteral) { if (builder != null && subroutine is KtFunctionLiteral) {
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie) pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
} } else {
else {
pushBuilder(subroutine, subroutine, shouldInlnie) pushBuilder(subroutine, subroutine, shouldInlnie)
} }
delegateBuilder.enterBlockScope(subroutine) delegateBuilder.enterBlockScope(subroutine)
@@ -86,8 +84,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val builder = builders.peek() val builder = builders.peek()
if (invocationKind == null) { if (invocationKind == null) {
builder.declareFunction(subroutine, worker.pseudocode) builder.declareFunction(subroutine, worker.pseudocode)
} } else {
else {
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind) builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
} }
} }
@@ -133,7 +130,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
createUnboundLabel("loop exit point"), createUnboundLabel("loop exit point"),
createUnboundLabel("body entry point"), createUnboundLabel("body entry point"),
createUnboundLabel("body exit point"), createUnboundLabel("body exit point"),
createUnboundLabel("condition entry point")) createUnboundLabel("condition entry point")
)
bindLabel(info.entryPoint) bindLabel(info.entryPoint)
elementToLoopInfo.put(expression, info) elementToLoopInfo.put(expression, info)
return info return info
@@ -160,7 +158,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
val blockInfo = SubroutineInfo( val blockInfo = SubroutineInfo(
subroutine, subroutine,
/* entry point */ createUnboundLabel(), /* entry point */ createUnboundLabel(),
/* exit point */ createUnboundLabel()) /* exit point */ createUnboundLabel()
)
elementToSubroutineInfo.put(subroutine, blockInfo) elementToSubroutineInfo.put(subroutine, blockInfo)
allBlocks.push(blockInfo) allBlocks.push(blockInfo)
bindLabel(blockInfo.entryPoint) bindLabel(blockInfo.entryPoint)
@@ -175,7 +174,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun getLoopExitPoint(loop: KtLoopExpression): Label? =// It's quite possible to have null here, see testBreakInsideLocal 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) 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 elementToSubroutineInfo[labelElement]?.exitPoint
private val currentScope: BlockScope private val currentScope: BlockScope
@@ -256,7 +256,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
lValue: KtElement, lValue: KtElement,
rValue: PseudoValue, rValue: PseudoValue,
target: AccessTarget, target: AccessTarget,
receiverValues: Map<PseudoValue, ReceiverValue>) { receiverValues: Map<PseudoValue, ReceiverValue>
) {
add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue)) add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue))
} }
@@ -355,9 +356,11 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
instructionElement: KtElement, instructionElement: KtElement,
valueElement: KtElement?, valueElement: KtElement?,
inputValues: List<PseudoValue>, inputValues: List<PseudoValue>,
kind: MagicKind): MagicInstruction { kind: MagicKind
): MagicInstruction {
val instruction = MagicInstruction( val instruction = MagicInstruction(
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory) instructionElement, valueElement, currentScope, inputValues, kind, valueFactory
)
add(instruction) add(instruction)
return instruction return instruction
} }
@@ -378,7 +381,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
valueElement: KtElement, valueElement: KtElement,
resolvedCall: ResolvedCall<*>, resolvedCall: ResolvedCall<*>,
receiverValues: Map<PseudoValue, ReceiverValue>, receiverValues: Map<PseudoValue, ReceiverValue>,
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction { arguments: Map<PseudoValue, ValueParameterDescriptor>
): CallInstruction {
val returnType = resolvedCall.resultingDescriptor.returnType val returnType = resolvedCall.resultingDescriptor.returnType
val instruction = CallInstruction( val instruction = CallInstruction(
valueElement, valueElement,
@@ -386,7 +390,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
resolvedCall, resolvedCall,
receiverValues, receiverValues,
arguments, arguments,
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory) if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory
)
add(instruction) add(instruction)
return instruction return instruction
} }
@@ -394,7 +399,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
override fun predefinedOperation( override fun predefinedOperation(
expression: KtExpression, expression: KtExpression,
operation: ControlFlowBuilder.PredefinedOperation, operation: ControlFlowBuilder.PredefinedOperation,
inputValues: List<PseudoValue>): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation)) inputValues: List<PseudoValue>
): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) { private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) {
ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND
@@ -63,7 +63,8 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
resolvedCall.dispatchReceiver -> { resolvedCall.dispatchReceiver -> {
val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors() val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors()
return or(rootCallableDescriptors.mapNotNull { 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()
}) })
} }
} }
@@ -164,8 +165,7 @@ fun getExpectedTypePredicate(
val receiverValue = it.receiverValues[value] val receiverValue = it.receiverValues[value]
if (receiverValue != null) { if (receiverValue != null) {
typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue)) typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue))
} } else {
else {
val expectedType = when (accessTarget) { val expectedType = when (accessTarget) {
is AccessTarget.Call -> is AccessTarget.Call ->
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type (accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
@@ -182,8 +182,7 @@ fun getExpectedTypePredicate(
val receiverValue = it.receiverValues[value] val receiverValue = it.receiverValues[value]
if (receiverValue != null) { if (receiverValue != null) {
typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue)) typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue))
} } else {
else {
it.arguments[value]?.let { parameter -> it.arguments[value]?.let { parameter ->
val expectedType = when (it.resolvedCall.valueArguments[parameter]) { val expectedType = when (it.resolvedCall.valueArguments[parameter]) {
is VarargValueArgument -> is VarargValueArgument ->
@@ -27,7 +27,8 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver 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? { override fun visitIsExpression(expression: KtIsExpression, data: Unit): BooleanExpression? {
val variable = dispatcher.parseVariable(expression.leftHandSide) ?: return null val variable = dispatcher.parseVariable(expression.leftHandSide) ?: return null
val typeReference = expression.typeReference ?: return null val typeReference = expression.typeReference ?: return null
@@ -101,7 +102,12 @@ internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiCo
if (expression.operationToken != KtTokens.EXCL) return super.visitUnaryExpression(expression, data) if (expression.operationToken != KtTokens.EXCL) return super.visitUnaryExpression(expression, data)
val arg = expression.baseExpression?.accept(this, data) ?: return null val arg = expression.baseExpression?.accept(this, data) ?: return null
if (arg !is ContractDescriptionValue) { 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) return LogicalNot(arg)
} }
@@ -24,4 +24,5 @@ internal interface PsiEffectParser {
fun tryParseEffect(expression: KtExpression): EffectDeclaration? 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> { override fun mark(element: PsiElement): List<TextRange> {
when (element) { when (element) {
is KtObjectLiteralExpression -> { is KtObjectLiteralExpression -> {
@@ -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> { override fun mark(element: KtDeclaration): List<TextRange> {
return markElement(getElementToMark(element)) 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> { override fun mark(element: KtNamedDeclaration): List<TextRange> {
val nameIdentifier = element.nameIdentifier val nameIdentifier = element.nameIdentifier
return when { return when {
@@ -125,7 +128,8 @@ object PositioningStrategies {
private val classKindTokens = TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD, KtTokens.INTERFACE_KEYWORD) 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> { override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out KtNamedDeclaration>): List<TextRange> {
val element = diagnostic.psiElement val element = diagnostic.psiElement
val callableDeclaration = element as? KtCallableDeclaration val callableDeclaration = element as? KtCallableDeclaration
@@ -141,8 +145,7 @@ object PositioningStrategies {
?: element.nameIdentifier ?: element.nameIdentifier
if (startElement != null && endElement != null) { if (startElement != null && endElement != null) {
return markRange(startElement, endElement) return markRange(startElement, endElement)
} } else {
else {
endElement endElement
} }
} }
@@ -181,7 +184,8 @@ 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> { override fun mark(element: KtNamedDeclaration): List<TextRange> {
val nameIdentifier = element.nameIdentifier val nameIdentifier = element.nameIdentifier
if (nameIdentifier != null) { if (nameIdentifier != null) {
@@ -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> { override fun mark(element: KtDeclaration): List<TextRange> {
when (element) { when (element) {
is KtConstructor<*> -> { is KtConstructor<*> -> {
@@ -216,13 +221,11 @@ object PositioningStrategies {
?: element.valueParameterList ?: element.valueParameterList
?: element.nameIdentifier ?: element.nameIdentifier
?: element ?: element
val startElement val startElement = if (element is KtFunctionLiteral) {
= if (element is KtFunctionLiteral) {
element.getReceiverTypeReference() element.getReceiverTypeReference()
?: element.getValueParameterList() ?: element.getValueParameterList()
?: element ?: element
} } else element
else element
return markRange(startElement, endOfSignatureElement) return markRange(startElement, endOfSignatureElement)
} }
is KtProperty -> { is KtProperty -> {
@@ -239,7 +242,8 @@ object PositioningStrategies {
} }
is KtClass -> { is KtClass -> {
val nameAsDeclaration = element.nameIdentifier ?: return markElement(element) 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) return markRange(nameAsDeclaration, primaryConstructorParameterList)
} }
is KtObjectDeclaration -> { 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> { override fun mark(element: PsiElement): List<TextRange> {
return if (element is KtDeclaration) return if (element is KtDeclaration)
DECLARATION_SIGNATURE.mark(element) 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> = override fun mark(element: KtDeclaration): List<TextRange> =
markElement( markElement(
when (element) { when (element) {
is KtClassOrObject -> is KtClassOrObject ->
element.getDeclarationKeyword() ?: element.getDeclarationKeyword() ?: element.nameIdentifier ?: element
element.nameIdentifier ?:
element
is KtNamedFunction -> is KtNamedFunction ->
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?: element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?: element.funKeyword ?: element
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> { override fun mark(element: KtDeclaration): List<TextRange> {
if (element is KtTypeParameterListOwner) { if (element is KtTypeParameterListOwner) {
val jetTypeParameterList = element.typeParameterList 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> { override fun mark(element: PsiElement): List<TextRange> {
val nameIdentifier = when (element) { val nameIdentifier = when (element) {
is KtNamedDeclaration -> element.nameIdentifier is KtNamedDeclaration -> element.nameIdentifier
@@ -325,7 +335,8 @@ object PositioningStrategies {
return markElement(nameIdentifier ?: element) 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> { override fun mark(element: KtReferenceExpression): List<TextRange> {
if (element is KtArrayAccessExpression) { if (element is KtArrayAccessExpression) {
val ranges = element.bracketRanges 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>() { return object : PositioningStrategy<KtModifierListOwner>() {
override fun mark(element: KtModifierListOwner): List<TextRange> { override fun mark(element: KtModifierListOwner): List<TextRange> {
val modifierList = element.modifierList.sure { "No modifier list, but modifier has been found by the analyzer" } 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> { override fun mark(element: KtArrayAccessExpression): List<TextRange> {
return markElement(element.indicesNode) 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> { 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 modifierList = element.modifierList
val result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange } val result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange }
@@ -380,38 +395,44 @@ object PositioningStrategies {
is KtPropertyAccessor -> element.namePlaceholder is KtPropertyAccessor -> element.namePlaceholder
is KtAnonymousInitializer -> element is KtAnonymousInitializer -> element
else -> throw IllegalArgumentException( 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) 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> { override fun mark(element: KtTypeProjection): List<TextRange> {
return markElement(element.projectionToken!!) 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> { override fun mark(element: KtParameter): List<TextRange> {
return markNode(element.defaultValue!!.node) 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> { override fun mark(element: KtParameter): List<TextRange> {
val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!! val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!!
return markNode(varargModifier.node) 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> { override fun mark(element: PsiElement): List<TextRange> {
return markElement((element as? KtCallElement)?.calleeExpression ?: element) 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> { override fun mark(element: KtDeclarationWithBody): List<TextRange> {
val lastBracketRange = (element.bodyExpression as? KtBlockExpression)?.lastBracketRange val lastBracketRange = (element.bodyExpression as? KtBlockExpression)?.lastBracketRange
return if (lastBracketRange != null) 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> { override fun mark(element: KtNamedDeclaration): List<TextRange> {
return when (element) { return when (element) {
is KtParameter -> markElement(element.valOrVarKeyword ?: element) is KtParameter -> markElement(element.valOrVarKeyword ?: element)
@@ -435,25 +457,29 @@ 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> { override fun mark(element: KtWhenEntry): List<TextRange> {
return markElement(element.elseKeyword!!) 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> { override fun mark(element: KtWhenExpression): List<TextRange> {
return markElement(element.whenKeyword) 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> { override fun mark(element: KtWhenConditionInRange): List<TextRange> {
return markElement(element.operationReference) 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> = override fun mark(element: KtExpression): List<TextRange> =
when (element) { when (element) {
is KtWhenExpression -> markElement(element.whenKeyword) is KtWhenExpression -> markElement(element.whenKeyword)
@@ -463,13 +489,15 @@ object PositioningStrategies {
} }
} }
@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> { override fun mark(element: KtNullableType): List<TextRange> {
return markNode(element.questionMarkNode) 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> { override fun mark(element: PsiElement): List<TextRange> {
if (element is KtCallExpression) { if (element is KtCallExpression) {
return markRange(element, element.typeArgumentList ?: element.calleeExpression ?: element) 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> { override fun mark(element: KtElement): List<TextRange> {
return markElement((element as? KtValueArgumentList)?.rightParenthesis ?: element) 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> { override fun mark(element: KtFunction): List<TextRange> {
val valueParameterList = element.valueParameterList val valueParameterList = element.valueParameterList
if (valueParameterList != null) { 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> { override fun mark(element: KtElement): List<TextRange> {
if (element is KtConstantExpression) { if (element is KtConstantExpression) {
if (element.node.elementType == KtNodeTypes.CHARACTER_CONSTANT) { 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> { override fun mark(element: KtElement): List<TextRange> {
if (element is KtConstantExpression) { if (element is KtConstantExpression) {
if (element.node.elementType == KtNodeTypes.INTEGER_CONSTANT) { 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> { override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out PsiElement>): List<TextRange> {
return Errors.UNREACHABLE_CODE.cast(diagnostic).a 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> { override fun mark(element: KtBinaryExpressionWithTypeRHS): List<TextRange> {
return markRange(element.operationReference, element) 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> { override fun mark(element: KtObjectDeclaration): List<TextRange> {
if (element.hasModifier(KtTokens.COMPANION_KEYWORD)) { if (element.hasModifier(KtTokens.COMPANION_KEYWORD)) {
return modifierSetPosition(KtTokens.COMPANION_KEYWORD).mark(element) return modifierSetPosition(KtTokens.COMPANION_KEYWORD).mark(element)
@@ -542,7 +577,8 @@ object PositioningStrategies {
} }
} }
@JvmField val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> = @JvmField
val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
object : PositioningStrategy<KtConstructorDelegationCall>() { object : PositioningStrategy<KtConstructorDelegationCall>() {
override fun mark(element: KtConstructorDelegationCall): List<TextRange> { override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
if (element.isImplicit) { if (element.isImplicit) {
@@ -554,26 +590,30 @@ object PositioningStrategies {
} }
} }
@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> { override fun mark(element: KtEnumEntry): List<TextRange> {
val specifiers = element.superTypeListEntries val specifiers = element.superTypeListEntries
return markElement(if (specifiers.isEmpty()) element else specifiers[0]) 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> { override fun mark(element: KtBinaryExpression): List<TextRange> {
return listOf(TextRange(element.left!!.startOffset, element.operationReference.endOffset)) 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> { override fun mark(element: KtBinaryExpression): List<TextRange> {
return listOf(TextRange(element.operationReference.startOffset, element.endOffset)) 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> { override fun mark(element: KtImportDirective): List<TextRange> {
element.alias?.nameIdentifier?.let { return markElement(it) } element.alias?.nameIdentifier?.let { return markElement(it) }
element.importedReference?.let { 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> { override fun mark(element: KtReturnExpression): List<TextRange> {
val labeledExpression = element.labeledExpression val labeledExpression = element.labeledExpression
if (labeledExpression != null) { 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> { override fun mark(element: KtCallableDeclaration): List<TextRange> {
element.receiverTypeReference?.let { return markElement(it) } element.receiverTypeReference?.let { return markElement(it) }
return DEFAULT.mark(element) return DEFAULT.mark(element)
@@ -20,10 +20,11 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any =
= renderer?.render(parameter, context) ?: parameter 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) fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassifierKindPrefix(this)
@@ -57,27 +57,33 @@ object Renderers {
private val LOG = Logger.getInstance(Renderers::class.java) private val LOG = Logger.getInstance(Renderers::class.java)
@JvmField val TO_STRING = Renderer<Any> { @JvmField
element -> val TO_STRING = Renderer<Any> { element ->
if (element is DeclarationDescriptor) { if (element is DeclarationDescriptor) {
LOG.warn("Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n" 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, " + "This is usually a bad idea, because descriptors' toString() includes some debug information, "
+ "which should not be seen by the user.\nDescriptor: " + element) + "which should not be seen by the user.\nDescriptor: " + element
)
} }
element.toString() 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() val writer = StringWriter()
it.printStackTrace(PrintWriter(writer)) it.printStackTrace(PrintWriter(writer))
StringUtil.first(writer.toString(), 2048, true) 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() val platform = it.getMultiTargetPlatform()
" ${it.getCapability(ModuleInfo.Capability)?.displayedName ?: ""}" + when (platform) { " ${it.getCapability(ModuleInfo.Capability)?.displayedName ?: ""}" + when (platform) {
MultiTargetPlatform.Common -> "" MultiTargetPlatform.Common -> ""
@@ -86,13 +92,15 @@ object Renderers {
} }
} }
@JvmField val VISIBILITY = Renderer<Visibility> { @JvmField
val VISIBILITY = Renderer<Visibility> {
if (it == Visibilities.INVISIBLE_FAKE) if (it == Visibilities.INVISIBLE_FAKE)
"invisible (private in a supertype)" "invisible (private in a supertype)"
else it.displayName else it.displayName
} }
@JvmField val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> { @JvmField
val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
val name = it.name.asString() val name = it.name.asString()
when (it) { when (it) {
is PackageFragmentDescriptor -> "package '$name'" 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 declarationWithNameAndKind = DECLARATION_NAME_WITH_KIND.render(descriptor, context)
val withPlatform = if (descriptor is MemberDescriptor && descriptor.isActual) val withPlatform = if (descriptor is MemberDescriptor && descriptor.isActual)
"actual $declarationWithNameAndKind" "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) { if (DescriptorUtils.isTopLevelDeclaration(it) && it is DeclarationDescriptorWithVisibility && it.visibility == Visibilities.PRIVATE) {
"file" "file"
} } else {
else {
val containingDeclaration = it.containingDeclaration val containingDeclaration = it.containingDeclaration
if (containingDeclaration is PackageFragmentDescriptor) { if (containingDeclaration is PackageFragmentDescriptor) {
containingDeclaration.fqName.asString().wrapIntoQuotes() containingDeclaration.fqName.asString().wrapIntoQuotes()
} } else {
else {
containingDeclaration!!.name.asString().wrapIntoQuotes() 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 { @JvmField
classOrObject: KtClassOrObject -> val RENDER_CLASS_OR_OBJECT = Renderer { classOrObject: KtClassOrObject ->
val name = classOrObject.name?.let { " ${it.wrapIntoQuotes()}" } ?: "" val name = classOrObject.name?.let { " ${it.wrapIntoQuotes()}" } ?: ""
if (classOrObject is KtClass) "Class" + name else "Object" + name 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 { @JvmField
variance: Variance -> val RENDER_POSITION_VARIANCE = Renderer { variance: Variance ->
when (variance) { when (variance) {
Variance.INVARIANT -> "invariant" Variance.INVARIANT -> "invariant"
Variance.IN_VARIANCE -> "in" Variance.IN_VARIANCE -> "in"
@@ -157,8 +169,8 @@ object Renderers {
} }
} }
@JvmField val AMBIGUOUS_CALLS = Renderer { @JvmField
calls: Collection<ResolvedCall<*>> -> val AMBIGUOUS_CALLS = Renderer { calls: Collection<ResolvedCall<*>> ->
val descriptors = calls.map { it.resultingDescriptor } val descriptors = calls.map { it.resultingDescriptor }
val context = RenderingContext.Impl(descriptors) val context = RenderingContext.Impl(descriptors)
descriptors descriptors
@@ -166,8 +178,8 @@ object Renderers {
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) } .joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
} }
@JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> { @JvmStatic
collection, context -> fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> { collection, context ->
buildString { buildString {
val iterator = collection.iterator() val iterator = collection.iterator()
while (iterator.hasNext()) { 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() 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() 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() 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() 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() renderCannotCaptureTypeParameterError(it, TabledDescriptorRenderer.create()).toString()
} }
@JvmStatic fun renderConflictingSubstitutionsInferenceError( @JvmStatic
fun renderConflictingSubstitutionsInferenceError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
LOG.assertTrue(inferenceErrorData.constraintSystem.status.hasConflictingConstraints(), LOG.assertTrue(
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData)) inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData)
)
val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>() val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>()
val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem) val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
@@ -219,10 +239,12 @@ object Renderers {
return result return result
} }
result.text(newText() result.text(
newText()
.normal("Cannot infer type parameter ") .normal("Cannot infer type parameter ")
.strong(firstConflictingVariable.name) .strong(firstConflictingVariable.name)
.normal(" in ")) .normal(" in ")
)
val table = newTable() val table = newTable()
result.table(table) result.table(table)
table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions") table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions")
@@ -249,12 +271,14 @@ object Renderers {
table.functionArgumentTypeList(receiverType, parameterTypes, { errorPositions.contains(it) }) 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 return result
} }
@JvmStatic fun renderParameterConstraintError( @JvmStatic
fun renderParameterConstraintError(
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
val constraintErrors = inferenceErrorData.constraintSystem.status.constraintErrors val constraintErrors = inferenceErrorData.constraintSystem.status.constraintErrors
@@ -266,11 +290,13 @@ object Renderers {
.text("cannot be applied to") .text("cannot be applied to")
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType, .functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
inferenceErrorData.valueArgumentsTypes, inferenceErrorData.valueArgumentsTypes,
{ errorPositions.contains(it) })) { errorPositions.contains(it) })
)
} }
@JvmStatic fun renderNoInformationForParameterError( @JvmStatic
fun renderNoInformationForParameterError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable -> val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
@@ -280,21 +306,28 @@ object Renderers {
} }
return result return result
.text(newText().normal("Not enough information to infer parameter ") .text(
newText().normal("Not enough information to infer parameter ")
.strong(firstUnknownVariable.name) .strong(firstUnknownVariable.name)
.normal(" in ")) .normal(" in ")
.table(newTable() )
.table(
newTable()
.descriptor(inferenceErrorData.descriptor) .descriptor(inferenceErrorData.descriptor)
.text("Please specify it explicitly.")) .text("Please specify it explicitly.")
)
} }
@JvmStatic fun renderUpperBoundViolatedInferenceError( @JvmStatic
fun renderUpperBoundViolatedInferenceError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
val constraintSystem = inferenceErrorData.constraintSystem val constraintSystem = inferenceErrorData.constraintSystem
val status = constraintSystem.status val status = constraintSystem.status
LOG.assertTrue(status.hasViolatedUpperBound(), LOG.assertTrue(
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData)) status.hasViolatedUpperBound(),
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData)
)
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION) val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION)
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull { val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
@@ -313,7 +346,12 @@ object Renderers {
return if (status.hasConflictingConstraints()) return if (status.hasConflictingConstraints())
renderConflictingSubstitutionsInferenceError(inferenceErrorData, result) renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
else { 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 result
} }
} }
@@ -321,21 +359,30 @@ object Renderers {
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor) val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
if (inferredValueForTypeParameter == null) { if (inferredValueForTypeParameter == null) {
LOG.error(debugMessage("System without weak constraints is not successful, there is no value for type parameter " + LOG.error(
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData)) debugMessage(
"System without weak constraints is not successful, there is no value for type parameter " +
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData
)
)
return result return result
} }
result.text(newText() result.text(
newText()
.normal("Type parameter bound for ") .normal("Type parameter bound for ")
.strong(typeParameterDescriptor.name) .strong(typeParameterDescriptor.name)
.normal(" in ")) .normal(" in ")
.table(newTable() )
.descriptor(inferenceErrorData.descriptor)) .table(
newTable()
.descriptor(inferenceErrorData.descriptor)
)
var violatedUpperBound: KotlinType? = null var violatedUpperBound: KotlinType? = null
for (upperBound in typeParameterDescriptor.upperBounds) { for (upperBound in typeParameterDescriptor.upperBounds) {
val upperBoundWithSubstitutedInferredTypes = systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT) val upperBoundWithSubstitutedInferredTypes =
systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
if (upperBoundWithSubstitutedInferredTypes != null if (upperBoundWithSubstitutedInferredTypes != null
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) { && !KotlinTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
violatedUpperBound = upperBoundWithSubstitutedInferredTypes violatedUpperBound = upperBoundWithSubstitutedInferredTypes
@@ -343,19 +390,25 @@ object Renderers {
} }
} }
if (violatedUpperBound == null) { if (violatedUpperBound == null) {
LOG.error(debugMessage("Type parameter (chosen as violating its upper bound)" + LOG.error(
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData)) debugMessage(
"Type parameter (chosen as violating its upper bound)" +
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData
)
)
return result return result
} }
// TODO: context should be in fact shared for the table and these two types // TODO: context should be in fact shared for the table and these two types
val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound) val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound)
val typeRenderer = result.typeRenderer val typeRenderer = result.typeRenderer
result.text(newText() result.text(
newText()
.normal(" is not satisfied: inferred type ") .normal(" is not satisfied: inferred type ")
.error(typeRenderer.render(inferredValueForTypeParameter, context)) .error(typeRenderer.render(inferredValueForTypeParameter, context))
.normal(" is not a subtype of ") .normal(" is not a subtype of ")
.strong(typeRenderer.render(violatedUpperBound, context))) .strong(typeRenderer.render(violatedUpperBound, context))
)
return result return result
} }
@@ -391,12 +444,16 @@ object Renderers {
val context = RenderingContext.of(violatingInferredType, violatedUpperBound) val context = RenderingContext.of(violatingInferredType, violatedUpperBound)
val typeRenderer = result.typeRenderer val typeRenderer = result.typeRenderer
result.text(newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name) result.text(
.normal(" in type inferred from type alias expansion for ")) newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
.normal(" in type inferred from type alias expansion for ")
)
.table(newTable().descriptor(inferenceErrorData.descriptor)) .table(newTable().descriptor(inferenceErrorData.descriptor))
result.text(newText().normal(" is not satisfied: inferred type ").error(typeRenderer.render(violatingInferredType, context)) result.text(
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context))) 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 return result
} }
@@ -404,7 +461,8 @@ object Renderers {
return null return null
} }
@JvmStatic fun renderCannotCaptureTypeParameterError( @JvmStatic
fun renderCannotCaptureTypeParameterError(
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
val system = inferenceErrorData.constraintSystem val system = inferenceErrorData.constraintSystem
@@ -419,7 +477,12 @@ object Renderers {
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() } val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
if (capturedTypeConstructor == null) { 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 return result
} }
@@ -431,20 +494,25 @@ object Renderers {
} }
val explanation = val explanation =
"Type parameter has an upper bound ${result.typeRenderer.render(upperBound, RenderingContext.of(upperBound)).wrapIntoQuotes()}" + "Type parameter has an upper bound ${result.typeRenderer.render(
upperBound,
RenderingContext.of(upperBound)
).wrapIntoQuotes()}" +
" that cannot be satisfied capturing 'in' projection" " that cannot be satisfied capturing 'in' projection"
result.text(newText().normal( result.text(
newText().normal(
typeParameter.name.wrapIntoQuotes() + typeParameter.name.wrapIntoQuotes() +
" cannot capture " + " cannot capture " +
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " + "${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
explanation explanation
)) )
)
return result return result
} }
@JvmField val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> { @JvmField
descriptors -> val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> { descriptors ->
buildString { buildString {
var index = 0 var index = 0
for (descriptor in descriptors) { for (descriptor in descriptors) {
@@ -452,17 +520,18 @@ object Renderers {
index++ index++
if (index <= descriptors.size - 2) { if (index <= descriptors.size - 2) {
append(", ") append(", ")
} } else if (index == descriptors.size - 1) {
else if (index == descriptors.size - 1) {
append(" or ") 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 { fun renderConstraintSystem(constraintSystem: ConstraintSystem, shortTypeBounds: Boolean): String {
val typeBounds = linkedSetOf<TypeBounds>() val typeBounds = linkedSetOf<TypeBounds>()
@@ -488,8 +557,7 @@ object Renderers {
val typeVariableName = typeBounds.typeVariable.name val typeVariableName = typeBounds.typeVariable.name
return if (typeBounds.bounds.isEmpty()) { return if (typeBounds.bounds.isEmpty()) {
typeVariableName.asString() typeVariableName.asString()
} } else
else
"$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}" "$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}"
} }
@@ -503,8 +571,7 @@ object Renderers {
val context = RenderingContext.Empty val context = RenderingContext.Empty
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) { if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
append(inferenceErrorData.expectedType) append(inferenceErrorData.expectedType)
} } else {
else {
append(RENDER_TYPE.render(inferenceErrorData.expectedType, context)) append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
} }
append("\nArgument types:\n") append("\nArgument types:\n")
@@ -519,26 +586,33 @@ object Renderers {
private val WHEN_MISSING_LIMIT = 7 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) { if (!it.hasUnknown) {
val list = it.joinToString(", ", limit = WHEN_MISSING_LIMIT) { "'$it'" } val list = it.joinToString(", ", limit = WHEN_MISSING_LIMIT) { "'$it'" }
val branches = if (it.size > 1) "branches" else "branch" val branches = if (it.size > 1) "branches" else "branch"
"$list $branches or 'else' branch instead" "$list $branches or 'else' branch instead"
} } else {
else {
"'else' branch" "'else' branch"
} }
} }
@JvmField val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer() @JvmField
@JvmField val COMPACT = DescriptorRenderer.COMPACT.asRenderer() val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
@JvmField val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer() @JvmField
@JvmField val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions { val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
@JvmField
val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
@JvmField
val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
modifiers = emptySet() modifiers = emptySet()
}.asRenderer() }.asRenderer()
@JvmField val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer() @JvmField
@JvmField val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer() val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
@JvmField val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions { @JvmField
val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
@JvmField
val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
withoutTypeParameters = false withoutTypeParameters = false
receiverAfterName = false receiverAfterName = false
renderAccessors = true renderAccessors = true
@@ -83,8 +83,7 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
} }
contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType -> contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType ->
diagnosticType.contains { diagnosticType.contains { innerType ->
innerType ->
innerType.addMentionedTypeConstructor() innerType.addMentionedTypeConstructor()
innerType.getAbbreviation()?.addMentionedTypeConstructor() innerType.getAbbreviation()?.addMentionedTypeConstructor()
false false
@@ -101,12 +100,14 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
collectMentionedClassifiersFqNames(it.upperBounds, result) collectMentionedClassifiersFqNames(it.upperBounds, result)
} }
contextObjects.filterIsInstance<CallableDescriptor>().forEach { contextObjects.filterIsInstance<CallableDescriptor>().forEach {
collectMentionedClassifiersFqNames(listOf( collectMentionedClassifiersFqNames(
listOf(
it.typeParameters, it.typeParameters,
it.returnType, it.returnType,
it.valueParameters, it.valueParameters,
it.dispatchReceiverParameter?.type, it.dispatchReceiverParameter?.type,
it.extensionReceiverParameter?.type it.extensionReceiverParameter?.type
), result) ), result
)
} }
} }
@@ -34,7 +34,8 @@ class MainFunctionDetector {
/** Assumes that the function declaration is already resolved and the descriptor can be found in the `bindingContext`. */ /** Assumes that the function declaration is already resolved and the descriptor can be found in the `bindingContext`. */
constructor(bindingContext: BindingContext) { constructor(bindingContext: BindingContext) {
this.getFunctionDescriptor = { function -> 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)
} }
} }
@@ -29,14 +29,17 @@ import org.jetbrains.kotlin.lexer.KtTokens
*/ */
class KDocLinkParser : PsiParser { class KDocLinkParser : PsiParser {
companion object { companion object {
@JvmStatic fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode { @JvmStatic
fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
val parentElement = chameleon.treeParent.psi val parentElement = chameleon.treeParent.psi
val project = parentElement.project val project = parentElement.project
val builder = PsiBuilderFactory.getInstance().createBuilder(project, val builder = PsiBuilderFactory.getInstance().createBuilder(
project,
chameleon, chameleon,
KotlinLexer(), KotlinLexer(),
root.language, root.language,
chameleon.text) chameleon.text
)
val parser = KDocLinkParser() val parser = KDocLinkParser()
return parser.parse(root, builder).firstChildNode return parser.parse(root, builder).firstChildNode
@@ -60,8 +63,7 @@ class KDocLinkParser : PsiParser {
if (builder.tokenType == KtTokens.RBRACKET) { if (builder.tokenType == KtTokens.RBRACKET) {
builder.advanceLexer() builder.advanceLexer()
} }
} } else {
else {
if (!builder.eof()) { if (!builder.eof()) {
builder.error("Expression expected") builder.error("Expression expected")
while (!builder.eof()) { while (!builder.eof()) {
@@ -44,6 +44,5 @@ class KDocSection(node: ASTNode) : KDocTag(node) {
return getChildrenOfType<KDocTag>().filter { it.name == name } return getChildrenOfType<KDocTag>().filter { it.name == name }
} }
fun findTagByName(name: String): KDocTag? fun findTagByName(name: String): KDocTag? = findTagsByName(name).firstOrNull()
= findTagsByName(name).firstOrNull()
} }
@@ -109,8 +109,7 @@ open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
if (!isCodeBlock()) if (!isCodeBlock())
indentedCodeBlock = indentedCodeBlock || node.text.startsWith(indentationWhiteSpaces) || node.text.startsWith("\t") indentedCodeBlock = indentedCodeBlock || node.text.startsWith(indentationWhiteSpaces) || node.text.startsWith("\t")
startCodeBlock() startCodeBlock()
} } else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
flushCodeBlock() flushCodeBlock()
indentedCodeBlock = false indentedCodeBlock = false
} }
@@ -63,7 +63,9 @@ class KotlinParserDefinition : ParserDefinition {
return when (elementType) { return when (elementType) {
is KtStubElementType<*, *> -> elementType.createPsiFromAst(astNode) 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) is KDocElementType -> elementType.createPsi(astNode)
KDocTokens.MARKDOWN_LINK -> KDocLink(astNode) KDocTokens.MARKDOWN_LINK -> KDocLink(astNode)
else -> (elementType as KtNodeType).createPsi(astNode) else -> (elementType as KtNodeType).createPsi(astNode)
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.lexer.KtTokens
object PrecedingCommentsBinder : WhitespacesAndCommentsBinder { object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
override fun getEdgePosition( 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 if (tokens.isEmpty()) return 0
// 1. bind doc comment // 1. bind doc comment
@@ -54,7 +55,8 @@ object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder { object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
override fun getEdgePosition( 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 if (tokens.isEmpty()) return 0
for (idx in tokens.indices.reversed()) { for (idx in tokens.indices.reversed()) {
@@ -68,7 +70,8 @@ object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
// Binds comments on the same line // Binds comments on the same line
object TrailingCommentsBinder : WhitespacesAndCommentsBinder { object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
override fun getEdgePosition( 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 if (tokens.isEmpty()) return 0
var result = 0 var result = 0
@@ -89,7 +92,8 @@ object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder { private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
override fun getEdgePosition( 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 if (tokens.isEmpty()) return 0
val size = tokens.size val size = tokens.size
@@ -110,14 +114,16 @@ val TRAILING_ALL_COMMENTS_BINDER: WhitespacesAndCommentsBinder = AllCommentsBind
object DoNotBindAnything : WhitespacesAndCommentsBinder { object DoNotBindAnything : WhitespacesAndCommentsBinder {
override fun getEdgePosition( override fun getEdgePosition(
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int { tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
): Int {
return 0 return 0
} }
} }
object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder { object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
override fun getEdgePosition( 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) { if (tokens.firstOrNull() == KtTokens.SHEBANG_COMMENT) {
return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1 return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1
} }
@@ -128,7 +134,8 @@ object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder { class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
override fun getEdgePosition( 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 return if (!isTrailing) 0 else tokens.size
} }
} }
@@ -35,7 +35,8 @@ abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtExpressi
} }
is KtSimpleNameStringTemplateEntry -> { is KtSimpleNameStringTemplateEntry -> {
if (newElement !is KtSimpleNameExpression && !newElement.isThisWithoutLabel()) { 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!! return newEntry.expression!!
} }
} }
@@ -43,8 +43,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
if (this.modifierList == null) { if (this.modifierList == null) {
getConstructorKeyword()?.delete() getConstructorKeyword()?.delete()
} }
} } else {
else {
if (modifier == KtTokens.PUBLIC_KEYWORD) return if (modifier == KtTokens.PUBLIC_KEYWORD) return
val newModifierList = KtPsiFactory(this).createModifierList(modifier) val newModifierList = KtPsiFactory(this).createModifierList(modifier)
addBefore(newModifierList, getOrCreateConstructorKeyword()) addBefore(newModifierList, getOrCreateConstructorKeyword())
@@ -62,8 +61,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
val modifierList = modifierList val modifierList = modifierList
return if (modifierList != null) { return if (modifierList != null) {
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
} } else {
else {
val parameterList = valueParameterList!! val parameterList = valueParameterList!!
val newModifierList = KtPsiFactory(project).createModifierList(annotationEntry.text) val newModifierList = KtPsiFactory(project).createModifierList(annotationEntry.text)
(addBefore(newModifierList, parameterList) as KtModifierList).annotationEntries.first() (addBefore(newModifierList, parameterList) as KtModifierList).annotationEntries.first()
@@ -26,7 +26,8 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
fun KtPsiFactory(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated) fun KtPsiFactory(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated)
@JvmOverloads @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" + 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"
@@ -109,7 +110,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
} }
fun createFunctionTypeParameter(typeReference: KtTypeReference): KtParameter { 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 { fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
@@ -193,7 +195,14 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
} }
private fun doCreateFile(fileName: String, text: String): KtFile { 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 { fun createFile(fileName: String, text: String): KtFile {
@@ -217,7 +226,13 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
} }
fun createPhysicalFile(fileName: String, text: String): KtFile { 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 { fun createProperty(modifiers: String?, name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty {
@@ -445,8 +460,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
fun createConstructorKeyword(): PsiElement = fun createConstructorKeyword(): PsiElement =
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!! createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
fun createLabeledExpression(labelName: String): KtLabeledExpression fun createLabeledExpression(labelName: String): KtLabeledExpression = createExpression("$labelName@ 1") as KtLabeledExpression
= createExpression("$labelName@ 1") as KtLabeledExpression
fun createTypeCodeFragment(text: String, context: PsiElement?): KtTypeCodeFragment { fun createTypeCodeFragment(text: String, context: PsiElement?): KtTypeCodeFragment {
return KtTypeCodeFragment(project, "fragment.kt", text, context) return KtTypeCodeFragment(project, "fragment.kt", text, context)
@@ -512,6 +526,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
TYPE_CONSTRAINTS, TYPE_CONSTRAINTS,
DONE DONE
} }
private val sb = StringBuilder() private val sb = StringBuilder()
private var state = State.MODIFIERS private var state = State.MODIFIERS
@@ -820,7 +835,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
return BlockWrapper(block, expression) 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> { override fun getStatements(): List<KtExpression> {
return listOf(expression) return listOf(expression)
} }
@@ -42,10 +42,10 @@ class KtTypeAlias : KtTypeParameterListOwnerStub<KotlinTypeAliasStub>, KtNamedDe
@IfNotParsed @IfNotParsed
fun getTypeReference(): KtTypeReference? { fun getTypeReference(): KtTypeReference? {
return if (stub != null) { return if (stub != null) {
val typeReferences = getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE) val typeReferences =
getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
typeReferences[0] typeReferences[0]
} } else {
else {
findChildByType(KtNodeTypes.TYPE_REFERENCE) findChildByType(KtNodeTypes.TYPE_REFERENCE)
} }
} }
@@ -40,8 +40,7 @@ fun KtModifierListOwner.setModifierList(newModifierList: KtModifierList) {
val currentModifierList = modifierList val currentModifierList = modifierList
if (currentModifierList != null) { if (currentModifierList != null) {
currentModifierList.replace(newModifierList) currentModifierList.replace(newModifierList)
} } else {
else {
addModifierList(newModifierList) addModifierList(newModifierList)
} }
} }
@@ -50,8 +49,7 @@ fun addModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken) {
val modifierList = owner.modifierList val modifierList = owner.modifierList
if (modifierList == null) { if (modifierList == null) {
createModifierList(modifier.value, owner) createModifierList(modifier.value, owner)
} } else {
else {
addModifier(modifierList, modifier) addModifier(modifierList, modifier)
} }
} }
@@ -60,8 +58,7 @@ fun addAnnotationEntry(owner: KtModifierListOwner, annotationEntry: KtAnnotation
val modifierList = owner.modifierList val modifierList = owner.modifierList
return if (modifierList == null) { return if (modifierList == null) {
createModifierList(annotationEntry.text, owner).annotationEntries.first() createModifierList(annotationEntry.text, owner).annotationEntries.first()
} } else {
else {
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
} }
} }
@@ -85,8 +82,7 @@ internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywo
} }
if (modifierToReplace != null && modifierList.firstChild == modifierList.lastChild) { if (modifierToReplace != null && modifierList.firstChild == modifierList.lastChild) {
modifierToReplace.replace(newModifier) modifierToReplace.replace(newModifier)
} } else {
else {
modifierToReplace?.delete() modifierToReplace?.delete()
val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier) val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier)
@@ -143,7 +139,8 @@ private val MODIFIERS_TO_REPLACE = mapOf(
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD) ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
) )
val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD, val MODIFIERS_ORDER = listOf(
PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD, FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
CONST_KEYWORD, CONST_KEYWORD,
@@ -159,4 +156,5 @@ val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD,
INLINE_KEYWORD, INLINE_KEYWORD,
INFIX_KEYWORD, INFIX_KEYWORD,
OPERATOR_KEYWORD, OPERATOR_KEYWORD,
DATA_KEYWORD) DATA_KEYWORD
)
@@ -28,8 +28,7 @@ val SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE: Key<Boolean> = Key.create<Boolean>("SUPP
fun KtElement.suppressDiagnosticsInDebugMode(): Boolean { fun KtElement.suppressDiagnosticsInDebugMode(): Boolean {
return if (this is KtFile) { return if (this is KtFile) {
this.suppressDiagnosticsInDebugMode this.suppressDiagnosticsInDebugMode
} } else {
else {
val file = this.containingFile val file = this.containingFile
file is KtFile && file.suppressDiagnosticsInDebugMode file is KtFile && file.suppressDiagnosticsInDebugMode
} }
@@ -31,23 +31,32 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.renderer.render
import java.util.* import java.util.*
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression =
= createByPattern(pattern, *args, reformat = reformat) { createExpression(it) } createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList =
= createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) } createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): TDeclaration fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(
= createByPattern(pattern, *args, reformat = reformat) { createDeclaration<TDeclaration>(it) } 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 fun KtPsiFactory.createDestructuringDeclarationByPattern(
= createByPattern(pattern, *args, reformat = reformat) { createDestructuringDeclaration(it) } 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 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 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 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 { override fun replacePlaceholderElement(placeholder: KtElement, argument: PsiChildRange): PsiChildRange {
val project = placeholder.project val project = placeholder.project
val codeStyleManager = CodeStyleManager.getInstance(project) val codeStyleManager = CodeStyleManager.getInstance(project)
@@ -79,8 +89,7 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node) codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
} }
PsiChildRange(first, last) PsiChildRange(first, last)
} } else {
else {
placeholder.delete() placeholder.delete()
PsiChildRange.EMPTY PsiChildRange.EMPTY
} }
@@ -98,7 +107,12 @@ private val SUPPORTED_ARGUMENT_TYPES = listOf(
@TestOnly @TestOnly
var CREATEBYPATTERN_MAY_NOT_REFORMAT = false 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 -> val argumentTypes = args.map { arg ->
SUPPORTED_ARGUMENT_TYPES.firstOrNull { it.klass.isInstance(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 }}")
@@ -164,8 +178,7 @@ fun <TElement : KtElement> createByPattern(pattern: String, vararg args: Any, re
// reformat whole text except for String arguments (as they can contain user's formatting to be preserved) // reformat whole text except for String arguments (as they can contain user's formatting to be preserved)
resultElement = if (stringPlaceholderRanges.none()) { resultElement = if (stringPlaceholderRanges.none()) {
codeStyleManager.reformat(resultElement, true) as TElement codeStyleManager.reformat(resultElement, true) as TElement
} } else {
else {
var bound = resultElement.endOffset - 1 var bound = resultElement.endOffset - 1
for (range in stringPlaceholderRanges) { for (range in stringPlaceholderRanges) {
// we extend reformatting range by 1 to the right because otherwise some of spaces are not reformatted // 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) val nextChar = charOrNull(++i)
if (nextChar == '$') { if (nextChar == '$') {
append(nextChar) append(nextChar)
} } else {
else {
check(nextChar?.isDigit() ?: false, "unclosed '$'") check(nextChar?.isDigit() ?: false, "unclosed '$'")
val lastIndex = (i..pattern.length - 1).firstOrNull { !pattern[it].isDigit() } ?: pattern.length 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 arg: Any? = if (n < args.size) args[n] else null /* report wrong number of arguments later */
val placeholderText = if (charOrNull(i) != ':' || charOrNull(i + 1) != '\'') { val placeholderText = if (charOrNull(i) != ':' || charOrNull(i + 1) != '\'') {
arg as? String ?: "xyz" arg as? String ?: "xyz"
} } else {
else {
check(arg !is String, "do not specify placeholder text for $$n - plain text argument passed") check(arg !is String, "do not specify placeholder text for $$n - plain text argument passed")
i += 2 // skip ':' and '\'' i += 2 // skip ':' and '\''
val endIndex = pattern.indexOf('\'', i) 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)) ranges.getOrPut(n, { ArrayList() }).add(Placeholder(range, placeholderText))
continue continue
} }
} } else {
else {
append(c) append(c)
} }
i++ i++
@@ -159,8 +159,7 @@ fun KtExpression.isDotReceiver(): Boolean =
fun KtElement.blockExpressionsOrSingle(): Sequence<KtElement> = 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 fun KtExpression.lastBlockStatementOrThis(): KtExpression = (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
= (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
fun KtBlockExpression.contentRange(): PsiChildRange { fun KtBlockExpression.contentRange(): PsiChildRange {
val first = (lBrace?.nextSibling ?: firstChild) val first = (lBrace?.nextSibling ?: firstChild)
@@ -248,8 +247,7 @@ fun KtAnnotationsContainer.collectAnnotationEntriesFromStubOrPsi(): List<KtAnnot
} }
private fun StubElement<*>.collectAnnotationEntriesFromStubElement(): List<KtAnnotationEntry> { private fun StubElement<*>.collectAnnotationEntriesFromStubElement(): List<KtAnnotationEntry> {
return childrenStubs.flatMap { return childrenStubs.flatMap { child ->
child ->
when (child.stubType) { when (child.stubType) {
KtNodeTypes.ANNOTATION_ENTRY -> listOf(child.psi as KtAnnotationEntry) KtNodeTypes.ANNOTATION_ENTRY -> listOf(child.psi as KtAnnotationEntry)
KtNodeTypes.ANNOTATION -> (child.psi as KtAnnotation).entries KtNodeTypes.ANNOTATION -> (child.psi as KtAnnotation).entries
@@ -283,7 +281,10 @@ 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)) } return forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
} }
@@ -376,8 +377,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
if (callElement != null) { if (callElement != null) {
val ktConstructorCalleeExpression = callElement.calleeExpression as? KtConstructorCalleeExpression val ktConstructorCalleeExpression = callElement.calleeExpression as? KtConstructorCalleeExpression
(ktConstructorCalleeExpression?.typeReference?.typeElement as? KtUserType)?.referenceExpression == this (ktConstructorCalleeExpression?.typeReference?.typeElement as? KtUserType)?.referenceExpression == this
} } else {
else {
false false
} }
} }
@@ -387,8 +387,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
val KtStringTemplateExpression.plainContent: String val KtStringTemplateExpression.plainContent: String
get() = getContentRange().substring(text) get() = getContentRange().substring(text)
fun KtStringTemplateExpression.isSingleQuoted(): Boolean fun KtStringTemplateExpression.isSingleQuoted(): Boolean = node.firstChildNode.textLength == 1
= node.firstChildNode.textLength == 1
fun KtNamedDeclaration.getValueParameters(): List<KtParameter> { fun KtNamedDeclaration.getValueParameters(): List<KtParameter> {
return getValueParameterList()?.parameters ?: Collections.emptyList() return getValueParameterList()?.parameters ?: Collections.emptyList()
@@ -423,13 +422,12 @@ private fun KtModifierListOwner.modifierFromTokenSet(set: TokenSet) = modifierLi
fun KtModifierList.visibilityModifier() = modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS) fun KtModifierList.visibilityModifier() = modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken? fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken? = visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
fun KtModifierListOwner.visibilityModifier() = modifierList?.modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS) fun KtModifierListOwner.visibilityModifier() = modifierList?.modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken? fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken? =
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken? visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
private val MODALITY_MODIFIERS = TokenSet.create( 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
@@ -438,7 +436,8 @@ private val MODALITY_MODIFIERS = TokenSet.create(
fun KtDeclaration.modalityModifier() = modifierFromTokenSet(MODALITY_MODIFIERS) fun KtDeclaration.modalityModifier() = modifierFromTokenSet(MODALITY_MODIFIERS)
fun KtStringTemplateExpression.isPlain() = entries.all { it is KtLiteralStringTemplateEntry } 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) // Correct for class members only (including constructors and nested classes)
// Returns null e.g. for member function parameters, member function locals, property accessors // Returns null e.g. for member function parameters, member function locals, property accessors
@@ -516,7 +515,8 @@ fun isTypeConstructorReference(e: PsiElement): Boolean {
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar() 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 { fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
valueParameterList?.let { return it } valueParameterList?.let { return it }
@@ -535,15 +535,16 @@ fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList { fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
valueArgumentList?.let { return it } valueArgumentList?.let { return it }
return addAfter(KtPsiFactory(this).createCallArguments("()"), return addAfter(
typeArgumentList ?: calleeExpression) as KtValueArgumentList KtPsiFactory(this).createCallArguments("()"),
typeArgumentList ?: calleeExpression
) as KtValueArgumentList
} }
fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) { fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) {
if (typeArgumentList != null) { if (typeArgumentList != null) {
typeArgumentList?.addArgument(typeArgument) typeArgumentList?.addArgument(typeArgument)
} } else {
else {
addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression) addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
} }
} }
@@ -68,11 +68,9 @@ val PsiElement.parentsWithSelf: Sequence<PsiElement>
val PsiElement.parents: Sequence<PsiElement> val PsiElement.parents: Sequence<PsiElement>
get() = parentsWithSelf.drop(1) get() = parentsWithSelf.drop(1)
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement? fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.prevLeaf(this, skipEmptyElements)
= PsiTreeUtil.prevLeaf(this, skipEmptyElements)
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement? fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.nextLeaf(this, skipEmptyElements)
= PsiTreeUtil.nextLeaf(this, skipEmptyElements)
val PsiElement.prevLeafs: Sequence<PsiElement> val PsiElement.prevLeafs: Sequence<PsiElement>
get() = generateSequence({ prevLeaf() }, { it.prevLeaf() }) get() = generateSequence({ prevLeaf() }, { it.prevLeaf() })
@@ -175,7 +173,10 @@ inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranch(strict:
return getParentOfType<T>(strict)?.getIfChildIsInBranch(this, branch) 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) return getParentOfType<T>(strict)?.getIfChildIsInBranches(this, branches)
} }
@@ -188,7 +189,9 @@ fun PsiElement.isInsideOf(elements: Iterable<PsiElement>): Boolean = elements.an
fun PsiChildRange.trimWhiteSpaces(): PsiChildRange { fun PsiChildRange.trimWhiteSpaces(): PsiChildRange {
if (first == null) return this 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 -------------------------------------------------------------------------------------------- // -------------------- Recursive tree visiting --------------------------------------------------------------------------------------------
@@ -197,7 +200,10 @@ inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline
forEachDescendantOfType({ true }, action) 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() { this.accept(object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
if (canGoInside(element)) { if (canGoInside(element)) {
@@ -215,7 +221,10 @@ inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(noinline pred
return findDescendantOfType(predicate) != null 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 return findDescendantOfType(canGoInside, predicate) != null
} }
@@ -223,7 +232,10 @@ inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(noinline pre
return findDescendantOfType({ true }, predicate) 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 var result: T? = null
this.accept(object : PsiRecursiveElementWalkingVisitor() { this.accept(object : PsiRecursiveElementWalkingVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
@@ -245,7 +257,10 @@ inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(noinline
return collectDescendantsOfType({ true }, predicate) 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>() val result = ArrayList<T>()
forEachDescendantOfType<T>(canGoInside) { forEachDescendantOfType<T>(canGoInside) {
if (predicate(it)) { if (predicate(it)) {
@@ -333,8 +348,8 @@ fun PsiElement.getElementTextWithContext(): String {
} }
// Find parent for element among file children // Find parent for element among file children
val topLevelElement = PsiTreeUtil.findFirstParent(this, { it.parent is PsiFile }) ?: 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") ?: throw AssertionError("For non-file element we should always be able to find parent in file children")
val startContextOffset = topLevelElement.startOffset val startContextOffset = topLevelElement.startOffset
val elementContextOffset = textRange.startOffset val elementContextOffset = textRange.startOffset
@@ -25,7 +25,8 @@ import org.jetbrains.kotlin.psi.KtAnnotationUseSiteTarget
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinAnnotationUseSiteTargetStubImpl 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 debugName, KtAnnotationUseSiteTarget::class.java, KotlinAnnotationUseSiteTargetStub::class.java
) { ) {
@@ -25,14 +25,17 @@ import org.jetbrains.kotlin.psi.KtEnumEntrySuperclassReferenceExpression
import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub
import org.jetbrains.kotlin.psi.stubs.impl.KotlinEnumEntrySuperclassReferenceExpressionStubImpl import org.jetbrains.kotlin.psi.stubs.impl.KotlinEnumEntrySuperclassReferenceExpressionStubImpl
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String) class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String) :
: KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>( KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
debugName, debugName,
KtEnumEntrySuperclassReferenceExpression::class.java, KtEnumEntrySuperclassReferenceExpression::class.java,
KotlinEnumEntrySuperclassReferenceExpressionStub::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())!!) return KotlinEnumEntrySuperclassReferenceExpressionStubImpl(parentStub, StringRef.fromString(psi.getReferencedName())!!)
} }
@@ -39,6 +39,7 @@ class KotlinFunctionStubImpl(
throw IllegalArgumentException("fqName shouldn't be null for top level functions") throw IllegalArgumentException("fqName shouldn't be null for top level functions")
} }
} }
override fun getFqName() = fqName override fun getFqName() = fqName
override fun getName() = StringRef.toString(nameRef) override fun getName() = StringRef.toString(nameRef)
@@ -30,7 +30,8 @@ import java.util.ArrayList
val STUB_TO_STRING_PREFIX = "KotlinStub$" 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 { override fun toString(): String {
val stubInterface = this::class.java.interfaces.single { it.name.contains("Stub") } 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 value = property.invoke(this)
val name = getPropertyName(property) val name = getPropertyName(property)
"$name=$value" "$name=$value"
} } catch (e: Exception) {
catch (e: Exception) {
LOGGER.error(e) LOGGER.error(e)
null null
} }
@@ -80,6 +80,11 @@ open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?,
companion object { companion object {
private val LOGGER: Logger = Logger.getInstance(KotlinStubBaseImpl::class.java) 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
)
} }
} }
@@ -62,8 +62,10 @@ class SyntheticClassOrObjectDescriptor(
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
private val typeConstructor = SyntheticTypeConstructor(c.storageManager) private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, { outerScope }) private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, { outerScope })
private val syntheticSupertypes = mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) } private val syntheticSupertypes =
private val unsubstitutedMemberScope = LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace) mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
private val unsubstitutedMemberScope =
LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
private val unsubstitutedPrimaryConstructor = createUnsubstitutedPrimaryConstructor(constructorVisibility) private val unsubstitutedPrimaryConstructor = createUnsubstitutedPrimaryConstructor(constructorVisibility)
override val annotations: Annotations get() = Annotations.EMPTY override val annotations: Annotations get() = Annotations.EMPTY
@@ -97,11 +99,15 @@ class SyntheticClassOrObjectDescriptor(
override fun getScopeForClassHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForClassHeaderResolution() override fun getScopeForClassHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForClassHeaderResolution()
override fun getScopeForConstructorHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForConstructorHeaderResolution() override fun getScopeForConstructorHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForConstructorHeaderResolution()
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForCompanionObjectHeaderResolution() override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope =
override fun getScopeForMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForMemberDeclarationResolution() resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
override fun getScopeForStaticMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForStaticMemberDeclarationResolution()
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 override fun toString(): String = "synthetic class " + name.toString() + " in " + containingDeclaration
@@ -34,8 +34,7 @@ class AllUnderImportScope(
private val scopes: List<MemberScope> = if (descriptor is ClassDescriptor) { private val scopes: List<MemberScope> = if (descriptor is ClassDescriptor) {
listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope) listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope)
} } else {
else {
assert(descriptor is PackageViewDescriptor) { assert(descriptor is PackageViewDescriptor) {
"Must be class or package view descriptor: $descriptor" "Must be class or package view descriptor: $descriptor"
} }
@@ -44,8 +43,7 @@ class AllUnderImportScope(
private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization
emptySet<Name>() emptySet<Name>()
} } else {
else {
val fqName = DescriptorUtils.getFqNameSafe(descriptor) val fqName = DescriptorUtils.getFqNameSafe(descriptor)
// toSet() is used here instead mapNotNullTo(hashSetOf()) because it results in not keeping empty sets as separate instances // 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() excludedImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null }.toSet()
@@ -60,8 +58,7 @@ class AllUnderImportScope(
): Collection<DeclarationDescriptor> { ): Collection<DeclarationDescriptor> {
val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization
nameFilter nameFilter
} } else {
else {
{ it !in excludedNames && nameFilter(it) } { it !in excludedNames && nameFilter(it) }
} }
@@ -34,22 +34,18 @@ object DataClassDescriptorResolver {
private val COMPONENT_FUNCTION_NAME_PREFIX = "component" private val COMPONENT_FUNCTION_NAME_PREFIX = "component"
fun createComponentName(index: Int): Name fun createComponentName(index: Int): Name = Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
= Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
fun getComponentIndex(componentName: String): Int fun getComponentIndex(componentName: String): Int = componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
= componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
fun isComponentLike(name: Name): Boolean fun isComponentLike(name: Name): Boolean = isComponentLike(name.asString())
= isComponentLike(name.asString())
private fun isComponentLike(name: String): Boolean { private fun isComponentLike(name: String): Boolean {
if (!name.startsWith(COMPONENT_FUNCTION_NAME_PREFIX)) return false if (!name.startsWith(COMPONENT_FUNCTION_NAME_PREFIX)) return false
try { try {
getComponentIndex(name) getComponentIndex(name)
} } catch (e: NumberFormatException) {
catch (e: NumberFormatException) {
return false return false
} }
@@ -74,7 +74,10 @@ class DeclarationResolver(
} }
} }
fun checkRedeclarationsInPackages(topLevelDescriptorProvider: TopLevelDescriptorProvider, topLevelFqNames: Multimap<FqName, KtElement>) { fun checkRedeclarationsInPackages(
topLevelDescriptorProvider: TopLevelDescriptorProvider,
topLevelFqNames: Multimap<FqName, KtElement>
) {
for ((fqName, declarationsOrPackageDirectives) in topLevelFqNames.asMap()) { for ((fqName, declarationsOrPackageDirectives) in topLevelFqNames.asMap()) {
if (fqName.isRoot) continue if (fqName.isRoot) continue
@@ -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>() val descriptors = HashSet<DeclarationDescriptor>()
descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName)) descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName))
@@ -204,7 +204,11 @@ class DeclarationsChecker(
// Do nothing: this should've been reported during type resolution. // 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)) trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(typeReference, substitutedArgument))
} }
@@ -212,7 +216,12 @@ class DeclarationsChecker(
trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeReference, typeAlias)) 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 // TODO more precise diagnostics
if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) { if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) {
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter)) trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
@@ -272,8 +281,7 @@ class DeclarationsChecker(
val classDescriptor = constructorDescriptor.containingDeclaration val classDescriptor = constructorDescriptor.containingDeclaration
if (classDescriptor.kind == ClassKind.ENUM_CLASS) { if (classDescriptor.kind == ClassKind.ENUM_CLASS) {
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_ENUM.on(visibilityModifier)) 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)) trace.report(NON_PRIVATE_CONSTRUCTOR_IN_SEALED.on(visibilityModifier))
} }
} }
@@ -301,7 +309,8 @@ class DeclarationsChecker(
is KtClass -> { is KtClass -> {
checkClassButNotObject(classOrObject, classDescriptor) checkClassButNotObject(classOrObject, classDescriptor)
descriptorResolver.checkNamesInConstraints( descriptorResolver.checkNamesInConstraints(
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace) classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace
)
} }
is KtObjectDeclaration -> { is KtObjectDeclaration -> {
checkObject(classOrObject, classDescriptor) checkObject(classOrObject, classDescriptor)
@@ -370,8 +379,7 @@ class DeclarationsChecker(
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() } allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
problematicBound?.first ?: declaration problematicBound?.first ?: declaration
} } else {
else {
// Otherwise report the diagnostic on the type parameter declaration // Otherwise report the diagnostic on the type parameter declaration
declaration declaration
} }
@@ -403,14 +411,17 @@ class DeclarationsChecker(
?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration) ?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration)
if (sourceElement is KtClassOrObject) { if (sourceElement is KtClassOrObject) {
val delegationSpecifierList = sourceElement.getSuperTypeList() ?: continue val delegationSpecifierList = sourceElement.getSuperTypeList() ?: continue
trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES.on( trace.report(
INCONSISTENT_TYPE_PARAMETER_VALUES.on(
delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes
)) )
} )
else if (sourceElement is KtTypeParameter) { } else if (sourceElement is KtTypeParameter) {
trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS.on( trace.report(
INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes
)) )
)
} }
} }
} }
@@ -521,8 +532,7 @@ class DeclarationsChecker(
for (parameter in aClass.primaryConstructorParameters) { for (parameter in aClass.primaryConstructorParameters) {
if (!parameter.hasValOrVar()) { if (!parameter.hasValOrVar()) {
trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter)) trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter))
} } else if (parameter.isMutable) {
else if (parameter.isMutable) {
trace.report(VAR_ANNOTATION_PARAMETER.on(parameter)) trace.report(VAR_ANNOTATION_PARAMETER.on(parameter))
} }
} }
@@ -537,8 +547,7 @@ class DeclarationsChecker(
if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) { if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) {
if (classDescriptor.kind == ClassKind.OBJECT) { if (classDescriptor.kind == ClassKind.OBJECT) {
trace.report(NON_FINAL_MEMBER_IN_OBJECT.on(member)) trace.report(NON_FINAL_MEMBER_IN_OBJECT.on(member))
} } else {
else {
trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member)) trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member))
} }
} }
@@ -607,8 +616,7 @@ class DeclarationsChecker(
trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, property.name ?: "", classDescriptor)) trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, property.name ?: "", classDescriptor))
return return
} }
} } else if (classDescriptor.kind == ClassKind.INTERFACE &&
else if (classDescriptor.kind == ClassKind.INTERFACE &&
modifierList.hasModifier(KtTokens.OPEN_KEYWORD) && modifierList.hasModifier(KtTokens.OPEN_KEYWORD) &&
propertyDescriptor.modality == Modality.ABSTRACT) { propertyDescriptor.modality == Modality.ABSTRACT) {
trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(property)) trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(property))
@@ -659,35 +667,33 @@ class DeclarationsChecker(
!backingFieldRequired -> trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer)) !backingFieldRequired -> trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer))
property.receiverTypeReference != null -> trace.report(EXTENSION_PROPERTY_WITH_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) { if (inInterface) {
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate)) trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
} } else if (isExpect) {
else if (isExpect) {
trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate)) trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
} }
} } else {
else {
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
val isExternal = propertyDescriptor.isEffectivelyExternal() val isExternal = propertyDescriptor.isEffectivelyExternal()
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) { if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) { if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property)) 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) { if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
trace.report(MUST_BE_INITIALIZED.on(property)) trace.report(MUST_BE_INITIALIZED.on(property))
} } else {
else {
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property)) trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
} }
} }
} } else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) { trace.report(
trace.report(Errors.UNSUPPORTED_FEATURE.on(property, LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings)) Errors.UNSUPPORTED_FEATURE.on(
} property,
else if (noExplicitTypeOrGetterType(property)) { LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings
)
)
} else if (noExplicitTypeOrGetterType(property)) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property)) trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
} }
@@ -744,8 +750,7 @@ class DeclarationsChecker(
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) { diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, 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 && if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isExpect &&
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) { diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor)) trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
@@ -785,8 +790,7 @@ class DeclarationsChecker(
if (it.contains { type -> type.constructor is IntersectionTypeConstructor }) { if (it.contains { type -> type.constructor is IntersectionTypeConstructor }) {
trace.report(IMPLICIT_INTERSECTION_TYPE.on(target, it)) trace.report(IMPLICIT_INTERSECTION_TYPE.on(target, it))
} }
} } else if (it.isNothing() && it is AbbreviatedType) {
else if (it.isNothing() && it is AbbreviatedType) {
trace.report( 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) { if (accessor != null) {
modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor) modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor)
identifierChecker.checkDeclaration(accessor, trace) identifierChecker.checkDeclaration(accessor, trace)
} } else {
else {
modifiersChecker.runDeclarationCheckers(property, accessorDescriptor) modifiersChecker.runDeclarationCheckers(property, accessorDescriptor)
} }
} }
@@ -833,23 +836,19 @@ class DeclarationsChecker(
if (accessor.isGetter) { if (accessor.isGetter) {
if (accessorDescriptor.visibility != propertyDescriptor.visibility) { if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY) reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
} } else {
else {
reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER) reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER)
} }
} } else {
else {
if (propertyDescriptor.isOverridable if (propertyDescriptor.isOverridable
&& accessorDescriptor.visibility == Visibilities.PRIVATE && accessorDescriptor.visibility == Visibilities.PRIVATE
&& propertyDescriptor.visibility != Visibilities.PRIVATE) { && propertyDescriptor.visibility != Visibilities.PRIVATE) {
if (propertyDescriptor.modality == Modality.ABSTRACT) { if (propertyDescriptor.modality == Modality.ABSTRACT) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY) reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
} } else {
else {
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY) reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY)
} }
} } else {
else {
val compare = Visibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility) val compare = Visibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility)
if (compare == null || compare > 0) { if (compare == null || compare > 0) {
reportVisibilityModifierDiagnostics(tokens.values, Errors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY) 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)) trace.report(EXPECTED_ENUM_ENTRY_WITH_BODY.on(enumEntry))
} }
} }
} } else {
else {
assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass } assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass }
} }
} }
@@ -922,7 +920,10 @@ class DeclarationsChecker(
return isImplementingMethodOfAnyInternal(member, HashSet<ClassDescriptor>()) 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) { for (overridden in member.overriddenDescriptors) {
val containingDeclaration = overridden.containingDeclaration val containingDeclaration = overridden.containingDeclaration
if (containingDeclaration !is ClassDescriptor) continue if (containingDeclaration !is ClassDescriptor) continue
@@ -122,7 +122,16 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
delegationFilter: DelegationFilter, delegationFilter: DelegationFilter,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings
): Collection<T> = ): Collection<T> =
DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver, delegationFilter, languageVersionSettings) DelegationResolver(
classOrObject,
ownerDescriptor,
existingMembers,
trace,
memberExtractor,
typeResolver,
delegationFilter,
languageVersionSettings
)
.generateDelegatedMembers() .generateDelegatedMembers()
private fun isOverridingAnyOf( private fun isOverridingAnyOf(
@@ -47,14 +47,16 @@ object DescriptorToSourceUtils {
result.add(descriptor) result.add(descriptor)
} }
@JvmStatic fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> { @JvmStatic
fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
val result = ArrayList<DeclarationDescriptor>() val result = ArrayList<DeclarationDescriptor>()
collectEffectiveReferencedDescriptors(result, descriptor.original) collectEffectiveReferencedDescriptors(result, descriptor.original)
return result return result
} }
// TODO Fix in descriptor // TODO Fix in descriptor
@JvmStatic private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? { @JvmStatic
private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
// Only for extension receivers // Only for extension receivers
if (descriptor.source != SourceElement.NO_SOURCE || descriptor.value !is ExtensionReceiver) return null if (descriptor.source != SourceElement.NO_SOURCE || descriptor.value !is ExtensionReceiver) return null
val containingDeclaration = descriptor.containingDeclaration as? CallableDescriptor ?: return null val containingDeclaration = descriptor.containingDeclaration as? CallableDescriptor ?: return null
@@ -62,7 +64,8 @@ object DescriptorToSourceUtils {
return psi.receiverTypeReference return psi.receiverTypeReference
} }
@JvmStatic fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? { @JvmStatic
fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
if (descriptor is ReceiverParameterDescriptor) { if (descriptor is ReceiverParameterDescriptor) {
getSourceForExtensionReceiverParameterDescriptor(descriptor)?.let { return it } getSourceForExtensionReceiverParameterDescriptor(descriptor)?.let { return it }
} }
@@ -70,7 +73,8 @@ object DescriptorToSourceUtils {
return (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi() return (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()
} }
@JvmStatic fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? { @JvmStatic
fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? {
return descriptor.source.getPsi() as? 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 // 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. // with multiple declarations), returns null. It can't find declarations in builtins or decompiled code.
// In IDE, use DescriptorToSourceUtilsIde instead. // In IDE, use DescriptorToSourceUtilsIde instead.
@JvmStatic fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? { @JvmStatic
fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
val effectiveReferencedDescriptors = getEffectiveReferencedDescriptors(descriptor) val effectiveReferencedDescriptors = getEffectiveReferencedDescriptors(descriptor)
return if (effectiveReferencedDescriptors.size == 1) getSourceFromDescriptor(effectiveReferencedDescriptors.firstOrNull()!!) else null 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 // 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 // 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 val descriptor = findTopLevelParent(declarationDescriptor) ?: return null
@@ -38,7 +38,8 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
return result and checkFunction(constructor, constructorDescriptor) return result and checkFunction(constructor, constructorDescriptor)
} }
fun checkDeclarationWithVisibility(modifierListOwner: KtModifierListOwner, fun checkDeclarationWithVisibility(
modifierListOwner: KtModifierListOwner,
descriptor: DeclarationDescriptorWithVisibility, descriptor: DeclarationDescriptorWithVisibility,
visibility: Visibility visibility: Visibility
): Boolean { ): Boolean {
@@ -60,12 +61,17 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val typeAliasVisibility = typeAliasDescriptor.effectiveVisibility() val typeAliasVisibility = typeAliasDescriptor.effectiveVisibility()
val restricting = expandedType.leastPermissiveDescriptor(typeAliasVisibility) val restricting = expandedType.leastPermissiveDescriptor(typeAliasVisibility)
if (restricting != null) { if (restricting != null) {
trace.report(Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(typeAlias.nameIdentifier ?: typeAlias, trace.report(
typeAliasVisibility, restricting, restricting.effectiveVisibility())) Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(
typeAlias.nameIdentifier ?: typeAlias,
typeAliasVisibility, restricting, restricting.effectiveVisibility()
)
)
} }
} }
fun checkFunction(function: KtFunction, fun checkFunction(
function: KtFunction,
functionDescriptor: FunctionDescriptor, functionDescriptor: FunctionDescriptor,
// for checking situation with modified basic visibility // for checking situation with modified basic visibility
visibility: Visibility = functionDescriptor.visibility visibility: Visibility = functionDescriptor.visibility
@@ -75,23 +81,32 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
if (function !is KtConstructor<*>) { if (function !is KtConstructor<*>) {
val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility) val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility)
if (restricting != null) { if (restricting != null) {
trace.report(Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(function.nameIdentifier ?: function, functionVisibility, trace.report(
restricting, restricting.effectiveVisibility())) Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(
function.nameIdentifier ?: function, functionVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false result = false
} }
} }
functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor -> functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility) val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility)
if (restricting != null && i < function.valueParameters.size) { if (restricting != null && i < function.valueParameters.size) {
trace.report(Errors.EXPOSED_PARAMETER_TYPE.on(function.valueParameters[i], functionVisibility, trace.report(
restricting, restricting.effectiveVisibility())) Errors.EXPOSED_PARAMETER_TYPE.on(
function.valueParameters[i], functionVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false result = false
} }
} }
return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor) return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor)
} }
fun checkProperty(property: KtProperty, fun checkProperty(
property: KtProperty,
propertyDescriptor: PropertyDescriptor, propertyDescriptor: PropertyDescriptor,
// for checking situation with modified basic visibility // for checking situation with modified basic visibility
visibility: Visibility = propertyDescriptor.visibility visibility: Visibility = propertyDescriptor.visibility
@@ -100,8 +115,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility) val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility)
var result = true var result = true
if (restricting != null) { if (restricting != null) {
trace.report(Errors.EXPOSED_PROPERTY_TYPE.on(property.nameIdentifier ?: property, propertyVisibility, trace.report(
restricting, restricting.effectiveVisibility())) Errors.EXPOSED_PROPERTY_TYPE.on(
property.nameIdentifier ?: property, propertyVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false result = false
} }
return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor) return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor)
@@ -113,8 +132,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val memberVisibility = memberDescriptor.effectiveVisibility() val memberVisibility = memberDescriptor.effectiveVisibility()
val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility) val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility)
if (restricting != null) { if (restricting != null) {
trace.report(Errors.EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility, trace.report(
restricting, restricting.effectiveVisibility())) Errors.EXPOSED_RECEIVER_TYPE.on(
typeReference, memberVisibility,
restricting, restricting.effectiveVisibility()
)
)
return false return false
} }
return true return true
@@ -135,12 +158,19 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
val restricting = superType.leastPermissiveDescriptor(classVisibility) val restricting = superType.leastPermissiveDescriptor(classVisibility)
if (restricting != null) { if (restricting != null) {
if (isInterface) { if (isInterface) {
trace.report(Errors.EXPOSED_SUPER_INTERFACE.on(delegationList[i], classVisibility, trace.report(
restricting, restricting.effectiveVisibility())) Errors.EXPOSED_SUPER_INTERFACE.on(
} delegationList[i], classVisibility,
else { restricting, restricting.effectiveVisibility()
trace.report(Errors.EXPOSED_SUPER_CLASS.on(delegationList[i], classVisibility, )
restricting, restricting.effectiveVisibility())) )
} else {
trace.report(
Errors.EXPOSED_SUPER_CLASS.on(
delegationList[i], classVisibility,
restricting, restricting.effectiveVisibility()
)
)
} }
result = false result = false
} }
@@ -157,8 +187,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
for (upperBound in typeParameterDescriptor.upperBounds) { for (upperBound in typeParameterDescriptor.upperBounds) {
val restricting = upperBound.leastPermissiveDescriptor(classVisibility) val restricting = upperBound.leastPermissiveDescriptor(classVisibility)
if (restricting != null) { if (restricting != null) {
trace.report(Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameterList[i], classVisibility, trace.report(
restricting, restricting.effectiveVisibility())) Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(
typeParameterList[i], classVisibility,
restricting, restricting.effectiveVisibility()
)
)
result = false result = false
break break
} }
@@ -109,8 +109,10 @@ class LazyTopDownAnalyzer(
} }
override fun visitClassOrObject(classOrObject: KtClassOrObject) { override fun visitClassOrObject(classOrObject: KtClassOrObject) {
val location = if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION val location =
val descriptor = lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
val descriptor =
lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
c.declaredClasses.put(classOrObject, descriptor) c.declaredClasses.put(classOrObject, descriptor)
registerDeclarations(classOrObject.declarations) registerDeclarations(classOrObject.declarations)
@@ -127,12 +129,10 @@ class LazyTopDownAnalyzer(
trace.report(MANY_COMPANION_OBJECTS.on(jetDeclaration)) trace.report(MANY_COMPANION_OBJECTS.on(jetDeclaration))
} }
companionObjectAlreadyFound = true companionObjectAlreadyFound = true
} } else if (jetDeclaration is KtSecondaryConstructor) {
else if (jetDeclaration is KtSecondaryConstructor) {
if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) { if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) {
trace.report(CONSTRUCTOR_IN_OBJECT.on(jetDeclaration)) 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)) trace.report(CONSTRUCTOR_IN_INTERFACE.on(jetDeclaration))
} }
} }
@@ -147,13 +147,19 @@ class LazyTopDownAnalyzer(
private fun registerPrimaryConstructorParameters(klass: KtClass) { private fun registerPrimaryConstructorParameters(klass: KtClass) {
for (jetParameter in klass.primaryConstructorParameters) { for (jetParameter in klass.primaryConstructorParameters) {
if (jetParameter.hasValOrVar()) { 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) { 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) { override fun visitEnumEntry(enumEntry: KtEnumEntry) {
@@ -165,7 +171,8 @@ class LazyTopDownAnalyzer(
} }
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer) { 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) c.anonymousInitializers.put(initializer, containerDescriptor)
} }
@@ -237,7 +244,11 @@ class LazyTopDownAnalyzer(
fileScopeProvider.getImportResolver(file).forceResolveAllImports() 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) { for (typeAlias in typeAliases) {
val descriptor = lazyDeclarationResolver.resolveToDescriptor(typeAlias) as TypeAliasDescriptor 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) { for (property in properties) {
val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor
@@ -271,7 +286,8 @@ class LazyTopDownAnalyzer(
private fun createPropertiesFromDestructuringDeclarations( private fun createPropertiesFromDestructuringDeclarations(
c: TopDownAnalysisContext, c: TopDownAnalysisContext,
topLevelFqNames: Multimap<FqName, KtElement>, topLevelFqNames: Multimap<FqName, KtElement>,
destructuringDeclarations: List<KtDestructuringDeclaration>) { destructuringDeclarations: List<KtDestructuringDeclaration>
) {
for (destructuringDeclaration in destructuringDeclarations) { for (destructuringDeclaration in destructuringDeclarations) {
for (entry in destructuringDeclaration.entries) { for (entry in destructuringDeclaration.entries) {
val descriptor = lazyDeclarationResolver.resolveToDescriptor(entry) as PropertyDescriptor 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)) { if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
val fqName = declaration.fqName val fqName = declaration.fqName
if (fqName != null) { if (fqName != null) {
@@ -52,9 +52,11 @@ object ModifierCheckerCore {
COMPATIBLE_FOR_CLASSES_ONLY COMPATIBLE_FOR_CLASSES_ONLY
} }
private val defaultVisibilityTargets = EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, private val defaultVisibilityTargets = EnumSet.of(
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS) MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS
)
val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>( val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS), ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
@@ -67,8 +69,10 @@ object ModifierCheckerCore {
PRIVATE_KEYWORD to defaultVisibilityTargets, PRIVATE_KEYWORD to defaultVisibilityTargets,
PUBLIC_KEYWORD to defaultVisibilityTargets, PUBLIC_KEYWORD to defaultVisibilityTargets,
INTERNAL_KEYWORD to defaultVisibilityTargets, INTERNAL_KEYWORD to defaultVisibilityTargets,
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, PROTECTED_KEYWORD to EnumSet.of(
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS), 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), IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION), OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER), REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
@@ -87,9 +91,33 @@ object ModifierCheckerCore {
OPERATOR_KEYWORD to EnumSet.of(FUNCTION), OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
INFIX_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), 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), 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), 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) 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( private val featureDependencies = mapOf(
@@ -122,8 +150,10 @@ object ModifierCheckerCore {
) )
private val possibleParentTargetPredicateMap = mapOf<KtModifierKeywordToken, TargetAllowedPredicate>( private val possibleParentTargetPredicateMap = mapOf<KtModifierKeywordToken, TargetAllowedPredicate>(
INNER_KEYWORD to or(always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS), INNER_KEYWORD to or(
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)), 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), 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), 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), INTERNAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, FILE),
@@ -201,8 +231,10 @@ object ModifierCheckerCore {
sufficient: KtModifierKeywordToken, sufficient: KtModifierKeywordToken,
redundant: KtModifierKeywordToken redundant: KtModifierKeywordToken
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> { ): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
return mapOf(Pair(sufficient, redundant) to Compatibility.REDUNDANT, return mapOf(
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT) Pair(sufficient, redundant) to Compatibility.REDUNDANT,
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
)
} }
private fun compatibilityRegister( private fun compatibilityRegister(
@@ -229,22 +261,24 @@ object ModifierCheckerCore {
private fun compatibility(first: KtModifierKeywordToken, second: KtModifierKeywordToken): Compatibility { private fun compatibility(first: KtModifierKeywordToken, second: KtModifierKeywordToken): Compatibility {
return if (first == second) { return if (first == second) {
Compatibility.REPEATED Compatibility.REPEATED
} } else {
else {
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
} }
} }
private fun checkCompatibility(trace: BindingTrace, private fun checkCompatibility(
trace: BindingTrace,
firstNode: ASTNode, firstNode: ASTNode,
secondNode: ASTNode, secondNode: ASTNode,
owner: PsiElement, owner: PsiElement,
incorrectNodes: MutableSet<ASTNode>) { incorrectNodes: MutableSet<ASTNode>
) {
val first = firstNode.elementType as KtModifierKeywordToken val first = firstNode.elementType as KtModifierKeywordToken
val second = secondNode.elementType as KtModifierKeywordToken val second = secondNode.elementType as KtModifierKeywordToken
val compatibility = compatibility(first, second) val compatibility = compatibility(first, second)
when (compatibility) { when (compatibility) {
Compatibility.COMPATIBLE -> {} Compatibility.COMPATIBLE -> {
}
Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) { Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) {
trace.report(Errors.REPEATED_MODIFIER.on(secondNode.psi, first)) trace.report(Errors.REPEATED_MODIFIER.on(secondNode.psi, first))
} }
@@ -285,9 +319,21 @@ object ModifierCheckerCore {
deprecatedModifierReplacement != null -> deprecatedModifierReplacement != null ->
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement)) trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
actualTargets.any { it in deprecatedTargets } -> 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 } -> 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 return true
} }
@@ -313,8 +359,7 @@ object ModifierCheckerCore {
if (featureSupport == LanguageFeature.State.DISABLED) { if (featureSupport == LanguageFeature.State.DISABLED) {
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData)) trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData))
} } else {
else {
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData)) trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData))
} }
return false return false
@@ -330,7 +375,12 @@ object ModifierCheckerCore {
// Should return false if error is reported, true otherwise // 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 modifier = node.elementType as KtModifierKeywordToken
val actualParents: List<KotlinTarget> = when (parentDescriptor) { val actualParents: List<KotlinTarget> = when (parentDescriptor) {
is ClassDescriptor -> KotlinTarget.classActualTargets(parentDescriptor) is ClassDescriptor -> KotlinTarget.classActualTargets(parentDescriptor)
@@ -341,12 +391,24 @@ object ModifierCheckerCore {
} }
val deprecatedParents = deprecatedParentTargetMap[modifier] val deprecatedParents = deprecatedParentTargetMap[modifier]
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) { 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 return true
} }
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) 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 return false
} }
@@ -413,7 +475,8 @@ private fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object
target in targetSet target in targetSet
} }
private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate { private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
object : TargetAllowedPredicate {
private val targetSet = EnumSet.of(target, *targets) private val targetSet = EnumSet.of(target, *targets)
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) = override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
@@ -104,11 +104,14 @@ object NonExpansiveInheritanceRestrictionChecker {
for (typeParameter in typeParameters) { for (typeParameter in typeParameters) {
if (typeParameter.defaultType in constituents || typeParameter.defaultType.makeNullableAsSpecified(true) in constituents) { 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 // 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 // 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. // 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 bounds = hashSetOf<KotlinType>()
val substitutor = TypeConstructorSubstitution.create(constituentType).buildSubstitutor() 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) bounds.addAll(adaptedUpperBounds)
if (!typeProjection.isStarProjection) { if (!typeProjection.isStarProjection) {
@@ -106,7 +106,10 @@ class OverrideResolver(
// don't care // don't care
} }
override fun abstractMemberWithMoreSpecificType(abstractMember: CallableMemberDescriptor, concreteMember: CallableMemberDescriptor) { override fun abstractMemberWithMoreSpecificType(
abstractMember: CallableMemberDescriptor,
concreteMember: CallableMemberDescriptor
) {
shouldImplement.add(abstractMember) shouldImplement.add(abstractMember)
} }
} }
@@ -147,17 +150,18 @@ class OverrideResolver(
if (descriptor1 is PropertyDescriptor && descriptor2 is PropertyDescriptor) { if (descriptor1 is PropertyDescriptor && descriptor2 is PropertyDescriptor) {
if (descriptor1.isVar || descriptor2.isVar) { if (descriptor1.isVar || descriptor2.isVar) {
reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2) reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
} } else {
else {
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2) reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
} }
} } else {
else {
reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2) 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) typeMismatchOnInheritance(abstractMember, concreteMember)
} }
@@ -181,7 +185,8 @@ class OverrideResolver(
overridden: CallableMemberDescriptor overridden: CallableMemberDescriptor
) { ) {
reportDelegationProblemIfRequired( 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( override fun propertyTypeMismatchOnOverride(
@@ -189,7 +194,8 @@ class OverrideResolver(
overridden: PropertyDescriptor overridden: PropertyDescriptor
) { ) {
reportDelegationProblemIfRequired( 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) { override fun varOverriddenByVal(overriding: CallableMemberDescriptor, overridden: CallableMemberDescriptor) {
@@ -204,7 +210,9 @@ class OverrideResolver(
) { ) {
assert(delegate.kind == DELEGATION) { "Delegate expected, got " + delegate + " of kind " + delegate.kind } 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) onceErrorsReported.add(diagnosticFactory)
trace.report(diagnosticFactory.on(klass, delegate, overridden)) trace.report(diagnosticFactory.on(klass, delegate, overridden))
} }
@@ -214,8 +222,7 @@ class OverrideResolver(
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor) val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) { if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.first())) 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())) trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.first()))
} }
@@ -223,8 +230,7 @@ class OverrideResolver(
multipleImplementations.removeAll(conflictingReturnTypes) multipleImplementations.removeAll(conflictingReturnTypes)
if (!conflictingInterfaceMembers.isEmpty()) { if (!conflictingInterfaceMembers.isEmpty()) {
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next())) 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())) 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 (declared.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) {
if (DataClassDescriptorResolver.isComponentLike(declared.name)) { if (DataClassDescriptorResolver.isComponentLike(declared.name)) {
checkOverrideForComponentFunction(declared) checkOverrideForComponentFunction(declared)
} } else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
checkOverrideForCopyFunction(declared) checkOverrideForCopyFunction(declared)
} }
return return
@@ -257,7 +262,8 @@ class OverrideResolver(
return 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 modifierList = member.modifierList
val hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD) val hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
@@ -288,8 +294,7 @@ class OverrideResolver(
typeMismatchError = true typeMismatchError = true
if (overridden.isVar) { if (overridden.isVar) {
trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)) trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
} } else {
else {
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)) 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)) trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden))
} }
@@ -310,8 +318,7 @@ class OverrideResolver(
trace.report(NOTHING_TO_OVERRIDE.on(member, declared)) 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() val overridden = overriddenDescriptors.iterator().next()
trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.containingDeclaration)) trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.containingDeclaration))
} }
@@ -354,8 +361,7 @@ class OverrideResolver(
val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration) val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration)
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) { if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) {
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR.on(dataModifier, copyFunction, baseClassifier)) 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)) trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING.on(dataModifier, copyFunction, baseClassifier))
} }
} }
@@ -397,15 +403,15 @@ class OverrideResolver(
if (isDeclaration) { if (isDeclaration) {
checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper) checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper)
} } else {
else {
checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper) checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper)
} }
} }
} }
private fun checkNameAndDefaultForDeclaredParameter(descriptor: ValueParameterDescriptor, multipleDefaultsInSuper: Boolean) { 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()) { if (descriptor.declaresDefaultValue()) {
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter)) trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter))
@@ -418,10 +424,12 @@ class OverrideResolver(
for (parameterFromSuperclass in descriptor.overriddenDescriptors) { for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) { if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
trace.report(PARAMETER_NAME_CHANGED_ON_OVERRIDE.on( trace.report(
PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
parameter, parameter,
parameterFromSuperclass.containingDeclaration.containingDeclaration as ClassDescriptor, parameterFromSuperclass.containingDeclaration.containingDeclaration as ClassDescriptor,
parameterFromSuperclass) parameterFromSuperclass
)
) )
} }
} }
@@ -433,7 +441,8 @@ class OverrideResolver(
multipleDefaultsInSuper: Boolean multipleDefaultsInSuper: Boolean
) { ) {
val containingClass = containingFunction.containingDeclaration 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) { if (multipleDefaultsInSuper) {
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, descriptor)) 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) { for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) { 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, classElement,
containingFunction.overriddenDescriptors, containingFunction.overriddenDescriptors,
parameterFromSuperclass.index + 1) parameterFromSuperclass.index + 1
)
) )
} }
} }
@@ -468,11 +479,24 @@ class OverrideResolver(
for (descriptor in memberDescriptor.overriddenDescriptors) { for (descriptor in memberDescriptor.overriddenDescriptors) {
val compare = Visibilities.compare(visibility, descriptor.visibility) val compare = Visibilities.compare(visibility, descriptor.visibility)
if (compare == null) { 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 return
} } else if (compare < 0) {
else if (compare < 0) { trace.report(
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(declaration, descriptor.visibility, descriptor, descriptor.containingDeclaration)) CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(
declaration,
descriptor.visibility,
descriptor,
descriptor.containingDeclaration
)
)
return return
} }
} }
@@ -545,9 +569,11 @@ class OverrideResolver(
val allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values) val allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values)
val allFilteredOverriddenDeclarations = OverridingUtil.filterOutOverridden( val allFilteredOverriddenDeclarations = OverridingUtil.filterOutOverridden(
Sets.newLinkedHashSet(allOverriddenDeclarations)) Sets.newLinkedHashSet(allOverriddenDeclarations)
)
val relevantDirectlyOverridden = getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations) val relevantDirectlyOverridden =
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
checkInheritedDescriptorsGroup(descriptor, relevantDirectlyOverridden, reportingStrategy) checkInheritedDescriptorsGroup(descriptor, relevantDirectlyOverridden, reportingStrategy)
@@ -608,8 +634,7 @@ class OverrideResolver(
if (overridden.modality === Modality.ABSTRACT) { if (overridden.modality === Modality.ABSTRACT) {
overridesAbstractInBaseClass = overridden overridesAbstractInBaseClass = overridden
} }
} } else if (containingDeclaration.kind == ClassKind.INTERFACE) {
else if (containingDeclaration.kind == ClassKind.INTERFACE) {
overriddenInterfaceMembers.add(overridden) overriddenInterfaceMembers.add(overridden)
if (overridden.modality !== Modality.ABSTRACT) { if (overridden.modality !== Modality.ABSTRACT) {
overridesNonAbstractInterfaceMember = true overridesNonAbstractInterfaceMember = true
@@ -713,12 +738,12 @@ class OverrideResolver(
for (overriddenDescriptor in overriddenDescriptors) { for (overriddenDescriptor in overriddenDescriptors) {
if (propertyDescriptor != null) { 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)) { if (!isPropertyTypeOkForOverride(overriddenPropertyDescriptor, propertyDescriptor)) {
reportingStrategy.typeMismatchOnInheritance(propertyDescriptor, overriddenPropertyDescriptor) reportingStrategy.typeMismatchOnInheritance(propertyDescriptor, overriddenPropertyDescriptor)
} }
} } else {
else {
if (!isReturnTypeOkForOverride(overriddenDescriptor, descriptor)) { if (!isReturnTypeOkForOverride(overriddenDescriptor, descriptor)) {
reportingStrategy.typeMismatchOnInheritance(descriptor, overriddenDescriptor) reportingStrategy.typeMismatchOnInheritance(descriptor, overriddenDescriptor)
} }
@@ -743,8 +768,7 @@ class OverrideResolver(
val invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass) val invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass)
if (invisibleOverriddenDescriptor != null) { if (invisibleOverriddenDescriptor != null) {
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor) reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor)
} } else {
else {
reportError.nothingToOverride(declared) reportError.nothingToOverride(declared)
} }
} }
@@ -769,8 +793,7 @@ class OverrideResolver(
if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) { if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) {
reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty) reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty)
} }
} } else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden) reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden)
} }
@@ -821,8 +844,7 @@ class OverrideResolver(
return if (superDescriptor.isVar) { return if (superDescriptor.isVar) {
KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.type, substitutedSuperReturnType) KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.type, substitutedSuperReturnType)
} } else {
else {
KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.type, substitutedSuperReturnType) KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.type, substitutedSuperReturnType)
} }
} }
@@ -850,8 +872,10 @@ class OverrideResolver(
for (fromSuper in all) { for (fromSuper in all) {
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null).result == OVERRIDABLE) { if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null).result == OVERRIDABLE) {
if (OverridingUtil.isVisibleForOverride(declared, fromSuper)) { if (OverridingUtil.isVisibleForOverride(declared, fromSuper)) {
throw IllegalStateException("Descriptor " + fromSuper + " is overridable by " + declared + throw IllegalStateException(
" and visible but does not appear in its getOverriddenDescriptors()") "Descriptor " + fromSuper + " is overridable by " + declared +
" and visible but does not appear in its getOverriddenDescriptors()"
)
} }
return fromSuper return fromSuper
} }
@@ -116,8 +116,7 @@ private class AbbreviatedTypeBinding(
override val isInAbbreviation: Boolean get() = true override val isInAbbreviation: Boolean get() = true
override val arguments: List<TypeArgumentBinding<KtTypeElement>?> override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
argumentType ->
AbbreviatedTypeBinding(argumentType, psiElement) AbbreviatedTypeBinding(argumentType, psiElement)
} }
} }
@@ -130,8 +129,7 @@ private class NoTypeElementBinding<out P : PsiElement>(
override val isInAbbreviation: Boolean get() = false override val isInAbbreviation: Boolean get() = false
override val arguments: List<TypeArgumentBinding<P>?> override val arguments: List<TypeArgumentBinding<P>?>
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
argumentType ->
NoTypeElementBinding(trace, psiElement, argumentType) NoTypeElementBinding(trace, psiElement, argumentType)
} }
} }
@@ -113,16 +113,20 @@ class CallCompleter(
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val candidates = (if (context.collectAllCandidates) { val candidates = (if (context.collectAllCandidates) {
results.allCandidates!! results.allCandidates!!
} } else {
else {
results.resultingCalls results.resultingCalls
}) as Collection<MutableResolvedCall<D>> }) as Collection<MutableResolvedCall<D>>
val temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call") val temporaryBindingTrace =
candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach { TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
resolvedCall -> candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach { resolvedCall ->
completeResolvedCallAndArguments(resolvedCall, results, context.replaceBindingTrace(temporaryBindingTrace), TracingStrategy.EMPTY) completeResolvedCallAndArguments(
resolvedCall,
results,
context.replaceBindingTrace(temporaryBindingTrace),
TracingStrategy.EMPTY
)
} }
} }
@@ -159,8 +163,7 @@ class CallCompleter(
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963) // TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType() if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
else TypeUtils.NO_EXPECTED_TYPE else TypeUtils.NO_EXPECTED_TYPE
} } else expectedType
else expectedType
fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? = fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? =
type?.let { type?.let {
@@ -181,8 +184,7 @@ class CallCompleter(
if (returnTypeInSystem != null) { if (returnTypeInSystem != null) {
builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position()) builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position())
builder.build() builder.build()
} } else null
else null
} }
} }
@@ -206,16 +208,20 @@ class CallCompleter(
builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position()) builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position())
val system = builder.build() val system = builder.build()
if (system.status.isSuccessful()) system else null if (system.status.isSuccessful()) system else null
} } else null
else null
} }
} }
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) { if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
updateSystemIfNeeded { builder -> updateSystemIfNeeded { builder ->
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType()).forEach { (parameter, argument) -> candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType())
.forEach { (parameter, argument) ->
val valueParameterInSystem = builder.typeInSystem(parameter.type) val valueParameterInSystem = builder.typeInSystem(parameter.type)
builder.addSubtypeConstraint(valueParameterInSystem, argument.type, VALUE_PARAMETER_POSITION.position(parameter.index)) builder.addSubtypeConstraint(
valueParameterInSystem,
argument.type,
VALUE_PARAMETER_POSITION.position(parameter.index)
)
} }
builder.build() builder.build()
@@ -268,8 +274,7 @@ class CallCompleter(
val resolvedCall = results.resultingCall val resolvedCall = results.resultingCall
getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) } getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) }
getDataFlowInfoForArgument = { argument -> resolvedCall.dataFlowInfoForArguments.getInfo(argument) } getDataFlowInfoForArgument = { argument -> resolvedCall.dataFlowInfoForArguments.getInfo(argument) }
} } else {
else {
getArgumentMapping = { ArgumentUnmapped } getArgumentMapping = { ArgumentUnmapped }
getDataFlowInfoForArgument = { context.dataFlowInfo } getDataFlowInfoForArgument = { context.dataFlowInfo }
} }
@@ -279,7 +284,8 @@ class CallCompleter(
val (expectedType, callPosition) = when (argumentMapping) { val (expectedType, callPosition) = when (argumentMapping) {
is ArgumentMatch -> Pair( is ArgumentMatch -> Pair(
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context), getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument)) CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument)
)
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown) else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
} }
val newContext = val newContext =
@@ -307,8 +313,7 @@ class CallCompleter(
val resolvedCall = results.resultingCall val resolvedCall = results.resultingCall
updatedType = if (resolvedCall.hasInferredReturnType()) { updatedType = if (resolvedCall.hasInferredReturnType()) {
resolvedCall.makeNullableTypeIfSafeReceiver(resolvedCall.resultingDescriptor?.returnType, context) 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.), // For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.),
@@ -89,8 +89,11 @@ class CallExpressionResolver(
checkArguments: CheckArgumentTypesMode, checkArguments: CheckArgumentTypesMode,
initialDataFlowInfoForArguments: DataFlowInfo initialDataFlowInfoForArguments: DataFlowInfo
): Pair<Boolean, ResolvedCall<FunctionDescriptor>?> { ): Pair<Boolean, ResolvedCall<FunctionDescriptor>?> {
val results = callResolver.resolveFunctionCall(BasicCallResolutionContext.create( val results = callResolver.resolveFunctionCall(
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call))) BasicCallResolutionContext.create(
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
)
)
return if (!results.isNothing) return if (!results.isNothing)
Pair(true, OverloadResolutionResultsUtil.getResultingCall(results, context)) Pair(true, OverloadResolutionResultsUtil.getResultingCall(results, context))
else else
@@ -102,11 +105,13 @@ class CallExpressionResolver(
callOperationNode: ASTNode?, context: ExpressionTypingContext callOperationNode: ASTNode?, context: ExpressionTypingContext
): Pair<Boolean, KotlinType?> { ): Pair<Boolean, KotlinType?> {
val temporaryForVariable = TemporaryTraceAndCache.create( 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 call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression)
val contextForVariable = BasicCallResolutionContext.create( val contextForVariable = BasicCallResolutionContext.create(
context.replaceTraceAndCache(temporaryForVariable), context.replaceTraceAndCache(temporaryForVariable),
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
)
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable) val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
// if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved // if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
@@ -122,8 +127,10 @@ class CallExpressionResolver(
} }
temporaryForVariable.commit() temporaryForVariable.commit()
return Pair(!resolutionResult.isNothing, return Pair(
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null) !resolutionResult.isNothing,
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null
)
} }
fun getSimpleNameExpressionTypeInfo( fun getSimpleNameExpressionTypeInfo(
@@ -138,9 +145,12 @@ class CallExpressionResolver(
): KotlinTypeInfo { ): KotlinTypeInfo {
val temporaryForVariable = TemporaryTraceAndCache.create( val temporaryForVariable = TemporaryTraceAndCache.create(
context, "trace to resolve as variable", nameExpression) context, "trace to resolve as variable", nameExpression
val (notNothing, type) = getVariableType(nameExpression, receiver, callOperationNode, )
context.replaceTraceAndCache(temporaryForVariable)) val (notNothing, type) = getVariableType(
nameExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable)
)
if (notNothing) { if (notNothing) {
temporaryForVariable.commit() temporaryForVariable.commit()
@@ -149,10 +159,12 @@ class CallExpressionResolver(
val call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, emptyList()) val call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, emptyList())
val temporaryForFunction = TemporaryTraceAndCache.create( val temporaryForFunction = TemporaryTraceAndCache.create(
context, "trace to resolve as function", nameExpression) context, "trace to resolve as function", nameExpression
)
val newContext = context.replaceTraceAndCache(temporaryForFunction) val newContext = context.replaceTraceAndCache(temporaryForFunction)
val (resolveResult, resolvedCall) = getResolvedCallForFunction( val (resolveResult, resolvedCall) = getResolvedCallForFunction(
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments) call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments
)
if (resolveResult) { if (resolveResult) {
val functionDescriptor = resolvedCall?.resultingDescriptor val functionDescriptor = resolvedCall?.resultingDescriptor
if (functionDescriptor !is ConstructorDescriptor) { if (functionDescriptor !is ConstructorDescriptor) {
@@ -177,7 +189,8 @@ class CallExpressionResolver(
callOperationNode: ASTNode?, context: ExpressionTypingContext callOperationNode: ASTNode?, context: ExpressionTypingContext
): KotlinTypeInfo { ): KotlinTypeInfo {
val typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck( val typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
callExpression, receiver, callOperationNode, context, context.dataFlowInfo) callExpression, receiver, callOperationNode, context, context.dataFlowInfo
)
if (context.contextDependency == INDEPENDENT) { if (context.contextDependency == INDEPENDENT) {
dataFlowAnalyzer.checkType(typeInfo.type, callExpression, context) dataFlowAnalyzer.checkType(typeInfo.type, callExpression, context)
} }
@@ -196,12 +209,14 @@ class CallExpressionResolver(
val call = CallMaker.makeCall(receiver, callOperationNode, callExpression) val call = CallMaker.makeCall(receiver, callOperationNode, callExpression)
val temporaryForFunction = TemporaryTraceAndCache.create( val temporaryForFunction = TemporaryTraceAndCache.create(
context, "trace to resolve as function call", callExpression) context, "trace to resolve as function call", callExpression
)
val (resolveResult, resolvedCall) = getResolvedCallForFunction( val (resolveResult, resolvedCall) = getResolvedCallForFunction(
call, call,
context.replaceTraceAndCache(temporaryForFunction), context.replaceTraceAndCache(temporaryForFunction),
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
initialDataFlowInfoForArguments) initialDataFlowInfoForArguments
)
if (resolveResult) { if (resolveResult) {
val functionDescriptor = resolvedCall?.resultingDescriptor val functionDescriptor = resolvedCall?.resultingDescriptor
temporaryForFunction.commit() temporaryForFunction.commit()
@@ -246,9 +261,12 @@ class CallExpressionResolver(
val calleeExpression = callExpression.calleeExpression val calleeExpression = callExpression.calleeExpression
if (calleeExpression is KtSimpleNameExpression && callExpression.typeArgumentList == null) { if (calleeExpression is KtSimpleNameExpression && callExpression.typeArgumentList == null) {
val temporaryForVariable = TemporaryTraceAndCache.create( val temporaryForVariable = TemporaryTraceAndCache.create(
context, "trace to resolve as variable with 'invoke' call", callExpression) context, "trace to resolve as variable with 'invoke' call", callExpression
val (notNothing, type) = getVariableType(calleeExpression, receiver, callOperationNode, )
context.replaceTraceAndCache(temporaryForVariable)) val (notNothing, type) = getVariableType(
calleeExpression, receiver, callOperationNode,
context.replaceTraceAndCache(temporaryForVariable)
)
val qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression) val qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression)
if (notNothing && (qualifier == null || qualifier !is PackageQualifier)) { if (notNothing && (qualifier == null || qualifier !is PackageQualifier)) {
@@ -258,8 +276,12 @@ class CallExpressionResolver(
} }
temporaryForVariable.commit() temporaryForVariable.commit()
context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression, context.trace.report(
type ?: ErrorUtils.createErrorType(""))) FUNCTION_EXPECTED.on(
calleeExpression, calleeExpression,
type ?: ErrorUtils.createErrorType("")
)
)
argumentTypeResolver.analyzeArgumentsAndRecordTypes( argumentTypeResolver.analyzeArgumentsAndRecordTypes(
BasicCallResolutionContext.create( BasicCallResolutionContext.create(
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
@@ -275,14 +297,12 @@ class CallExpressionResolver(
} }
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) = private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) { qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) { nameExpression ->
nameExpression ->
val resolutionResult = resolveSimpleName(context, nameExpression) val resolutionResult = resolveSimpleName(context, nameExpression)
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) { if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
false false
} } else when (resolutionResult.resultCode) {
else when (resolutionResult.resultCode) {
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
} }
@@ -307,9 +327,11 @@ class CallExpressionResolver(
initialDataFlowInfoForArguments: DataFlowInfo initialDataFlowInfoForArguments: DataFlowInfo
): KotlinTypeInfo = when (selectorExpression) { ): KotlinTypeInfo = when (selectorExpression) {
is KtCallExpression -> getCallExpressionTypeInfoWithoutFinalTypeCheck( is KtCallExpression -> getCallExpressionTypeInfoWithoutFinalTypeCheck(
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments) selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
)
is KtSimpleNameExpression -> getSimpleNameExpressionTypeInfo( is KtSimpleNameExpression -> getSimpleNameExpressionTypeInfo(
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments) selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
)
is KtExpression -> { is KtExpression -> {
expressionTypingServices.getTypeInfo(selectorExpression, context) expressionTypingServices.getTypeInfo(selectorExpression, context)
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression)) context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression))
@@ -328,9 +350,9 @@ class CallExpressionResolver(
// Additional "receiver != null" information should be applied if we consider a safe call // Additional "receiver != null" information should be applied if we consider a safe call
if (receiverCanBeNull) { if (receiverCanBeNull) {
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate( initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings) receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings
} )
else if (receiver is ReceiverValue) { } else if (receiver is ReceiverValue) {
reportUnnecessarySafeCall(context.trace, receiver.type, element.node, receiver) reportUnnecessarySafeCall(context.trace, receiver.type, element.node, receiver)
} }
} }
@@ -361,8 +383,7 @@ class CallExpressionResolver(
val value = constantExpressionEvaluator.evaluateExpression(qualified, context.trace, context.expectedType) val value = constantExpressionEvaluator.evaluateExpression(qualified, context.trace, context.expectedType)
return if (value != null && value.isPure) { return if (value != null && value.isPure) {
dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, qualified, context) dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, qualified, context)
} } else {
else {
if (context.contextDependency == INDEPENDENT) { if (context.contextDependency == INDEPENDENT) {
dataFlowAnalyzer.checkType(selectorTypeInfo.type, qualified, context) dataFlowAnalyzer.checkType(selectorTypeInfo.type, qualified, context)
} }
@@ -418,8 +439,7 @@ class CallExpressionResolver(
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) { if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
// Call with nullable receiver: take data flow info from branch point // Call with nullable receiver: take data flow info from branch point
branchPointDataFlowInfo branchPointDataFlowInfo
} } else {
else {
// Take data flow info from the current receiver // Take data flow info from the current receiver
receiverTypeInfo.dataFlowInfo receiverTypeInfo.dataFlowInfo
} }
@@ -432,8 +452,9 @@ class CallExpressionResolver(
branchPointDataFlowInfo = selectorTypeInfo.dataFlowInfo branchPointDataFlowInfo = selectorTypeInfo.dataFlowInfo
} }
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector). resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).replaceDataFlowInfo(
replaceDataFlowInfo(branchPointDataFlowInfo) branchPointDataFlowInfo
)
if (!lastStage) { if (!lastStage) {
recordResultTypeInfo(qualifiedExpression, resultTypeInfo, contextForSelector) recordResultTypeInfo(qualifiedExpression, resultTypeInfo, contextForSelector)
} }
@@ -469,8 +490,7 @@ class CallExpressionResolver(
if (parent != null) { if (parent != null) {
return isUnderAnnotationClassDeclaration(trace, parent) return isUnderAnnotationClassDeclaration(trace, parent)
} }
} } else if (parent is KtParameter) {
else if (parent is KtParameter) {
return isUnderAnnotationClassDeclaration(trace, parent) return isUnderAnnotationClassDeclaration(trace, parent)
} }
return false return false
@@ -487,8 +507,7 @@ class CallExpressionResolver(
) = trace.report( ) = trace.report(
if (explicitReceiver is ExpressionReceiver && explicitReceiver.expression is KtSuperExpression) { if (explicitReceiver is ExpressionReceiver && explicitReceiver.expression is KtSuperExpression) {
UNEXPECTED_SAFE_CALL.on(callOperationNode.psi) UNEXPECTED_SAFE_CALL.on(callOperationNode.psi)
} } else {
else {
UNNECESSARY_SAFE_CALL.on(callOperationNode.psi, type) UNNECESSARY_SAFE_CALL.on(callOperationNode.psi, type)
} }
) )
@@ -125,8 +125,10 @@ fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescript
receiverType.constructor receiverType.constructor
} }
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(receiverType.annotations, receiverTypeConstructor, fakeTypeArguments, return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true)) receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true)
)
} }
fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boolean { fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boolean {
@@ -245,7 +247,8 @@ fun createResolutionCandidatesForConstructors(
else else
null null
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver) ?: classWithConstructors.constructors val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver)
?: classWithConstructors.constructors
if (constructors.isEmpty()) return emptyList() if (constructors.isEmpty()) return emptyList()
@@ -262,8 +265,7 @@ fun createResolutionCandidatesForConstructors(
receiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER receiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
dispatchReceiver = receiver.value dispatchReceiver = receiver.value
} } else {
else {
receiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER receiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
dispatchReceiver = null dispatchReceiver = null
} }
@@ -107,8 +107,7 @@ class CandidateResolver(
&& candidateCall.knownTypeParametersSubstitutor == null && candidateCall.knownTypeParametersSubstitutor == null
) { ) {
genericCandidateResolver.inferTypeArguments(this) genericCandidateResolver.inferTypeArguments(this)
} } else {
else {
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
} }
} }
@@ -117,8 +116,7 @@ class CandidateResolver(
val ktTypeArguments = call.typeArguments val ktTypeArguments = call.typeArguments
if (candidateCall.knownTypeParametersSubstitutor != null) { if (candidateCall.knownTypeParametersSubstitutor != null) {
candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!) candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
} } else if (ktTypeArguments.isNotEmpty()) {
else if (ktTypeArguments.isNotEmpty()) {
// Explicit type arguments passed // Explicit type arguments passed
val typeArguments = ArrayList<KotlinType>() val typeArguments = ArrayList<KotlinType>()
@@ -130,9 +128,11 @@ class CandidateResolver(
val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size
for (index in ktTypeArguments.size..expectedTypeArgumentCount - 1) { for (index in ktTypeArguments.size..expectedTypeArgumentCount - 1) {
typeArguments.add(ErrorUtils.createErrorType( typeArguments.add(
ErrorUtils.createErrorType(
"Explicit type argument expected for " + candidateDescriptor.typeParameters[index].name "Explicit type argument expected for " + candidateDescriptor.typeParameters[index].name
)) )
)
} }
val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments) val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments)
val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution)) val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution))
@@ -140,8 +140,7 @@ class CandidateResolver(
if (expectedTypeArgumentCount != ktTypeArguments.size) { if (expectedTypeArgumentCount != ktTypeArguments.size) {
candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR) candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR)
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor) tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor)
} } else {
else {
checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace) checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
} }
@@ -149,17 +148,16 @@ class CandidateResolver(
} }
} }
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments() private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments() = check {
= check {
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters( val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
call, tracing, candidateCall) call, tracing, candidateCall
)
if (!argumentMappingStatus.isSuccess) { if (!argumentMappingStatus.isSuccess) {
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR) candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
} }
} }
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType() private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType() = check {
= check {
if (!noExpectedType(expectedType)) { if (!noExpectedType(expectedType)) {
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference( val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
candidateCall.candidateDescriptor, candidateCall.candidateDescriptor,
@@ -195,7 +193,8 @@ class CandidateResolver(
smartCastType: KotlinType? smartCastType: KotlinType?
): ResolutionStatus { ): ResolutionStatus {
val invisibleMember = Visibilities.findInvisibleMember( val invisibleMember = Visibilities.findInvisibleMember(
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor) getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor
)
return if (invisibleMember != null) { return if (invisibleMember != null) {
tracing.invisibleMember(trace, invisibleMember) tracing.invisibleMember(trace, invisibleMember)
INVISIBLE_MEMBER_ERROR INVISIBLE_MEMBER_ERROR
@@ -224,17 +223,14 @@ class CandidateResolver(
if (receiverParameter != null && receiverArgument == null) { if (receiverParameter != null && receiverArgument == null) {
tracing.missingReceiver(candidateCall.trace, receiverParameter) tracing.missingReceiver(candidateCall.trace, receiverParameter)
OTHER_ERROR OTHER_ERROR
} } else if (receiverParameter == null && receiverArgument != null) {
else if (receiverParameter == null && receiverArgument != null) {
tracing.noReceiverAllowed(candidateCall.trace) tracing.noReceiverAllowed(candidateCall.trace)
if (call.calleeExpression is KtSimpleNameExpression) { if (call.calleeExpression is KtSimpleNameExpression) {
RECEIVER_PRESENCE_ERROR RECEIVER_PRESENCE_ERROR
} } else {
else {
OTHER_ERROR OTHER_ERROR
} }
} } else {
else {
SUCCESS SUCCESS
} }
} }
@@ -248,8 +244,7 @@ class CandidateResolver(
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration) && DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration)
) { ) {
nestedClass = candidateDescriptor.containingDeclaration nestedClass = candidateDescriptor.containingDeclaration
} } else if (candidateDescriptor is FakeCallableDescriptorForObject) {
else if (candidateDescriptor is FakeCallableDescriptorForObject) {
nestedClass = candidateDescriptor.getReferencedObject() nestedClass = candidateDescriptor.getReferencedObject()
} }
if (nestedClass != null) { if (nestedClass != null) {
@@ -342,7 +337,8 @@ class CandidateResolver(
fun <D : CallableDescriptor> checkAllValueArguments( fun <D : CallableDescriptor> checkAllValueArguments(
context: CallCandidateResolutionContext<D>, context: CallCandidateResolutionContext<D>,
resolveFunctionArgumentBodies: ResolveArgumentsMode): ValueArgumentsCheckingResult { resolveFunctionArgumentBodies: ResolveArgumentsMode
): ValueArgumentsCheckingResult {
val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies) val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies)
var resultStatus = checkingResult.status var resultStatus = checkingResult.status
resultStatus = resultStatus.combine(checkReceivers(context)) resultStatus = resultStatus.combine(checkReceivers(context))
@@ -373,27 +369,26 @@ class CandidateResolver(
var resultingType: KotlinType? = type var resultingType: KotlinType? = type
if (type == null || (type.isError && !type.isFunctionPlaceholder)) { if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
} } else if (!noExpectedType(expectedType)) {
else if (!noExpectedType(expectedType)) {
if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) { if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext) val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
if (smartCast == null) { if (smartCast == null) {
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
} } else {
else {
resultingType = smartCast resultingType = smartCast
} }
} } else if (ErrorUtils.containsUninferredParameter(expectedType)) {
else if (ErrorUtils.containsUninferredParameter(expectedType)) {
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
} }
val spreadElement = argument.getSpreadElement() val spreadElement = argument.getSpreadElement()
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) { if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context) val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context, val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
call = null, recordExpressionType = false) dataFlowValue, expectedType, expression, context,
call = null, recordExpressionType = false
)
if (smartCastResult == null || !smartCastResult.isCorrect) { if (smartCastResult == null || !smartCastResult.isCorrect) {
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement)) context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
} }
@@ -463,22 +458,26 @@ class CandidateResolver(
// both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'. // 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. // 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,
candidateCall.resultingDescriptor.extensionReceiverParameter, candidateCall.resultingDescriptor.extensionReceiverParameter,
candidateCall.extensionReceiver, candidateCall.extensionReceiver,
candidateCall.explicitReceiverKind.isExtensionReceiver, candidateCall.explicitReceiverKind.isExtensionReceiver,
implicitInvokeCheck = false, isDispatchReceiver = false implicitInvokeCheck = false, isDispatchReceiver = false
)) )
)
resultStatus = resultStatus.combine(context.checkReceiver( resultStatus = resultStatus.combine(
context.checkReceiver(
candidateCall, candidateCall,
candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver, candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver,
candidateCall.explicitReceiverKind.isDispatchReceiver, 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 // 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, implicitInvokeCheck = context.call is CallForImplicitInvoke,
isDispatchReceiver = true isDispatchReceiver = true
)) )
)
if (!context.isDebuggerContext if (!context.isDebuggerContext
&& candidateCall.dispatchReceiver != null && candidateCall.dispatchReceiver != null
@@ -486,7 +485,9 @@ class CandidateResolver(
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) { && context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
resultStatus = resultStatus.combine( resultStatus = resultStatus.combine(
context.checkVisibilityWithDispatchReceiver( context.checkVisibilityWithDispatchReceiver(
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType)) candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType
)
)
} }
return resultStatus return resultStatus
@@ -514,7 +515,8 @@ class CandidateResolver(
if (smartCastSubtypingResult == null) { if (smartCastSubtypingResult == null) {
tracing.wrongReceiverType( tracing.wrongReceiverType(
trace, receiverParameter, receiverArgument, trace, receiverParameter, receiverArgument,
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))) this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))
)
return OTHER_ERROR return OTHER_ERROR
} }
@@ -547,8 +549,7 @@ class CandidateResolver(
if (dataFlowValue.immanentNullability.canBeNonNull()) { if (dataFlowValue.immanentNullability.canBeNonNull()) {
expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) } 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 // Look if smart cast has some useful nullability info
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast( val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
@@ -561,12 +562,10 @@ class CandidateResolver(
if (notNullReceiverExpected) { if (notNullReceiverExpected) {
reportUnsafeCall = true reportUnsafeCall = true
} }
} } else {
else {
if (isDispatchReceiver) { if (isDispatchReceiver) {
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType) candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
} } else {
else {
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType) candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
} }
if (!smartCastResult.isCorrect) { if (!smartCastResult.isCorrect) {
@@ -627,7 +626,11 @@ class CandidateResolver(
// can't happen in single-step expansion // 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 // can't happen in single-step expansion
} }
@@ -639,14 +642,18 @@ class CandidateResolver(
// can't happen in single-step expansion // 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 descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor
val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument] val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument]
val argumentTypeReferenceElement = argumentElement?.typeReference val argumentTypeReferenceElement = argumentElement?.typeReference
if (argumentTypeReferenceElement != null) { if (argumentTypeReferenceElement != null) {
trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument)) trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument))
} } else {
else {
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(callElement, bound, argument, typeParameter)) trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(callElement, bound, argument, typeParameter))
} }
} }
@@ -695,9 +702,20 @@ class CandidateResolver(
val typeParameter = typeParameters[i] val typeParameter = typeParameters[i]
val substitutedTypeArgument = substitutedTypeProjection.type val substitutedTypeArgument = substitutedTypeProjection.type
val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].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
)
} }
} }
@@ -53,7 +53,10 @@ class DiagnosticReporterByTrackingStrategy(
override fun onCall(diagnostic: KotlinCallDiagnostic) { override fun onCall(diagnostic: KotlinCallDiagnostic) {
when (diagnostic.javaClass) { when (diagnostic.javaClass) {
VisibilityError::class.java -> tracingStrategy.invisibleMember(trace, (diagnostic as VisibilityError).invisibleMember) 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) InstantiationOfAbstractClass::class.java -> tracingStrategy.instantiationOfAbstractClass(trace)
AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace) AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace)
} }
@@ -123,8 +126,8 @@ class DiagnosticReporterByTrackingStrategy(
} }
override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) { override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression ?: val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression
error("Argument name should be not null for argument: $callArgument") ?: error("Argument name should be not null for argument: $callArgument")
when (diagnostic.javaClass) { when (diagnostic.javaClass) {
NamedArgumentReference::class.java -> { NamedArgumentReference::class.java -> {
trace.record(BindingContext.REFERENCE_TARGET, nameReference, (diagnostic as NamedArgumentReference).parameterDescriptor) 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)) NameForAmbiguousParameter::class.java -> trace.report(NAME_FOR_AMBIGUOUS_PARAMETER.on(nameReference))
NameNotFound::class.java -> trace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference, 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, nameReference,
if ((diagnostic as NamedArgumentNotAllowed).descriptor is FunctionInvokeDescriptor) INVOKE_ON_FUNCTION_TYPE else NON_KOTLIN_FUNCTION 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)) ArgumentPassedTwice::class.java -> trace.report(ARGUMENT_PASSED_TWICE.on(nameReference))
} }
} }
@@ -156,11 +161,15 @@ class DiagnosticReporterByTrackingStrategy(
is ExpressionKotlinCallArgumentImpl -> { is ExpressionKotlinCallArgumentImpl -> {
trace.markAsReported() trace.markAsReported()
val context = context.replaceDataFlowInfo(expressionArgument.dataFlowInfoBeforeThisArgument) 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) val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast( SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call, dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
recordExpressionType = true) recordExpressionType = true
)
} }
is ReceiverExpressionKotlinCallArgument -> { is ReceiverExpressionKotlinCallArgument -> {
trace.markAsReported() trace.markAsReported()
@@ -168,11 +177,13 @@ class DiagnosticReporterByTrackingStrategy(
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context) val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast( SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call, dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
recordExpressionType = true) recordExpressionType = true
)
} }
else -> null 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 != null && smartCastResult != null) {
if (resolvedCall.extensionReceiver == expressionArgument.receiver.receiverValue) { if (resolvedCall.extensionReceiver == expressionArgument.receiver.receiverValue) {
resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType) resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
@@ -218,7 +229,12 @@ class DiagnosticReporterByTrackingStrategy(
val capturedError = diagnostic as CapturedTypeFromSubtyping val capturedError = diagnostic as CapturedTypeFromSubtyping
(capturedError.position as? ArgumentConstraintPosition)?.let { (capturedError.position as? ArgumentConstraintPosition)?.let {
val expression = it.argument.psiExpression ?: return 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}"
)
)
} }
} }
} }
@@ -185,8 +185,7 @@ class GenericCandidateResolver(
val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) { val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) {
if (possibleQualifiedExpression.selectorExpression != callExpression) return null if (possibleQualifiedExpression.selectorExpression != callExpression) return null
possibleQualifiedExpression possibleQualifiedExpression
} } else {
else {
callExpression callExpression
} }
@@ -268,7 +267,8 @@ class GenericCandidateResolver(
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return 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 if (argumentExpression is KtCallableReferenceExpression && type == null) return
@@ -345,7 +345,8 @@ class GenericCandidateResolver(
// to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument` // to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument`
val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) { val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) {
CallCandidateResolutionContext.create( 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 { } else {
context context
} }
@@ -356,8 +357,10 @@ class GenericCandidateResolver(
for (valueArgument in resolvedValueArgument.arguments) { for (valueArgument in resolvedValueArgument.arguments) {
valueArgument.getArgumentExpression()?.let { argumentExpression -> valueArgument.getArgumentExpression()?.let { argumentExpression ->
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral -> ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral ->
addConstraintForFunctionLiteralArgument(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext, addConstraintForFunctionLiteralArgument(
resolvedCall.candidateDescriptor.returnType) functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
resolvedCall.candidateDescriptor.returnType
)
} }
// as inference for callable references depends on expected type, // as inference for callable references depends on expected type,
@@ -367,10 +370,10 @@ class GenericCandidateResolver(
// For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression) // 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) { val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
newContext newContext
} } else {
else {
val temporaryBindingTrace = TemporaryBindingTrace.create( 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) newContext.replaceBindingTrace(temporaryBindingTrace)
} }
@@ -380,7 +383,8 @@ class GenericCandidateResolver(
valueArgument, valueArgument,
valueParameterDescriptor, valueParameterDescriptor,
constraintSystem, constraintSystem,
temporaryContextForCall) temporaryContextForCall
)
} }
} }
} }
@@ -446,17 +450,20 @@ class GenericCandidateResolver(
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
if (hasExpectedReturnType) { if (hasExpectedReturnType) {
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create( 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 statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return
val mismatch = BooleanArray(1) val mismatch = BooleanArray(1)
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch( val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch) temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch
)
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType) val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache) .replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
.replaceContextDependency(INDEPENDENT) .replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo( val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS
).type
if (!mismatch[0]) { if (!mismatch[0]) {
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position) constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
temporaryToResolveFunctionLiteral.commit() temporaryToResolveFunctionLiteral.commit()
@@ -467,7 +474,9 @@ class GenericCandidateResolver(
val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType) val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType)
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument) val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
.replaceContextDependency(INDEPENDENT) .replaceContextDependency(INDEPENDENT)
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type val type =
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
.type
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position) constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
} }
@@ -515,7 +524,8 @@ class GenericCandidateResolver(
valueArgument: ValueArgument valueArgument: ValueArgument
): KotlinType? { ): KotlinType? {
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument) 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 val newContext = context
.replaceExpectedType(expectedTypeWithoutReturnType) .replaceExpectedType(expectedTypeWithoutReturnType)
.replaceDataFlowInfo(dataFlowInfoForArgument) .replaceDataFlowInfo(dataFlowInfoForArgument)
@@ -32,11 +32,16 @@ class CallableReferenceCompatibilityChecker : CallChecker {
for ((_, resolvedArgument) in resolvedCall.valueArguments) { for ((_, resolvedArgument) in resolvedCall.valueArguments) {
inner@ for (argument in resolvedArgument.arguments) { inner@ for (argument in resolvedArgument.arguments) {
val argumentExpression = argument.getArgumentExpression() as? KtCallableReferenceExpression ?: continue@inner 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() && if (callableReferenceResolvedCall.call.isCallableReference() &&
callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) { callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) {
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression, context.trace.report(
typeInferenceForCallableReferencesFeature to context.languageVersionSettings)) Errors.UNSUPPORTED_FEATURE.on(
argumentExpression,
typeInferenceForCallableReferencesFeature to context.languageVersionSettings
)
)
} }
} }
} }
@@ -58,8 +58,7 @@ object DeprecatedCallChecker : CallChecker {
for (deprecation in deprecations) { for (deprecation in deprecations) {
trace.report(createDeprecationDiagnostic(element, deprecation, languageVersionSettings)) 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) } targetDescriptor.getter?.let { check(it, trace, element, languageVersionSettings, deprecationResolver) }
} }
} }
@@ -49,9 +49,11 @@ class OperatorCallChecker : CallChecker {
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) { call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
val outerCall = call.outerCall val outerCall = call.outerCall
if (isConventionCall(outerCall) || isWrongCallWithExplicitTypeArguments(resolvedCall, outerCall)) { if (isConventionCall(outerCall) || isWrongCallWithExplicitTypeArguments(resolvedCall, outerCall)) {
throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. " + throw AssertionError(
"Illegal resolved call to variable with invoke for $outerCall. " +
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" + "Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}") "Invoke: ${resolvedCall.functionCall.resultingDescriptor}"
)
} }
} }
@@ -117,8 +119,7 @@ private fun checkModConvention(
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) { if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier) addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
} }
} } else {
else {
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) { if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier) addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
} }
@@ -67,19 +67,32 @@ object CoroutineSuspendCallChecker : CallChecker {
if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) { if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) {
context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn)) 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.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) checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
} }
else -> { else -> {
when (descriptor) { when (descriptor) {
is FunctionDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn, resolvedCall.candidateDescriptor)) is FunctionDescriptor -> context.trace.report(
is PropertyDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(reportOn, resolvedCall.candidateDescriptor)) Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(
reportOn,
resolvedCall.candidateDescriptor
)
)
is PropertyDescriptor -> context.trace.report(
Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(
reportOn,
resolvedCall.candidateDescriptor
)
)
} }
} }
} }
@@ -82,8 +82,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
typeParameters.map { typeParameters.map {
TypeVariable(call, it, it, true) TypeVariable(call, it, it, true)
} }
} } else {
else {
val freshTypeParameters = ArrayList<TypeParameterDescriptor>(typeParameters.size) val freshTypeParameters = ArrayList<TypeParameterDescriptor>(typeParameters.size)
DescriptorSubstitutor.substituteTypeParameters( DescriptorSubstitutor.substituteTypeParameters(
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
@@ -106,20 +105,29 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
} }
} }
return storeSubstitutor(call, TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap( return storeSubstitutor(
call, TypeSubstitutor.create(
TypeConstructorSubstitution.createByParametersMap(
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap() typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
))) )
)
)
} }
private fun KotlinType.isProper() = !TypeUtils.contains(this) { private fun KotlinType.isProper() = !TypeUtils.contains(this) { type ->
type -> type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) } type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
} }
internal fun getNestedTypeVariables(type: KotlinType): List<TypeVariable> = 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) { 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( fun addConstraint(
@@ -131,8 +139,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
val constraintPosition = constraintContext.position val constraintPosition = constraintContext.position
// when processing nested constraints, `derivedFrom` information should be reset // when processing nested constraints, `derivedFrom` information should be reset
val newConstraintContext = ConstraintContext(constraintContext.position, derivedFrom = null, initial = false, val newConstraintContext = ConstraintContext(
initialReduction = constraintContext.initialReduction) constraintContext.position, derivedFrom = null, initial = false,
initialReduction = constraintContext.initialReduction
)
val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks { val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks {
private var depth = 0 private var depth = 0
@@ -212,8 +222,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
return return
} }
createTypeForFunctionPlaceholder(subType, superType) createTypeForFunctionPlaceholder(subType, superType)
} } else {
else {
subType subType
} }
@@ -230,8 +239,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
val superType2 = simplifyType(superType, constraintContext.initial) val superType2 = simplifyType(superType, constraintContext.initial)
val result = if (constraintKind == EQUAL) { val result = if (constraintKind == EQUAL) {
typeCheckingProcedure.equalTypes(subType2, superType2) typeCheckingProcedure.equalTypes(subType2, superType2)
} } else {
else {
typeCheckingProcedure.isSubtypeOf(subType2, superType) typeCheckingProcedure.isSubtypeOf(subType2, superType)
} }
if (!result) errors.add(newTypeInferenceOrParameterConstraintError(constraintPosition)) if (!result) errors.add(newTypeInferenceOrParameterConstraintError(constraintPosition))
@@ -259,8 +267,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
kind: TypeBounds.BoundKind, kind: TypeBounds.BoundKind,
constraintContext: ConstraintContext constraintContext: ConstraintContext
) { ) {
val bound = Bound(typeVariable, constrainingType, kind, constraintContext.position, val bound = Bound(
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet()) typeVariable, constrainingType, kind, constraintContext.position,
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet()
)
val typeBounds = getTypeBounds(typeVariable) val typeBounds = getTypeBounds(typeVariable)
if (typeBounds.bounds.contains(bound)) return if (typeBounds.bounds.contains(bound)) return
@@ -332,8 +342,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
} }
val typeProjection = if (isTypeMarkedNullable) { val typeProjection = if (isTypeMarkedNullable) {
TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type)) TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type))
} } else {
else {
constrainingTypeProjection constrainingTypeProjection
} }
val capturedType = createCapturedType(typeProjection) val capturedType = createCapturedType(typeProjection)
@@ -341,8 +350,8 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
} }
internal fun getTypeBounds(variable: TypeVariable): TypeBoundsImpl { internal fun getTypeBounds(variable: TypeVariable): TypeBoundsImpl {
return allTypeParameterBounds[variable] ?: return allTypeParameterBounds[variable]
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable") ?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
} }
private fun isMyTypeVariable(typeParameter: TypeParameterDescriptor) = private fun isMyTypeVariable(typeParameter: TypeParameterDescriptor) =
@@ -358,7 +367,12 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
private fun getMyTypeVariable(typeParameter: TypeParameterDescriptor): TypeVariable? = 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)) initialConstraints.add(Constraint(constraintKind, subType, superType, position))
} }
@@ -445,11 +459,12 @@ internal fun createTypeForFunctionPlaceholder(
val result = arrayListOf<KotlinType>() val result = arrayListOf<KotlinType>()
(1..functionArgumentsSize).forEach { result.add(DONT_CARE) } (1..functionArgumentsSize).forEach { result.add(DONT_CARE) }
result result
} } else {
else {
functionPlaceholderTypeConstructor.argumentTypes functionPlaceholderTypeConstructor.argumentTypes
} }
val receiverType = if (isExtension) DONT_CARE else null val receiverType = if (isExtension) DONT_CARE else null
return createFunctionType(functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE, return createFunctionType(
suspendFunction = expectedType.isSuspendFunctionType) functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
suspendFunction = expectedType.isSuspendFunctionType
)
} }
@@ -130,8 +130,8 @@ internal class ConstraintSystemImpl(
get() = allTypeParameterBounds.keys get() = allTypeParameterBounds.keys
override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl { override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl {
return allTypeParameterBounds[typeVariable] ?: return allTypeParameterBounds[typeVariable]
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable") ?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
} }
override val resultingSubstitutor: TypeSubstitutor override val resultingSubstitutor: TypeSubstitutor
@@ -159,8 +159,7 @@ internal class ConstraintSystemImpl(
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) } val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT) fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
return initialConstraints.all { return initialConstraints.all { (kind, subtype, superType, position) ->
(kind, subtype, superType, position) ->
val resultSubType = subtype.substitute()?.let { val resultSubType = subtype.substitute()?.let {
// the call might be done via safe access, so we check for notNullable receiver type; // the call might be done via safe access, so we check for notNullable receiver type;
// 'unsafe call' error is reported otherwise later // 'unsafe call' error is reported otherwise later
@@ -155,13 +155,16 @@ class CoroutineInferenceSupport(
val approximationSubstitutor = object : DelegatedTypeSubstitution(constraintSystem.currentSubstitutor.substitution) { val approximationSubstitutor = object : DelegatedTypeSubstitution(constraintSystem.currentSubstitutor.substitution) {
override fun approximateContravariantCapturedTypes() = true 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, val newExpectedType = createFunctionType(
newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType,
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType), approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
parameterNames = null, // TODO: parameterNames parameterNames = null, // TODO: parameterNames
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(), returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
suspendFunction = true) suspendFunction = true
)
if (hasUnknownFunctionParameter(newExpectedType)) return if (hasUnknownFunctionParameter(newExpectedType)) return
@@ -169,7 +172,8 @@ class CoroutineInferenceSupport(
// this trace shouldn't be committed // this trace shouldn't be committed
val temporaryForCoroutine = TemporaryTraceAndCache.create( 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) val newContext = context.replaceExpectedType(newExpectedType)
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)) .replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
@@ -197,8 +201,7 @@ class CoroutineInferenceSupport(
inferenceData.badCallHappened() inferenceData.badCallHappened()
} }
forceInferenceForArguments(context) { forceInferenceForArguments(context) { valueArgument: ValueArgument, kotlinType: KotlinType ->
valueArgument: ValueArgument, kotlinType: KotlinType ->
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch
?: return@forceInferenceForArguments ?: return@forceInferenceForArguments
@@ -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 infoForArguments = context.dataFlowInfoForArguments
val call = context.call val call = context.call
val baseContext = context.replaceContextDependency(ContextDependency.INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE) val baseContext = context.replaceContextDependency(ContextDependency.INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)
@@ -36,7 +36,8 @@ data class ConstraintContext(
// see TypeBounds.Bound.derivedFrom // see TypeBounds.Bound.derivedFrom
val derivedFrom: Set<TypeVariable>? = null, val derivedFrom: Set<TypeVariable>? = null,
val initial: Boolean = false, val initial: Boolean = false,
val initialReduction: Boolean = false) val initialReduction: Boolean = false
)
fun ConstraintSystemBuilderImpl.incorporateBound(newBound: Bound) { fun ConstraintSystemBuilderImpl.incorporateBound(newBound: Bound) {
val typeVariable = newBound.typeVariable val typeVariable = newBound.typeVariable
@@ -64,5 +64,4 @@ class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor):
} }
//TODO: temporary hack until status.isSuccess is not always correct //TODO: temporary hack until status.isSuccess is not always correct
fun ResolvedCall<*>.isReallySuccess(): Boolean fun ResolvedCall<*>.isReallySuccess(): Boolean = status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
= status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
@@ -28,9 +28,11 @@ private val KotlinType.immanentNullability: Nullability
* This class describes an arbitrary object which has some value in data flow analysis. * This class describes an arbitrary object which has some value in data flow analysis.
* In general case it's some r-value. * In general case it's some r-value.
*/ */
class DataFlowValue(val identifierInfo: IdentifierInfo, class DataFlowValue(
val identifierInfo: IdentifierInfo,
val type: KotlinType, val type: KotlinType,
val immanentNullability: Nullability = type.immanentNullability) { val immanentNullability: Nullability = type.immanentNullability
) {
val kind: Kind get() = identifierInfo.kind val kind: Kind get() = identifierInfo.kind
@@ -82,8 +82,7 @@ internal class DelegatingDataFlowInfo private constructor(
private fun getNullability(key: DataFlowValue, stableOnly: Boolean) = private fun getNullability(key: DataFlowValue, stableOnly: Boolean) =
if (stableOnly && !key.isStable) { if (stableOnly && !key.isStable) {
key.immanentNullability key.immanentNullability
} } else {
else {
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
} }
@@ -110,8 +109,10 @@ internal class DelegatingDataFlowInfo private constructor(
val receiverType = identifierInfo.receiverType val receiverType = identifierInfo.receiverType
if (identifierInfo.safe && receiverType != null) { if (identifierInfo.safe && receiverType != null) {
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType) val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
putNullabilityAndTypeInfo(map, receiverValue, nullability, putNullabilityAndTypeInfo(
languageVersionSettings, typeInfo, recordUnstable = recordUnstable) map, receiverValue, nullability,
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
)
} }
} }
is IdentifierInfo.SafeCast -> { is IdentifierInfo.SafeCast -> {
@@ -121,16 +122,20 @@ internal class DelegatingDataFlowInfo private constructor(
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) { languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType) val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
putNullabilityAndTypeInfo(map, subjectValue, nullability, putNullabilityAndTypeInfo(
languageVersionSettings, typeInfo, recordUnstable = false) map, subjectValue, nullability,
languageVersionSettings, typeInfo, recordUnstable = false
)
if (subjectValue.isStable) { if (subjectValue.isStable) {
typeInfo?.put(subjectValue, targetType) typeInfo?.put(subjectValue, targetType)
} }
} }
} }
is IdentifierInfo.Variable -> identifierInfo.bound?.let { is IdentifierInfo.Variable -> identifierInfo.bound?.let {
putNullabilityAndTypeInfo(map, it, nullability, putNullabilityAndTypeInfo(
languageVersionSettings, typeInfo, recordUnstable = recordUnstable) map, it, nullability,
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
)
} }
} }
} }
@@ -182,6 +187,7 @@ internal class DelegatingDataFlowInfo private constructor(
else else
TypeUtils.makeNotNullable(this) TypeUtils.makeNotNullable(this)
} }
/** /**
* Call this function to clear all data flow information about * Call this function to clear all data flow information about
* the given data flow value. * the given data flow value.
@@ -222,8 +228,20 @@ internal class DelegatingDataFlowInfo private constructor(
val newTypeInfo = newTypeInfo() val newTypeInfo = newTypeInfo()
var changed = var changed =
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB), languageVersionSettings, newTypeInfo) or putNullabilityAndTypeInfo(
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA), languageVersionSettings, newTypeInfo) 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 // NB: == has no guarantees of type equality, see KT-11280 for the example
if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) { if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) {
@@ -252,8 +270,7 @@ internal class DelegatingDataFlowInfo private constructor(
if (current is DelegatingDataFlowInfo) { if (current is DelegatingDataFlowInfo) {
types.addAll(current.typeInfo.get(value)) types.addAll(current.typeInfo.get(value))
current = if (value == current.valueWithGivenTypeInfo) null else current.parent current = if (value == current.valueWithGivenTypeInfo) null else current.parent
} } else {
else {
types.addAll(current.getCollectedTypes(value, languageVersionSettings)) types.addAll(current.getCollectedTypes(value, languageVersionSettings))
break break
} }
@@ -271,8 +288,20 @@ internal class DelegatingDataFlowInfo private constructor(
val newTypeInfo = newTypeInfo() val newTypeInfo = newTypeInfo()
val changed = val changed =
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB.invert()), languageVersionSettings, newTypeInfo) or putNullabilityAndTypeInfo(
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA.invert()), languageVersionSettings, newTypeInfo) 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 return if (changed) create(this, resultNullabilityInfo, if (newTypeInfo.isEmpty) EMPTY_TYPE_INFO else newTypeInfo) else this
@@ -362,7 +391,8 @@ internal class DelegatingDataFlowInfo private constructor(
fun newTypeInfo(): SetMultimap<DataFlowValue, KotlinType> = LinkedHashMultimap.create<DataFlowValue, KotlinType>() fun newTypeInfo(): SetMultimap<DataFlowValue, KotlinType> = LinkedHashMultimap.create<DataFlowValue, KotlinType>()
private fun create(parent: DataFlowInfo?, private fun create(
parent: DataFlowInfo?,
nullabilityInfo: Map<DataFlowValue, Nullability>, nullabilityInfo: Map<DataFlowValue, Nullability>,
// NB: typeInfo must be mutable here! // NB: typeInfo must be mutable here!
typeInfo: SetMultimap<DataFlowValue, KotlinType>, typeInfo: SetMultimap<DataFlowValue, KotlinType>,
@@ -81,8 +81,7 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> { override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
return if (call.valueArgumentList == null && call.valueArguments.isEmpty()) { return if (call.valueArgumentList == null && call.valueArguments.isEmpty()) {
listOf(createDynamicProperty(owner, name, call)) listOf(createDynamicProperty(owner, name, call))
} } else listOf()
else listOf()
} }
} }
@@ -144,8 +143,8 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
return ReceiverParameterDescriptorImpl(owner, TransientReceiver(dynamicType)) return ReceiverParameterDescriptorImpl(owner, TransientReceiver(dynamicType))
} }
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> = call.typeArguments.indices.map { private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> =
index call.typeArguments.indices.map { index
-> ->
TypeParameterDescriptorImpl.createWithDefaultBound( TypeParameterDescriptorImpl.createWithDefaultBound(
owner, owner,
@@ -163,7 +162,8 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
fun addParameter(arg: ValueArgument, outType: KotlinType, varargElementType: KotlinType?) { fun addParameter(arg: ValueArgument, outType: KotlinType, varargElementType: KotlinType?) {
val index = parameters.size val index = parameters.size
parameters.add(ValueParameterDescriptorImpl( parameters.add(
ValueParameterDescriptorImpl(
owner, owner,
null, null,
index, index,
@@ -175,7 +175,8 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
/* isNoinline = */ false, /* isNoinline = */ false,
varargElementType, varargElementType,
SourceElement.NO_SOURCE SourceElement.NO_SOURCE
)) )
)
} }
fun getFunctionType(funLiteralExpr: KtLambdaExpression): KotlinType { fun getFunctionType(funLiteralExpr: KtLambdaExpression): KotlinType {
@@ -85,19 +85,26 @@ class KotlinResolutionCallbacksImpl(
val outerCallContext = psiCallArgument.outerCallContext val outerCallContext = psiCallArgument.outerCallContext
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) = fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor, createSimplePSICallArgument(
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings) trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings
)
val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE, val lambdaInfo = LambdaInfo(
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT) expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT
)
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo) trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null, val expectedType = createFunctionType(
lambdaInfo.expectedType, isSuspend) 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 val actualContext = outerCallContext
.replaceBindingTrace(trace) .replaceBindingTrace(trace)
@@ -116,8 +123,7 @@ class KotlinResolutionCallbacksImpl(
returnedExpression, returnedExpression,
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression") typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
) )
} } else {
else {
hasReturnWithoutExpression = true hasReturnWithoutExpression = true
EmptyLabeledReturn(expression, builtIns) EmptyLabeledReturn(expression, builtIns)
} }
@@ -141,8 +147,7 @@ class KotlinResolutionCallbacksImpl(
val lastExpression: KtExpression? val lastExpression: KtExpression?
if (psiCallArgument is LambdaKotlinCallArgumentImpl) { if (psiCallArgument is LambdaKotlinCallArgumentImpl) {
lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull() lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull()
} } else {
else {
lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis() lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis()
} }
@@ -86,7 +86,13 @@ class NewResolutionOldInference(
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
): ScopeTowerProcessor<MyCandidate> { ): ScopeTowerProcessor<MyCandidate> {
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing) 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
)
} }
} }
@@ -125,7 +131,12 @@ class NewResolutionOldInference(
"Call should be CallForImplicitInvoke, but it is: ${context.call}" "Call should be CallForImplicitInvoke, but it is: ${context.call}"
} }
return createProcessorWithReceiverValueOrEmpty(explicitReceiver) { return createProcessorWithReceiverValueOrEmpty(explicitReceiver) {
createCallTowerProcessorForExplicitInvoke(scopeTower, functionFactory, context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver), it) createCallTowerProcessorForExplicitInvoke(
scopeTower,
functionFactory,
context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver),
it
)
} }
} }
@@ -150,8 +161,7 @@ class NewResolutionOldInference(
val explicitReceiver = context.call.explicitReceiver val explicitReceiver = context.call.explicitReceiver
val detailedReceiver = if (explicitReceiver is QualifierReceiver?) { val detailedReceiver = if (explicitReceiver is QualifierReceiver?) {
explicitReceiver explicitReceiver
} } else {
else {
context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue) context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue)
} }
@@ -171,15 +181,22 @@ class NewResolutionOldInference(
return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor, nameToResolve)) 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 // Temporary hack to resolve 'rem' as 'mod' if the first is do not present
val emptyOrInapplicableCandidates = candidates.isEmpty() || val emptyOrInapplicableCandidates = candidates.isEmpty() ||
candidates.all { it.resultingApplicability.isInapplicable } candidates.all { it.resultingApplicability.isInapplicable }
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) { if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name] val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context) val processorForDeprecatedName =
candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference, name = deprecatedName) kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
candidates = towerResolver.runResolve(
scopeTower,
processorForDeprecatedName,
useOrder = kind != ResolutionKind.CallableReference,
name = deprecatedName
)
} }
if (candidates.isEmpty()) { if (candidates.isEmpty()) {
@@ -219,19 +236,23 @@ class NewResolutionOldInference(
} }
} }
if (basicCallContext.collectAllCandidates) { if (basicCallContext.collectAllCandidates) {
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), val allCandidates = towerResolver.runWithEmptyTowerData(
TowerResolver.AllCandidatesCollector(), useOrder = false) KnownResultProcessor(resolvedCandidates),
TowerResolver.AllCandidatesCollector(), useOrder = false
)
return allCandidatesResult(allCandidates) return allCandidatesResult(allCandidates)
} }
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates), val processedCandidates = towerResolver.runWithEmptyTowerData(
TowerResolver.SuccessfulResultCollector(), useOrder = true) KnownResultProcessor(resolvedCandidates),
TowerResolver.SuccessfulResultCollector(), useOrder = true
)
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings) return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
} }
private fun <D: CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>) private fun <D : CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>) =
= OverloadResolutionResultsImpl.nameNotFound<D>().apply { OverloadResolutionResultsImpl.nameNotFound<D>().apply {
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> } this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
} }
@@ -260,8 +281,17 @@ class NewResolutionOldInference(
if (resolvedCall.status.possibleTransformToSuccess()) { if (resolvedCall.status.possibleTransformToSuccess()) {
for (error in diagnostics) { for (error in diagnostics) {
when (error) { when (error) {
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message)) is UnsupportedInnerClassCall -> resolvedCall.trace.report(
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind) Errors.UNSUPPORTED.on(
resolvedCall.call.callElement,
error.message
)
)
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(
resolvedCall.trace,
error.classDescriptor,
resolvedCall.explicitReceiverKind
)
is ErrorDescriptorDiagnostic -> { is ErrorDescriptorDiagnostic -> {
// todo // todo
// return@map null // return@map null
@@ -445,7 +475,11 @@ class NewResolutionOldInference(
val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let { val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let {
if (stripExplicitReceiver) CallTransformer.stripReceiver(it) else it 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( override fun factoryForInvoke(
@@ -467,15 +501,18 @@ class NewResolutionOldInference(
return null // todo: create special check that there is no invoke on variable return null // todo: create special check that there is no invoke on variable
} }
val basicCallContext = functionContext.basicCallContext val basicCallContext = functionContext.basicCallContext
val variableReceiver = ExpressionReceiver.create(calleeExpression!!, val variableReceiver = ExpressionReceiver.create(
calleeExpression!!,
variableType, variableType,
basicCallContext.trace.bindingContext) basicCallContext.trace.bindingContext
)
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression // used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall) functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
// todo hacks // todo hacks
val functionCall = CallTransformer.CallForImplicitInvoke( val functionCall = CallTransformer.CallForImplicitInvoke(
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver }, basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
variableReceiver, basicCallContext.call, true) variableReceiver, basicCallContext.call, true
)
val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type) val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type)
val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace) val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace)
.replaceCall(functionCall) .replaceCall(functionCall)
@@ -93,7 +93,8 @@ class PSICallResolver(
val expectedType = calculateExpectedType(context) val expectedType = calculateExpectedType(context)
var result = kotlinCallResolver.resolveCall( var result = kotlinCallResolver.resolveCall(
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates) scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates
)
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) { if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
@@ -115,18 +116,22 @@ class PSICallResolver(
): OverloadResolutionResults<D> { ): OverloadResolutionResults<D> {
val dispatchReceiver = resolutionCandidates.firstNotNullResult { it.dispatchReceiver } 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 scopeTower = ASTScopeTower(context)
val resolutionCallbacks = createResolutionCallbacks(context) val resolutionCallbacks = createResolutionCallbacks(context)
val givenCandidates = resolutionCandidates.map { val givenCandidates = resolutionCandidates.map {
GivenCandidate(it.descriptor as FunctionDescriptor, GivenCandidate(
it.descriptor as FunctionDescriptor,
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) }, it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
it.knownTypeParametersResultingSubstitutor) it.knownTypeParametersResultingSubstitutor
)
} }
val result = kotlinCallResolver.resolveGivenCandidates( 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) return convertToOverloadResolutionResults(context, result, tracingStrategy)
} }
@@ -143,8 +148,10 @@ class PSICallResolver(
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy) val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName) val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType, return kotlinCallResolver.resolveCall(
refinedProviderForInvokeFactory, context.collectAllCandidates) scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
refinedProviderForInvokeFactory, context.collectAllCandidates
)
} }
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name { private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
@@ -153,9 +160,11 @@ class PSICallResolver(
} }
private fun createResolutionCallbacks(context: BasicCallResolutionContext) = private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, KotlinResolutionCallbacksImpl(
context, expressionTypingServices, typeApproximator,
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer, argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
constantExpressionEvaluator) constantExpressionEvaluator
)
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? { private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
val expectedType = context.expectedType.unwrap() val expectedType = context.expectedType.unwrap()
@@ -165,8 +174,7 @@ class PSICallResolver(
"Should have no expected type, got: $expectedType" "Should have no expected type, got: $expectedType"
} }
null null
} } else {
else {
if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType
} }
} }
@@ -197,28 +205,26 @@ class PSICallResolver(
if (it.candidates.areAllFailed()) { if (it.candidates.areAllFailed()) {
tracingStrategy.noneApplicable(trace, resolvedCalls) tracingStrategy.noneApplicable(trace, resolvedCalls)
tracingStrategy.recordAmbiguity(trace, resolvedCalls) tracingStrategy.recordAmbiguity(trace, resolvedCalls)
} } else {
else {
tracingStrategy.recordAmbiguity(trace, resolvedCalls) tracingStrategy.recordAmbiguity(trace, resolvedCalls)
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) { if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls) tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
} } else {
else {
tracingStrategy.ambiguity(trace, resolvedCalls) tracingStrategy.ambiguity(trace, resolvedCalls)
} }
} }
return ManyCandidates(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 resolvedCall = if (isInapplicableReceiver) {
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result") val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also { kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also {
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it)) tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
} }
} } else {
else {
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context) kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
} }
@@ -285,7 +291,14 @@ class PSICallResolver(
for (candidate in errorCandidates) { for (candidate in errorCandidates) {
if (candidate is ErrorCandidate.Classifier) { if (candidate is ErrorCandidate.Classifier) {
context.trace.record(BindingContext.REFERENCE_TARGET, reference, candidate.descriptor) 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 return true
} }
} }
@@ -297,7 +310,8 @@ class PSICallResolver(
val context: BasicCallResolutionContext val context: BasicCallResolutionContext
) : ImplicitScopeTower { ) : ImplicitScopeTower {
// todo may be for invoke for case variable + invoke we should create separate dynamicScope(by newCall for invoke) // 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 // same for location
override val location: LookupLocation = context.call.createLookupLocation() override val location: LookupLocation = context.call.createLookupLocation()
@@ -350,8 +364,7 @@ class PSICallResolver(
val explicitReceiver = kotlinCall.explicitReceiver val explicitReceiver = kotlinCall.explicitReceiver
val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) { val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) {
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument) PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
} } else {
else {
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null) PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
} }
@@ -369,22 +382,32 @@ class PSICallResolver(
variable.forceResolution() variable.forceResolution()
val variableReceiver = createReceiverValueWithSmartCastInfo(variable) val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
if (variableReceiver.possibleTypes.isNotEmpty()) { if (variableReceiver.possibleTypes.isNotEmpty()) {
return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true) return ReceiverExpressionKotlinCallArgument(
createReceiverValueWithSmartCastInfo(variable),
isVariableReceiverForInvoke = true
)
} }
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage()) val variableResult = CallResolutionResult(
return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression), CallResolutionResult.Type.PARTIAL,
variable.resolvedCall,
listOf(),
variable.getSystem().asReadOnlyStorage()
)
return SubKotlinCallArgumentImpl(
CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver, psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
variableResult) variableResult
)
} }
// todo: decrease hacks count // todo: decrease hacks count
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo { private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?: val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression
error("Unexpected call : ${callForVariable.baseCall.psiCall}") ?: error("Unexpected call : ${callForVariable.baseCall.psiCall}")
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate") val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
@@ -392,7 +415,8 @@ class PSICallResolver(
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext) val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor) 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( return ReceiverValueWithSmartCastInfo(
variableReceiver, variableReceiver,
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings), context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
@@ -410,13 +434,13 @@ class PSICallResolver(
tracingStrategy: TracingStrategy, tracingStrategy: TracingStrategy,
forcedExplicitReceiver: Receiver? = null forcedExplicitReceiver: Receiver? = null
): PSIKotlinCallImpl { ): 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 resolvedTypeArguments = resolveTypeArguments(context, oldCall.typeArguments)
val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) { val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
oldCall.valueArguments oldCall.valueArguments
} } else {
else {
oldCall.valueArguments.dropLast(1) oldCall.valueArguments.dropLast(1)
} }
@@ -428,8 +452,7 @@ class PSICallResolver(
"Unexpected lambda parameters for call $oldCall" "Unexpected lambda parameters for call $oldCall"
} }
oldCall.valueArguments.last() oldCall.valueArguments.last()
} } else {
else {
if (externalLambdaArguments.size > 2) { if (externalLambdaArguments.size > 2) {
externalLambdaArguments.drop(1).forEach { externalLambdaArguments.drop(1).forEach {
context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression())) context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression()))
@@ -451,11 +474,17 @@ class PSICallResolver(
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) } resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis, return PSIKotlinCallImpl(
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments) kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments
)
} }
private fun resolveExplicitReceiver(context: BasicCallResolutionContext, oldReceiver: Receiver?, isSafeCall: Boolean): ReceiverKotlinCallArgument? = private fun resolveExplicitReceiver(
context: BasicCallResolutionContext,
oldReceiver: Receiver?,
isSafeCall: Boolean
): ReceiverKotlinCallArgument? =
when (oldReceiver) { when (oldReceiver) {
null -> null null -> null
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
@@ -474,8 +503,10 @@ class PSICallResolver(
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it) bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
} }
if (onlyResolvedCall != null) { if (onlyResolvedCall != null) {
subCallArgument = SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument(oldReceiver.expression), subCallArgument = SubKotlinCallArgumentImpl(
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall) CallMaker.makeExternalValueArgument(oldReceiver.expression),
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall
)
} }
} }
@@ -500,7 +531,8 @@ class PSICallResolver(
} }
ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings) ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings)
resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) } ?: TypeArgumentPlaceholder resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) }
?: TypeArgumentPlaceholder
} }
private fun resolveArgumentsInParenthesis( private fun resolveArgumentsInParenthesis(
@@ -534,7 +566,8 @@ class PSICallResolver(
if (ktExpression is KtCollectionLiteralExpression) { if (ktExpression is KtCollectionLiteralExpression) {
return CollectionLiteralKotlinCallArgumentImpl( return CollectionLiteralKotlinCallArgumentImpl(
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext) valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext
)
} }
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT) val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
@@ -544,7 +577,10 @@ class PSICallResolver(
checkNoSpread(outerCallContext, valueArgument) checkNoSpread(outerCallContext, valueArgument)
val expressionTypingContext = ExpressionTypingContext.newContext(context) 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 newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo
val name = ktExpression.callableReference.getReferencedNameAsName() val name = ktExpression.callableReference.getReferencedNameAsName()
@@ -556,12 +592,10 @@ class PSICallResolver(
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny() val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) { if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
LHSResult.Object(ClassQualifier(calleeExpression, classifier)) LHSResult.Object(ClassQualifier(calleeExpression, classifier))
} } else {
else {
LHSResult.Error LHSResult.Error
} }
} } else {
else {
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression) val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo) val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
@@ -573,15 +607,16 @@ class PSICallResolver(
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression) val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
if (qualifier is ClassQualifier) { if (qualifier is ClassQualifier) {
LHSResult.Type(qualifier, lhsResult.type.unwrap()) LHSResult.Type(qualifier, lhsResult.type.unwrap())
} } else {
else {
LHSResult.Error LHSResult.Error
} }
} }
} }
return CallableReferenceKotlinCallArgumentImpl(ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo, return CallableReferenceKotlinCallArgumentImpl(
ktExpression, argumentName, lhsNewResult, name) ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
ktExpression, argumentName, lhsNewResult, name
)
} }
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression // argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
@@ -602,17 +637,21 @@ class PSICallResolver(
val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) { val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) {
is KtLambdaExpression -> is KtLambdaExpression ->
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression, LambdaKotlinCallArgumentImpl(
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral)) outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral)
)
is KtNamedFunction -> { is KtNamedFunction -> {
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference) val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference)
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray() val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray()
val returnType = resolveType(outerCallContext, postponedExpression.typeReference) ?: val returnType = resolveType(outerCallContext, postponedExpression.typeReference)
if (postponedExpression.hasBlockBody()) builtIns.unitType else null ?: if (postponedExpression.hasBlockBody()) builtIns.unitType else null
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, FunctionExpressionImpl(
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType) outerCallContext, valueArgument, startDataFlowInfo, argumentName,
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType
)
} }
else -> return null else -> return null
@@ -79,7 +79,12 @@ class ResolvedAtomCompleter(
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection<KotlinCallDiagnostic>): ResolvedCall<*>? { fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection<KotlinCallDiagnostic>): ResolvedCall<*>? {
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null 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.bindAndReport(topLevelCallContext, trace, resolvedCall, diagnostics)
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext) kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
@@ -123,8 +128,8 @@ class ResolvedAtomCompleter(
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument") else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
} }
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?: val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl
throw AssertionError("No function descriptor for resolved lambda argument") ?: throw AssertionError("No function descriptor for resolved lambda argument")
functionDescriptor.setReturnType(returnType) functionDescriptor.setReturnType(returnType)
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument") val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
@@ -139,19 +144,24 @@ class ResolvedAtomCompleter(
// todo report meanfull diagnostic here // todo report meanfull diagnostic here
return 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 psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression 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 // write down type for callable reference expression
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT) val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter, argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
trace, expressionTypingServices.statementFilter,
resultType, resultType,
callableReferenceExpression) callableReferenceExpression
)
val reference = callableReferenceExpression.callableReference val reference = callableReferenceExpression.callableReference
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) { val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
@@ -166,9 +176,11 @@ class ResolvedAtomCompleter(
val tracing = TracingStrategyImpl.create(reference, psiCall) val tracing = TracingStrategyImpl.create(reference, psiCall)
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call") val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue, val resolvedCall = ResolvedCallImpl(
psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind, callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)) null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)
)
resolvedCall.setResultingSubstitutor(resultSubstitutor) resolvedCall.setResultingSubstitutor(resultSubstitutor)
tracing.bindCall(trace, psiCall) tracing.bindCall(trace, psiCall)
@@ -179,22 +191,35 @@ class ResolvedAtomCompleter(
resolvedCall.markCallAsCompleted() resolvedCall.markCallAsCompleted()
when (callableCandidate.candidate) { when (callableCandidate.candidate) {
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext) is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext) callableReferenceExpression,
resultType,
topLevelCallContext
)
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(
callableReferenceExpression,
resultType,
topLevelCallContext
)
} }
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo // TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
trace.recordType(callableReferenceExpression, resultType) trace.recordType(callableReferenceExpression, resultType)
trace.record(BindingContext.PROCESSED, callableReferenceExpression) trace.record(BindingContext.PROCESSED, callableReferenceExpression)
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression) doubleColonExpressionResolver.checkReferenceIsToAllowedMember(
callableCandidate.candidate,
topLevelCallContext.trace,
callableReferenceExpression
)
} }
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) { private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
val context = psiCallArgument.outerCallContext 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 val actualContext = context
.replaceBindingTrace(trace) .replaceBindingTrace(trace)
@@ -49,8 +49,8 @@ fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedParameters(): Boolean {
return !parameterToArgumentMap.keys.containsAll(resultingDescriptor.valueParameters) return !parameterToArgumentMap.keys.containsAll(resultingDescriptor.valueParameters)
} }
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped() fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped() =
= call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch } call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParameter(parameter: ValueParameterDescriptor): Boolean { fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
val resolvedValueArgument = valueArguments[parameter] val resolvedValueArgument = valueArguments[parameter]
@@ -93,8 +93,7 @@ fun KtCallElement.getValueArgumentsInParentheses(): List<ValueArgument> = valueA
fun Call.getValueArgumentListOrElement(): KtElement = fun Call.getValueArgumentListOrElement(): KtElement =
if (this is CallTransformer.CallForImplicitInvoke) { if (this is CallTransformer.CallForImplicitInvoke) {
outerCall.getValueArgumentListOrElement() outerCall.getValueArgumentListOrElement()
} } else {
else {
valueArgumentList ?: calleeExpression ?: callElement valueArgumentList ?: calleeExpression ?: callElement
} }
@@ -111,6 +110,7 @@ fun Call.getValueArgumentForExpression(expression: KtExpression): ValueArgument?
else -> null else -> null
} }
} }
fun KtElement.isParenthesizedExpression() = generateSequence(this) { it.deparenthesizeStructurally() }.any { it == expression } fun KtElement.isParenthesizedExpression() = generateSequence(this) { it.deparenthesizeStructurally() }.any { it == expression }
return valueArguments.firstOrNull { it?.getArgumentExpression()?.isParenthesizedExpression() ?: false } return valueArguments.firstOrNull { it?.getArgumentExpression()?.isParenthesizedExpression() ?: false }
} }
@@ -157,7 +157,8 @@ fun KtElement.getCall(context: BindingContext): Call? {
fun KtElement.getParentCall(context: BindingContext, strict: Boolean = true): Call? { fun KtElement.getParentCall(context: BindingContext, strict: Boolean = true): Call? {
val callExpressionTypes = arrayOf<Class<out KtElement>?>( val callExpressionTypes = arrayOf<Class<out KtElement>?>(
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java, KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java) KtUnaryExpression::class.java, KtArrayAccessExpression::class.java
)
val parent = if (strict) { val parent = if (strict) {
PsiTreeUtil.getParentOfType(this, *callExpressionTypes) PsiTreeUtil.getParentOfType(this, *callExpressionTypes)
@@ -263,5 +264,4 @@ fun ResolvedCall<*>.getFirstArgumentExpression(): KtExpression? =
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() } valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
fun ResolvedCall<*>.getReceiverExpression(): KtExpression? = fun ResolvedCall<*>.getReceiverExpression(): KtExpression? =
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
@@ -47,9 +47,11 @@ object ConstModifierChecker : SimpleDeclarationChecker {
fun canBeConst(declaration: KtDeclaration, constModifierPsiElement: PsiElement, descriptor: VariableDescriptor): Boolean = fun canBeConst(declaration: KtDeclaration, constModifierPsiElement: PsiElement, descriptor: VariableDescriptor): Boolean =
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
private fun checkCanBeConst(declaration: KtDeclaration, private fun checkCanBeConst(
declaration: KtDeclaration,
constModifierPsiElement: PsiElement, constModifierPsiElement: PsiElement,
descriptor: VariableDescriptor): ConstApplicability { descriptor: VariableDescriptor
): ConstApplicability {
if (descriptor.isVar) { if (descriptor.isVar) {
return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable() return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable()
} }
@@ -71,7 +71,13 @@ class DelegationChecker : DeclarationChecker {
if (nonAbstractReachable.isNotEmpty()) { if (nonAbstractReachable.isNotEmpty()) {
/*In case of MANY_IMPL_MEMBER_NOT_IMPLEMENTED error there could be several elements otherwise only one*/ /*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
)
)
} }
} }
} }
@@ -71,8 +71,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
if (descriptor.isExpect) { if (descriptor.isExpect) {
checkExpectedDeclarationHasActual(declaration, descriptor, diagnosticHolder, descriptor.module, expectActualTracker) checkExpectedDeclarationHasActual(declaration, descriptor, diagnosticHolder, descriptor.module, expectActualTracker)
} } else {
else {
val checkActual = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckActual) val checkActual = !languageVersionSettings.getFlag(AnalysisFlag.multiPlatformDoNotCheckActual)
checkActualDeclarationHasExpected(declaration, descriptor, diagnosticHolder, checkActual) checkActualDeclarationHasExpected(declaration, descriptor, diagnosticHolder, checkActual)
} }
@@ -102,8 +101,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val incompatibility = compatibility as Map<Incompatible, Collection<MemberDescriptor>> val incompatibility = compatibility as Map<Incompatible, Collection<MemberDescriptor>>
diagnosticHolder.report(Errors.NO_ACTUAL_FOR_EXPECT.on(reportOn, descriptor, platformModule, incompatibility)) diagnosticHolder.report(Errors.NO_ACTUAL_FOR_EXPECT.on(reportOn, descriptor, platformModule, incompatibility))
} } else {
else {
val actualMembers = compatibility.asSequence() val actualMembers = compatibility.asSequence()
.filter { (compatibility, _) -> .filter { (compatibility, _) ->
compatibility is Compatible || (compatibility is Incompatible && compatibility.kind != Compatibility.IncompatibilityKind.STRONG) compatibility is Compatible || (compatibility is Incompatible && compatibility.kind != Compatibility.IncompatibilityKind.STRONG)
@@ -132,7 +130,10 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
fun Map<out Compatibility, Collection<MemberDescriptor>>.allStrongIncompatibilities(): Boolean = fun Map<out Compatibility, Collection<MemberDescriptor>>.allStrongIncompatibilities(): Boolean =
this.keys.all { it is Incompatible && it.kind == Compatibility.IncompatibilityKind.STRONG } this.keys.all { it is Incompatible && it.kind == Compatibility.IncompatibilityKind.STRONG }
private fun findActualForExpected(expected: MemberDescriptor, platformModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? { private fun findActualForExpected(
expected: MemberDescriptor,
platformModule: ModuleDescriptor
): Map<Compatibility, List<MemberDescriptor>>? {
return when (expected) { return when (expected) {
is CallableMemberDescriptor -> { is CallableMemberDescriptor -> {
expected.findNamesakesFromModule(platformModule).filter { actual -> expected.findNamesakesFromModule(platformModule).filter { actual ->
@@ -207,12 +208,13 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
val classDescriptor = val classDescriptor =
(descriptor as? TypeAliasDescriptor)?.expandedType?.constructor?.declarationDescriptor as? ClassDescriptor (descriptor as? TypeAliasDescriptor)?.expandedType?.constructor?.declarationDescriptor as? ClassDescriptor
?: (descriptor as ClassDescriptor) ?: (descriptor as ClassDescriptor)
diagnosticHolder.report(Errors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS.on( diagnosticHolder.report(
Errors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS.on(
reportOn, classDescriptor, nonTrivialUnfulfilled reportOn, classDescriptor, nonTrivialUnfulfilled
)) )
)
} }
} } else if (Compatible !in compatibility) {
else if (Compatible !in compatibility) {
assert(compatibility.keys.all { it is Incompatible }) assert(compatibility.keys.all { it is Incompatible })
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val incompatibility = compatibility as Map<Incompatible, Collection<MemberDescriptor>> val incompatibility = compatibility as Map<Incompatible, Collection<MemberDescriptor>>
@@ -229,14 +231,18 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
else -> true else -> true
} }
private fun findExpectedForActual(actual: MemberDescriptor, commonModule: ModuleDescriptor): Map<Compatibility, List<MemberDescriptor>>? { private fun findExpectedForActual(
actual: MemberDescriptor,
commonModule: ModuleDescriptor
): Map<Compatibility, List<MemberDescriptor>>? {
return when (actual) { return when (actual) {
is CallableMemberDescriptor -> { is CallableMemberDescriptor -> {
val container = actual.containingDeclaration val container = actual.containingDeclaration
val candidates = when (container) { val candidates = when (container) {
is ClassDescriptor -> { is ClassDescriptor -> {
// TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored // TODO: replace with 'singleOrNull' as soon as multi-module diagnostic tests are refactored
val expectedClass = findExpectedForActual(container, commonModule)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor val expectedClass =
findExpectedForActual(container, commonModule)?.values?.firstOrNull()?.firstOrNull() as? ClassDescriptor
expectedClass?.getMembers(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty() expectedClass?.getMembers(actual.name)?.filterIsInstance<CallableMemberDescriptor>().orEmpty()
} }
is PackageFragmentDescriptor -> actual.findNamesakesFromModule(commonModule) is PackageFragmentDescriptor -> actual.findNamesakesFromModule(commonModule)
@@ -252,8 +258,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
val expectedClass = declaration.containingDeclaration as ClassDescriptor val expectedClass = declaration.containingDeclaration as ClassDescriptor
// TODO: this might not work for members of inner generic classes // TODO: this might not work for members of inner generic classes
Substitutor(expectedClass.declaredTypeParameters, container.declaredTypeParameters) Substitutor(expectedClass.declaredTypeParameters, container.declaredTypeParameters)
} } else null
else null
areCompatibleCallables(declaration, actual, parentSubstitutor = substitutor) areCompatibleCallables(declaration, actual, parentSubstitutor = substitutor)
} }
} }
@@ -350,13 +355,17 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
object ValueParameterHasDefault : Incompatible("some parameters have default values") object ValueParameterHasDefault : Incompatible("some parameters have default values")
object ValueParameterVararg : Incompatible("some value parameter is vararg in one declaration and non-vararg in the other") object ValueParameterVararg : Incompatible("some value parameter is vararg in one declaration and non-vararg in the other")
object ValueParameterNoinline : Incompatible("some value parameter is noinline in one declaration and not noinline in the other") object ValueParameterNoinline :
object ValueParameterCrossinline : Incompatible("some value parameter is crossinline in one declaration and not crossinline in the other") Incompatible("some value parameter is noinline in one declaration and not noinline in the other")
object ValueParameterCrossinline :
Incompatible("some value parameter is crossinline in one declaration and not crossinline in the other")
// Functions // Functions
object FunctionModifiersDifferent : Incompatible("modifiers are different (suspend)") object FunctionModifiersDifferent : Incompatible("modifiers are different (suspend)")
object FunctionModifiersNotSubset : Incompatible("some modifiers on expected declaration are missing on the actual one (external, infix, inline, operator, tailrec)") object FunctionModifiersNotSubset :
Incompatible("some modifiers on expected declaration are missing on the actual one (external, infix, inline, operator, tailrec)")
// Properties // Properties
@@ -425,7 +434,11 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
return Incompatible.ParameterTypes return Incompatible.ParameterTypes
if (!areCompatibleTypes(substitutor(a.returnType), b.returnType, platformModule)) return Incompatible.ReturnType if (!areCompatibleTypes(substitutor(a.returnType), b.returnType, platformModule)) return Incompatible.ReturnType
if (b.hasStableParameterNames() && !equalsBy(aParams, bParams, ValueParameterDescriptor::getName)) return Incompatible.ParameterNames if (b.hasStableParameterNames() && !equalsBy(
aParams,
bParams,
ValueParameterDescriptor::getName
)) return Incompatible.ParameterNames
if (!equalsBy(aTypeParams, bTypeParams, TypeParameterDescriptor::getName)) return Incompatible.TypeParameterNames if (!equalsBy(aTypeParams, bTypeParams, TypeParameterDescriptor::getName)) return Incompatible.TypeParameterNames
if (!areCompatibleModalities(a.modality, b.modality)) return Incompatible.Modality if (!areCompatibleModalities(a.modality, b.modality)) return Incompatible.Modality
@@ -636,6 +649,7 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
if (a.kind == ClassKind.ENUM_CLASS) { if (a.kind == ClassKind.ENUM_CLASS) {
fun ClassDescriptor.enumEntries() = fun ClassDescriptor.enumEntries() =
unsubstitutedMemberScope.getDescriptorsFiltered().filter(DescriptorUtils::isEnumEntry).map { it.name } unsubstitutedMemberScope.getDescriptorsFiltered().filter(DescriptorUtils::isEnumEntry).map { it.name }
val aEntries = a.enumEntries() val aEntries = a.enumEntries()
val bEntries = b.enumEntries() val bEntries = b.enumEntries()
@@ -29,7 +29,12 @@ import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
object KClassWithIncorrectTypeArgumentChecker : SimpleDeclarationChecker { object KClassWithIncorrectTypeArgumentChecker : SimpleDeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink, bindingContext: BindingContext) { override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
if (descriptor !is CallableMemberDescriptor || descriptor.visibility == Visibilities.LOCAL) return if (descriptor !is CallableMemberDescriptor || descriptor.visibility == Visibilities.LOCAL) return
if (declaration !is KtCallableDeclaration || declaration.typeReference != null) return if (declaration !is KtCallableDeclaration || declaration.typeReference != null) return
@@ -53,7 +58,12 @@ object KClassWithIncorrectTypeArgumentChecker : SimpleDeclarationChecker {
} }
if (typeParameterWithoutNotNullableUpperBound != null) { if (typeParameterWithoutNotNullableUpperBound != null) {
diagnosticHolder.report(Errors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE.on(declaration, typeParameterWithoutNotNullableUpperBound!!)) diagnosticHolder.report(
Errors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE.on(
declaration,
typeParameterWithoutNotNullableUpperBound!!
)
)
} }
} }
@@ -107,8 +107,7 @@ class ConstantExpressionEvaluator(
if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null if (parameterDescriptor.declaresDefaultValue() && compileTimeConstants.isEmpty()) return null
return constantValueFactory.createArrayValue(constants, parameterDescriptor.type) return constantValueFactory.createArrayValue(constants, parameterDescriptor.type)
} } else {
else {
// we should actually get only one element, but just in case of getting many, we take the last one // we should actually get only one element, but just in case of getting many, we take the last one
return constants.lastOrNull() return constants.lastOrNull()
} }
@@ -137,7 +136,12 @@ class ConstantExpressionEvaluator(
getArgumentExpressionsForArrayCall(argumentExpression, trace)?.let { checkArgumentsAreCompileTimeConstants(it, trace) } getArgumentExpressionsForArrayCall(argumentExpression, trace)?.let { checkArgumentsAreCompileTimeConstants(it, trace) }
} }
if (argumentExpression is KtCollectionLiteralExpression) { if (argumentExpression is KtCollectionLiteralExpression) {
getArgumentExpressionsForCollectionLiteralCall(argumentExpression, trace)?.let { checkArgumentsAreCompileTimeConstants(it, trace) } getArgumentExpressionsForCollectionLiteralCall(argumentExpression, trace)?.let {
checkArgumentsAreCompileTimeConstants(
it,
trace
)
}
} }
val constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.bindingContext) val constant = ConstantExpressionEvaluator.getConstant(argumentExpression, trace.bindingContext)
@@ -162,16 +166,17 @@ class ConstantExpressionEvaluator(
val descriptor = expressionType.constructor.declarationDescriptor val descriptor = expressionType.constructor.declarationDescriptor
if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) { if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression)) trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression))
} } else if (descriptor is ClassDescriptor && KotlinBuiltIns.isKClass(descriptor)) {
else if (descriptor is ClassDescriptor && KotlinBuiltIns.isKClass(descriptor)) {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression)) trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_KCLASS_LITERAL.on(argumentExpression))
} } else {
else {
trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression)) trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression))
} }
} }
private fun checkArgumentsAreCompileTimeConstants(argumentsWithComponentType: Pair<List<KtExpression>, KotlinType?>, trace: BindingTrace) { private fun checkArgumentsAreCompileTimeConstants(
argumentsWithComponentType: Pair<List<KtExpression>, KotlinType?>,
trace: BindingTrace
) {
val (arguments, componentType) = argumentsWithComponentType val (arguments, componentType) = argumentsWithComponentType
for (expression in arguments) { for (expression in arguments) {
checkCompileTimeConstant(expression, componentType!!, trace) checkCompileTimeConstant(expression, componentType!!, trace)
@@ -188,7 +193,8 @@ class ConstantExpressionEvaluator(
private fun getArgumentExpressionsForCollectionLiteralCall( private fun getArgumentExpressionsForCollectionLiteralCall(
expression: KtCollectionLiteralExpression, expression: KtCollectionLiteralExpression,
trace: BindingTrace): Pair<List<KtExpression>, KotlinType?>? { trace: BindingTrace
): Pair<List<KtExpression>, KotlinType?>? {
val resolvedCall = trace[COLLECTION_LITERAL_CALL, expression] ?: return null val resolvedCall = trace[COLLECTION_LITERAL_CALL, expression] ?: return null
return getArgumentExpressionsForArrayLikeCall(resolvedCall) return getArgumentExpressionsForArrayLikeCall(resolvedCall)
} }
@@ -222,7 +228,8 @@ class ConstantExpressionEvaluator(
private fun resolveAnnotationValueArguments( private fun resolveAnnotationValueArguments(
resolvedValueArgument: ResolvedValueArgument, resolvedValueArgument: ResolvedValueArgument,
expectedType: KotlinType, expectedType: KotlinType,
trace: BindingTrace): List<CompileTimeConstant<*>> { trace: BindingTrace
): List<CompileTimeConstant<*>> {
val constants = ArrayList<CompileTimeConstant<*>>() val constants = ArrayList<CompileTimeConstant<*>>()
for (argument in resolvedValueArgument.arguments) { for (argument in resolvedValueArgument.arguments) {
val argumentExpression = argument.getArgumentExpression() ?: continue val argumentExpression = argument.getArgumentExpression() ?: continue
@@ -260,7 +267,8 @@ class ConstantExpressionEvaluator(
companion object { companion object {
@JvmStatic fun getConstant(expression: KtExpression, bindingContext: BindingContext): CompileTimeConstant<*>? { @JvmStatic
fun getConstant(expression: KtExpression, bindingContext: BindingContext): CompileTimeConstant<*>? {
val constant = getPossiblyErrorConstant(expression, bindingContext) ?: return null val constant = getPossiblyErrorConstant(expression, bindingContext) ?: return null
return if (!constant.isError) constant else null return if (!constant.isError) constant else null
} }
@@ -315,7 +323,10 @@ private class ConstantExpressionEvaluatorVisitor(
return entry.accept(this, null) return entry.accept(this, null)
} }
override fun visitStringTemplateEntryWithExpression(entry: KtStringTemplateEntryWithExpression, data: Nothing?): TypedCompileTimeConstant<String>? { override fun visitStringTemplateEntryWithExpression(
entry: KtStringTemplateEntryWithExpression,
data: Nothing?
): TypedCompileTimeConstant<String>? {
val expression = entry.expression ?: return null val expression = entry.expression ?: return null
return evaluate(expression, constantExpressionEvaluator.builtIns.stringType)?.let { return evaluate(expression, constantExpressionEvaluator.builtIns.stringType)?.let {
@@ -323,9 +334,11 @@ private class ConstantExpressionEvaluatorVisitor(
} }
} }
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?) = factory.createStringValue(entry.text).wrap() override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?) =
factory.createStringValue(entry.text).wrap()
override fun visitEscapeStringTemplateEntry(entry: KtEscapeStringTemplateEntry, data: Nothing?) = factory.createStringValue(entry.unescapedValue).wrap() override fun visitEscapeStringTemplateEntry(entry: KtEscapeStringTemplateEntry, data: Nothing?) =
factory.createStringValue(entry.unescapedValue).wrap()
} }
override fun visitConstantExpression(expression: KtConstantExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { override fun visitConstantExpression(expression: KtConstantExpression, expectedType: KotlinType?): CompileTimeConstant<*>? {
@@ -360,7 +373,11 @@ private class ConstantExpressionEvaluatorVisitor(
} }
val isLongWithSuffix = nodeElementType == KtNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text) val isLongWithSuffix = nodeElementType == KtNodeTypes.INTEGER_CONSTANT && hasLongSuffix(text)
return createConstant(result, expectedType, CompileTimeConstant.Parameters(true, !isLongWithSuffix, false, usesNonConstValAsConstant = false)) return createConstant(
result,
expectedType,
CompileTimeConstant.Parameters(true, !isLongWithSuffix, false, usesNonConstValAsConstant = false)
)
} }
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, expectedType: KotlinType?): CompileTimeConstant<*>? {
@@ -390,8 +407,7 @@ private class ConstantExpressionEvaluatorVisitor(
if (constant == null) { if (constant == null) {
interupted = true interupted = true
break break
} } else {
else {
if (!constant.canBeUsedInAnnotations) canBeUsedInAnnotation = false if (!constant.canBeUsedInAnnotations) canBeUsedInAnnotation = false
if (constant.usesVariableAsConstant) usesVariableAsConstant = true if (constant.usesVariableAsConstant) usesVariableAsConstant = true
if (constant.usesNonConstValAsConstant) usesNonConstantVariableAsConstant = true if (constant.usesNonConstValAsConstant) usesNonConstantVariableAsConstant = true
@@ -416,7 +432,10 @@ private class ConstantExpressionEvaluatorVisitor(
return ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.isStandaloneOnlyConstant() ?: return false return ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.isStandaloneOnlyConstant() ?: return false
} }
override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS, expectedType: KotlinType?): CompileTimeConstant<*>? { override fun visitBinaryWithTypeRHSExpression(
expression: KtBinaryExpressionWithTypeRHS,
expectedType: KotlinType?
): CompileTimeConstant<*>? {
val compileTimeConstant = evaluate(expression.left, expectedType) val compileTimeConstant = evaluate(expression.left, expectedType)
if (compileTimeConstant != null) { if (compileTimeConstant != null) {
if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) { if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) {
@@ -467,18 +486,24 @@ private class ConstantExpressionEvaluatorVisitor(
usesNonConstValAsConstant = leftConstant.usesNonConstValAsConstant || rightConstant.usesNonConstValAsConstant usesNonConstValAsConstant = leftConstant.usesNonConstValAsConstant || rightConstant.usesNonConstValAsConstant
) )
) )
} } else {
else {
return evaluateCall(expression.operationReference, leftExpression, expectedType) return evaluateCall(expression.operationReference, leftExpression, expectedType)
} }
} }
override fun visitCollectionLiteralExpression(expression: KtCollectionLiteralExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { override fun visitCollectionLiteralExpression(
expression: KtCollectionLiteralExpression,
expectedType: KotlinType?
): CompileTimeConstant<*>? {
val resolvedCall = trace.bindingContext[COLLECTION_LITERAL_CALL, expression] ?: return null val resolvedCall = trace.bindingContext[COLLECTION_LITERAL_CALL, expression] ?: return null
return createConstantValueForArrayFunctionCall(resolvedCall) return createConstantValueForArrayFunctionCall(resolvedCall)
} }
private fun evaluateCall(callExpression: KtExpression, receiverExpression: KtExpression, expectedType: KotlinType?): CompileTimeConstant<*>? { private fun evaluateCall(
callExpression: KtExpression,
receiverExpression: KtExpression,
expectedType: KotlinType?
): CompileTimeConstant<*>? {
val resolvedCall = callExpression.getResolvedCall(trace.bindingContext) ?: return null val resolvedCall = callExpression.getResolvedCall(trace.bindingContext) ?: return null
if (!KotlinBuiltIns.isUnderKotlinPackage(resolvedCall.resultingDescriptor)) return null if (!KotlinBuiltIns.isUnderKotlinPackage(resolvedCall.resultingDescriptor)) return null
@@ -504,10 +529,10 @@ private class ConstantExpressionEvaluatorVisitor(
CompileTimeConstant.Parameters( CompileTimeConstant.Parameters(
canBeUsedInAnnotation, canBeUsedInAnnotation,
!isNumberConversionMethod && isArgumentPure, !isNumberConversionMethod && isArgumentPure,
usesVariableAsConstant, usesNonConstValAsConstant) usesVariableAsConstant, usesNonConstValAsConstant
) )
} )
else if (argumentsEntrySet.size == 1) { } else if (argumentsEntrySet.size == 1) {
val (parameter, argument) = argumentsEntrySet.first() val (parameter, argument) = argumentsEntrySet.first()
val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter) ?: return null val argumentForParameter = createOperationArgumentForFirstParameter(argument, parameter) ?: return null
if (isStandaloneOnlyConstant(argumentForParameter.expression)) { if (isStandaloneOnlyConstant(argumentForParameter.expression)) {
@@ -524,15 +549,23 @@ private class ConstantExpressionEvaluatorVisitor(
} }
} }
val result = evaluateBinaryAndCheck(argumentForReceiver, argumentForParameter, resultingDescriptorName.asString(), callExpression) ?: return null val result =
evaluateBinaryAndCheck(argumentForReceiver, argumentForParameter, resultingDescriptorName.asString(), callExpression)
?: return null
val areArgumentsPure = isPureConstant(argumentForReceiver.expression) && isPureConstant(argumentForParameter.expression) val areArgumentsPure = isPureConstant(argumentForReceiver.expression) && isPureConstant(argumentForParameter.expression)
val canBeUsedInAnnotation = canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression) val canBeUsedInAnnotation =
val usesVariableAsConstant = usesVariableAsConstant(argumentForReceiver.expression) || usesVariableAsConstant(argumentForParameter.expression) canBeUsedInAnnotation(argumentForReceiver.expression) && canBeUsedInAnnotation(argumentForParameter.expression)
val usesNonConstValAsConstant = usesNonConstValAsConstant(argumentForReceiver.expression) || usesNonConstValAsConstant(argumentForParameter.expression) val usesVariableAsConstant =
val parameters = CompileTimeConstant.Parameters(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant, usesNonConstValAsConstant) usesVariableAsConstant(argumentForReceiver.expression) || usesVariableAsConstant(argumentForParameter.expression)
val usesNonConstValAsConstant =
usesNonConstValAsConstant(argumentForReceiver.expression) || usesNonConstValAsConstant(argumentForParameter.expression)
val parameters =
CompileTimeConstant.Parameters(canBeUsedInAnnotation, areArgumentsPure, usesVariableAsConstant, usesNonConstValAsConstant)
return when (resultingDescriptorName) { return when (resultingDescriptorName) {
OperatorNameConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, factory)?.wrap(parameters) OperatorNameConventions.COMPARE_TO -> createCompileTimeConstantForCompareTo(result, callExpression, factory)?.wrap(
parameters
)
OperatorNameConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, factory)?.wrap(parameters) OperatorNameConventions.EQUALS -> createCompileTimeConstantForEquals(result, callExpression, factory)?.wrap(parameters)
else -> { else -> {
createConstant(result, expectedType, parameters) createConstant(result, expectedType, parameters)
@@ -543,13 +576,17 @@ private class ConstantExpressionEvaluatorVisitor(
return null return null
} }
private fun usesVariableAsConstant(expression: KtExpression) = ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.usesVariableAsConstant ?: false private fun usesVariableAsConstant(expression: KtExpression) =
private fun usesNonConstValAsConstant(expression: KtExpression) ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.usesVariableAsConstant ?: false
= ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.usesNonConstValAsConstant ?: false
private fun canBeUsedInAnnotation(expression: KtExpression) = ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.canBeUsedInAnnotations ?: false private fun usesNonConstValAsConstant(expression: KtExpression) =
ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.usesNonConstValAsConstant ?: false
private fun isPureConstant(expression: KtExpression) = ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.isPure ?: false private fun canBeUsedInAnnotation(expression: KtExpression) =
ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.canBeUsedInAnnotations ?: false
private fun isPureConstant(expression: KtExpression) =
ConstantExpressionEvaluator.getConstant(expression, trace.bindingContext)?.isPure ?: false
private fun evaluateUnaryAndCheck(receiver: OperationArgument, name: String, callExpression: KtExpression): Any? { private fun evaluateUnaryAndCheck(receiver: OperationArgument, name: String, callExpression: KtExpression): Any? {
val functions = unaryOperations[UnaryOperationKey(receiver.ctcType, name)] ?: return null val functions = unaryOperations[UnaryOperationKey(receiver.ctcType, name)] ?: return null
@@ -568,14 +605,18 @@ private class ConstantExpressionEvaluatorVisitor(
return result return result
} }
private fun evaluateBinaryAndCheck(receiver: OperationArgument, parameter: OperationArgument, name: String, callExpression: KtExpression): Any? { private fun evaluateBinaryAndCheck(
receiver: OperationArgument,
parameter: OperationArgument,
name: String,
callExpression: KtExpression
): Any? {
val functions = getBinaryOperation(receiver, parameter, name) ?: return null val functions = getBinaryOperation(receiver, parameter, name) ?: return null
val (function, checker) = functions val (function, checker) = functions
val actualResult = try { val actualResult = try {
function(receiver.value, parameter.value) function(receiver.value, parameter.value)
} } catch (e: Exception) {
catch (e: Exception) {
null null
} }
if (checker == emptyBinaryFun) { if (checker == emptyBinaryFun) {
@@ -587,8 +628,7 @@ private class ConstantExpressionEvaluatorVisitor(
val refinedChecker = if (name == OperatorNameConventions.MOD.asString()) { val refinedChecker = if (name == OperatorNameConventions.MOD.asString()) {
getBinaryOperation(receiver, parameter, OperatorNameConventions.REM.asString())?.second ?: return null getBinaryOperation(receiver, parameter, OperatorNameConventions.REM.asString())?.second ?: return null
} } else {
else {
checker checker
} }
@@ -769,7 +809,10 @@ private class ConstantExpressionEvaluatorVisitor(
return createOperationArgument(expression, receiverExpressionType, receiverCompileTimeType) return createOperationArgument(expression, receiverExpressionType, receiverCompileTimeType)
} }
private fun createOperationArgumentForFirstParameter(argument: ResolvedValueArgument, parameter: ValueParameterDescriptor): OperationArgument? { private fun createOperationArgumentForFirstParameter(
argument: ResolvedValueArgument,
parameter: ValueParameterDescriptor
): OperationArgument? {
val argumentCompileTimeType = getCompileTimeType(parameter.type) ?: return null val argumentCompileTimeType = getCompileTimeType(parameter.type) ?: return null
val arguments = argument.arguments val arguments = argument.arguments
@@ -798,7 +841,11 @@ private class ConstantExpressionEvaluatorVisitor(
} }
} }
private fun createOperationArgument(expression: KtExpression, parameterType: KotlinType, compileTimeType: CompileTimeType<*>): OperationArgument? { private fun createOperationArgument(
expression: KtExpression,
parameterType: KotlinType,
compileTimeType: CompileTimeType<*>
): OperationArgument? {
val compileTimeConstant = constantExpressionEvaluator.evaluateExpression(expression, trace, parameterType) ?: return null val compileTimeConstant = constantExpressionEvaluator.evaluateExpression(expression, trace, parameterType) ?: return null
if (compileTimeConstant is TypedCompileTimeConstant && !compileTimeConstant.type.isSubtypeOf(parameterType)) return null if (compileTimeConstant is TypedCompileTimeConstant && !compileTimeConstant.type.isSubtypeOf(parameterType)) return null
val evaluationResult = compileTimeConstant.getValue(parameterType) ?: return null val evaluationResult = compileTimeConstant.getValue(parameterType) ?: return null
@@ -812,8 +859,7 @@ private class ConstantExpressionEvaluatorVisitor(
): CompileTimeConstant<*>? { ): CompileTimeConstant<*>? {
return if (parameters.isPure) { return if (parameters.isPure) {
return createCompileTimeConstant(value, parameters, expectedType ?: TypeUtils.NO_EXPECTED_TYPE) return createCompileTimeConstant(value, parameters, expectedType ?: TypeUtils.NO_EXPECTED_TYPE)
} } else {
else {
factory.createConstantValue(value)?.wrap(parameters) factory.createConstantValue(value)?.wrap(parameters)
} }
} }
@@ -847,16 +893,16 @@ private class ConstantExpressionEvaluatorVisitor(
}.wrap(parameters) }.wrap(parameters)
} }
private fun <T> ConstantValue<T>.wrap(parameters: CompileTimeConstant.Parameters): TypedCompileTimeConstant<T> private fun <T> ConstantValue<T>.wrap(parameters: CompileTimeConstant.Parameters): TypedCompileTimeConstant<T> =
= TypedCompileTimeConstant(this, parameters) TypedCompileTimeConstant(this, parameters)
private fun <T> ConstantValue<T>.wrap( private fun <T> ConstantValue<T>.wrap(
canBeUsedInAnnotation: Boolean = this !is NullValue, canBeUsedInAnnotation: Boolean = this !is NullValue,
isPure: Boolean = false, isPure: Boolean = false,
usesVariableAsConstant: Boolean = false, usesVariableAsConstant: Boolean = false,
usesNonConstValAsConstant: Boolean = false usesNonConstValAsConstant: Boolean = false
): TypedCompileTimeConstant<T> ): TypedCompileTimeConstant<T> =
= wrap(CompileTimeConstant.Parameters(canBeUsedInAnnotation, isPure, usesVariableAsConstant, usesNonConstValAsConstant)) wrap(CompileTimeConstant.Parameters(canBeUsedInAnnotation, isPure, usesVariableAsConstant, usesNonConstValAsConstant))
} }
private fun hasLongSuffix(text: String) = text.endsWith('l') || text.endsWith('L') private fun hasLongSuffix(text: String) = text.endsWith('l') || text.endsWith('L')
@@ -877,8 +923,7 @@ private fun parseLong(text: String): Long? {
val (number, radix) = extractRadix(text) val (number, radix) = extractRadix(text)
return parseLong(number, radix) return parseLong(number, radix)
} } catch (e: NumberFormatException) {
catch (e: NumberFormatException) {
return null return null
} }
} }
@@ -893,8 +938,7 @@ private fun parseFloatingLiteral(text: String): Any? {
private fun parseDouble(text: String): Double? { private fun parseDouble(text: String): Double? {
try { try {
return java.lang.Double.parseDouble(text) return java.lang.Double.parseDouble(text)
} } catch (e: NumberFormatException) {
catch (e: NumberFormatException) {
return null return null
} }
} }
@@ -902,8 +946,7 @@ private fun parseDouble(text: String): Double? {
private fun parseFloat(text: String): Float? { private fun parseFloat(text: String): Float? {
try { try {
return java.lang.Float.parseFloat(text) return java.lang.Float.parseFloat(text)
} } catch (e: NumberFormatException) {
catch (e: NumberFormatException) {
return null return null
} }
} }
@@ -911,8 +954,7 @@ private fun parseFloat(text: String): Float? {
private fun parseBoolean(text: String): Boolean { private fun parseBoolean(text: String): Boolean {
if ("true".equals(text)) { if ("true".equals(text)) {
return true return true
} } else if ("false".equals(text)) {
else if ("false".equals(text)) {
return false return false
} }
@@ -920,7 +962,11 @@ private fun parseBoolean(text: String): Boolean {
} }
private fun createCompileTimeConstantForEquals(result: Any?, operationReference: KtExpression, factory: ConstantValueFactory): ConstantValue<*>? { private fun createCompileTimeConstantForEquals(
result: Any?,
operationReference: KtExpression,
factory: ConstantValueFactory
): ConstantValue<*>? {
if (result is Boolean) { if (result is Boolean) {
assert(operationReference is KtSimpleNameExpression) { "This method should be called only for equals operations" } assert(operationReference is KtSimpleNameExpression) { "This method should be called only for equals operations" }
val operationToken = (operationReference as KtSimpleNameExpression).getReferencedNameElementType() val operationToken = (operationReference as KtSimpleNameExpression).getReferencedNameElementType()
@@ -938,7 +984,11 @@ private fun createCompileTimeConstantForEquals(result: Any?, operationReference:
return null return null
} }
private fun createCompileTimeConstantForCompareTo(result: Any?, operationReference: KtExpression, factory: ConstantValueFactory): ConstantValue<*>? { private fun createCompileTimeConstantForCompareTo(
result: Any?,
operationReference: KtExpression,
factory: ConstantValueFactory
): ConstantValue<*>? {
if (result is Int) { if (result is Int) {
assert(operationReference is KtSimpleNameExpression) { "This method should be called only for compareTo operations" } assert(operationReference is KtSimpleNameExpression) { "This method should be called only for compareTo operations" }
val operationToken = (operationReference as KtSimpleNameExpression).getReferencedNameElementType() val operationToken = (operationReference as KtSimpleNameExpression).getReferencedNameElementType()
@@ -991,7 +1041,10 @@ internal fun <A, B> binaryOperation(
functionName: String, functionName: String,
operation: Function2<A, B, Any>, operation: Function2<A, B, Any>,
checker: Function2<BigInteger, BigInteger, BigInteger> checker: Function2<BigInteger, BigInteger, BigInteger>
) = BinaryOperationKey(a, b, functionName) to Pair(operation, checker) as Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>> ) = BinaryOperationKey(a, b, functionName) to Pair(
operation,
checker
) as Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
internal fun <A> unaryOperation( internal fun <A> unaryOperation(
@@ -24,8 +24,8 @@ import java.util.HashMap
internal val emptyBinaryFun: Function2<BigInteger, BigInteger, BigInteger> = { a, b -> BigInteger("0") } internal val emptyBinaryFun: Function2<BigInteger, BigInteger, BigInteger> = { a, b -> BigInteger("0") }
internal val emptyUnaryFun: Function1<Long, Long> = { a -> 1.toLong() } internal val emptyUnaryFun: Function1<Long, Long> = { a -> 1.toLong() }
internal val unaryOperations: HashMap<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>> internal val unaryOperations: HashMap<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>> =
= hashMapOf<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>>( hashMapOf<UnaryOperationKey<*>, Pair<Function1<Any?, Any>, Function1<Long, Long>>>(
unaryOperation(BOOLEAN, "not", { a -> a.not() }, emptyUnaryFun), unaryOperation(BOOLEAN, "not", { a -> a.not() }, emptyUnaryFun),
unaryOperation(BOOLEAN, "toString", { a -> a.toString() }, emptyUnaryFun), unaryOperation(BOOLEAN, "toString", { a -> a.toString() }, emptyUnaryFun),
unaryOperation(BYTE, "toByte", { a -> a.toByte() }, emptyUnaryFun), unaryOperation(BYTE, "toByte", { a -> a.toByte() }, emptyUnaryFun),
@@ -102,8 +102,8 @@ internal val unaryOperations: HashMap<UnaryOperationKey<*>, Pair<Function1<Any?,
unaryOperation(STRING, "toString", { a -> a.toString() }, emptyUnaryFun) unaryOperation(STRING, "toString", { a -> a.toString() }, emptyUnaryFun)
) )
internal val binaryOperations: HashMap<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>> internal val binaryOperations: HashMap<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>> =
= hashMapOf<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>>( hashMapOf<BinaryOperationKey<*, *>, Pair<Function2<Any?, Any?, Any>, Function2<BigInteger, BigInteger, BigInteger>>>(
binaryOperation(BOOLEAN, BOOLEAN, "and", { a, b -> a.and(b) }, emptyBinaryFun), binaryOperation(BOOLEAN, BOOLEAN, "and", { a, b -> a.and(b) }, emptyBinaryFun),
binaryOperation(BOOLEAN, BOOLEAN, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun), binaryOperation(BOOLEAN, BOOLEAN, "compareTo", { a, b -> a.compareTo(b) }, emptyBinaryFun),
binaryOperation(BOOLEAN, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun), binaryOperation(BOOLEAN, ANY, "equals", { a, b -> a.equals(b) }, emptyBinaryFun),
@@ -97,7 +97,8 @@ private data class DeprecatedByOverridden(private val deprecations: Collection<D
return "${additionalMessage()}. $message" return "${additionalMessage()}. $message"
} }
internal fun additionalMessage() = "Overrides deprecated member in '${DescriptorUtils.getContainingClass(target)!!.fqNameSafe.asString()}'" internal fun additionalMessage() =
"Overrides deprecated member in '${DescriptorUtils.getContainingClass(target)!!.fqNameSafe.asString()}'"
} }
private data class DeprecatedByVersionRequirement( private data class DeprecatedByVersionRequirement(
@@ -123,8 +124,7 @@ private data class DeprecatedByVersionRequirement(
if (errorCode != null) { if (errorCode != null) {
append(" (error code $errorCode)") append(" (error code $errorCode)")
} }
} } else {
else {
append("Error code $errorCode") append("Error code $errorCode")
} }
} }
@@ -155,8 +155,10 @@ internal fun createDeprecationDiagnostic(
WARNING -> Errors.VERSION_REQUIREMENT_DEPRECATION WARNING -> Errors.VERSION_REQUIREMENT_DEPRECATION
ERROR, HIDDEN -> Errors.VERSION_REQUIREMENT_DEPRECATION_ERROR ERROR, HIDDEN -> Errors.VERSION_REQUIREMENT_DEPRECATION_ERROR
} }
factory.on(element, targetOriginal, deprecation.versionRequirement.version, factory.on(
languageVersionSettings.languageVersion to deprecation.message) element, targetOriginal, deprecation.versionRequirement.version,
languageVersionSettings.languageVersion to deprecation.message
)
} }
is DeprecatedTypealiasByAnnotation -> { is DeprecatedTypealiasByAnnotation -> {
@@ -311,7 +313,11 @@ class DeprecationResolver(
fun addUseSiteTargetedDeprecationIfPresent(annotatedDescriptor: DeclarationDescriptor, useSiteTarget: AnnotationUseSiteTarget?) { fun addUseSiteTargetedDeprecationIfPresent(annotatedDescriptor: DeclarationDescriptor, useSiteTarget: AnnotationUseSiteTarget?) {
if (useSiteTarget != null) { if (useSiteTarget != null) {
val annotation = Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, KotlinBuiltIns.FQ_NAMES.deprecated) val annotation = Annotations.findUseSiteTargetedAnnotation(
annotatedDescriptor.annotations,
useSiteTarget,
KotlinBuiltIns.FQ_NAMES.deprecated
)
?: Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, JAVA_DEPRECATED) ?: Annotations.findUseSiteTargetedAnnotation(annotatedDescriptor.annotations, useSiteTarget, JAVA_DEPRECATED)
if (annotation != null) { if (annotation != null) {
result.add(DeprecatedByAnnotation(annotation, this)) result.add(DeprecatedByAnnotation(annotation, this))
@@ -43,8 +43,7 @@ class InlineAnalyzerExtension(
} }
checkDefaults(descriptor, functionOrProperty as KtNamedFunction, trace) checkDefaults(descriptor, functionOrProperty as KtNamedFunction, trace)
checkHasInlinableAndNullability(descriptor, functionOrProperty, trace) checkHasInlinableAndNullability(descriptor, functionOrProperty, trace)
} } else {
else {
assert(descriptor is PropertyDescriptor) { assert(descriptor is PropertyDescriptor) {
"PropertyDescriptor expected, but was $descriptor" "PropertyDescriptor expected, but was $descriptor"
} }
@@ -59,7 +58,11 @@ class InlineAnalyzerExtension(
} }
} }
private fun notSupportedInInlineCheck(descriptor: CallableMemberDescriptor, functionOrProperty: KtCallableDeclaration, trace: BindingTrace) { private fun notSupportedInInlineCheck(
descriptor: CallableMemberDescriptor,
functionOrProperty: KtCallableDeclaration,
trace: BindingTrace
) {
val visitor = object : KtVisitorVoid() { val visitor = object : KtVisitorVoid() {
override fun visitKtElement(element: KtElement) { override fun visitKtElement(element: KtElement) {
super.visitKtElement(element) super.visitKtElement(element)
@@ -73,8 +76,7 @@ class InlineAnalyzerExtension(
override fun visitNamedFunction(function: KtNamedFunction) { override fun visitNamedFunction(function: KtNamedFunction) {
if (function.parent.parent is KtObjectDeclaration) { if (function.parent.parent is KtObjectDeclaration) {
super.visitNamedFunction(function) super.visitNamedFunction(function)
} } else {
else {
trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(function, "Local functions")) trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(function, "Local functions"))
} }
} }
@@ -86,7 +88,8 @@ class InlineAnalyzerExtension(
private fun checkDefaults( private fun checkDefaults(
functionDescriptor: FunctionDescriptor, functionDescriptor: FunctionDescriptor,
function: KtFunction, function: KtFunction,
trace: BindingTrace) { trace: BindingTrace
) {
val ktParameters = function.valueParameters val ktParameters = function.valueParameters
for (parameter in functionDescriptor.valueParameters) { for (parameter in functionDescriptor.valueParameters) {
if (parameter.hasDefaultValue()) { if (parameter.hasDefaultValue()) {
@@ -95,9 +98,13 @@ class InlineAnalyzerExtension(
val inheritDefaultValues = !parameter.declaresDefaultValue() val inheritDefaultValues = !parameter.declaresDefaultValue()
if (checkInlinableParameter(parameter, ktParameter, functionDescriptor, null) || inheritDefaultValues) { if (checkInlinableParameter(parameter, ktParameter, functionDescriptor, null) || inheritDefaultValues) {
if (inheritDefaultValues || !languageVersionSettings.supportsFeature(LanguageFeature.InlineDefaultFunctionalParameters)) { if (inheritDefaultValues || !languageVersionSettings.supportsFeature(LanguageFeature.InlineDefaultFunctionalParameters)) {
trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(ktParameter, "Functional parameters with inherited default values")) trace.report(
} Errors.NOT_YET_SUPPORTED_IN_INLINE.on(
else { ktParameter,
"Functional parameters with inherited default values"
)
)
} else {
checkDefaultValue(trace, parameter, ktParameter) checkDefaultValue(trace, parameter, ktParameter)
} }
} }
@@ -116,7 +123,8 @@ class InlineAnalyzerExtension(
private fun checkModalityAndOverrides( private fun checkModalityAndOverrides(
callableDescriptor: CallableMemberDescriptor, callableDescriptor: CallableMemberDescriptor,
functionOrProperty: KtCallableDeclaration, functionOrProperty: KtCallableDeclaration,
trace: BindingTrace) { trace: BindingTrace
) {
if (callableDescriptor.containingDeclaration is PackageFragmentDescriptor) { if (callableDescriptor.containingDeclaration is PackageFragmentDescriptor) {
return return
} }
@@ -155,8 +163,7 @@ class InlineAnalyzerExtension(
private fun checkHasInlinableAndNullability(functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) { private fun checkHasInlinableAndNullability(functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) {
var hasInlineArgs = false var hasInlineArgs = false
function.valueParameters.zip(functionDescriptor.valueParameters).forEach { function.valueParameters.zip(functionDescriptor.valueParameters).forEach { (parameter, descriptor) ->
(parameter, descriptor) ->
hasInlineArgs = hasInlineArgs or checkInlinableParameter(descriptor, parameter, functionDescriptor, trace) hasInlineArgs = hasInlineArgs or checkInlinableParameter(descriptor, parameter, functionDescriptor, trace)
} }
if (hasInlineArgs) return if (hasInlineArgs) return
@@ -173,12 +180,12 @@ class InlineAnalyzerExtension(
parameter: ParameterDescriptor, parameter: ParameterDescriptor,
expression: KtElement, expression: KtElement,
functionDescriptor: CallableDescriptor, functionDescriptor: CallableDescriptor,
trace: BindingTrace?): Boolean { trace: BindingTrace?
): Boolean {
if (InlineUtil.isInlineParameterExceptNullability(parameter)) { if (InlineUtil.isInlineParameterExceptNullability(parameter)) {
if (parameter.type.isMarkedNullable) { if (parameter.type.isMarkedNullable) {
trace?.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor)) trace?.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor))
} } else {
else {
return true return true
} }
} }
@@ -50,8 +50,7 @@ class DefaultImportProvider(
for (packageFqName in packages) { for (packageFqName in packages) {
dependencyModuleDescriptor.packageFragmentProviderForContent.getPackageFragments(packageFqName) dependencyModuleDescriptor.packageFragmentProviderForContent.getPackageFragments(packageFqName)
.flatMapTo(result) { .flatMapTo(result) { packageFragmentDescriptor ->
packageFragmentDescriptor ->
packageFragmentDescriptor.getMemberScope() packageFragmentDescriptor.getMemberScope()
.getContributedDescriptors(DescriptorKindFilter.TYPE_ALIASES) .getContributedDescriptors(DescriptorKindFilter.TYPE_ALIASES)
.filterIsInstance<TypeAliasDescriptor>() .filterIsInstance<TypeAliasDescriptor>()
@@ -103,7 +103,8 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
getClassDescriptorIfAny(declaration, lookupLocationFor(declaration, declaration.isTopLevel())) getClassDescriptorIfAny(declaration, lookupLocationFor(declaration, declaration.isTopLevel()))
override fun visitTypeParameter(parameter: KtTypeParameter, data: Nothing?): DeclarationDescriptor? { override fun visitTypeParameter(parameter: KtTypeParameter, data: Nothing?): DeclarationDescriptor? {
val ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner::class.java) ?: error("Owner not found for type parameter: " + parameter.text) val ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner::class.java)
?: error("Owner not found for type parameter: " + parameter.text)
val ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false) ?: return null val ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false) ?: return null
val typeParameters: List<TypeParameterDescriptor> val typeParameters: List<TypeParameterDescriptor>
@@ -136,7 +137,8 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
classDescriptor == null -> null classDescriptor == null -> null
parameter.hasValOrVar() -> { parameter.hasValOrVar() -> {
classDescriptor.defaultType.memberScope.getContributedVariables( classDescriptor.defaultType.memberScope.getContributedVariables(
parameter.nameAsSafeName, lookupLocationFor(parameter, false)) parameter.nameAsSafeName, lookupLocationFor(parameter, false)
)
bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter) bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter)
} }
else -> { else -> {
@@ -202,8 +204,10 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
getScriptDescriptor(script, lookupLocationFor(script, true)) getScriptDescriptor(script, lookupLocationFor(script, true))
override fun visitKtElement(element: KtElement, data: Nothing?): DeclarationDescriptor? { override fun visitKtElement(element: KtElement, data: Nothing?): DeclarationDescriptor? {
throw IllegalArgumentException("Unsupported declaration type: " + element + " " + throw IllegalArgumentException(
element.getElementTextWithContext()) "Unsupported declaration type: " + element + " " +
element.getElementTextWithContext()
)
} }
}, null) }, null)
} }
@@ -218,13 +222,14 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
topLevelDescriptorProvider.assertValid() topLevelDescriptorProvider.assertValid()
val packageDescriptor = topLevelDescriptorProvider.getPackageFragmentOrDiagnoseFailure(fqName, ktFile) val packageDescriptor = topLevelDescriptorProvider.getPackageFragmentOrDiagnoseFailure(fqName, ktFile)
return packageDescriptor.getMemberScope() return packageDescriptor.getMemberScope()
} } else {
else {
return when (parentDeclaration) { return when (parentDeclaration) {
is KtClassOrObject -> getClassDescriptor(parentDeclaration, location).unsubstitutedMemberScope is KtClassOrObject -> getClassDescriptor(parentDeclaration, location).unsubstitutedMemberScope
is KtScript -> getScriptDescriptor(parentDeclaration, location).unsubstitutedMemberScope is KtScript -> getScriptDescriptor(parentDeclaration, location).unsubstitutedMemberScope
else -> throw IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" + else -> throw IllegalStateException(
declaration.getElementTextWithContext()) "Don't call this method for local declarations: " + declaration + "\n" +
declaration.getElementTextWithContext()
)
} }
} }
} }
@@ -30,8 +30,8 @@ class CombinedPackageMemberDeclarationProvider(
override fun containsFile(file: KtFile) = providers.any { it.containsFile(file) } override fun containsFile(file: KtFile) = providers.any { it.containsFile(file) }
override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) =
= providers.flatMap { it.getDeclarations(kindFilter, nameFilter) } providers.flatMap { it.getDeclarations(kindFilter, nameFilter) }
override fun getFunctionDeclarations(name: Name) = providers.flatMap { it.getFunctionDeclarations(name) } override fun getFunctionDeclarations(name: Name) = providers.flatMap { it.getFunctionDeclarations(name) }
@@ -37,7 +37,8 @@ abstract class DeclarationProviderFactoryService {
): DeclarationProviderFactory ): DeclarationProviderFactory
companion object { companion object {
@JvmStatic fun createDeclarationProviderFactory( @JvmStatic
fun createDeclarationProviderFactory(
project: Project, project: Project,
storageManager: StorageManager, storageManager: StorageManager,
syntheticFiles: Collection<KtFile>, syntheticFiles: Collection<KtFile>,
@@ -57,8 +58,8 @@ abstract class DeclarationProviderFactoryService {
} }
private class SyntheticFilesFilteringScope(syntheticFiles: Collection<KtFile>, baseScope: GlobalSearchScope) private class SyntheticFilesFilteringScope(syntheticFiles: Collection<KtFile>, baseScope: GlobalSearchScope) :
: DelegatingGlobalSearchScope(baseScope) { DelegatingGlobalSearchScope(baseScope) {
private val originals = syntheticFiles.mapNotNullTo(HashSet<VirtualFile>()) { it.originalFile.virtualFile } private val originals = syntheticFiles.mapNotNullTo(HashSet<VirtualFile>()) { it.originalFile.virtualFile }
@@ -21,8 +21,8 @@ import org.jetbrains.kotlin.storage.StorageManager
class PsiBasedClassMemberDeclarationProvider( class PsiBasedClassMemberDeclarationProvider(
storageManager: StorageManager, storageManager: StorageManager,
override val ownerInfo: KtClassLikeInfo) override val ownerInfo: KtClassLikeInfo
: AbstractPsiBasedDeclarationProvider(storageManager), ClassMemberDeclarationProvider { ) : AbstractPsiBasedDeclarationProvider(storageManager), ClassMemberDeclarationProvider {
override fun doCreateIndex(index: AbstractPsiBasedDeclarationProvider.Index) { override fun doCreateIndex(index: AbstractPsiBasedDeclarationProvider.Index) {
for (declaration in ownerInfo.declarations) { for (declaration in ownerInfo.declarations) {
@@ -45,10 +45,14 @@ protected constructor(
) : MemberScopeImpl() { ) : MemberScopeImpl() {
protected val storageManager: StorageManager = c.storageManager protected val storageManager: StorageManager = c.storageManager
private val classDescriptors: MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> = storageManager.createMemoizedFunction { doGetClasses(it) } private val classDescriptors: MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> =
private val functionDescriptors: MemoizedFunctionToNotNull<Name, Collection<SimpleFunctionDescriptor>> = storageManager.createMemoizedFunction { doGetFunctions(it) } storageManager.createMemoizedFunction { doGetClasses(it) }
private val propertyDescriptors: MemoizedFunctionToNotNull<Name, Collection<PropertyDescriptor>> = storageManager.createMemoizedFunction { doGetProperties(it) } private val functionDescriptors: MemoizedFunctionToNotNull<Name, Collection<SimpleFunctionDescriptor>> =
private val typeAliasDescriptors: MemoizedFunctionToNotNull<Name, Collection<TypeAliasDescriptor>> = storageManager.createMemoizedFunction { doGetTypeAliases(it) } storageManager.createMemoizedFunction { doGetFunctions(it) }
private val propertyDescriptors: MemoizedFunctionToNotNull<Name, Collection<PropertyDescriptor>> =
storageManager.createMemoizedFunction { doGetProperties(it) }
private val typeAliasDescriptors: MemoizedFunctionToNotNull<Name, Collection<TypeAliasDescriptor>> =
storageManager.createMemoizedFunction { doGetTypeAliases(it) }
private fun doGetClasses(name: Name): List<ClassDescriptor> { private fun doGetClasses(name: Name): List<ClassDescriptor> {
val result = Sets.newLinkedHashSet<ClassDescriptor>() val result = Sets.newLinkedHashSet<ClassDescriptor>()
@@ -92,12 +96,15 @@ protected constructor(
val declarations = declarationProvider.getFunctionDeclarations(name) val declarations = declarationProvider.getFunctionDeclarations(name)
for (functionDeclaration in declarations) { for (functionDeclaration in declarations) {
result.add(c.functionDescriptorResolver.resolveFunctionDescriptor( result.add(
c.functionDescriptorResolver.resolveFunctionDescriptor(
thisDescriptor, thisDescriptor,
getScopeForMemberDeclarationResolution(functionDeclaration), getScopeForMemberDeclarationResolution(functionDeclaration),
functionDeclaration, functionDeclaration,
trace, trace,
c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(functionDeclaration))) c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(functionDeclaration)
)
)
} }
getNonDeclaredFunctions(name, result) getNonDeclaredFunctions(name, result)
@@ -129,7 +136,8 @@ protected constructor(
getScopeForInitializerResolution(propertyDeclaration), getScopeForInitializerResolution(propertyDeclaration),
propertyDeclaration, propertyDeclaration,
trace, trace,
c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(propertyDeclaration)) c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(propertyDeclaration)
)
result.add(propertyDescriptor) result.add(propertyDescriptor)
} }
@@ -140,7 +148,8 @@ protected constructor(
getScopeForInitializerResolution(entry), getScopeForInitializerResolution(entry),
entry, entry,
trace, trace,
c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(entry)) c.declarationScopeProvider.getOuterDataFlowInfoForDeclaration(entry)
)
result.add(propertyDescriptor) result.add(propertyDescriptor)
} }
@@ -162,7 +171,8 @@ protected constructor(
thisDescriptor, thisDescriptor,
getScopeForMemberDeclarationResolution(ktTypeAlias), getScopeForMemberDeclarationResolution(ktTypeAlias),
ktTypeAlias, ktTypeAlias,
trace) trace
)
}.toList() }.toList()
protected fun computeDescriptorsFromDeclaredElements( protected fun computeDescriptorsFromDeclaredElements(
@@ -55,8 +55,7 @@ class LazyAnnotations(
) : Annotations, LazyEntity { ) : Annotations, LazyEntity {
override fun isEmpty() = annotationEntries.isEmpty() override fun isEmpty() = annotationEntries.isEmpty()
private val annotation = c.storageManager.createMemoizedFunction { private val annotation = c.storageManager.createMemoizedFunction { entry: KtAnnotationEntry ->
entry: KtAnnotationEntry ->
val descriptor = LazyAnnotationDescriptor(c, entry) val descriptor = LazyAnnotationDescriptor(c, entry)
val target = entry.useSiteTarget?.getAnnotationUseSiteTarget() val target = entry.useSiteTarget?.getAnnotationUseSiteTarget()
@@ -105,8 +104,7 @@ class LazyAnnotationDescriptor(
private val scope = if (c.scope.ownerDescriptor is PackageFragmentDescriptor) { private val scope = if (c.scope.ownerDescriptor is PackageFragmentDescriptor) {
LexicalScope.Base(c.scope, FileDescriptorForVisibilityChecks(source, c.scope.ownerDescriptor)) LexicalScope.Base(c.scope, FileDescriptorForVisibilityChecks(source, c.scope.ownerDescriptor))
} } else {
else {
c.scope c.scope
} }
@@ -52,14 +52,20 @@ open class LazyClassMemberScope(
) : AbstractLazyMemberScope<ClassDescriptorWithResolutionScopes, ClassMemberDeclarationProvider>(c, declarationProvider, thisClass, trace) { ) : AbstractLazyMemberScope<ClassDescriptorWithResolutionScopes, ClassMemberDeclarationProvider>(c, declarationProvider, thisClass, trace) {
private val descriptorsFromDeclaredElements = storageManager.createLazyValue { private val descriptorsFromDeclaredElements = storageManager.createLazyValue {
computeDescriptorsFromDeclaredElements(DescriptorKindFilter.ALL, MemberScope.ALL_NAME_FILTER, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) computeDescriptorsFromDeclaredElements(
DescriptorKindFilter.ALL,
MemberScope.ALL_NAME_FILTER,
NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS
)
} }
private val extraDescriptors: NotNullLazyValue<Collection<DeclarationDescriptor>> = storageManager.createLazyValue { private val extraDescriptors: NotNullLazyValue<Collection<DeclarationDescriptor>> = storageManager.createLazyValue {
computeExtraDescriptors(NoLookupLocation.FOR_ALREADY_TRACKED) computeExtraDescriptors(NoLookupLocation.FOR_ALREADY_TRACKED)
} }
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, override fun getContributedDescriptors(
nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> { kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
val result = LinkedHashSet(descriptorsFromDeclaredElements()) val result = LinkedHashSet(descriptorsFromDeclaredElements())
result.addAll(extraDescriptors()) result.addAll(extraDescriptors())
return result return result
@@ -71,8 +77,7 @@ open class LazyClassMemberScope(
for (descriptor in supertype.memberScope.getContributedDescriptors()) { for (descriptor in supertype.memberScope.getContributedDescriptors()) {
if (descriptor is FunctionDescriptor) { if (descriptor is FunctionDescriptor) {
result.addAll(getContributedFunctions(descriptor.name, location)) result.addAll(getContributedFunctions(descriptor.name, location))
} } else if (descriptor is PropertyDescriptor) {
else if (descriptor is PropertyDescriptor) {
result.addAll(getContributedVariables(descriptor.name, location)) result.addAll(getContributedVariables(descriptor.name, location))
} }
// Nothing else is inherited // Nothing else is inherited
@@ -123,8 +128,8 @@ open class LazyClassMemberScope(
fun extract(extractFrom: KotlinType, name: Name): Collection<T> fun extract(extractFrom: KotlinType, name: Name): Collection<T>
} }
private val primaryConstructor: NullableLazyValue<ClassConstructorDescriptor> private val primaryConstructor: NullableLazyValue<ClassConstructorDescriptor> =
= c.storageManager.createNullableLazyValue { resolvePrimaryConstructor() } c.storageManager.createNullableLazyValue { resolvePrimaryConstructor() }
override fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration): LexicalScope = override fun getScopeForMemberDeclarationResolution(declaration: KtDeclaration): LexicalScope =
thisDescriptor.scopeForMemberDeclarationResolution thisDescriptor.scopeForMemberDeclarationResolution
@@ -132,21 +137,47 @@ open class LazyClassMemberScope(
override fun getScopeForInitializerResolution(declaration: KtDeclaration): LexicalScope = override fun getScopeForInitializerResolution(declaration: KtDeclaration): LexicalScope =
thisDescriptor.scopeForInitializerResolution thisDescriptor.scopeForInitializerResolution
private fun <D : CallableMemberDescriptor> generateFakeOverrides(name: Name, fromSupertypes: Collection<D>, result: MutableCollection<D>, exactDescriptorClass: Class<out D>) { private fun <D : CallableMemberDescriptor> generateFakeOverrides(
OverridingUtil.generateOverridesInFunctionGroup(name, fromSupertypes, ArrayList(result), thisDescriptor, object : OverridingStrategy() { name: Name,
fromSupertypes: Collection<D>,
result: MutableCollection<D>,
exactDescriptorClass: Class<out D>
) {
OverridingUtil.generateOverridesInFunctionGroup(
name,
fromSupertypes,
ArrayList(result),
thisDescriptor,
object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) { override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
assert(exactDescriptorClass.isInstance(fakeOverride)) { "Wrong descriptor type in an override: " + fakeOverride + " while expecting " + exactDescriptorClass.simpleName } assert(exactDescriptorClass.isInstance(fakeOverride)) { "Wrong descriptor type in an override: " + fakeOverride + " while expecting " + exactDescriptorClass.simpleName }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
result.add(fakeOverride as D) result.add(fakeOverride as D)
} }
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) { override fun overrideConflict(
reportOnDeclarationOrFail(trace, fromCurrent) { Errors.CONFLICTING_OVERLOADS.on(it, listOf(fromCurrent, fromSuper)) } fromSuper: CallableMemberDescriptor,
fromCurrent: CallableMemberDescriptor
) {
reportOnDeclarationOrFail(
trace,
fromCurrent
) { Errors.CONFLICTING_OVERLOADS.on(it, listOf(fromCurrent, fromSuper)) }
} }
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) { override fun inheritanceConflict(
reportOnDeclarationAs<KtClassOrObject>(trace, thisDescriptor) { ktClassOrObject -> first: CallableMemberDescriptor,
Errors.CONFLICTING_INHERITED_MEMBERS.on(ktClassOrObject, thisDescriptor, listOf(first, second)) second: CallableMemberDescriptor
) {
reportOnDeclarationAs<KtClassOrObject>(
trace,
thisDescriptor
) { ktClassOrObject ->
Errors.CONFLICTING_INHERITED_MEMBERS.on(
ktClassOrObject,
thisDescriptor,
listOf(first, second)
)
} }
} }
}) })
@@ -205,9 +236,11 @@ open class LazyClassMemberScope(
++componentIndex ++componentIndex
if (name == DataClassDescriptorResolver.createComponentName(componentIndex)) { if (name == DataClassDescriptorResolver.createComponentName(componentIndex)) {
result.add(DataClassDescriptorResolver.createComponentFunctionDescriptor( result.add(
DataClassDescriptorResolver.createComponentFunctionDescriptor(
componentIndex, property, parameter, thisDescriptor, trace componentIndex, property, parameter, thisDescriptor, trace
)) )
)
break break
} }
} }
@@ -253,11 +286,21 @@ open class LazyClassMemberScope(
} }
private fun addSyntheticFunctions(result: MutableCollection<DeclarationDescriptor>, location: LookupLocation) { private fun addSyntheticFunctions(result: MutableCollection<DeclarationDescriptor>, location: LookupLocation) {
result.addAll(c.syntheticResolveExtension.getSyntheticFunctionNames(thisDescriptor).flatMap { getContributedFunctions(it, location) }.toList()) result.addAll(c.syntheticResolveExtension.getSyntheticFunctionNames(thisDescriptor).flatMap {
getContributedFunctions(
it,
location
)
}.toList())
} }
private fun addSyntheticNestedClasses(result: MutableCollection<DeclarationDescriptor>, location: LookupLocation) { private fun addSyntheticNestedClasses(result: MutableCollection<DeclarationDescriptor>, location: LookupLocation) {
result.addAll(c.syntheticResolveExtension.getSyntheticNestedClassNames(thisDescriptor).mapNotNull { getContributedClassifier(it, location) }.toList()) result.addAll(c.syntheticResolveExtension.getSyntheticNestedClassNames(thisDescriptor).mapNotNull {
getContributedClassifier(
it,
location
)
}.toList())
} }
private fun generateSyntheticCompanionObject(name: Name, result: MutableSet<ClassDescriptor>) { private fun generateSyntheticCompanionObject(name: Name, result: MutableSet<ClassDescriptor>) {
@@ -316,13 +359,18 @@ open class LazyClassMemberScope(
if (parameter.hasValOrVar()) { if (parameter.hasValOrVar()) {
val propertyDescriptor = c.descriptorResolver.resolvePrimaryConstructorParameterToAProperty( val propertyDescriptor = c.descriptorResolver.resolvePrimaryConstructorParameterToAProperty(
// TODO: can't test because we get types from cache for this case // TODO: can't test because we get types from cache for this case
thisDescriptor, valueParameterDescriptor, thisDescriptor.scopeForConstructorHeaderResolution, parameter, trace) thisDescriptor, valueParameterDescriptor, thisDescriptor.scopeForConstructorHeaderResolution, parameter, trace
)
result.add(propertyDescriptor) result.add(propertyDescriptor)
} }
} }
} }
private fun <T : CallableMemberDescriptor> generateDelegatingDescriptors(name: Name, extractor: MemberExtractor<T>, existingDescriptors: Collection<CallableDescriptor>): Collection<T> { private fun <T : CallableMemberDescriptor> generateDelegatingDescriptors(
name: Name,
extractor: MemberExtractor<T>,
existingDescriptors: Collection<CallableDescriptor>
): Collection<T> {
val classOrObject = declarationProvider.correspondingClassOrObject ?: return setOf() val classOrObject = declarationProvider.correspondingClassOrObject ?: return setOf()
val lazyTypeResolver = object : DelegationResolver.TypeResolver { val lazyTypeResolver = object : DelegationResolver.TypeResolver {
@@ -358,8 +406,8 @@ open class LazyClassMemberScope(
result.addAll(getContributedFunctions(Name.identifier("copy"), location)) result.addAll(getContributedFunctions(Name.identifier("copy"), location))
} }
private val secondaryConstructors: NotNullLazyValue<Collection<ClassConstructorDescriptor>> private val secondaryConstructors: NotNullLazyValue<Collection<ClassConstructorDescriptor>> =
= c.storageManager.createLazyValue { resolveSecondaryConstructors() } c.storageManager.createLazyValue { resolveSecondaryConstructors() }
fun getConstructors(): Collection<ClassConstructorDescriptor> { fun getConstructors(): Collection<ClassConstructorDescriptor> {
val result = secondaryConstructors() val result = secondaryConstructors()
@@ -380,7 +428,8 @@ open class LazyClassMemberScope(
if (DescriptorUtils.canHaveDeclaredConstructors(thisDescriptor) || hasPrimaryConstructor) { if (DescriptorUtils.canHaveDeclaredConstructors(thisDescriptor) || hasPrimaryConstructor) {
val constructor = c.functionDescriptorResolver.resolvePrimaryConstructorDescriptor( val constructor = c.functionDescriptorResolver.resolvePrimaryConstructorDescriptor(
thisDescriptor.scopeForConstructorHeaderResolution, thisDescriptor, classOrObject, trace) thisDescriptor.scopeForConstructorHeaderResolution, thisDescriptor, classOrObject, trace
)
constructor ?: return null constructor ?: return null
setDeferredReturnType(constructor) setDeferredReturnType(constructor)
return constructor return constructor
@@ -29,10 +29,18 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
class LazyPackageMemberScope( class LazyPackageMemberScope(
private val resolveSession: ResolveSession, private val resolveSession: ResolveSession,
declarationProvider: PackageMemberDeclarationProvider, declarationProvider: PackageMemberDeclarationProvider,
thisPackage: PackageFragmentDescriptor) thisPackage: PackageFragmentDescriptor
: AbstractLazyMemberScope<PackageFragmentDescriptor, PackageMemberDeclarationProvider>(resolveSession, declarationProvider, thisPackage, resolveSession.trace) { ) : AbstractLazyMemberScope<PackageFragmentDescriptor, PackageMemberDeclarationProvider>(
resolveSession,
declarationProvider,
thisPackage,
resolveSession.trace
) {
override fun getContributedDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> { override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
return computeDescriptorsFromDeclaredElements(kindFilter, nameFilter, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) return computeDescriptorsFromDeclaredElements(kindFilter, nameFilter, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS)
} }
@@ -30,8 +30,8 @@ class LazyScriptClassMemberScope(
resolveSession: ResolveSession, resolveSession: ResolveSession,
declarationProvider: ClassMemberDeclarationProvider, declarationProvider: ClassMemberDeclarationProvider,
private val scriptDescriptor: LazyScriptDescriptor, private val scriptDescriptor: LazyScriptDescriptor,
trace: BindingTrace) trace: BindingTrace
: LazyClassMemberScope(resolveSession, declarationProvider, scriptDescriptor, trace) { ) : LazyClassMemberScope(resolveSession, declarationProvider, scriptDescriptor, trace) {
override fun resolvePrimaryConstructor(): ClassConstructorDescriptor? { override fun resolvePrimaryConstructor(): ClassConstructorDescriptor? {
val constructor = ClassConstructorDescriptorImpl.create( val constructor = ClassConstructorDescriptorImpl.create(
@@ -49,7 +49,8 @@ class LazyScriptClassMemberScope(
} }
private fun createScriptParameters(constructor: ClassConstructorDescriptorImpl): List<ValueParameterDescriptor> { private fun createScriptParameters(constructor: ClassConstructorDescriptorImpl): List<ValueParameterDescriptor> {
return ScriptHelper.getInstance().getScriptParameters(scriptDescriptor.scriptDefinition, scriptDescriptor).mapIndexed { index, (name, type) -> return ScriptHelper.getInstance().getScriptParameters(scriptDescriptor.scriptDefinition, scriptDescriptor)
.mapIndexed { index, (name, type) ->
ValueParameterDescriptorImpl( ValueParameterDescriptorImpl(
constructor, null, index, Annotations.EMPTY, name, type, constructor, null, index, Annotations.EMPTY, name, type,
/* declaresDefaultValue = */ false, /* declaresDefaultValue = */ false,
@@ -67,19 +67,28 @@ abstract class AbstractLocalRedeclarationChecker(val overloadChecker: OverloadCh
class ThrowingLocalRedeclarationChecker(overloadChecker: OverloadChecker) : AbstractLocalRedeclarationChecker(overloadChecker) { class ThrowingLocalRedeclarationChecker(overloadChecker: OverloadChecker) : AbstractLocalRedeclarationChecker(overloadChecker) {
override fun handleRedeclaration(first: DeclarationDescriptor, second: DeclarationDescriptor) { override fun handleRedeclaration(first: DeclarationDescriptor, second: DeclarationDescriptor) {
throw IllegalStateException(String.format("Redeclaration: %s (%s) and %s (%s) (no line info available)", throw IllegalStateException(
String.format(
"Redeclaration: %s (%s) and %s (%s) (no line info available)",
DescriptorUtils.getFqName(first), first, DescriptorUtils.getFqName(first), first,
DescriptorUtils.getFqName(second), second)) DescriptorUtils.getFqName(second), second
)
)
} }
override fun handleConflictingOverloads(first: CallableMemberDescriptor, second: CallableMemberDescriptor) { override fun handleConflictingOverloads(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
throw IllegalStateException(String.format("Conflicting overloads: %s (%s) and %s (%s) (no line info available)", throw IllegalStateException(
String.format(
"Conflicting overloads: %s (%s) and %s (%s) (no line info available)",
DescriptorUtils.getFqName(first), first, DescriptorUtils.getFqName(first), first,
DescriptorUtils.getFqName(second), second)) DescriptorUtils.getFqName(second), second
)
)
} }
} }
class TraceBasedLocalRedeclarationChecker(val trace: BindingTrace, overloadChecker: OverloadChecker): AbstractLocalRedeclarationChecker(overloadChecker) { class TraceBasedLocalRedeclarationChecker(val trace: BindingTrace, overloadChecker: OverloadChecker) :
AbstractLocalRedeclarationChecker(overloadChecker) {
override fun handleRedeclaration(first: DeclarationDescriptor, second: DeclarationDescriptor) { override fun handleRedeclaration(first: DeclarationDescriptor, second: DeclarationDescriptor) {
reportOnDeclarationOrFail(trace, first) { Errors.REDECLARATION.on(it, listOf(first, second)) } reportOnDeclarationOrFail(trace, first) { Errors.REDECLARATION.on(it, listOf(first, second)) }
reportOnDeclarationOrFail(trace, second) { Errors.REDECLARATION.on(it, listOf(first, second)) } reportOnDeclarationOrFail(trace, second) { Errors.REDECLARATION.on(it, listOf(first, second)) }
@@ -107,8 +107,7 @@ class DoubleColonExpressionResolver(
if (expression.isEmptyLHS) { if (expression.isEmptyLHS) {
// "::class" will maybe mean "this::class", a class of "this" instance // "::class" will maybe mean "this::class", a class of "this" instance
c.trace.report(UNSUPPORTED.on(expression, "Class literals with empty left hand side are not yet supported")) c.trace.report(UNSUPPORTED.on(expression, "Class literals with empty left hand side are not yet supported"))
} } else {
else {
val result = resolveDoubleColonLHS(expression, c) val result = resolveDoubleColonLHS(expression, c)
if (result != null && !result.type.isError) { if (result != null && !result.type.isError) {
val inherentType = result.type val inherentType = result.type
@@ -158,8 +157,7 @@ class DoubleColonExpressionResolver(
// Note that "T::class" is allowed for type parameter T without a non-null upper bound // Note that "T::class" is allowed for type parameter T without a non-null upper bound
else if ((TypeUtils.isNullableType(type) && descriptor !is TypeParameterDescriptor) || expression.hasQuestionMarks) { else if ((TypeUtils.isNullableType(type) && descriptor !is TypeParameterDescriptor) || expression.hasQuestionMarks) {
c.trace.report(NULLABLE_TYPE_IN_CLASS_LITERAL_LHS.on(expression)) c.trace.report(NULLABLE_TYPE_IN_CLASS_LITERAL_LHS.on(expression))
} } else if (!result.possiblyBareType.isBare && !isAllowedInClassLiteral(type)) {
else if (!result.possiblyBareType.isBare && !isAllowedInClassLiteral(type)) {
c.trace.report(CLASS_LITERAL_LHS_NOT_A_CLASS.on(expression)) c.trace.report(CLASS_LITERAL_LHS_NOT_A_CLASS.on(expression))
} }
for (additionalChecker in additionalCheckers) { for (additionalChecker in additionalCheckers) {
@@ -205,7 +203,12 @@ class DoubleColonExpressionResolver(
private fun reportUnsupportedIfNeeded(expression: KtDoubleColonExpression, c: ExpressionTypingContext) { private fun reportUnsupportedIfNeeded(expression: KtDoubleColonExpression, c: ExpressionTypingContext) {
if (!languageVersionSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) { if (!languageVersionSettings.supportsFeature(LanguageFeature.BoundCallableReferences)) {
c.trace.report(UNSUPPORTED_FEATURE.on(expression.receiverExpression!!, LanguageFeature.BoundCallableReferences to languageVersionSettings)) c.trace.report(
UNSUPPORTED_FEATURE.on(
expression.receiverExpression!!,
LanguageFeature.BoundCallableReferences to languageVersionSettings
)
)
} }
} }
@@ -228,8 +231,7 @@ class DoubleColonExpressionResolver(
val receiver = finger.receiverExpression val receiver = finger.receiverExpression
if (receiver is KtQualifiedExpression) { if (receiver is KtQualifiedExpression) {
finger = receiver finger = receiver
} } else {
else {
result.push(receiver) result.push(receiver)
return result.toList() return result.toList()
} }
@@ -266,8 +268,7 @@ class DoubleColonExpressionResolver(
} }
private fun resolveReservedExpressionOnLHS(expression: KtExpression, c: ExpressionTypingContext): DoubleColonLHS.Expression? { private fun resolveReservedExpressionOnLHS(expression: KtExpression, c: ExpressionTypingContext): DoubleColonLHS.Expression? {
val doubleColonExpression = expression.parent as? KtDoubleColonExpression ?: val doubleColonExpression = expression.parent as? KtDoubleColonExpression ?: return null // should assert here?
return null // should assert here?
if (expression is KtCallExpression && expression.typeArguments.isNotEmpty()) { if (expression is KtCallExpression && expression.typeArguments.isNotEmpty()) {
val callee = expression.calleeExpression ?: return null val callee = expression.calleeExpression ?: return null
@@ -279,11 +280,9 @@ class DoubleColonExpressionResolver(
} }
return calleeAsDoubleColonLHS return calleeAsDoubleColonLHS
} } else if (doubleColonExpression.hasQuestionMarks) {
else if (doubleColonExpression.hasQuestionMarks) {
return resolveExpressionOnLHS(expression, c) return resolveExpressionOnLHS(expression, c)
} } else {
else {
return null return null
} }
} }
@@ -293,7 +292,8 @@ class DoubleColonExpressionResolver(
val newExpression = expression.buildNewExpressionForReservedGenericPropertyCallChainResolution() ?: return null val newExpression = expression.buildNewExpressionForReservedGenericPropertyCallChainResolution() ?: return null
val temporaryTraceAndCache = TemporaryTraceAndCache.create(c, "resolve reserved generic property call chain in '::' LHS", newExpression) val temporaryTraceAndCache =
TemporaryTraceAndCache.create(c, "resolve reserved generic property call chain in '::' LHS", newExpression)
val contextForCallChainResolution = val contextForCallChainResolution =
c.replaceTraceAndCache(temporaryTraceAndCache) c.replaceTraceAndCache(temporaryTraceAndCache)
.replaceExpectedType(NO_EXPECTED_TYPE) .replaceExpectedType(NO_EXPECTED_TYPE)
@@ -304,9 +304,11 @@ class DoubleColonExpressionResolver(
private fun resolveReservedExpressionSyntaxOnDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext): private fun resolveReservedExpressionSyntaxOnDoubleColonLHS(doubleColonExpression: KtDoubleColonExpression, c: ExpressionTypingContext):
Pair<Boolean, DoubleColonLHS?> { Pair<Boolean, DoubleColonLHS?> {
val resultForReservedExpr = tryResolveLHS(doubleColonExpression, c, val resultForReservedExpr = tryResolveLHS(
doubleColonExpression, c,
this::shouldTryResolveLHSAsReservedExpression, this::shouldTryResolveLHSAsReservedExpression,
this::resolveReservedExpressionOnLHS) this::resolveReservedExpressionOnLHS
)
if (resultForReservedExpr != null) { if (resultForReservedExpr != null) {
val lhs = resultForReservedExpr.lhs val lhs = resultForReservedExpr.lhs
if (lhs != null) { if (lhs != null) {
@@ -315,9 +317,11 @@ class DoubleColonExpressionResolver(
} }
} }
val resultForReservedCallChain = tryResolveLHS(doubleColonExpression, c, val resultForReservedCallChain = tryResolveLHS(
doubleColonExpression, c,
this::shouldTryResolveLHSAsReservedCallChain, this::shouldTryResolveLHSAsReservedCallChain,
this::resolveReservedCallChainOnLHS) this::resolveReservedCallChainOnLHS
)
if (resultForReservedCallChain != null) { if (resultForReservedCallChain != null) {
val lhs = resultForReservedCallChain.lhs val lhs = resultForReservedCallChain.lhs
if (lhs != null) { if (lhs != null) {
@@ -473,8 +477,7 @@ class DoubleColonExpressionResolver(
Annotations.EMPTY, descriptor.typeConstructor, arguments, Annotations.EMPTY, descriptor.typeConstructor, arguments,
possiblyBareType.isNullable || doubleColonExpression.hasQuestionMarks possiblyBareType.isNullable || doubleColonExpression.hasQuestionMarks
) )
} } else {
else {
val actualType = possiblyBareType.actualType val actualType = possiblyBareType.actualType
if (doubleColonExpression.hasQuestionMarks) actualType.makeNullable() else actualType if (doubleColonExpression.hasQuestionMarks) actualType.makeNullable() else actualType
} }
@@ -526,8 +529,7 @@ class DoubleColonExpressionResolver(
if (resolutionResults != null && !resolutionResults.isNothing) { if (resolutionResults != null && !resolutionResults.isNothing) {
val resolvedCall = OverloadResolutionResultsUtil.getResultingCall(resolutionResults, context) val resolvedCall = OverloadResolutionResultsUtil.getResultingCall(resolutionResults, context)
resolvedCall?.resultingDescriptor ?: return null resolvedCall?.resultingDescriptor ?: return null
} } else {
else {
if (lhs != null || expression.isEmptyLHS) { if (lhs != null || expression.isEmptyLHS) {
context.trace.report(UNRESOLVED_REFERENCE.on(expression.callableReference, expression.callableReference)) context.trace.report(UNRESOLVED_REFERENCE.on(expression.callableReference, expression.callableReference))
} }
@@ -553,9 +555,11 @@ class DoubleColonExpressionResolver(
if (!languageVersionSettings.supportsFeature(LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS)) { if (!languageVersionSettings.supportsFeature(LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS)) {
if (expression.isEmptyLHS && if (expression.isEmptyLHS &&
(descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) { (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) {
trace.report(UNSUPPORTED_FEATURE.on( trace.report(
UNSUPPORTED_FEATURE.on(
simpleName, LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS to languageVersionSettings simpleName, LanguageFeature.CallableReferencesToClassMembersWithEmptyLHS to languageVersionSettings
)) )
)
} }
} }
if (descriptor is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(descriptor.containingDeclaration)) { if (descriptor is ConstructorDescriptor && DescriptorUtils.isAnnotationClass(descriptor.containingDeclaration)) {
@@ -594,7 +598,11 @@ class DoubleColonExpressionResolver(
context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor) context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor)
} }
internal fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) { internal fun bindPropertyReference(
expression: KtCallableReferenceExpression,
referenceType: KotlinType,
context: ResolutionContext<*>
) {
val localVariable = LocalVariableDescriptor( val localVariable = LocalVariableDescriptor(
context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType, context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType,
expression.toSourceElement() expression.toSourceElement()
@@ -652,7 +660,8 @@ class DoubleColonExpressionResolver(
): ResolutionResultsAndTraceCommitCallback? { ): ResolutionResultsAndTraceCommitCallback? {
// we should preserve information about `call` because callable references are analyzed two times, // we should preserve information about `call` because callable references are analyzed two times,
// otherwise there will be not completed calls in trace // otherwise there will be not completed calls in trace
val call = outerContext.trace[BindingContext.CALL, reference] ?: CallMaker.makeCall(reference, receiver, null, reference, emptyList()) val call =
outerContext.trace[BindingContext.CALL, reference] ?: CallMaker.makeCall(reference, receiver, null, reference, emptyList())
val temporaryTrace = TemporaryTraceAndCache.create(outerContext, traceTitle, reference) val temporaryTrace = TemporaryTraceAndCache.create(outerContext, traceTitle, reference)
val newContext = val newContext =
if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS) if (resolutionMode == ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS)
@@ -773,8 +782,10 @@ class DoubleColonExpressionResolver(
val returnType = descriptor.returnType ?: return null val returnType = descriptor.returnType ?: return null
val parametersTypes = descriptor.valueParameters.map { it.type } val parametersTypes = descriptor.valueParameters.map { it.type }
val parametersNames = descriptor.valueParameters.map { it.name } val parametersNames = descriptor.valueParameters.map { it.name }
return reflectionTypes.getKFunctionType(Annotations.EMPTY, receiverType, return reflectionTypes.getKFunctionType(
parametersTypes, parametersNames, returnType, descriptor.builtIns) Annotations.EMPTY, receiverType,
parametersTypes, parametersNames, returnType, descriptor.builtIns
)
} }
is PropertyDescriptor -> { is PropertyDescriptor -> {
val mutable = descriptor.isVar && run { val mutable = descriptor.isVar && run {
@@ -58,7 +58,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo) context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo)
} }
val resultTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo.replaceType(components.builtIns.booleanType), expression, contextWithExpectedType) val resultTypeInfo = components.dataFlowAnalyzer.checkType(
typeInfo.replaceType(components.builtIns.booleanType),
expression,
contextWithExpectedType
)
if (typeReference != null) { if (typeReference != null) {
val rhsType = context.trace[BindingContext.TYPE, typeReference] val rhsType = context.trace[BindingContext.TYPE, typeReference]
@@ -103,7 +107,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
} ?: DataFlowValue.nullValue(components.builtIns) } ?: DataFlowValue.nullValue(components.builtIns)
val possibleTypesForSubject = subjectTypeInfo?.dataFlowInfo?.getStableTypes( val possibleTypesForSubject = subjectTypeInfo?.dataFlowInfo?.getStableTypes(
subjectDataFlowValue, components.languageVersionSettings) ?: emptySet() subjectDataFlowValue, components.languageVersionSettings
) ?: emptySet()
checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subjectType, possibleTypesForSubject) checkSmartCastsInSubjectIfRequired(expression, contextBeforeSubject, subjectType, possibleTypesForSubject)
val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType) val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType)
@@ -120,8 +125,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
// Without else expression in non-exhaustive when, we *must* take initial data flow info into account, // Without else expression in non-exhaustive when, we *must* take initial data flow info into account,
// because data flow can bypass all when branches in this case // because data flow can bypass all when branches in this case
branchesDataFlowInfo.or(contextAfterSubject.dataFlowInfo) branchesDataFlowInfo.or(contextAfterSubject.dataFlowInfo)
} } else {
else {
branchesDataFlowInfo branchesDataFlowInfo
} }
@@ -147,7 +151,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val wrappedArgumentExpressions = wrapWhenEntryExpressionsAsSpecialCallArguments(expression) val wrappedArgumentExpressions = wrapWhenEntryExpressionsAsSpecialCallArguments(expression)
val callForWhen = createCallForSpecialConstruction(expression, expression, wrappedArgumentExpressions) val callForWhen = createCallForSpecialConstruction(expression, expression, wrappedArgumentExpressions)
val dataFlowInfoForArguments = createDataFlowInfoForArgumentsOfWhenCall(callForWhen, contextAfterSubject.dataFlowInfo, dataFlowInfoForEntries) val dataFlowInfoForArguments =
createDataFlowInfoForArgumentsOfWhenCall(callForWhen, contextAfterSubject.dataFlowInfo, dataFlowInfoForEntries)
val resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall( val resolvedCall = components.controlStructureTypingUtils.resolveSpecialConstructionAsCall(
callForWhen, ResolveConstruct.WHEN, callForWhen, ResolveConstruct.WHEN,
@@ -156,7 +161,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
override val size: Int get() = wrappedArgumentExpressions.size override val size: Int get() = wrappedArgumentExpressions.size
}, },
Collections.nCopies(wrappedArgumentExpressions.size, false), Collections.nCopies(wrappedArgumentExpressions.size, false),
contextWithExpectedType, dataFlowInfoForArguments) contextWithExpectedType, dataFlowInfoForArguments
)
return resolvedCall.resultingDescriptor.returnType return resolvedCall.resultingDescriptor.returnType
} }
@@ -179,9 +185,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val argumentDataFlowInfos = ArrayList<DataFlowInfo>() val argumentDataFlowInfos = ArrayList<DataFlowInfo>()
var inputDataFlowInfo = contextAfterSubject.dataFlowInfo var inputDataFlowInfo = contextAfterSubject.dataFlowInfo
for (whenEntry in expression.entries) { for (whenEntry in expression.entries) {
val conditionsInfo = analyzeWhenEntryConditions(whenEntry, val conditionsInfo = analyzeWhenEntryConditions(
whenEntry,
contextAfterSubject.replaceDataFlowInfo(inputDataFlowInfo), contextAfterSubject.replaceDataFlowInfo(inputDataFlowInfo),
subjectExpression, subjectType, subjectDataFlowValue) subjectExpression, subjectType, subjectDataFlowValue
)
inputDataFlowInfo = inputDataFlowInfo.and(conditionsInfo.elseInfo) inputDataFlowInfo = inputDataFlowInfo.and(conditionsInfo.elseInfo)
if (whenEntry.expression != null) { if (whenEntry.expression != null) {
@@ -206,8 +214,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
for (whenEntry in expression.entries) { for (whenEntry in expression.entries) {
val entryExpression = whenEntry.expression ?: continue val entryExpression = whenEntry.expression ?: continue
val entryTypeInfo = BindingContextUtils.getRecordedTypeInfo(entryExpression, bindingContext) ?: val entryTypeInfo = BindingContextUtils.getRecordedTypeInfo(entryExpression, bindingContext) ?: continue
continue
val entryType = entryTypeInfo.type val entryType = entryTypeInfo.type
if (entryType == null) { if (entryType == null) {
errorTypeExistInBranch = true errorTypeExistInBranch = true
@@ -217,8 +224,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
if (whenResultValue != null && entryType != null) { if (whenResultValue != null && entryType != null) {
val entryValue = DataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject) val entryValue = DataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject)
entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue, components.languageVersionSettings) entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue, components.languageVersionSettings)
} } else {
else {
entryTypeInfo.dataFlowInfo entryTypeInfo.dataFlowInfo
} }
@@ -250,8 +256,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
for (possibleCastType in possibleTypesForSubject) { for (possibleCastType in possibleTypesForSubject) {
val possibleCastClass = possibleCastType.constructor.declarationDescriptor as? ClassDescriptor ?: continue val possibleCastClass = possibleCastType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
if (possibleCastClass.kind == ClassKind.ENUM_CLASS || possibleCastClass.modality == Modality.SEALED) { if (possibleCastClass.kind == ClassKind.ENUM_CLASS || possibleCastClass.modality == Modality.SEALED) {
if (checkSmartCastToExpectedTypeInSubject(contextBeforeSubject, subjectExpression, subjectType, if (checkSmartCastToExpectedTypeInSubject(
possibleCastType)) { contextBeforeSubject, subjectExpression, subjectType,
possibleCastType
)) {
return return
} }
} }
@@ -260,8 +268,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val bindingContext = contextBeforeSubject.trace.bindingContext val bindingContext = contextBeforeSubject.trace.bindingContext
if (isNullableType && !WhenChecker.containsNullCase(expression, bindingContext)) { if (isNullableType && !WhenChecker.containsNullCase(expression, bindingContext)) {
val notNullableType = TypeUtils.makeNotNullable(subjectType) val notNullableType = TypeUtils.makeNotNullable(subjectType)
if (checkSmartCastToExpectedTypeInSubject(contextBeforeSubject, subjectExpression, subjectType, if (checkSmartCastToExpectedTypeInSubject(
notNullableType)) { contextBeforeSubject, subjectExpression, subjectType,
notNullableType
)) {
return return
} }
} }
@@ -276,7 +286,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val trace = TemporaryBindingTrace.create(contextBeforeSubject.trace, "Temporary trace for when subject nullability") val trace = TemporaryBindingTrace.create(contextBeforeSubject.trace, "Temporary trace for when subject nullability")
val subjectContext = contextBeforeSubject.replaceExpectedType(expectedType).replaceBindingTrace(trace) val subjectContext = contextBeforeSubject.replaceExpectedType(expectedType).replaceBindingTrace(trace)
val castResult = DataFlowAnalyzer.checkPossibleCast( val castResult = DataFlowAnalyzer.checkPossibleCast(
subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext) subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext
)
if (castResult != null && castResult.isCorrect) { if (castResult != null && castResult.isCorrect) {
trace.commit() trace.commit()
return true return true
@@ -298,8 +309,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
var entryInfo: ConditionalDataFlowInfo? = null var entryInfo: ConditionalDataFlowInfo? = null
var contextForCondition = context var contextForCondition = context
for (condition in whenEntry.conditions) { for (condition in whenEntry.conditions) {
val conditionInfo = checkWhenCondition(subjectExpression, subjectType, condition, val conditionInfo = checkWhenCondition(
contextForCondition, subjectDataFlowValue) subjectExpression, subjectType, condition,
contextForCondition, subjectDataFlowValue
)
entryInfo = entryInfo?.let { entryInfo = entryInfo?.let {
ConditionalDataFlowInfo(it.thenInfo.or(conditionInfo.thenInfo), it.elseInfo.and(conditionInfo.elseInfo)) ConditionalDataFlowInfo(it.thenInfo.or(conditionInfo.thenInfo), it.elseInfo.and(conditionInfo.elseInfo))
} ?: conditionInfo } ?: conditionInfo
@@ -328,8 +341,10 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
return return
} }
val argumentForSubject = CallMaker.makeExternalValueArgument(subjectExpression) val argumentForSubject = CallMaker.makeExternalValueArgument(subjectExpression)
val typeInfo = facade.checkInExpression(condition, condition.operationReference, val typeInfo = facade.checkInExpression(
argumentForSubject, rangeExpression, context) condition, condition.operationReference,
argumentForSubject, rangeExpression, context
)
val dataFlowInfo = typeInfo.dataFlowInfo val dataFlowInfo = typeInfo.dataFlowInfo
newDataFlowInfo = ConditionalDataFlowInfo(dataFlowInfo) newDataFlowInfo = ConditionalDataFlowInfo(dataFlowInfo)
val type = typeInfo.type val type = typeInfo.type
@@ -347,8 +362,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val result = checkTypeForIs(context, condition, condition.isNegated, subjectType, typeReference, subjectDataFlowValue) val result = checkTypeForIs(context, condition, condition.isNegated, subjectType, typeReference, subjectDataFlowValue)
newDataFlowInfo = if (condition.isNegated) { newDataFlowInfo = if (condition.isNegated) {
ConditionalDataFlowInfo(result.elseInfo, result.thenInfo) ConditionalDataFlowInfo(result.elseInfo, result.thenInfo)
} } else {
else {
result result
} }
val rhsType = context.trace[BindingContext.TYPE, typeReference] val rhsType = context.trace[BindingContext.TYPE, typeReference]
@@ -370,9 +384,11 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val expression = condition.expression val expression = condition.expression
if (expression != null) { if (expression != null) {
val basicDataFlowInfo = checkTypeForExpressionCondition( val basicDataFlowInfo = checkTypeForExpressionCondition(
context, expression, subjectType, subjectExpression == null, subjectDataFlowValue) context, expression, subjectType, subjectExpression == null, subjectDataFlowValue
)
val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor) val moduleDescriptor = DescriptorUtils.getContainingModule(context.scope.ownerDescriptor)
val dataFlowInfoFromES = components.effectSystem.getDataFlowInfoWhenEquals(subjectExpression, expression, context.trace, moduleDescriptor) val dataFlowInfoFromES =
components.effectSystem.getDataFlowInfoWhenEquals(subjectExpression, expression, context.trace, moduleDescriptor)
newDataFlowInfo = basicDataFlowInfo.and(dataFlowInfoFromES) newDataFlowInfo = basicDataFlowInfo.and(dataFlowInfoFromES)
} }
} }
@@ -409,12 +425,16 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val expressionDataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, newContext) val expressionDataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, newContext)
val result = noChange(newContext) val result = noChange(newContext)
return ConditionalDataFlowInfo( return ConditionalDataFlowInfo(
result.thenInfo.equate(subjectDataFlowValue, expressionDataFlowValue, result.thenInfo.equate(
subjectDataFlowValue, expressionDataFlowValue,
identityEquals = DataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression), identityEquals = DataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression),
languageVersionSettings = components.languageVersionSettings), languageVersionSettings = components.languageVersionSettings
result.elseInfo.disequate(subjectDataFlowValue, ),
result.elseInfo.disequate(
subjectDataFlowValue,
expressionDataFlowValue, expressionDataFlowValue,
components.languageVersionSettings) components.languageVersionSettings
)
) )
} }
@@ -426,9 +446,16 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
typeReferenceAfterIs: KtTypeReference, typeReferenceAfterIs: KtTypeReference,
subjectDataFlowValue: DataFlowValue subjectDataFlowValue: DataFlowValue
): ConditionalDataFlowInfo { ): ConditionalDataFlowInfo {
val typeResolutionContext = TypeResolutionContext(context.scope, context.trace, true, /*allowBareTypes=*/ true, context.isDebuggerContext) val typeResolutionContext =
TypeResolutionContext(context.scope, context.trace, true, /*allowBareTypes=*/ true, context.isDebuggerContext)
val possiblyBareTarget = components.typeResolver.resolvePossiblyBareType(typeResolutionContext, typeReferenceAfterIs) val possiblyBareTarget = components.typeResolver.resolvePossiblyBareType(typeResolutionContext, typeReferenceAfterIs)
val targetType = TypeReconstructionUtil.reconstructBareType(typeReferenceAfterIs, possiblyBareTarget, subjectType, context.trace, components.builtIns) val targetType = TypeReconstructionUtil.reconstructBareType(
typeReferenceAfterIs,
possiblyBareTarget,
subjectType,
context.trace,
components.builtIns
)
if (targetType.isDynamic()) { if (targetType.isDynamic()) {
context.trace.report(DYNAMIC_NOT_ALLOWED.on(typeReferenceAfterIs)) context.trace.report(DYNAMIC_NOT_ALLOWED.on(typeReferenceAfterIs))
@@ -464,7 +491,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
) { ) {
if (subjectType.containsError() || targetType.containsError()) return if (subjectType.containsError() || targetType.containsError()) return
val possibleTypes = DataFlowAnalyzer.getAllPossibleTypes(subjectType, context, subjectDataFlowValue, context.languageVersionSettings) val possibleTypes =
DataFlowAnalyzer.getAllPossibleTypes(subjectType, context, subjectDataFlowValue, context.languageVersionSettings)
if (CastDiagnosticsUtil.isRefinementUseless(possibleTypes, targetType, false)) { if (CastDiagnosticsUtil.isRefinementUseless(possibleTypes, targetType, false)) {
context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated)) context.trace.report(Errors.USELESS_IS_CHECK.on(isCheck, !negated))
} }
@@ -53,8 +53,10 @@ class PreliminaryDeclarationVisitor(
fun createForDeclaration(declaration: KtDeclaration, trace: BindingTrace, languageVersionSettings: LanguageVersionSettings) { fun createForDeclaration(declaration: KtDeclaration, trace: BindingTrace, languageVersionSettings: LanguageVersionSettings) {
val visitorOwner = topMostNonClassDeclaration(declaration) val visitorOwner = topMostNonClassDeclaration(declaration)
if (trace.get(BindingContext.PRELIMINARY_VISITOR, visitorOwner) != null) return if (trace.get(BindingContext.PRELIMINARY_VISITOR, visitorOwner) != null) return
trace.record(BindingContext.PRELIMINARY_VISITOR, visitorOwner, trace.record(
PreliminaryDeclarationVisitor(visitorOwner, languageVersionSettings)) BindingContext.PRELIMINARY_VISITOR, visitorOwner,
PreliminaryDeclarationVisitor(visitorOwner, languageVersionSettings)
)
} }
fun getVisitorByVariable(variableDescriptor: VariableDescriptor, bindingContext: BindingContext): PreliminaryDeclarationVisitor? { fun getVisitorByVariable(variableDescriptor: VariableDescriptor, bindingContext: BindingContext): PreliminaryDeclarationVisitor? {
@@ -33,8 +33,7 @@ protected constructor(
val (app, extensions) = cached val (app, extensions) = cached
return if (app == ApplicationManager.getApplication()) { return if (app == ApplicationManager.getApplication()) {
extensions extensions
} } else {
else {
update() update()
} }
} }
@@ -50,6 +49,7 @@ protected constructor(
class ExtensionProvider<T>(epName: ExtensionPointName<T>) : MappedExtensionProvider<T, List<T>>(epName, { it }) { class ExtensionProvider<T>(epName: ExtensionPointName<T>) : MappedExtensionProvider<T, List<T>>(epName, { it }) {
companion object { companion object {
@JvmStatic fun <T> create(epName: ExtensionPointName<T>): ExtensionProvider<T> = ExtensionProvider(epName) @JvmStatic
fun <T> create(epName: ExtensionPointName<T>): ExtensionProvider<T> = ExtensionProvider(epName)
} }
} }
@@ -51,7 +51,8 @@ abstract class PerformanceCounter protected constructor(val name: String) {
} }
} }
@JvmOverloads fun create(name: String, reenterable: Boolean = false): PerformanceCounter { @JvmOverloads
fun create(name: String, reenterable: Boolean = false): PerformanceCounter {
return if (reenterable) return if (reenterable)
ReenterableCounter(name) ReenterableCounter(name)
else else
@@ -92,8 +93,7 @@ abstract class PerformanceCounter protected constructor(val name: String) {
excludedFrom.forEach { it.enterExcludedMethod() } excludedFrom.forEach { it.enterExcludedMethod() }
try { try {
return countTime(block) return countTime(block)
} } finally {
finally {
excludedFrom.forEach { it.exitExcludedMethod() } excludedFrom.forEach { it.exitExcludedMethod() }
} }
} }
@@ -112,8 +112,7 @@ abstract class PerformanceCounter protected constructor(val name: String) {
fun report(consumer: (String) -> Unit) { fun report(consumer: (String) -> Unit) {
if (totalTimeNanos == 0L) { if (totalTimeNanos == 0L) {
consumer("$name performed $count times") consumer("$name performed $count times")
} } else {
else {
val millis = TimeUnit.NANOSECONDS.toMillis(totalTimeNanos) val millis = TimeUnit.NANOSECONDS.toMillis(totalTimeNanos)
consumer("$name performed $count times, total time $millis ms") consumer("$name performed $count times, total time $millis ms")
} }
@@ -125,8 +124,7 @@ private class SimpleCounter(name: String): PerformanceCounter(name) {
val startTime = PerformanceCounter.currentTime() val startTime = PerformanceCounter.currentTime()
try { try {
return block() return block()
} } finally {
finally {
incrementTime(PerformanceCounter.currentTime() - startTime) incrementTime(PerformanceCounter.currentTime() - startTime)
} }
} }
@@ -148,8 +146,7 @@ private class ReenterableCounter(name: String): PerformanceCounter(name) {
val needTime = enterCounter(this) val needTime = enterCounter(this)
try { try {
return block() return block()
} } finally {
finally {
if (needTime) { if (needTime) {
incrementTime(PerformanceCounter.currentTime() - startTime) incrementTime(PerformanceCounter.currentTime() - startTime)
leaveCounter(this) leaveCounter(this)
@@ -168,8 +165,8 @@ internal class CounterWithExclude(name: String, vararg excludedCounters: Perform
companion object { companion object {
private val counterToCallStackMapThreadLocal = ThreadLocal<MutableMap<CounterWithExclude, CallStackWithTime>>() private val counterToCallStackMapThreadLocal = ThreadLocal<MutableMap<CounterWithExclude, CallStackWithTime>>()
private fun getCallStack(counter: CounterWithExclude) private fun getCallStack(counter: CounterWithExclude) =
= PerformanceCounter.getOrPut(counterToCallStackMapThreadLocal) { HashMap() }.getOrPut(counter) { CallStackWithTime() } PerformanceCounter.getOrPut(counterToCallStackMapThreadLocal) { HashMap() }.getOrPut(counter) { CallStackWithTime() }
} }
init { init {
@@ -183,8 +180,7 @@ internal class CounterWithExclude(name: String, vararg excludedCounters: Perform
incrementTime(callStack.push(true)) incrementTime(callStack.push(true))
try { try {
return block() return block()
} } finally {
finally {
incrementTime(callStack.pop(true)) incrementTime(callStack.pop(true))
} }
} }
@@ -21,8 +21,7 @@ fun getExceptionMessage(
if (location != null) { if (location != null) {
result.append("File being compiled at position: ").append(location).append("\n") result.append("File being compiled at position: ").append(location).append("\n")
} } else {
else {
result.append("Element is unknown") result.append("Element is unknown")
} }