KT-1191 Wrong detection of unused parameters
KT-1219 Incorrect 'unused value' error in closures
This commit is contained in:
@@ -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)
|
||||
}
|
||||
+2
-2
@@ -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++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user