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() {
return dataMap.get(pseudocode.getSinkInstruction()).getFirst();
return dataMap.get(pseudocode.getExitInstruction()).getFirst();
}
interface InstructionDataMergeStrategy<D> {
@@ -711,6 +711,14 @@ public class JetControlFlowProcessor {
value(initializer, false);
builder.write(property, property);
}
for (JetPropertyAccessor accessor : property.getAccessors()) {
value(accessor, false);
}
}
@Override
public void visitPropertyAccessor(JetPropertyAccessor accessor) {
processLocalDeclaration(accessor);
}
@Override
@@ -41,6 +41,7 @@ import org.jetbrains.jet.plugin.JetMainDetector;
import java.util.*;
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;
/**
@@ -254,7 +255,7 @@ public class JetFlowInformationProvider {
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);
}
if (!error) {
if (!error && processClassOrObject) {
error = checkAssignmentBeforeDeclaration(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor));
}
if (!error && processClassOrObject) {
@@ -265,7 +266,7 @@ public class JetFlowInformationProvider {
});
recordInitializedVariables(declaredVariables, traverser.getResultInfo());
analyzeLocalDeclarations(processLocalDeclaration, pseudocode);
analyzeLocalDeclarations(pseudocode, processLocalDeclaration);
}
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()) {
if (instruction instanceof LocalDeclarationInstruction) {
JetElement element = ((LocalDeclarationInstruction) instruction).getElement();
@@ -595,6 +596,7 @@ public class JetFlowInformationProvider {
!DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
VariableStatus variableStatus = enterData.get(variableDescriptor);
if (instruction instanceof WriteValueInstruction) {
if (trace.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor)) return;
JetElement element = ((WriteValueInstruction) instruction).getElement();
if (variableStatus != VariableStatus.READ) {
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()) {
JetProperty property = entry.getKey();
if (!context.completeAnalysisNeeded(property)) continue;
PropertyDescriptor propertyDescriptor = entry.getValue();
checkProperty(property, propertyDescriptor);
}
}
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());
flowInformationProvider.markUninitializedVariables((JetElement) klass, context.isDeclaredLocally());
}
@@ -95,7 +97,9 @@ public class ControlFlowAnalyzer {
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());
@@ -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 ==
class AnonymousInitializers() {
val k = 34
@@ -24,23 +37,22 @@ l0:
r(12) NEXT:[w($i)] PREV:[v(val i: Int)]
w($i) NEXT:[v(val j: Int get() = 20) ] PREV:[r(12)]
v(val j: Int
get() = 20) NEXT:[r(13)] PREV:[w($i)]
r(13) NEXT:[w($i)] PREV:[v(val j: Int get() = 20) ]
get() = 20) NEXT:[jmp?(l2)] PREV:[w($i)]
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)]
l1:
<END> NEXT:[<SINK>] PREV:[w($i)]
error:
<ERROR> NEXT:[] PREV:[]
sink:
<SINK> NEXT:[] PREV:[<END>]
=====================
== get_j ==
get() = 20
---------------------
l0:
<SINK> NEXT:[] PREV:[d(get() = 20), <END>]
l3:
<START> NEXT:[r(20)] PREV:[]
r(20) NEXT:[<END>] PREV:[<START>]
l1:
l4:
<END> NEXT:[<SINK>] PREV:[r(20)]
error:
<ERROR> NEXT:[] PREV:[]
@@ -328,7 +328,7 @@ fun func() {
val <!UNUSED_VARIABLE!>a<!> = object {
val x = b
{
<!VAL_REASSIGNMENT!>b<!> = <!UNUSED_VALUE!>4<!>
<!VAL_REASSIGNMENT!>b<!> = 4
<!UNRESOLVED_REFERENCE!>$b<!> = 3
}
}
@@ -93,7 +93,7 @@ class MyTest() {
fun testInnerFunctions() {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>y<!> = 1
fun foo() {
y = <!UNUSED_VALUE!>1<!>
y = 1
}
var z = 1
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
}
else {
z = <!UNUSED_VALUE!>34<!>
z = 34
}
}
val <!UNUSED_VARIABLE!>f<!>: ()-> Int = <!TYPE_MISMATCH!>r<!>
@@ -74,7 +74,7 @@ fun testCoercionToUnit() {
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>x<!> = 43
val checkType = {
if (true) {
x = <!UNUSED_VALUE!>4<!>
x = 4
} else {
45
}
@@ -31,7 +31,7 @@ fun main(args: Array<String>) {
var m: MyNumber = MyNumber()
val <!UNUSED_VARIABLE!>a<!> = { (): MyNumber ->
<!UNUSED_CHANGED_VALUE!>m++<!>
m++
}
}
+3 -3
View File
@@ -1,19 +1,19 @@
fun refs() {
var <info><warning>a</warning></info> = 1
val <warning>v</warning> = {
<info>a</info> = <warning>2</warning>
<info>a</info> = 2
}
var <info><warning>x</warning></info> = 1
val <warning>b</warning> = object {
fun foo() {
<info>x</info> = <warning>2</warning>
<info>x</info> = 2
}
}
var <info><warning>y</warning></info> = 1
fun foo() {
<info>y</info> = <warning>1</warning>
<info>y</info> = 1
}
}