KT-1191 Wrong detection of unused parameters

KT-1219 Incorrect 'unused value' error in closures
This commit is contained in:
Svetlana Isakova
2012-02-22 17:07:49 +04:00
parent 7f2a8100c4
commit cc244fad94
12 changed files with 94 additions and 22 deletions
@@ -167,7 +167,7 @@ public class JetControlFlowGraphTraverser<D> {
} }
public D getResultInfo() { public D getResultInfo() {
return dataMap.get(pseudocode.getSinkInstruction()).getFirst(); return dataMap.get(pseudocode.getExitInstruction()).getFirst();
} }
interface InstructionDataMergeStrategy<D> { interface InstructionDataMergeStrategy<D> {
@@ -711,6 +711,14 @@ public class JetControlFlowProcessor {
value(initializer, false); value(initializer, false);
builder.write(property, property); builder.write(property, property);
} }
for (JetPropertyAccessor accessor : property.getAccessors()) {
value(accessor, false);
}
}
@Override
public void visitPropertyAccessor(JetPropertyAccessor accessor) {
processLocalDeclaration(accessor);
} }
@Override @Override
@@ -41,6 +41,7 @@ import org.jetbrains.jet.plugin.JetMainDetector;
import java.util.*; import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.MUST_BE_WRAPPED_IN_A_REF;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
/** /**
@@ -254,7 +255,7 @@ public class JetFlowInformationProvider {
if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration if (!error && !processLocalDeclaration) { // error has been generated before, while processing outer function of this local declaration
error = checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated); error = checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated);
} }
if (!error) { if (!error && processClassOrObject) {
error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor)); error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor));
} }
if (!error && processClassOrObject) { if (!error && processClassOrObject) {
@@ -265,7 +266,7 @@ public class JetFlowInformationProvider {
}); });
recordInitializedVariables(declaredVariables, traverser.getResultInfo()); recordInitializedVariables(declaredVariables, traverser.getResultInfo());
analyzeLocalDeclarations(processLocalDeclaration, pseudocode); analyzeLocalDeclarations(pseudocode, processLocalDeclaration);
} }
private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor, private void checkIsInitialized(@NotNull VariableDescriptor variableDescriptor,
@@ -442,7 +443,7 @@ public class JetFlowInformationProvider {
} }
} }
private void analyzeLocalDeclarations(boolean processLocalDeclaration, Pseudocode pseudocode) { private void analyzeLocalDeclarations(Pseudocode pseudocode, boolean processLocalDeclaration) {
for (Instruction instruction : pseudocode.getInstructions()) { for (Instruction instruction : pseudocode.getInstructions()) {
if (instruction instanceof LocalDeclarationInstruction) { if (instruction instanceof LocalDeclarationInstruction) {
JetElement element = ((LocalDeclarationInstruction) instruction).getElement(); JetElement element = ((LocalDeclarationInstruction) instruction).getElement();
@@ -595,6 +596,7 @@ public class JetFlowInformationProvider {
!DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return; !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
VariableStatus variableStatus = enterData.get(variableDescriptor); VariableStatus variableStatus = enterData.get(variableDescriptor);
if (instruction instanceof WriteValueInstruction) { if (instruction instanceof WriteValueInstruction) {
if (trace.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor)) return;
JetElement element = ((WriteValueInstruction) instruction).getElement(); JetElement element = ((WriteValueInstruction) instruction).getElement();
if (variableStatus != VariableStatus.READ) { if (variableStatus != VariableStatus.READ) {
if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) { if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
@@ -66,12 +66,14 @@ public class ControlFlowAnalyzer {
} }
for (Map.Entry<JetProperty, PropertyDescriptor> entry : context.getProperties().entrySet()) { for (Map.Entry<JetProperty, PropertyDescriptor> entry : context.getProperties().entrySet()) {
JetProperty property = entry.getKey(); JetProperty property = entry.getKey();
if (!context.completeAnalysisNeeded(property)) continue;
PropertyDescriptor propertyDescriptor = entry.getValue(); PropertyDescriptor propertyDescriptor = entry.getValue();
checkProperty(property, propertyDescriptor); checkProperty(property, propertyDescriptor);
} }
} }
private void checkClassOrObject(JetClassOrObject klass) { private void checkClassOrObject(JetClassOrObject klass) {
// A pseudocode of class initialization corresponds to a class
JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace()); JetFlowInformationProvider flowInformationProvider = new JetFlowInformationProvider((JetDeclaration) klass, (JetExpression) klass, flowDataTraceFactory, context.getTrace());
flowInformationProvider.markUninitializedVariables((JetElement) klass, context.isDeclaredLocally()); flowInformationProvider.markUninitializedVariables((JetElement) klass, context.isDeclaredLocally());
} }
@@ -95,7 +97,9 @@ public class ControlFlowAnalyzer {
flowInformationProvider.checkDefiniteReturn(function, expectedReturnType); flowInformationProvider.checkDefiniteReturn(function, expectedReturnType);
flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally()); // Property accessor is checked through initialization of a class check (at 'checkClassOrObject')
boolean isPropertyAccessor = function instanceof JetPropertyAccessor;
flowInformationProvider.markUninitializedVariables(function.asElement(), context.isDeclaredLocally() || isPropertyAccessor);
flowInformationProvider.markUnusedVariables(function.asElement()); flowInformationProvider.markUnusedVariables(function.asElement());
@@ -1,3 +1,16 @@
== get_j ==
get() = 20
---------------------
l0:
<START> NEXT:[r(20)] PREV:[]
r(20) NEXT:[<END>] PREV:[<START>]
l1:
<END> NEXT:[<SINK>] PREV:[r(20)]
error:
<ERROR> NEXT:[] PREV:[]
sink:
<SINK> NEXT:[] PREV:[<END>]
=====================
== AnonymousInitializers == == AnonymousInitializers ==
class AnonymousInitializers() { class AnonymousInitializers() {
val k = 34 val k = 34
@@ -24,23 +37,22 @@ l0:
r(12) NEXT:[w($i)] PREV:[v(val i: Int)] r(12) NEXT:[w($i)] PREV:[v(val i: Int)]
w($i) NEXT:[v(val j: Int get() = 20) ] PREV:[r(12)] w($i) NEXT:[v(val j: Int get() = 20) ] PREV:[r(12)]
v(val j: Int v(val j: Int
get() = 20) NEXT:[r(13)] PREV:[w($i)] get() = 20) NEXT:[jmp?(l2)] PREV:[w($i)]
r(13) NEXT:[w($i)] PREV:[v(val j: Int get() = 20) ] jmp?(l2) NEXT:[r(13), d(get() = 20)] PREV:[v(val j: Int get() = 20) ]
d(get() = 20) NEXT:[<SINK>] PREV:[jmp?(l2)]
l2:
r(13) NEXT:[w($i)] PREV:[jmp?(l2)]
w($i) NEXT:[<END>] PREV:[r(13)] w($i) NEXT:[<END>] PREV:[r(13)]
l1: l1:
<END> NEXT:[<SINK>] PREV:[w($i)] <END> NEXT:[<SINK>] PREV:[w($i)]
error: error:
<ERROR> NEXT:[] PREV:[] <ERROR> NEXT:[] PREV:[]
sink: sink:
<SINK> NEXT:[] PREV:[<END>] <SINK> NEXT:[] PREV:[d(get() = 20), <END>]
===================== l3:
== get_j ==
get() = 20
---------------------
l0:
<START> NEXT:[r(20)] PREV:[] <START> NEXT:[r(20)] PREV:[]
r(20) NEXT:[<END>] PREV:[<START>] r(20) NEXT:[<END>] PREV:[<START>]
l1: l4:
<END> NEXT:[<SINK>] PREV:[r(20)] <END> NEXT:[<SINK>] PREV:[r(20)]
error: error:
<ERROR> NEXT:[] PREV:[] <ERROR> NEXT:[] PREV:[]
@@ -328,7 +328,7 @@ fun func() {
val <!UNUSED_VARIABLE!>a<!> = object { val <!UNUSED_VARIABLE!>a<!> = object {
val x = b val x = b
{ {
<!VAL_REASSIGNMENT!>b<!> = <!UNUSED_VALUE!>4<!> <!VAL_REASSIGNMENT!>b<!> = 4
<!UNRESOLVED_REFERENCE!>$b<!> = 3 <!UNRESOLVED_REFERENCE!>$b<!> = 3
} }
} }
@@ -93,7 +93,7 @@ class MyTest() {
fun testInnerFunctions() { fun testInnerFunctions() {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>y<!> = 1 var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>y<!> = 1
fun foo() { fun foo() {
y = <!UNUSED_VALUE!>1<!> y = 1
} }
var z = 1 var z = 1
fun bar() { fun bar() {
@@ -0,0 +1,21 @@
//KT-1191 Wrong detection of unused parameters
package kt1191
trait FunctionalList<T> {
val size: Int
val head: T
val tail: FunctionalList<T>
}
fun <erased T> FunctionalList<T>.plus(element: T) : FunctionalList<T> = object: FunctionalList<T> {
override val size: Int
get() = 1 + this@plus.size
override val tail: FunctionalList<T>
get() = this@plus
override val head: T
get() = element
}
fun foo(unused: Int) = object {
val a : Int get() = unused
}
@@ -0,0 +1,25 @@
//KT-1219 Incorrect 'unused value' error in closures
//+JDK
package kt1219
fun <T, R> Iterable<T>.fold(var r: R, op: (T, R) -> R) : R {
this.foreach { r = op(it, r) } //unused value here
return r
}
//KT-1301 Modification of local of outer function in a local function should not be marked as unused assignment
fun foo(){
var local = 0
fun bar(){
local = 1
}
bar()
System.out?.println(local)
}
fun <T> Iterable<T>.foreach(operation: (element: T) -> Unit) {
for (elem in this)
operation(elem)
}
@@ -23,7 +23,7 @@ fun foo() {
2 2
} }
else { else {
z = <!UNUSED_VALUE!>34<!> z = 34
} }
} }
val <!UNUSED_VARIABLE!>f<!>: ()-> Int = <!TYPE_MISMATCH!>r<!> val <!UNUSED_VARIABLE!>f<!>: ()-> Int = <!TYPE_MISMATCH!>r<!>
@@ -74,7 +74,7 @@ fun testCoercionToUnit() {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>x<!> = 43 var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>x<!> = 43
val checkType = { val checkType = {
if (true) { if (true) {
x = <!UNUSED_VALUE!>4<!> x = 4
} else { } else {
45 45
} }
@@ -31,7 +31,7 @@ fun main(args: Array<String>) {
var m: MyNumber = MyNumber() var m: MyNumber = MyNumber()
val <!UNUSED_VARIABLE!>a<!> = { (): MyNumber -> val <!UNUSED_VARIABLE!>a<!> = { (): MyNumber ->
<!UNUSED_CHANGED_VALUE!>m++<!> m++
} }
} }
+3 -3
View File
@@ -1,19 +1,19 @@
fun refs() { fun refs() {
var <info><warning>a</warning></info> = 1 var <info><warning>a</warning></info> = 1
val <warning>v</warning> = { val <warning>v</warning> = {
<info>a</info> = <warning>2</warning> <info>a</info> = 2
} }
var <info><warning>x</warning></info> = 1 var <info><warning>x</warning></info> = 1
val <warning>b</warning> = object { val <warning>b</warning> = object {
fun foo() { fun foo() {
<info>x</info> = <warning>2</warning> <info>x</info> = 2
} }
} }
var <info><warning>y</warning></info> = 1 var <info><warning>y</warning></info> = 1
fun foo() { fun foo() {
<info>y</info> = <warning>1</warning> <info>y</info> = 1
} }
} }