KT-11769 case with companion function call: error is now detected if companion receiver is stated explicitly
This commit is contained in:
@@ -48,7 +48,7 @@ interface ControlFlowBuilder {
|
||||
fun declareVariable(property: KtVariableDeclaration)
|
||||
fun declareFunction(subroutine: KtElement, pseudocode: Pseudocode)
|
||||
|
||||
fun declareEnumEntry(enumEntry: KtEnumEntry)
|
||||
fun declareEntryOrObject(entryOrObject: KtClassOrObject)
|
||||
|
||||
// Labels
|
||||
fun createUnboundLabel(): Label
|
||||
|
||||
@@ -200,8 +200,8 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
|
||||
delegateBuilder.declareFunction(subroutine, pseudocode)
|
||||
}
|
||||
|
||||
override fun declareEnumEntry(enumEntry: KtEnumEntry) {
|
||||
delegateBuilder.declareEnumEntry(enumEntry)
|
||||
override fun declareEntryOrObject(entryOrObject: KtClassOrObject) {
|
||||
delegateBuilder.declareEntryOrObject(entryOrObject)
|
||||
}
|
||||
|
||||
override fun repeatPseudocode(startLabel: Label, finishLabel: Label) {
|
||||
|
||||
@@ -328,8 +328,20 @@ class ControlFlowInformationProvider private constructor(
|
||||
when (variableDescriptor) {
|
||||
is ValueParameterDescriptor ->
|
||||
report(Errors.UNINITIALIZED_PARAMETER.on(element, variableDescriptor), ctxt)
|
||||
is FakeCallableDescriptorForObject ->
|
||||
report(Errors.UNINITIALIZED_ENUM_ENTRY.on(element, variableDescriptor.classDescriptor), ctxt)
|
||||
is FakeCallableDescriptorForObject -> {
|
||||
val classDescriptor = variableDescriptor.classDescriptor
|
||||
when (classDescriptor.kind) {
|
||||
ClassKind.ENUM_ENTRY ->
|
||||
report(Errors.UNINITIALIZED_ENUM_ENTRY.on(element, classDescriptor), ctxt)
|
||||
ClassKind.OBJECT -> if (classDescriptor.isCompanionObject) {
|
||||
val container = classDescriptor.containingDeclaration
|
||||
if (container is ClassDescriptor && container.kind == ClassKind.ENUM_CLASS) {
|
||||
report(Errors.UNINITIALIZED_ENUM_COMPANION.on(element, container), ctxt)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
is VariableDescriptor ->
|
||||
report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||
}
|
||||
|
||||
@@ -1266,6 +1266,16 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun processEntryOrObject(entryOrObject: KtClassOrObject) {
|
||||
val classDescriptor = trace[BindingContext.DECLARATION_TO_DESCRIPTOR, entryOrObject]
|
||||
if (classDescriptor is ClassDescriptor) {
|
||||
builder.declareEntryOrObject(entryOrObject)
|
||||
builder.write(entryOrObject, entryOrObject, createSyntheticValue(entryOrObject, MagicKind.FAKE_INITIALIZER),
|
||||
AccessTarget.Declaration(FakeCallableDescriptorForObject(classDescriptor)), emptyMap())
|
||||
generateInstructions(entryOrObject)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitClass(klass: KtClass) {
|
||||
if (klass.hasPrimaryConstructor()) {
|
||||
processParameters(klass.getPrimaryConstructorParameters())
|
||||
@@ -1281,16 +1291,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
klass.declarations.forEach {
|
||||
when (it) {
|
||||
is KtEnumEntry -> {
|
||||
val classDescriptor = trace[BindingContext.DECLARATION_TO_DESCRIPTOR, it]
|
||||
if (classDescriptor is ClassDescriptor) {
|
||||
builder.declareEnumEntry(it)
|
||||
builder.write(it, it, createSyntheticValue(it, MagicKind.FAKE_INITIALIZER),
|
||||
AccessTarget.Declaration(FakeCallableDescriptorForObject(classDescriptor)), emptyMap())
|
||||
generateInstructions(it)
|
||||
}
|
||||
processEntryOrObject(it)
|
||||
}
|
||||
is KtObjectDeclaration -> if (it.isCompanion()) {
|
||||
generateInstructions(it)
|
||||
processEntryOrObject(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -274,8 +274,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
add(LocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope))
|
||||
}
|
||||
|
||||
override fun declareEnumEntry(enumEntry: KtEnumEntry) {
|
||||
add(VariableDeclarationInstruction(enumEntry, currentScope))
|
||||
override fun declareEntryOrObject(entryOrObject: KtClassOrObject) {
|
||||
add(VariableDeclarationInstruction(entryOrObject, currentScope))
|
||||
}
|
||||
|
||||
override fun loadUnit(expression: KtExpression) {
|
||||
|
||||
+2
-5
@@ -16,22 +16,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.cfg.pseudocode.instructions.special
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtVariableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionWithNext
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.BlockScope
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitor
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithResult
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
|
||||
class VariableDeclarationInstruction(
|
||||
element: KtDeclaration,
|
||||
blockScope: BlockScope
|
||||
) : InstructionWithNext(element, blockScope) {
|
||||
init {
|
||||
assert(element is KtVariableDeclaration || element is KtParameter || element is KtEnumEntry) {
|
||||
assert(element is KtVariableDeclaration || element is KtParameter || element is KtEnumEntry || element is KtObjectDeclaration) {
|
||||
"Invalid element: ${render(element)}}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,6 +645,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<KtSimpleNameExpression, VariableDescriptor> UNINITIALIZED_VARIABLE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtSimpleNameExpression, ValueParameterDescriptor> UNINITIALIZED_PARAMETER = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtSimpleNameExpression, ClassDescriptor> UNINITIALIZED_ENUM_ENTRY = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<KtSimpleNameExpression, ClassDescriptor> UNINITIALIZED_ENUM_COMPANION = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<KtNamedDeclaration, VariableDescriptor> UNUSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
DiagnosticFactory1<KtParameter, VariableDescriptor> UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
|
||||
+1
@@ -265,6 +265,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(UNINITIALIZED_VARIABLE, "Variable ''{0}'' must be initialized", NAME);
|
||||
MAP.put(UNINITIALIZED_PARAMETER, "Parameter ''{0}'' is uninitialized here", NAME);
|
||||
MAP.put(UNINITIALIZED_ENUM_ENTRY, "Enum entry ''{0}'' is uninitialized here", NAME);
|
||||
MAP.put(UNINITIALIZED_ENUM_COMPANION, "Companion object of enum class ''{0}'' is uninitialized here", NAME);
|
||||
MAP.put(UNUSED_VARIABLE, "Variable ''{0}'' is never used", NAME);
|
||||
MAP.put(UNUSED_PARAMETER, "Parameter ''{0}'' is never used", NAME);
|
||||
MAP.put(ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE, "Variable ''{0}'' is assigned but never accessed", NAME);
|
||||
|
||||
@@ -71,7 +71,8 @@ public class BindingContextUtils {
|
||||
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable KtElement element, boolean onlyReference) {
|
||||
DeclarationDescriptor descriptor = null;
|
||||
if (!onlyReference &&
|
||||
(element instanceof KtVariableDeclaration || element instanceof KtParameter || element instanceof KtEnumEntry)) {
|
||||
(element instanceof KtVariableDeclaration || element instanceof KtParameter ||
|
||||
element instanceof KtEnumEntry || element instanceof KtObjectDeclaration)) {
|
||||
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
}
|
||||
else if (element instanceof KtSimpleNameExpression) {
|
||||
|
||||
Reference in New Issue
Block a user