Formatting.
This commit is contained in:
+161
-129
@@ -227,7 +227,9 @@ public class JetFlowInformationProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitExpression(@NotNull JetExpression expression) {
|
public void visitExpression(@NotNull JetExpression expression) {
|
||||||
if (blockBody && !noExpectedType(expectedReturnType) && !KotlinBuiltIns.getInstance().isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
|
if (blockBody && !noExpectedType(expectedReturnType)
|
||||||
|
&& !KotlinBuiltIns.getInstance().isUnit(expectedReturnType)
|
||||||
|
&& !rootUnreachableElements.contains(expression)) {
|
||||||
noReturnError[0] = true;
|
noReturnError[0] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +261,8 @@ public class JetFlowInformationProvider {
|
|||||||
final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
|
final boolean processClassOrObject = subroutine instanceof JetClassOrObject;
|
||||||
|
|
||||||
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||||
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
|
Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> initializers =
|
||||||
|
pseudocodeVariablesData.getVariableInitializers();
|
||||||
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true);
|
final Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, true);
|
||||||
final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariablesData.getLexicalScopeVariableInfo();
|
final LexicalScopeVariableInfo lexicalScopeVariableInfo = pseudocodeVariablesData.getLexicalScopeVariableInfo();
|
||||||
|
|
||||||
@@ -268,42 +271,47 @@ public class JetFlowInformationProvider {
|
|||||||
PseudocodeTraverserPackage.traverse(
|
PseudocodeTraverserPackage.traverse(
|
||||||
pseudocode, FORWARD, initializers,
|
pseudocode, FORWARD, initializers,
|
||||||
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableInitState>>() {
|
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableInitState>>() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull Instruction instruction,
|
public void execute(
|
||||||
@Nullable Map<VariableDescriptor, VariableInitState> in,
|
@NotNull Instruction instruction,
|
||||||
@Nullable Map<VariableDescriptor, VariableInitState> out) {
|
@Nullable Map<VariableDescriptor, VariableInitState> in,
|
||||||
assert in != null && out != null;
|
@Nullable Map<VariableDescriptor, VariableInitState> out
|
||||||
VariableInitContext ctxt = new VariableInitContext(instruction, reportedDiagnosticMap, in, out, lexicalScopeVariableInfo);
|
) {
|
||||||
if (ctxt.variableDescriptor == null) return;
|
assert in != null && out != null;
|
||||||
if (instruction instanceof ReadValueInstruction) {
|
VariableInitContext ctxt =
|
||||||
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
new VariableInitContext(instruction, reportedDiagnosticMap, in, out, lexicalScopeVariableInfo);
|
||||||
boolean error = checkBackingField(ctxt, element);
|
if (ctxt.variableDescriptor == null) return;
|
||||||
if (!error && declaredVariables.contains(ctxt.variableDescriptor)) {
|
if (instruction instanceof ReadValueInstruction) {
|
||||||
checkIsInitialized(ctxt, element, varWithUninitializedErrorGenerated);
|
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
||||||
|
boolean error = checkBackingField(ctxt, element);
|
||||||
|
if (!error && declaredVariables.contains(ctxt.variableDescriptor)) {
|
||||||
|
checkIsInitialized(ctxt, element, varWithUninitializedErrorGenerated);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!(instruction instanceof WriteValueInstruction)) return;
|
||||||
|
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
||||||
|
boolean error = checkBackingField(ctxt, element);
|
||||||
|
if (!(element instanceof JetExpression)) return;
|
||||||
|
if (!error) {
|
||||||
|
error = checkValReassignment(ctxt, (JetExpression) element, varWithValReassignErrorGenerated);
|
||||||
|
}
|
||||||
|
if (!error && processClassOrObject) {
|
||||||
|
error = checkAssignmentBeforeDeclaration(ctxt, (JetExpression) element);
|
||||||
|
}
|
||||||
|
if (!error && processClassOrObject) {
|
||||||
|
checkInitializationUsingBackingField(ctxt, (JetExpression) element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!(instruction instanceof WriteValueInstruction)) return;
|
);
|
||||||
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
|
||||||
boolean error = checkBackingField(ctxt, element);
|
|
||||||
if (!(element instanceof JetExpression)) return;
|
|
||||||
if (!error) {
|
|
||||||
error = checkValReassignment(ctxt, (JetExpression) element, varWithValReassignErrorGenerated);
|
|
||||||
}
|
|
||||||
if (!error && processClassOrObject) {
|
|
||||||
error = checkAssignmentBeforeDeclaration(ctxt, (JetExpression) element);
|
|
||||||
}
|
|
||||||
if (!error && processClassOrObject) {
|
|
||||||
checkInitializationUsingBackingField(ctxt, (JetExpression) element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recordInitializedVariables() {
|
public void recordInitializedVariables() {
|
||||||
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||||
Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode();
|
Pseudocode pseudocode = pseudocodeVariablesData.getPseudocode();
|
||||||
Map<Instruction, Edges<Map<VariableDescriptor,VariableInitState>>> initializers = pseudocodeVariablesData.getVariableInitializers();
|
Map<Instruction, Edges<Map<VariableDescriptor, VariableInitState>>> initializers =
|
||||||
|
pseudocodeVariablesData.getVariableInitializers();
|
||||||
recordInitializedVariables(pseudocode, initializers);
|
recordInitializedVariables(pseudocode, initializers);
|
||||||
for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
|
for (LocalFunctionDeclarationInstruction instruction : pseudocode.getLocalDeclarations()) {
|
||||||
recordInitializedVariables(instruction.getBody(), initializers);
|
recordInitializedVariables(instruction.getBody(), initializers);
|
||||||
@@ -364,13 +372,15 @@ public class JetFlowInformationProvider {
|
|||||||
if (variableDescriptor.isVar() && variableDescriptor instanceof PropertyDescriptor) {
|
if (variableDescriptor.isVar() && variableDescriptor instanceof PropertyDescriptor) {
|
||||||
DeclarationDescriptor descriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), expression);
|
DeclarationDescriptor descriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), expression);
|
||||||
PropertySetterDescriptor setterDescriptor = ((PropertyDescriptor) variableDescriptor).getSetter();
|
PropertySetterDescriptor setterDescriptor = ((PropertyDescriptor) variableDescriptor).getSetter();
|
||||||
if (Visibilities.isVisible(variableDescriptor, descriptor) && setterDescriptor != null && !Visibilities.isVisible(setterDescriptor, descriptor)) {
|
if (Visibilities.isVisible(variableDescriptor, descriptor) && setterDescriptor != null
|
||||||
|
&& !Visibilities.isVisible(setterDescriptor, descriptor)) {
|
||||||
report(Errors.INVISIBLE_SETTER.on(expression, variableDescriptor, setterDescriptor.getVisibility(),
|
report(Errors.INVISIBLE_SETTER.on(expression, variableDescriptor, setterDescriptor.getVisibility(),
|
||||||
variableDescriptor.getContainingDeclaration()), ctxt);
|
variableDescriptor.getContainingDeclaration()), ctxt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((isInitializedNotHere || !hasBackingField) && !variableDescriptor.isVar() && !varWithValReassignErrorGenerated.contains(variableDescriptor)) {
|
if ((isInitializedNotHere || !hasBackingField) && !variableDescriptor.isVar()
|
||||||
|
&& !varWithValReassignErrorGenerated.contains(variableDescriptor)) {
|
||||||
boolean hasReassignMethodReturningUnit = false;
|
boolean hasReassignMethodReturningUnit = false;
|
||||||
JetSimpleNameExpression operationReference = null;
|
JetSimpleNameExpression operationReference = null;
|
||||||
PsiElement parent = expression.getParent();
|
PsiElement parent = expression.getParent();
|
||||||
@@ -388,7 +398,8 @@ public class JetFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (descriptor == null) {
|
if (descriptor == null) {
|
||||||
Collection<? extends DeclarationDescriptor> descriptors = trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, operationReference);
|
Collection<? extends DeclarationDescriptor> descriptors =
|
||||||
|
trace.get(BindingContext.AMBIGUOUS_REFERENCE_TARGET, operationReference);
|
||||||
if (descriptors != null) {
|
if (descriptors != null) {
|
||||||
for (DeclarationDescriptor referenceDescriptor : descriptors) {
|
for (DeclarationDescriptor referenceDescriptor : descriptors) {
|
||||||
if (KotlinBuiltIns.getInstance().isUnit(((FunctionDescriptor) referenceDescriptor).getReturnType())) {
|
if (KotlinBuiltIns.getInstance().isUnit(((FunctionDescriptor) referenceDescriptor).getReturnType())) {
|
||||||
@@ -408,7 +419,8 @@ public class JetFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkAssignmentBeforeDeclaration(@NotNull VariableInitContext ctxt, @NotNull JetExpression expression) {
|
private boolean checkAssignmentBeforeDeclaration(@NotNull VariableInitContext ctxt, @NotNull JetExpression expression) {
|
||||||
if (!ctxt.enterInitState.isDeclared && !ctxt.exitInitState.isDeclared && !ctxt.enterInitState.isInitialized && ctxt.exitInitState.isInitialized) {
|
if (!ctxt.enterInitState.isDeclared && !ctxt.exitInitState.isDeclared
|
||||||
|
&& !ctxt.enterInitState.isInitialized && ctxt.exitInitState.isInitialized) {
|
||||||
report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt);
|
report(Errors.INITIALIZATION_BEFORE_DECLARATION.on(expression, ctxt.variableDescriptor), ctxt);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -422,7 +434,9 @@ public class JetFlowInformationProvider {
|
|||||||
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false;
|
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return false;
|
||||||
PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor);
|
PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor);
|
||||||
assert property instanceof JetProperty;
|
assert property instanceof JetProperty;
|
||||||
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && ((JetProperty) property).getSetter() == null) return false;
|
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && ((JetProperty) property).getSetter() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
JetExpression variable = expression;
|
JetExpression variable = expression;
|
||||||
if (expression instanceof JetDotQualifiedExpression) {
|
if (expression instanceof JetDotQualifiedExpression) {
|
||||||
if (((JetDotQualifiedExpression) expression).getReceiverExpression() instanceof JetThisExpression) {
|
if (((JetDotQualifiedExpression) expression).getReceiverExpression() instanceof JetThisExpression) {
|
||||||
@@ -457,7 +471,8 @@ public class JetFlowInformationProvider {
|
|||||||
PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor);
|
PsiElement property = BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), variableDescriptor);
|
||||||
boolean insideSelfAccessors = PsiTreeUtil.isAncestor(property, element, false);
|
boolean insideSelfAccessors = PsiTreeUtil.isAncestor(property, element, false);
|
||||||
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) &&
|
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) &&
|
||||||
!insideSelfAccessors) { // not to generate error in accessors of abstract properties, there is one: declared accessor of abstract property
|
// not to generate error in accessors of abstract properties, there is one: declared accessor of abstract property
|
||||||
|
!insideSelfAccessors) {
|
||||||
|
|
||||||
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.ABSTRACT) {
|
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.ABSTRACT) {
|
||||||
report(NO_BACKING_FIELD_ABSTRACT_PROPERTY.on(element), cxtx);
|
report(NO_BACKING_FIELD_ABSTRACT_PROPERTY.on(element), cxtx);
|
||||||
@@ -472,14 +487,20 @@ public class JetFlowInformationProvider {
|
|||||||
DeclarationDescriptor declarationDescriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), element);
|
DeclarationDescriptor declarationDescriptor = BindingContextUtils.getEnclosingDescriptor(trace.getBindingContext(), element);
|
||||||
|
|
||||||
DeclarationDescriptor containingDeclaration = variableDescriptor.getContainingDeclaration();
|
DeclarationDescriptor containingDeclaration = variableDescriptor.getContainingDeclaration();
|
||||||
if ((containingDeclaration instanceof ClassDescriptor) && DescriptorUtils.isAncestor(containingDeclaration, declarationDescriptor, false)) {
|
if ((containingDeclaration instanceof ClassDescriptor)
|
||||||
|
&& DescriptorUtils.isAncestor(containingDeclaration, declarationDescriptor, false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
report(Errors.INACCESSIBLE_BACKING_FIELD.on(element), cxtx);
|
report(Errors.INACCESSIBLE_BACKING_FIELD.on(element), cxtx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCorrectBackingFieldReference(@Nullable JetElement element, VariableContext ctxt, boolean[] error, boolean reportError) {
|
private boolean isCorrectBackingFieldReference(
|
||||||
|
@Nullable JetElement element,
|
||||||
|
VariableContext ctxt,
|
||||||
|
boolean[] error,
|
||||||
|
boolean reportError
|
||||||
|
) {
|
||||||
error[0] = false;
|
error[0] = false;
|
||||||
if (JetPsiUtil.isBackingFieldReference(element)) {
|
if (JetPsiUtil.isBackingFieldReference(element)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -497,7 +518,10 @@ public class JetFlowInformationProvider {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recordInitializedVariables(@NotNull Pseudocode pseudocode, @NotNull Map<Instruction, Edges<Map<VariableDescriptor,PseudocodeVariablesData.VariableInitState>>> initializersMap) {
|
private void recordInitializedVariables(
|
||||||
|
@NotNull Pseudocode pseudocode,
|
||||||
|
@NotNull Map<Instruction, Edges<Map<VariableDescriptor, PseudocodeVariablesData.VariableInitState>>> initializersMap
|
||||||
|
) {
|
||||||
Edges<Map<VariableDescriptor, VariableInitState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
|
Edges<Map<VariableDescriptor, VariableInitState>> initializers = initializersMap.get(pseudocode.getExitInstruction());
|
||||||
Set<VariableDescriptor> declaredVariables = getPseudocodeVariablesData().getDeclaredVariables(pseudocode, false);
|
Set<VariableDescriptor> declaredVariables = getPseudocodeVariablesData().getDeclaredVariables(pseudocode, false);
|
||||||
for (VariableDescriptor variable : declaredVariables) {
|
for (VariableDescriptor variable : declaredVariables) {
|
||||||
@@ -514,83 +538,91 @@ public class JetFlowInformationProvider {
|
|||||||
|
|
||||||
public void markUnusedVariables() {
|
public void markUnusedVariables() {
|
||||||
final PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
final PseudocodeVariablesData pseudocodeVariablesData = getPseudocodeVariablesData();
|
||||||
Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusData = pseudocodeVariablesData.getVariableUseStatusData();
|
Map<Instruction, Edges<Map<VariableDescriptor, VariableUseState>>> variableStatusData =
|
||||||
|
pseudocodeVariablesData.getVariableUseStatusData();
|
||||||
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
|
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
|
||||||
InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy =
|
InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>> variableStatusAnalyzeStrategy =
|
||||||
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>>() {
|
new InstructionDataAnalyzeStrategy<Map<VariableDescriptor, VariableUseState>>() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull Instruction instruction,
|
public void execute(
|
||||||
@Nullable Map<VariableDescriptor, VariableUseState> in,
|
@NotNull Instruction instruction,
|
||||||
@Nullable Map<VariableDescriptor, VariableUseState> out) {
|
@Nullable Map<VariableDescriptor, VariableUseState> in,
|
||||||
|
@Nullable Map<VariableDescriptor, VariableUseState> out
|
||||||
|
) {
|
||||||
|
|
||||||
assert in != null && out != null;
|
assert in != null && out != null;
|
||||||
VariableContext ctxt = new VariableUseContext(instruction, reportedDiagnosticMap, in, out);
|
VariableContext ctxt = new VariableUseContext(instruction, reportedDiagnosticMap, in, out);
|
||||||
Set<VariableDescriptor> declaredVariables = pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner(), false);
|
Set<VariableDescriptor> declaredVariables =
|
||||||
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(instruction, false,
|
pseudocodeVariablesData.getDeclaredVariables(instruction.getOwner(), false);
|
||||||
trace.getBindingContext());
|
VariableDescriptor variableDescriptor = PseudocodeUtil.extractVariableDescriptorIfAny(
|
||||||
if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor) ||
|
instruction, false, trace.getBindingContext());
|
||||||
!DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) return;
|
if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor)
|
||||||
PseudocodeVariablesData.VariableUseState variableUseState = in.get(variableDescriptor);
|
|| !DescriptorUtils.isLocal(variableDescriptor.getContainingDeclaration(), variableDescriptor)) {
|
||||||
if (instruction instanceof WriteValueInstruction) {
|
return;
|
||||||
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null) return;
|
}
|
||||||
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
PseudocodeVariablesData.VariableUseState variableUseState = in.get(variableDescriptor);
|
||||||
if (variableUseState != READ) {
|
if (instruction instanceof WriteValueInstruction) {
|
||||||
if (element instanceof JetBinaryExpression &&
|
if (trace.get(CAPTURED_IN_CLOSURE, variableDescriptor) != null) return;
|
||||||
((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
|
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
||||||
JetExpression right = ((JetBinaryExpression) element).getRight();
|
if (variableUseState != READ) {
|
||||||
if (right != null) {
|
if (element instanceof JetBinaryExpression &&
|
||||||
report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor), ctxt);
|
((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
|
||||||
|
JetExpression right = ((JetBinaryExpression) element).getRight();
|
||||||
|
if (right != null) {
|
||||||
|
report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor), ctxt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (element instanceof JetPostfixExpression) {
|
||||||
|
IElementType operationToken =
|
||||||
|
((JetPostfixExpression) element).getOperationReference().getReferencedNameElementType();
|
||||||
|
if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) {
|
||||||
|
report(Errors.UNUSED_CHANGED_VALUE.on(element, element), ctxt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (element instanceof JetPostfixExpression) {
|
else if (instruction instanceof VariableDeclarationInstruction) {
|
||||||
IElementType operationToken = ((JetPostfixExpression) element).getOperationReference().getReferencedNameElementType();
|
JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
||||||
if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) {
|
if (!(element instanceof JetNamedDeclaration)) return;
|
||||||
report(Errors.UNUSED_CHANGED_VALUE.on(element, element), ctxt);
|
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
|
||||||
|
if (nameIdentifier == null) return;
|
||||||
|
if (!VariableUseState.isUsed(variableUseState)) {
|
||||||
|
if (JetPsiUtil.isVariableNotParameterDeclaration(element)) {
|
||||||
|
report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor), ctxt);
|
||||||
|
}
|
||||||
|
else if (element instanceof JetParameter) {
|
||||||
|
PsiElement psiElement = element.getParent().getParent();
|
||||||
|
if (psiElement instanceof JetFunction) {
|
||||||
|
MainFunctionDetector mainFunctionDetector = new MainFunctionDetector(trace.getBindingContext());
|
||||||
|
boolean isMain = (psiElement instanceof JetNamedFunction) && mainFunctionDetector.isMain((JetNamedFunction) psiElement);
|
||||||
|
if (psiElement instanceof JetFunctionLiteral) return;
|
||||||
|
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
|
||||||
|
assert descriptor instanceof FunctionDescriptor : psiElement.getText();
|
||||||
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
if (!isMain && !functionDescriptor.getModality().isOverridable()
|
||||||
|
&& functionDescriptor.getOverriddenDescriptors().isEmpty()) {
|
||||||
|
report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor), ctxt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (variableUseState == ONLY_WRITTEN_NEVER_READ && JetPsiUtil.isVariableNotParameterDeclaration(element)) {
|
||||||
}
|
report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor), ctxt);
|
||||||
}
|
}
|
||||||
else if (instruction instanceof VariableDeclarationInstruction) {
|
else if (variableUseState == WRITTEN_AFTER_READ && element instanceof JetVariableDeclaration) {
|
||||||
JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
if (element instanceof JetProperty) {
|
||||||
if (!(element instanceof JetNamedDeclaration)) return;
|
JetExpression initializer = ((JetProperty) element).getInitializer();
|
||||||
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
|
if (initializer != null) {
|
||||||
if (nameIdentifier == null) return;
|
report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor), ctxt);
|
||||||
if (!VariableUseState.isUsed(variableUseState)) {
|
}
|
||||||
if (JetPsiUtil.isVariableNotParameterDeclaration(element)) {
|
}
|
||||||
report(Errors.UNUSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor), ctxt);
|
else if (element instanceof JetMultiDeclarationEntry) {
|
||||||
}
|
report(VARIABLE_WITH_REDUNDANT_INITIALIZER.on(element, variableDescriptor), ctxt);
|
||||||
else if (element instanceof JetParameter) {
|
|
||||||
PsiElement psiElement = element.getParent().getParent();
|
|
||||||
if (psiElement instanceof JetFunction) {
|
|
||||||
MainFunctionDetector mainFunctionDetector = new MainFunctionDetector(trace.getBindingContext());
|
|
||||||
boolean isMain = (psiElement instanceof JetNamedFunction) && mainFunctionDetector.isMain((JetNamedFunction) psiElement);
|
|
||||||
if (psiElement instanceof JetFunctionLiteral) return;
|
|
||||||
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
|
|
||||||
assert descriptor instanceof FunctionDescriptor : psiElement.getText();
|
|
||||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
|
||||||
if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) {
|
|
||||||
report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor), ctxt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (variableUseState == ONLY_WRITTEN_NEVER_READ && JetPsiUtil.isVariableNotParameterDeclaration(element)) {
|
};
|
||||||
report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, variableDescriptor), ctxt);
|
|
||||||
}
|
|
||||||
else if (variableUseState == WRITTEN_AFTER_READ && element instanceof JetVariableDeclaration) {
|
|
||||||
if (element instanceof JetProperty) {
|
|
||||||
JetExpression initializer = ((JetProperty) element).getInitializer();
|
|
||||||
if (initializer != null) {
|
|
||||||
report(Errors.VARIABLE_WITH_REDUNDANT_INITIALIZER.on(initializer, variableDescriptor), ctxt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (element instanceof JetMultiDeclarationEntry) {
|
|
||||||
report(VARIABLE_WITH_REDUNDANT_INITIALIZER.on(element, variableDescriptor), ctxt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
PseudocodeTraverserPackage.traverse(pseudocode, TraversalOrder.BACKWARD, variableStatusData, variableStatusAnalyzeStrategy);
|
PseudocodeTraverserPackage.traverse(pseudocode, TraversalOrder.BACKWARD, variableStatusData, variableStatusAnalyzeStrategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,31 +633,32 @@ public class JetFlowInformationProvider {
|
|||||||
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
|
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap = Maps.newHashMap();
|
||||||
PseudocodeTraverserPackage.traverse(
|
PseudocodeTraverserPackage.traverse(
|
||||||
pseudocode, FORWARD, new FunctionVoid1<Instruction>() {
|
pseudocode, FORWARD, new FunctionVoid1<Instruction>() {
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NotNull Instruction instruction) {
|
public void execute(@NotNull Instruction instruction) {
|
||||||
if (!(instruction instanceof ReadValueInstruction)) return;
|
if (!(instruction instanceof ReadValueInstruction)) return;
|
||||||
VariableContext ctxt = new VariableContext(instruction, reportedDiagnosticMap);
|
VariableContext ctxt = new VariableContext(instruction, reportedDiagnosticMap);
|
||||||
JetElement element =
|
JetElement element =
|
||||||
((ReadValueInstruction) instruction).getElement();
|
((ReadValueInstruction) instruction).getElement();
|
||||||
if (!(element instanceof JetFunctionLiteralExpression
|
if (!(element instanceof JetFunctionLiteralExpression
|
||||||
|| element instanceof JetConstantExpression
|
|| element instanceof JetConstantExpression
|
||||||
|| element instanceof JetStringTemplateExpression
|
|| element instanceof JetStringTemplateExpression
|
||||||
|| element instanceof JetSimpleNameExpression)) {
|
|| element instanceof JetSimpleNameExpression)) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
PsiElement parent = element.getParent();
|
|
||||||
if (parent instanceof JetBlockExpression) {
|
|
||||||
if (!JetPsiUtil.isImplicitlyUsed(element)) {
|
|
||||||
if (element instanceof JetFunctionLiteralExpression) {
|
|
||||||
report(Errors.UNUSED_FUNCTION_LITERAL.on((JetFunctionLiteralExpression) element), ctxt);
|
|
||||||
}
|
}
|
||||||
else {
|
PsiElement parent = element.getParent();
|
||||||
report(Errors.UNUSED_EXPRESSION.on(element), ctxt);
|
if (parent instanceof JetBlockExpression) {
|
||||||
|
if (!JetPsiUtil.isImplicitlyUsed(element)) {
|
||||||
|
if (element instanceof JetFunctionLiteralExpression) {
|
||||||
|
report(Errors.UNUSED_FUNCTION_LITERAL.on((JetFunctionLiteralExpression) element), ctxt);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
report(Errors.UNUSED_EXPRESSION.on(element), ctxt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -771,7 +804,7 @@ public class JetFlowInformationProvider {
|
|||||||
return (a == x && b == y) || (a == y && b == x);
|
return (a == x && b == y) || (a == y && b == x);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Utility classes and methods
|
// Utility classes and methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -823,7 +856,6 @@ public class JetFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private class VariableContext {
|
private class VariableContext {
|
||||||
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap;
|
final Map<Instruction, DiagnosticFactory> reportedDiagnosticMap;
|
||||||
final Instruction instruction;
|
final Instruction instruction;
|
||||||
|
|||||||
Reference in New Issue
Block a user