KT-610 Distinguish errors 'unused variable' and 'variable is assigned but never accessed'
This commit is contained in:
+36
-13
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jet.lang.cfg;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -19,31 +20,36 @@ import java.util.Map;
|
||||
public class JetControlFlowGraphTraverser<D> {
|
||||
private final Pseudocode pseudocode;
|
||||
private final boolean lookInside;
|
||||
private final boolean straightDirection;
|
||||
private final Map<Instruction, Pair<D, D>> dataMap = Maps.newLinkedHashMap();
|
||||
|
||||
public static <D> JetControlFlowGraphTraverser<D> create(Pseudocode pseudocode, boolean lookInside) {
|
||||
return new JetControlFlowGraphTraverser<D>(pseudocode, lookInside);
|
||||
public static <D> JetControlFlowGraphTraverser<D> create(Pseudocode pseudocode, boolean lookInside, boolean straightDirection) {
|
||||
return new JetControlFlowGraphTraverser<D>(pseudocode, lookInside, straightDirection);
|
||||
}
|
||||
|
||||
private JetControlFlowGraphTraverser(Pseudocode pseudocode, boolean lookInside) {
|
||||
private JetControlFlowGraphTraverser(Pseudocode pseudocode, boolean lookInside, boolean straightDirection) {
|
||||
this.pseudocode = pseudocode;
|
||||
this.lookInside = lookInside;
|
||||
this.straightDirection = straightDirection;
|
||||
}
|
||||
|
||||
private Instruction getStartInstruction(Pseudocode pseudocode) {
|
||||
return straightDirection ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction();
|
||||
}
|
||||
|
||||
public void collectInformationFromInstructionGraph(
|
||||
InstructionDataMergeStrategy<D> instructionDataMergeStrategy,
|
||||
D initialDataValue,
|
||||
D initialDataValueForEnterInstruction,
|
||||
boolean straightDirection) {
|
||||
D initialDataValueForEnterInstruction) {
|
||||
initializeDataMap(pseudocode, initialDataValue);
|
||||
dataMap.put(straightDirection ? pseudocode.getEnterInstruction() : pseudocode.getSinkInstruction(),
|
||||
dataMap.put(getStartInstruction(pseudocode),
|
||||
Pair.create(initialDataValueForEnterInstruction, initialDataValueForEnterInstruction));
|
||||
|
||||
boolean[] changed = new boolean[1];
|
||||
changed[0] = true;
|
||||
while (changed[0]) {
|
||||
changed[0] = false;
|
||||
traverseSubGraph(pseudocode, instructionDataMergeStrategy, Collections.<Instruction>emptyList(), straightDirection, changed, false);
|
||||
traverseSubGraph(pseudocode, instructionDataMergeStrategy, Collections.<Instruction>emptyList(), changed, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,20 +70,25 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
Pseudocode pseudocode,
|
||||
InstructionDataMergeStrategy<D> instructionDataMergeStrategy,
|
||||
Collection<Instruction> previousSubGraphInstructions,
|
||||
boolean straightDirection,
|
||||
boolean[] changed,
|
||||
boolean isLocal) {
|
||||
List<Instruction> instructions = pseudocode.getInstructions();
|
||||
SubroutineEnterInstruction enterInstruction = pseudocode.getEnterInstruction();
|
||||
Instruction startInstruction = getStartInstruction(pseudocode);
|
||||
|
||||
if (!straightDirection) {
|
||||
instructions = Lists.newArrayList(instructions);
|
||||
Collections.reverse(instructions);
|
||||
}
|
||||
for (Instruction instruction : instructions) {
|
||||
if (!isLocal && instruction instanceof SubroutineEnterInstruction) continue;
|
||||
boolean isStart = straightDirection ? instruction instanceof SubroutineEnterInstruction : instruction instanceof SubroutineSinkInstruction;
|
||||
if (!isLocal && isStart) continue;
|
||||
|
||||
Collection<Instruction> allPreviousInstructions;
|
||||
Collection<Instruction> previousInstructions = straightDirection
|
||||
? instruction.getPreviousInstructions()
|
||||
: instruction.getNextInstructions();
|
||||
|
||||
if (instruction == enterInstruction && !previousSubGraphInstructions.isEmpty()) {
|
||||
if (instruction == startInstruction && !previousSubGraphInstructions.isEmpty()) {
|
||||
allPreviousInstructions = Lists.newArrayList(previousInstructions);
|
||||
allPreviousInstructions.addAll(previousSubGraphInstructions);
|
||||
}
|
||||
@@ -87,7 +98,15 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
|
||||
if (lookInside && instruction instanceof LocalDeclarationInstruction) {
|
||||
Pseudocode subroutinePseudocode = ((LocalDeclarationInstruction) instruction).getBody();
|
||||
traverseSubGraph(subroutinePseudocode, instructionDataMergeStrategy, previousInstructions, straightDirection, changed, true);
|
||||
traverseSubGraph(subroutinePseudocode, instructionDataMergeStrategy, previousInstructions, changed, true);
|
||||
Instruction lastInstruction = straightDirection ? subroutinePseudocode.getSinkInstruction() : subroutinePseudocode.getEnterInstruction();
|
||||
Pair<D, D> previousValue = dataMap.get(instruction);
|
||||
Pair<D, D> newValue = dataMap.get(lastInstruction);
|
||||
if (!previousValue.equals(newValue)) {
|
||||
changed[0] = true;
|
||||
dataMap.put(instruction, newValue);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Pair<D, D> previousDataValue = dataMap.get(instruction);
|
||||
|
||||
@@ -116,12 +135,16 @@ public class JetControlFlowGraphTraverser<D> {
|
||||
Pseudocode pseudocode,
|
||||
InstructionDataAnalyzeStrategy<D> instructionDataAnalyzeStrategy) {
|
||||
List<Instruction> instructions = pseudocode.getInstructions();
|
||||
if (!straightDirection) {
|
||||
instructions = Lists.newArrayList(instructions);
|
||||
Collections.reverse(instructions);
|
||||
}
|
||||
for (Instruction instruction : instructions) {
|
||||
if (instruction.isDead()) continue;
|
||||
Pair<D, D> pair = dataMap.get(instruction);
|
||||
if (lookInside && instruction instanceof LocalDeclarationInstruction) {
|
||||
traverseAndAnalyzeInstructionGraph(((LocalDeclarationInstruction) instruction).getBody(), instructionDataAnalyzeStrategy);
|
||||
}
|
||||
Pair<D, D> pair = dataMap.get(instruction);
|
||||
instructionDataAnalyzeStrategy.execute(instruction,
|
||||
pair != null ? pair.getFirst() : null,
|
||||
pair != null ? pair.getSecond() : null);
|
||||
|
||||
@@ -194,7 +194,7 @@ public class JetFlowInformationProvider {
|
||||
final Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
JetControlFlowGraphTraverser<Map<VariableDescriptor, VariableInitializers>> traverser = JetControlFlowGraphTraverser.create(pseudocode, false);
|
||||
JetControlFlowGraphTraverser<Map<VariableDescriptor, VariableInitializers>> traverser = JetControlFlowGraphTraverser.create(pseudocode, false, true);
|
||||
|
||||
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
|
||||
final Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
|
||||
@@ -213,7 +213,7 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
};
|
||||
|
||||
traverser.collectInformationFromInstructionGraph(variableInitializersMergeStrategy, Collections.<VariableDescriptor, VariableInitializers>emptyMap(), initialMapForStartInstruction, true);
|
||||
traverser.collectInformationFromInstructionGraph(variableInitializersMergeStrategy, Collections.<VariableDescriptor, VariableInitializers>emptyMap(), initialMapForStartInstruction);
|
||||
|
||||
final Collection<VariableDescriptor> varWithUninitializedErrorGenerated = Sets.newHashSet();
|
||||
final Collection<VariableDescriptor> varWithValReassignErrorGenerated = Sets.newHashSet();
|
||||
@@ -396,7 +396,7 @@ public class JetFlowInformationProvider {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, Void enterData, Void exitData) {
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
@@ -419,73 +419,50 @@ public class JetFlowInformationProvider {
|
||||
public void markUnusedVariables(@NotNull JetElement subroutine) {
|
||||
Pseudocode pseudocode = pseudocodeMap.get(subroutine);
|
||||
assert pseudocode != null;
|
||||
|
||||
final Set<VariableDescriptor> usedVariables = Sets.newHashSet();
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) {
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
||||
usedVariables.add(variableDescriptor);
|
||||
}
|
||||
}
|
||||
});
|
||||
Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
|
||||
for (VariableDescriptor declaredVariable : declaredVariables) {
|
||||
if (!usedVariables.contains(declaredVariable)) {
|
||||
PsiElement element = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaredVariable);
|
||||
//todo
|
||||
if (element instanceof JetProperty && JetPsiUtil.isLocal((JetNamedDeclaration) element)) {
|
||||
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
|
||||
PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element;
|
||||
trace.report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration)element, elementToMark, declaredVariable));
|
||||
}
|
||||
}
|
||||
JetControlFlowGraphTraverser<Map<VariableDescriptor, VariableStatus>> traverser = JetControlFlowGraphTraverser.create(pseudocode, true, false);
|
||||
final Collection<VariableDescriptor> declaredVariables = collectDeclaredVariables(subroutine);
|
||||
Collection<VariableDescriptor> usedVariables = collectUsedVariables(pseudocode);
|
||||
Map<VariableDescriptor, VariableStatus> sinkInstructionData = Maps.newHashMap();
|
||||
for (VariableDescriptor usedVariable : usedVariables) {
|
||||
sinkInstructionData.put(usedVariable, VariableStatus.UNUSED);
|
||||
}
|
||||
|
||||
markUnusedValues(subroutine, pseudocode, declaredVariables);
|
||||
}
|
||||
|
||||
private void markUnusedValues(@NotNull JetElement subroutine, Pseudocode pseudocode, final Collection<VariableDescriptor> declaredVariables) {
|
||||
JetControlFlowGraphTraverser<Set<VariableDescriptor>> traverser = JetControlFlowGraphTraverser.create(pseudocode, true);
|
||||
traverser.collectInformationFromInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataMergeStrategy<Set<VariableDescriptor>>() {
|
||||
traverser.collectInformationFromInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataMergeStrategy<Map<VariableDescriptor, VariableStatus>>() {
|
||||
@Override
|
||||
public Pair<Set<VariableDescriptor>, Set<VariableDescriptor>> execute(Instruction instruction, @NotNull Collection<Set<VariableDescriptor>> incomingEdgesData) {
|
||||
Set<VariableDescriptor> enterResult = Sets.newHashSet();
|
||||
for (Set<VariableDescriptor> edgeData : incomingEdgesData) {
|
||||
enterResult.addAll(edgeData);
|
||||
}
|
||||
Set<VariableDescriptor> exitResult = Sets.newHashSet(enterResult);
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
|
||||
if (variableDescriptor != null) {
|
||||
exitResult.add(variableDescriptor);
|
||||
public Pair<Map<VariableDescriptor, VariableStatus>, Map<VariableDescriptor, VariableStatus>> execute(Instruction instruction, @NotNull Collection<Map<VariableDescriptor, VariableStatus>> incomingEdgesData) {
|
||||
Map<VariableDescriptor, VariableStatus> enterResult = Maps.newHashMap();
|
||||
for (Map<VariableDescriptor, VariableStatus> edgeData : incomingEdgesData) {
|
||||
for (Map.Entry<VariableDescriptor, VariableStatus> entry : edgeData.entrySet()) {
|
||||
VariableDescriptor variableDescriptor = entry.getKey();
|
||||
VariableStatus variableStatus = entry.getValue();
|
||||
enterResult.put(variableDescriptor, variableStatus.merge(enterResult.get(variableDescriptor)));
|
||||
}
|
||||
}
|
||||
else if (instruction instanceof WriteValueInstruction) {
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
|
||||
if (variableDescriptor != null) {
|
||||
exitResult.remove(variableDescriptor);
|
||||
Map<VariableDescriptor, VariableStatus> exitResult = Maps.newHashMap(enterResult);
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
|
||||
if (variableDescriptor != null) {
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
exitResult.put(variableDescriptor, VariableStatus.READ);
|
||||
}
|
||||
else if (instruction instanceof WriteValueInstruction) {
|
||||
exitResult.put(variableDescriptor, VariableStatus.WRITTEN);
|
||||
}
|
||||
}
|
||||
return new Pair<Set<VariableDescriptor>, Set<VariableDescriptor>>(enterResult, exitResult);
|
||||
return new Pair<Map<VariableDescriptor, VariableStatus>, Map<VariableDescriptor, VariableStatus>>(enterResult, exitResult);
|
||||
}
|
||||
}, Collections.<VariableDescriptor>emptySet(), Collections.<VariableDescriptor>emptySet(), false);
|
||||
traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Set<VariableDescriptor>>() {
|
||||
}, Collections.<VariableDescriptor, VariableStatus>emptyMap(), sinkInstructionData);
|
||||
traverser.traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableStatus>>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, @Nullable Set<VariableDescriptor> enterData, @Nullable Set<VariableDescriptor> exitData) {
|
||||
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, VariableStatus> enterData, @Nullable Map<VariableDescriptor, VariableStatus> exitData) {
|
||||
assert enterData != null && exitData != null;
|
||||
if (instruction instanceof WriteValueInstruction) {
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
||||
if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) {
|
||||
if (!enterData.contains(variableDescriptor)) {
|
||||
PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
||||
// assert variableDeclarationElement instanceof JetProperty || variableDeclarationElement instanceof JetParameter;
|
||||
// boolean isLocal = !(variableDeclarationElement instanceof JetProperty) || JetPsiUtil.isLocal((JetProperty) variableDeclarationElement);
|
||||
assert variableDeclarationElement instanceof JetDeclaration;
|
||||
boolean isLocal = JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement);
|
||||
if (isLocal) {
|
||||
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
||||
if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) {
|
||||
PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
||||
assert variableDeclarationElement instanceof JetDeclaration;
|
||||
boolean isLocal = JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement);
|
||||
if (isLocal) {
|
||||
if (instruction instanceof WriteValueInstruction) {
|
||||
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
||||
if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN || enterData.get(variableDescriptor) == VariableStatus.UNUSED) {
|
||||
if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
|
||||
JetExpression right = ((JetBinaryExpression) element).getRight();
|
||||
if (right != null) {
|
||||
@@ -499,6 +476,20 @@ public class JetFlowInformationProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instruction instanceof VariableDeclarationInstruction) {
|
||||
JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
||||
if (element instanceof JetProperty) {
|
||||
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
|
||||
PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element;
|
||||
if (enterData.get(variableDescriptor) == VariableStatus.UNUSED) {
|
||||
trace.report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration) element, elementToMark, variableDescriptor));
|
||||
}
|
||||
else if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN) {
|
||||
trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, elementToMark, variableDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,26 +497,44 @@ public class JetFlowInformationProvider {
|
||||
});
|
||||
}
|
||||
|
||||
private static enum VariableStatus {
|
||||
READ(2),
|
||||
WRITTEN(1),
|
||||
UNUSED(0);
|
||||
|
||||
private int importance;
|
||||
|
||||
private VariableStatus(int importance) {
|
||||
this.importance = importance;
|
||||
}
|
||||
|
||||
public VariableStatus merge(@Nullable VariableStatus variableStatus) {
|
||||
if (variableStatus == null || importance > variableStatus.importance) return this;
|
||||
return variableStatus;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Util methods
|
||||
|
||||
@Nullable
|
||||
private VariableDescriptor extractVariableDescriptorIfAny(Instruction instruction, boolean onlyReference) {
|
||||
VariableDescriptor variableDescriptor = null;
|
||||
JetElement element = null;
|
||||
if (instruction instanceof ReadValueInstruction) {
|
||||
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
||||
variableDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), element, onlyReference);
|
||||
element = ((ReadValueInstruction) instruction).getElement();
|
||||
}
|
||||
else if (instruction instanceof WriteValueInstruction) {
|
||||
JetElement lValue = ((WriteValueInstruction) instruction).getlValue();
|
||||
variableDescriptor = BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), lValue, onlyReference);
|
||||
element = ((WriteValueInstruction) instruction).getlValue();
|
||||
}
|
||||
return variableDescriptor;
|
||||
else if (instruction instanceof VariableDeclarationInstruction) {
|
||||
element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
||||
}
|
||||
return BindingContextUtils.extractVariableDescriptorIfAny(trace.getBindingContext(), element, onlyReference);
|
||||
}
|
||||
|
||||
private Collection<VariableDescriptor> collectUsedVariables(Pseudocode pseudocode) {
|
||||
final Set<VariableDescriptor> usedVariables = Sets.newHashSet();
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, true, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, Void enterData, Void exitData) {
|
||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
||||
@@ -542,7 +551,7 @@ public class JetFlowInformationProvider {
|
||||
assert pseudocode != null;
|
||||
|
||||
final Set<VariableDescriptor> declaredVariables = Sets.newHashSet();
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, false).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
JetControlFlowGraphTraverser.<Void>create(pseudocode, false, true).traverseAndAnalyzeInstructionGraph(new JetControlFlowGraphTraverser.InstructionDataAnalyzeStrategy<Void>() {
|
||||
@Override
|
||||
public void execute(Instruction instruction, @Nullable Void enterData, @Nullable Void exitData) {
|
||||
if (instruction instanceof VariableDeclarationInstruction) {
|
||||
|
||||
@@ -145,6 +145,7 @@ public interface Errors {
|
||||
|
||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> UNINITIALIZED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Variable ''{0}'' must be initialized", NAME);
|
||||
PsiElementOnlyDiagnosticFactory1<JetNamedDeclaration, DeclarationDescriptor> UNUSED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(WARNING, "Variable ''{0}'' is never used", NAME);
|
||||
PsiElementOnlyDiagnosticFactory1<JetNamedDeclaration, DeclarationDescriptor> ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE = PsiElementOnlyDiagnosticFactory1.create(WARNING, "Variable ''{0}'' is assigned but never accessed", NAME);
|
||||
PsiElementOnlyDiagnosticFactory2<JetElement, JetElement, DeclarationDescriptor> UNUSED_VALUE = new PsiElementOnlyDiagnosticFactory2<JetElement, JetElement, DeclarationDescriptor>(WARNING, "The value ''{0}'' assigned to ''{1}'' is never used", NAME) {
|
||||
@Override
|
||||
protected String makeMessageForA(@NotNull JetElement element) {
|
||||
|
||||
@@ -11,7 +11,7 @@ class C() {
|
||||
}
|
||||
|
||||
fun f(): Unit {
|
||||
var x: Int? = 1
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>x<!>: Int? = 1
|
||||
x = 1
|
||||
x <!UNSAFE_INFIX_CALL!>+<!> 1
|
||||
x <!UNSAFE_INFIX_CALL!>plus<!> 1
|
||||
|
||||
@@ -179,7 +179,7 @@ fun declarations(a: Any?) {
|
||||
}
|
||||
}
|
||||
fun vars(a: Any?) {
|
||||
var <!UNUSED_VARIABLE!>b<!>: Int = 0
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>b<!>: Int = 0
|
||||
if (a is Int) {
|
||||
b = <!UNUSED_VALUE!>a<!>
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class AClass() {
|
||||
val x : Any? = 1
|
||||
|
||||
fun Any?.vars(a: Any?) : Int {
|
||||
var <!UNUSED_VARIABLE!>b<!>: Int = 0
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>b<!>: Int = 0
|
||||
if (ns.y is Int) {
|
||||
b = <!UNUSED_VALUE!>ns.y<!>
|
||||
}
|
||||
@@ -74,7 +74,7 @@ trait T {}
|
||||
|
||||
open class C {
|
||||
fun foo() {
|
||||
var <!UNUSED_VARIABLE!>t<!> : T? = null
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>t<!> : T? = null
|
||||
if (this is T) {
|
||||
t = <!UNUSED_VALUE!>this<!>
|
||||
}
|
||||
|
||||
+3
-3
@@ -16,7 +16,7 @@ fun t1(b : Boolean) {
|
||||
}
|
||||
doSmth(<!UNINITIALIZED_VARIABLE!>u<!>)
|
||||
|
||||
var r: String
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>r<!>: String
|
||||
if (b) {
|
||||
r = "s"
|
||||
}
|
||||
@@ -63,10 +63,10 @@ fun t4(a: A, val b: A, var c: A) {
|
||||
// reassigned vals
|
||||
|
||||
fun t1() {
|
||||
val <!UNUSED_VARIABLE!>a<!> : Int = 1
|
||||
val <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>a<!> : Int = 1
|
||||
<!VAL_REASSIGNMENT!>a<!> = <!UNUSED_VALUE!>2<!>
|
||||
|
||||
var <!UNUSED_VARIABLE!>b<!> : Int = 1
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>b<!> : Int = 1
|
||||
b = <!UNUSED_VALUE!>3<!>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace unused_variables
|
||||
|
||||
fun testSimpleCases() {
|
||||
var i = 2
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>i<!> = 2
|
||||
i = <!UNUSED_VALUE!>34<!>
|
||||
i = 34
|
||||
doSmth(i)
|
||||
@@ -9,7 +9,7 @@ fun testSimpleCases() {
|
||||
|
||||
var j = 2
|
||||
j = <!UNUSED_CHANGED_VALUE!>j++<!>
|
||||
j = <!UNUSED_CHANGED_VALUE, UNUSED_VALUE!>j--<!>
|
||||
j = <!UNUSED_VALUE, UNUSED_CHANGED_VALUE!>j--<!>
|
||||
}
|
||||
|
||||
class IncDec() {
|
||||
@@ -45,7 +45,7 @@ class MyTest() {
|
||||
fun testSimple() {
|
||||
a = "rro"
|
||||
|
||||
var <!UNUSED_VARIABLE!>i<!> = 1;
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>i<!> = 1;
|
||||
i = <!UNUSED_VALUE!>34<!>;
|
||||
i = <!UNUSED_VALUE!>456<!>;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class MyTest() {
|
||||
}
|
||||
|
||||
fun testIf() {
|
||||
var a : Any
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>a<!> : Any
|
||||
if (1 < 2) {
|
||||
a = 23
|
||||
}
|
||||
@@ -91,7 +91,7 @@ class MyTest() {
|
||||
}
|
||||
|
||||
fun testInnerFunctions() {
|
||||
var <!UNUSED_VARIABLE!>y<!> = 1
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>y<!> = 1
|
||||
fun foo() {
|
||||
y = <!UNUSED_VALUE!>1<!>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//KT-610 Distinguish errors 'unused variable' and 'variable is assigned but never accessed'
|
||||
|
||||
namespace kt610
|
||||
|
||||
fun foo() {
|
||||
var <!UNUSED_VARIABLE!>j<!> = 9 //'unused variable' error
|
||||
|
||||
var <!ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE!>i<!> = 1 //should be an error 'variable i is assigned but never accessed'
|
||||
i = <!UNUSED_VALUE!>2<!>
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class JetPsiChecker implements Annotator {
|
||||
}
|
||||
else if (diagnostic.getSeverity() == Severity.WARNING) {
|
||||
annotation = holder.createWarningAnnotation(diagnostic.getFactory().getTextRange(diagnostic), getMessage(diagnostic));
|
||||
if (diagnostic.getFactory() == Errors.UNUSED_VARIABLE) {
|
||||
if (diagnostic.getFactory() == Errors.UNUSED_VARIABLE || diagnostic.getFactory() == Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE) {
|
||||
annotation.setHighlightType(ProblemHighlightType.LIKE_UNUSED_SYMBOL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class C() {
|
||||
}
|
||||
|
||||
fun f(): Unit {
|
||||
var x: Int? = 1
|
||||
var <warning>x</warning>: Int? = 1
|
||||
x = 1
|
||||
x <error>+</error> 1
|
||||
x <error>plus</error> 1
|
||||
|
||||
Reference in New Issue
Block a user