UNINITIALIZED_ENUM_ENTRY compiler warning introduced #KT-2349 Fixed
(cherry picked from commit 76ac6d1)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
b7ed68db05
commit
35446037bb
@@ -48,6 +48,8 @@ interface ControlFlowBuilder {
|
||||
fun declareVariable(property: KtVariableDeclaration)
|
||||
fun declareFunction(subroutine: KtElement, pseudocode: Pseudocode)
|
||||
|
||||
fun declareEnumEntry(enumEntry: KtEnumEntry)
|
||||
|
||||
// Labels
|
||||
fun createUnboundLabel(): Label
|
||||
|
||||
|
||||
@@ -200,6 +200,10 @@ abstract class ControlFlowBuilderAdapter : ControlFlowBuilder {
|
||||
delegateBuilder.declareFunction(subroutine, pseudocode)
|
||||
}
|
||||
|
||||
override fun declareEnumEntry(enumEntry: KtEnumEntry) {
|
||||
delegateBuilder.declareEnumEntry(enumEntry)
|
||||
}
|
||||
|
||||
override fun repeatPseudocode(startLabel: Label, finishLabel: Label) {
|
||||
delegateBuilder.repeatPseudocode(startLabel, finishLabel)
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getDispatchReceiverWithSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.hasThisOrNoDispatchReceiver
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils.*
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
@@ -325,8 +326,12 @@ class ControlFlowInformationProvider private constructor(
|
||||
variableDescriptor?.let { varWithUninitializedErrorGenerated.add(it) }
|
||||
}
|
||||
when (variableDescriptor) {
|
||||
is ValueParameterDescriptor -> report(Errors.UNINITIALIZED_PARAMETER.on(element, variableDescriptor), ctxt)
|
||||
is VariableDescriptor -> report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||
is ValueParameterDescriptor ->
|
||||
report(Errors.UNINITIALIZED_PARAMETER.on(element, variableDescriptor), ctxt)
|
||||
is FakeCallableDescriptorForObject ->
|
||||
report(Errors.UNINITIALIZED_ENUM_ENTRY.on(element, variableDescriptor.classDescriptor), ctxt)
|
||||
is VariableDescriptor ->
|
||||
report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1267,6 +1267,24 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
}
|
||||
|
||||
override fun visitClass(klass: KtClass) {
|
||||
if (klass.isEnum()) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
is KtObjectDeclaration -> {
|
||||
generateInstructions(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (klass.hasPrimaryConstructor()) {
|
||||
processParameters(klass.getPrimaryConstructorParameters())
|
||||
|
||||
|
||||
@@ -24,8 +24,11 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.collectData
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.getFakeDescriptorForObject
|
||||
import java.util.ArrayList
|
||||
import java.util.HashMap
|
||||
|
||||
@@ -74,19 +77,15 @@ class PseudocodeVariableDataCollector(
|
||||
pseudocode.traverse(TraversalOrder.FORWARD, { instruction ->
|
||||
if (instruction is VariableDeclarationInstruction) {
|
||||
val variableDeclarationElement = instruction.variableDeclarationElement
|
||||
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
|
||||
if (descriptor != null) {
|
||||
// TODO: investigate why tests fail without this eager computation here
|
||||
descriptor.toString()
|
||||
|
||||
assert(descriptor is VariableDescriptor) {
|
||||
"Variable descriptor should correspond to the instruction for ${instruction.element.text}.\n" +
|
||||
"Descriptor: $descriptor"
|
||||
}
|
||||
blockScopeVariableInfo.registerVariableDeclaredInScope(
|
||||
descriptor as VariableDescriptor, instruction.blockScope
|
||||
)
|
||||
}
|
||||
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse
|
||||
// TODO: investigate why tests fail without this eager computation here
|
||||
// TODO: https://youtrack.jetbrains.com/issue/KT-13354
|
||||
descriptor.toString()
|
||||
val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor)
|
||||
?: throw AssertionError("Variable or class descriptor should correspond to " +
|
||||
"the instruction for ${instruction.element.text}.\n" +
|
||||
"Descriptor: $descriptor")
|
||||
blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope)
|
||||
}
|
||||
})
|
||||
return blockScopeVariableInfo
|
||||
|
||||
@@ -25,9 +25,15 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.Edges
|
||||
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils.variableDescriptorForDeclaration
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.getFakeDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import java.util.Collections
|
||||
|
||||
class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingContext: BindingContext) {
|
||||
@@ -75,9 +81,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
if (instruction is VariableDeclarationInstruction) {
|
||||
val variableDeclarationElement = instruction.variableDeclarationElement
|
||||
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
|
||||
if (descriptor != null) {
|
||||
assert(descriptor is VariableDescriptor)
|
||||
declaredVariables.add(descriptor as VariableDescriptor?)
|
||||
variableDescriptorForDeclaration(descriptor)?.let {
|
||||
declaredVariables.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -274,6 +274,10 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
add(LocalFunctionDeclarationInstruction(subroutine, pseudocode, currentScope))
|
||||
}
|
||||
|
||||
override fun declareEnumEntry(enumEntry: KtEnumEntry) {
|
||||
add(VariableDeclarationInstruction(enumEntry, currentScope))
|
||||
}
|
||||
|
||||
override fun loadUnit(expression: KtExpression) {
|
||||
add(LoadUnitValueInstruction(expression, currentScope))
|
||||
}
|
||||
|
||||
+4
-1
@@ -24,13 +24,16 @@ 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
|
||||
|
||||
class VariableDeclarationInstruction(
|
||||
element: KtDeclaration,
|
||||
blockScope: BlockScope
|
||||
) : InstructionWithNext(element, blockScope) {
|
||||
init {
|
||||
assert(element is KtVariableDeclaration || element is KtParameter) { "Invalid element: ${render(element)}}" }
|
||||
assert(element is KtVariableDeclaration || element is KtParameter || element is KtEnumEntry) {
|
||||
"Invalid element: ${render(element)}}"
|
||||
}
|
||||
}
|
||||
|
||||
val variableDeclarationElement: KtDeclaration
|
||||
|
||||
@@ -171,9 +171,9 @@ fun getExpectedTypePredicate(
|
||||
else {
|
||||
val expectedType = when (accessTarget) {
|
||||
is AccessTarget.Call ->
|
||||
(accessTarget.resolvedCall.getResultingDescriptor() as? VariableDescriptor)?.getType()
|
||||
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
|
||||
is AccessTarget.Declaration ->
|
||||
accessTarget.descriptor.getType()
|
||||
accessTarget.descriptor.type
|
||||
else ->
|
||||
null
|
||||
}
|
||||
@@ -239,7 +239,7 @@ fun getExpectedTypePredicate(
|
||||
|
||||
fun Instruction.getPrimaryDeclarationDescriptorIfAny(bindingContext: BindingContext): DeclarationDescriptor? {
|
||||
return when (this) {
|
||||
is CallInstruction -> return resolvedCall.getResultingDescriptor()
|
||||
is CallInstruction -> return resolvedCall.resultingDescriptor
|
||||
else -> PseudocodeUtil.extractVariableDescriptorIfAny(this, false, bindingContext)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,6 +644,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<KtNamedDeclaration, VariableDescriptor> UNUSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
DiagnosticFactory1<KtParameter, VariableDescriptor> UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
|
||||
+1
@@ -264,6 +264,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(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);
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.TowerLevelsKt;
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.MutableDiagnosticsWithSuppression;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
@@ -56,10 +57,21 @@ public class BindingContextUtils {
|
||||
return (VariableDescriptor) resolvedCall.getResultingDescriptor();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VariableDescriptor variableDescriptorForDeclaration(@Nullable DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof VariableDescriptor)
|
||||
return (VariableDescriptor) descriptor;
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
return TowerLevelsKt.getFakeDescriptorForObject((ClassDescriptor) descriptor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VariableDescriptor extractVariableDescriptorIfAny(@NotNull BindingContext bindingContext, @Nullable KtElement element, boolean onlyReference) {
|
||||
DeclarationDescriptor descriptor = null;
|
||||
if (!onlyReference && (element instanceof KtVariableDeclaration || element instanceof KtParameter)) {
|
||||
if (!onlyReference &&
|
||||
(element instanceof KtVariableDeclaration || element instanceof KtParameter || element instanceof KtEnumEntry)) {
|
||||
descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
|
||||
}
|
||||
else if (element instanceof KtSimpleNameExpression) {
|
||||
@@ -68,10 +80,7 @@ public class BindingContextUtils {
|
||||
else if (element instanceof KtQualifiedExpression) {
|
||||
descriptor = extractVariableDescriptorIfAny(bindingContext, ((KtQualifiedExpression) element).getSelectorExpression(), onlyReference);
|
||||
}
|
||||
if (descriptor instanceof VariableDescriptor) {
|
||||
return (VariableDescriptor) descriptor;
|
||||
}
|
||||
return null;
|
||||
return variableDescriptorForDeclaration(descriptor);
|
||||
}
|
||||
|
||||
public static void recordFunctionDeclarationToDescriptor(@NotNull BindingTrace trace,
|
||||
|
||||
+4
@@ -63,4 +63,8 @@ class FakeCallableDescriptorForObject(
|
||||
override fun getSource(): SourceElement = classDescriptor.source
|
||||
|
||||
override fun isConst(): Boolean = false
|
||||
|
||||
override fun equals(other: Any?) = other is FakeCallableDescriptorForObject && classDescriptor == other.classDescriptor
|
||||
|
||||
override fun hashCode() = classDescriptor.hashCode()
|
||||
}
|
||||
|
||||
+33
-21
@@ -4,13 +4,25 @@ enum class Direction {
|
||||
}
|
||||
---------------------
|
||||
L0:
|
||||
1 <START> INIT: in: {} out: {}
|
||||
1 <START> INIT: in: {} out: {}
|
||||
v(NORTH,) INIT: in: {} out: {NORTH=D}
|
||||
magic[FAKE_INITIALIZER](NORTH,) -> <v0> INIT: in: {NORTH=D} out: {NORTH=D}
|
||||
w(NORTH|<v0>) INIT: in: {NORTH=D} out: {NORTH=ID}
|
||||
v(SOUTH,) INIT: in: {NORTH=ID} out: {NORTH=ID, SOUTH=D}
|
||||
magic[FAKE_INITIALIZER](SOUTH,) -> <v1> INIT: in: {NORTH=ID, SOUTH=D} out: {NORTH=ID, SOUTH=D}
|
||||
w(SOUTH|<v1>) INIT: in: {NORTH=ID, SOUTH=D} out: {NORTH=ID, SOUTH=ID}
|
||||
v(WEST,) INIT: in: {NORTH=ID, SOUTH=ID} out: {NORTH=ID, SOUTH=ID, WEST=D}
|
||||
magic[FAKE_INITIALIZER](WEST,) -> <v2> INIT: in: {NORTH=ID, SOUTH=ID, WEST=D} out: {NORTH=ID, SOUTH=ID, WEST=D}
|
||||
w(WEST|<v2>) INIT: in: {NORTH=ID, SOUTH=ID, WEST=D} out: {NORTH=ID, SOUTH=ID, WEST=ID}
|
||||
v(EAST) INIT: in: {NORTH=ID, SOUTH=ID, WEST=ID} out: {EAST=D, NORTH=ID, SOUTH=ID, WEST=ID}
|
||||
magic[FAKE_INITIALIZER](EAST) -> <v3> INIT: in: {EAST=D, NORTH=ID, SOUTH=ID, WEST=ID} out: {EAST=D, NORTH=ID, SOUTH=ID, WEST=ID}
|
||||
w(EAST|<v3>) INIT: in: {EAST=D, NORTH=ID, SOUTH=ID, WEST=ID} out: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID}
|
||||
L1:
|
||||
<END>
|
||||
<END> INIT: in: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID} out: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID}
|
||||
error:
|
||||
<ERROR>
|
||||
<ERROR> INIT: in: {} out: {}
|
||||
sink:
|
||||
<SINK> USE: in: {} out: {}
|
||||
<SINK> INIT: in: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID} out: {EAST=ID, NORTH=ID, SOUTH=ID, WEST=ID} USE: in: {} out: {}
|
||||
=====================
|
||||
== foo ==
|
||||
fun foo(dir: Direction): Int {
|
||||
@@ -28,48 +40,48 @@ L0:
|
||||
1 <START> INIT: in: {} out: {}
|
||||
v(dir: Direction) INIT: in: {} out: {dir=D}
|
||||
magic[FAKE_INITIALIZER](dir: Direction) -> <v0> INIT: in: {dir=D} out: {dir=D}
|
||||
w(dir|<v0>) INIT: in: {dir=D} out: {dir=ID} USE: in: {dir=READ} out: {dir=READ}
|
||||
w(dir|<v0>) INIT: in: {dir=D} out: {dir=ID} USE: in: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, dir=READ} out: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, dir=READ}
|
||||
2 mark({ val res: Int when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 } return res }) INIT: in: {dir=ID} out: {dir=ID}
|
||||
v(val res: Int) INIT: in: {dir=ID} out: {dir=ID, res=D}
|
||||
mark(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D} USE: in: {dir=READ, res=READ} out: {dir=READ, res=READ}
|
||||
r(dir) -> <v1> USE: in: {res=READ} out: {dir=READ, res=READ}
|
||||
mark(when (dir) { Direction.NORTH -> res = 1 Direction.SOUTH -> res = 2 Direction.WEST -> res = 3 Direction.EAST -> res = 4 }) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D} USE: in: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, dir=READ, res=READ} out: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, dir=READ, res=READ}
|
||||
r(dir) -> <v1> USE: in: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, res=READ} out: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, dir=READ, res=READ}
|
||||
mark(Direction.NORTH -> res = 1)
|
||||
mark(Direction.NORTH)
|
||||
mark(Direction.NORTH)
|
||||
r(NORTH) -> <v2>
|
||||
mark(Direction.NORTH) USE: in: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, res=READ} out: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, res=READ}
|
||||
r(NORTH) -> <v2> USE: in: {EAST=READ, SOUTH=READ, WEST=READ, res=READ} out: {EAST=READ, NORTH=READ, SOUTH=READ, WEST=READ, res=READ}
|
||||
magic[EQUALS_IN_WHEN_CONDITION](Direction.NORTH|<v1>, <v2>) -> <v3>
|
||||
jmp?(L4|<v3>) USE: in: {res=READ} out: {res=READ}
|
||||
jmp?(L4|<v3>) USE: in: {EAST=READ, SOUTH=READ, WEST=READ, res=READ} out: {EAST=READ, SOUTH=READ, WEST=READ, res=READ}
|
||||
L3 ['when' entry body]:
|
||||
r(1) -> <v4> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
|
||||
w(res|<v4>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
|
||||
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
|
||||
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=READ}
|
||||
L4 [next 'when' entry]:
|
||||
mark(Direction.SOUTH -> res = 2) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D}
|
||||
mark(Direction.SOUTH)
|
||||
mark(Direction.SOUTH)
|
||||
r(SOUTH) -> <v5>
|
||||
mark(Direction.SOUTH) USE: in: {EAST=READ, SOUTH=READ, WEST=READ, res=READ} out: {EAST=READ, SOUTH=READ, WEST=READ, res=READ}
|
||||
r(SOUTH) -> <v5> USE: in: {EAST=READ, WEST=READ, res=READ} out: {EAST=READ, SOUTH=READ, WEST=READ, res=READ}
|
||||
magic[EQUALS_IN_WHEN_CONDITION](Direction.SOUTH|<v1>, <v5>) -> <v6>
|
||||
jmp?(L6|<v6>) USE: in: {res=READ} out: {res=READ}
|
||||
jmp?(L6|<v6>) USE: in: {EAST=READ, WEST=READ, res=READ} out: {EAST=READ, WEST=READ, res=READ}
|
||||
L5 ['when' entry body]:
|
||||
r(2) -> <v7> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
|
||||
w(res|<v7>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
|
||||
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
|
||||
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=READ}
|
||||
L6 [next 'when' entry]:
|
||||
mark(Direction.WEST -> res = 3) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D}
|
||||
mark(Direction.WEST)
|
||||
mark(Direction.WEST)
|
||||
r(WEST) -> <v8>
|
||||
mark(Direction.WEST) USE: in: {EAST=READ, WEST=READ, res=READ} out: {EAST=READ, WEST=READ, res=READ}
|
||||
r(WEST) -> <v8> USE: in: {EAST=READ, res=READ} out: {EAST=READ, WEST=READ, res=READ}
|
||||
magic[EQUALS_IN_WHEN_CONDITION](Direction.WEST|<v1>, <v8>) -> <v9>
|
||||
jmp?(L8|<v9>) USE: in: {res=READ} out: {res=READ}
|
||||
jmp?(L8|<v9>) USE: in: {EAST=READ, res=READ} out: {EAST=READ, res=READ}
|
||||
L7 ['when' entry body]:
|
||||
r(3) -> <v10> USE: in: {res=WRITTEN_AFTER_READ} out: {res=WRITTEN_AFTER_READ}
|
||||
w(res|<v10>) INIT: in: {dir=ID, res=D} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=WRITTEN_AFTER_READ}
|
||||
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID}
|
||||
jmp(L2) INIT: in: {dir=ID, res=ID} out: {dir=ID, res=ID} USE: in: {res=READ} out: {res=READ}
|
||||
L8 [next 'when' entry]:
|
||||
mark(Direction.EAST -> res = 4) INIT: in: {dir=ID, res=D} out: {dir=ID, res=D}
|
||||
mark(Direction.EAST)
|
||||
mark(Direction.EAST)
|
||||
r(EAST) -> <v11>
|
||||
mark(Direction.EAST) USE: in: {EAST=READ, res=READ} out: {EAST=READ, res=READ}
|
||||
r(EAST) -> <v11> USE: in: {res=READ} out: {EAST=READ, res=READ}
|
||||
magic[EQUALS_IN_WHEN_CONDITION](Direction.EAST|<v1>, <v11>) -> <v12>
|
||||
jmp?(L10|<v12>) USE: in: {res=READ} out: {res=READ}
|
||||
L9 ['when' entry body]:
|
||||
|
||||
@@ -3,6 +3,10 @@ enum class Direction {
|
||||
NORTH, SOUTH, WEST, EAST
|
||||
}
|
||||
---------------------
|
||||
<v0>: Direction NEW: magic[FAKE_INITIALIZER](NORTH,) -> <v0>
|
||||
<v1>: Direction NEW: magic[FAKE_INITIALIZER](SOUTH,) -> <v1>
|
||||
<v2>: Direction NEW: magic[FAKE_INITIALIZER](WEST,) -> <v2>
|
||||
<v3>: Direction NEW: magic[FAKE_INITIALIZER](EAST) -> <v3>
|
||||
=====================
|
||||
== foo ==
|
||||
fun foo(dir: Direction): Int {
|
||||
|
||||
+8
-2
@@ -22,9 +22,15 @@ enum class E(val x: Int) {
|
||||
---------------------
|
||||
L0:
|
||||
1 <START>
|
||||
v(E1(0))
|
||||
magic[FAKE_INITIALIZER](E1(0)) -> <v0>
|
||||
w(E1|<v0>)
|
||||
r(0) -> <v1>
|
||||
mark((0))
|
||||
call((0), <init>|<v1>) -> <v2>
|
||||
v(val x: Int)
|
||||
magic[FAKE_INITIALIZER](val x: Int) -> <v0>
|
||||
w(x|<v0>)
|
||||
magic[FAKE_INITIALIZER](val x: Int) -> <v3>
|
||||
w(x|<v3>)
|
||||
L1:
|
||||
<END> NEXT:[<SINK>]
|
||||
error:
|
||||
|
||||
+4
-1
@@ -10,7 +10,10 @@ enum class E(val x: Int) {
|
||||
E1(0)
|
||||
}
|
||||
---------------------
|
||||
<v0>: Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> <v0>
|
||||
<v0>: E NEW: magic[FAKE_INITIALIZER](E1(0)) -> <v0>
|
||||
<v3>: Int NEW: magic[FAKE_INITIALIZER](val x: Int) -> <v3>
|
||||
0 <v1>: Int NEW: r(0) -> <v1>
|
||||
(0) <v2>: * NEW: call((0), <init>|<v1>) -> <v2>
|
||||
=====================
|
||||
== C ==
|
||||
class C {
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
enum class A(val v: A) {
|
||||
A1(<!UNINITIALIZED_ENUM_ENTRY!>A2<!>),
|
||||
A2(A1)
|
||||
}
|
||||
|
||||
enum class B(val x: Int) {
|
||||
B1(1),
|
||||
B2(2);
|
||||
|
||||
companion object {
|
||||
val SUM = B1.x + B2.x
|
||||
val COPY = B1
|
||||
}
|
||||
}
|
||||
|
||||
enum class C(val x: Int) {
|
||||
C1(<!UNINITIALIZED_VARIABLE!>SUM<!>),
|
||||
C2(1);
|
||||
|
||||
companion object {
|
||||
val COPY = C2
|
||||
val SUM = C1.x + COPY.x
|
||||
}
|
||||
}
|
||||
|
||||
enum class D(val x: Int) {
|
||||
D1(<!UNINITIALIZED_ENUM_ENTRY!>D2<!>.x),
|
||||
D2(D1.x)
|
||||
}
|
||||
|
||||
enum class E(val v: Int) {
|
||||
E1(Nested.COPY);
|
||||
|
||||
object Nested {
|
||||
val COPY = E1.v
|
||||
}
|
||||
}
|
||||
// From KT-13322
|
||||
object Object1 {
|
||||
val y: Any = Object2.z // z is not yet initialized (?!)
|
||||
object Object2 {
|
||||
val z: Any = Object1.y
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package
|
||||
|
||||
public final enum class A : kotlin.Enum<A> {
|
||||
enum entry A1
|
||||
|
||||
enum entry A2
|
||||
|
||||
private constructor A(/*0*/ v: A)
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
public final val v: A
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: A): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): A
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<A>
|
||||
}
|
||||
|
||||
public final enum class B : kotlin.Enum<B> {
|
||||
enum entry B1
|
||||
|
||||
enum entry B2
|
||||
|
||||
private constructor B(/*0*/ x: kotlin.Int)
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
public final val x: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: B): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public companion object Companion {
|
||||
private constructor Companion()
|
||||
public final val COPY: B
|
||||
public final val SUM: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): B
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<B>
|
||||
}
|
||||
|
||||
public final enum class C : kotlin.Enum<C> {
|
||||
enum entry C1
|
||||
|
||||
enum entry C2
|
||||
|
||||
private constructor C(/*0*/ x: kotlin.Int)
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
public final val x: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: C): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public companion object Companion {
|
||||
private constructor Companion()
|
||||
public final val COPY: C
|
||||
public final val SUM: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): C
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<C>
|
||||
}
|
||||
|
||||
public final enum class D : kotlin.Enum<D> {
|
||||
enum entry D1
|
||||
|
||||
enum entry D2
|
||||
|
||||
private constructor D(/*0*/ x: kotlin.Int)
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
public final val x: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: D): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): D
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<D>
|
||||
}
|
||||
|
||||
public final enum class E : kotlin.Enum<E> {
|
||||
enum entry E1
|
||||
|
||||
private constructor E(/*0*/ v: kotlin.Int)
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
public final val v: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public object Nested {
|
||||
private constructor Nested()
|
||||
public final val COPY: kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<E>
|
||||
}
|
||||
|
||||
public object Object1 {
|
||||
private constructor Object1()
|
||||
public final val y: kotlin.Any
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public object Object2 {
|
||||
private constructor Object2()
|
||||
public final val z: kotlin.Any
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
@@ -3270,6 +3270,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("enumInterdependence.kt")
|
||||
public void testEnumInterdependence() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/enumInterdependence.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("infiniteLoops.kt")
|
||||
public void testInfiniteLoops() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/infiniteLoops.kt");
|
||||
|
||||
Reference in New Issue
Block a user