backing fields resolve changed
KT-462 Consider allowing initializing properties via property names when it is safe KT-598 Allow to use backing fields after this expression
This commit is contained in:
@@ -821,6 +821,9 @@ public class JetControlFlowProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void visitClassOrObject(JetClassOrObject classOrObject) {
|
private void visitClassOrObject(JetClassOrObject classOrObject) {
|
||||||
|
for (JetDelegationSpecifier specifier : classOrObject.getDelegationSpecifiers()) {
|
||||||
|
value(specifier, inCondition);
|
||||||
|
}
|
||||||
List<JetDeclaration> declarations = classOrObject.getDeclarations();
|
List<JetDeclaration> declarations = classOrObject.getDeclarations();
|
||||||
List<JetProperty> properties = Lists.newArrayList();
|
List<JetProperty> properties = Lists.newArrayList();
|
||||||
for (JetDeclaration declaration : declarations) {
|
for (JetDeclaration declaration : declarations) {
|
||||||
@@ -839,6 +842,14 @@ public class JetControlFlowProcessor {
|
|||||||
visitClassOrObject(klass);
|
visitClassOrObject(klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
|
||||||
|
List<? extends ValueArgument> valueArguments = call.getValueArguments();
|
||||||
|
for (ValueArgument valueArgument : valueArguments) {
|
||||||
|
value(valueArgument.getArgumentExpression(), inCondition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitJetElement(JetElement element) {
|
public void visitJetElement(JetElement element) {
|
||||||
builder.unsupported(element);
|
builder.unsupported(element);
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import com.google.common.collect.Sets;
|
|||||||
import com.intellij.openapi.util.Pair;
|
import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.tree.IElementType;
|
import com.intellij.psi.tree.IElementType;
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
import org.jetbrains.jet.lang.cfg.pseudocode.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
@@ -223,22 +223,24 @@ public class JetFlowInformationProvider {
|
|||||||
@Override
|
@Override
|
||||||
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, VariableInitializers> enterData, @Nullable Map<VariableDescriptor, VariableInitializers> exitData) {
|
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, VariableInitializers> enterData, @Nullable Map<VariableDescriptor, VariableInitializers> exitData) {
|
||||||
assert enterData != null && exitData != null;
|
assert enterData != null && exitData != null;
|
||||||
|
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
|
||||||
|
if (variableDescriptor == null) return;
|
||||||
if (instruction instanceof ReadValueInstruction) {
|
if (instruction instanceof ReadValueInstruction) {
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
JetElement element = ((ReadValueInstruction) instruction).getElement();
|
||||||
if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) {
|
boolean error = checkBackingField(variableDescriptor, element);
|
||||||
checkIsInitialized(variableDescriptor, ((ReadValueInstruction) instruction).getElement(), exitData.get(variableDescriptor), varWithUninitializedErrorGenerated);
|
if (!error && declaredVariables.contains(variableDescriptor)) {
|
||||||
|
checkIsInitialized(variableDescriptor, element, exitData.get(variableDescriptor), varWithUninitializedErrorGenerated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (instruction instanceof WriteValueInstruction) {
|
else if (instruction instanceof WriteValueInstruction) {
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, true);
|
|
||||||
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
JetElement element = ((WriteValueInstruction) instruction).getlValue();
|
||||||
if (variableDescriptor != null && element instanceof JetExpression) {
|
boolean error = checkBackingField(variableDescriptor, element);
|
||||||
if (!processLocalDeclaration) { // error has been generated before while processing outer function of this local declaration
|
if (!(element instanceof JetExpression)) return;
|
||||||
checkValReassignment(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), varWithValReassignErrorGenerated);
|
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 (processClassOrObject) {
|
}
|
||||||
checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor));
|
if (!error && processClassOrObject) {
|
||||||
}
|
checkInitializationUsingBackingField(variableDescriptor, (JetExpression) element, enterData.get(variableDescriptor), exitData.get(variableDescriptor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,7 +265,7 @@ public class JetFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated) {
|
private boolean checkValReassignment(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull Collection<VariableDescriptor> varWithValReassignErrorGenerated) {
|
||||||
boolean isInitializedNotHere = enterInitializers.isInitialized();
|
boolean isInitializedNotHere = enterInitializers.isInitialized();
|
||||||
Set<JetElement> possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers();
|
Set<JetElement> possibleLocalInitializers = enterInitializers.getPossibleLocalInitializers();
|
||||||
if (possibleLocalInitializers.size() == 1) {
|
if (possibleLocalInitializers.size() == 1) {
|
||||||
@@ -298,12 +300,19 @@ public class JetFlowInformationProvider {
|
|||||||
}
|
}
|
||||||
if (!hasReassignMethodReturningUnit) {
|
if (!hasReassignMethodReturningUnit) {
|
||||||
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor));
|
trace.report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) {
|
private void checkInitializationUsingBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetExpression expression, @NotNull VariableInitializers enterInitializers, @NotNull VariableInitializers exitInitializers) {
|
||||||
if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) {
|
if (variableDescriptor instanceof PropertyDescriptor && !enterInitializers.isInitialized() && exitInitializers.isInitialized()) {
|
||||||
|
if (!variableDescriptor.isVar()) return;
|
||||||
|
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor)) return;
|
||||||
|
PsiElement property = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
||||||
|
assert property instanceof JetProperty;
|
||||||
|
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.FINAL && ((JetProperty) property).getSetter() == null) return;
|
||||||
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) {
|
||||||
@@ -313,12 +322,63 @@ public class JetFlowInformationProvider {
|
|||||||
if (variable instanceof JetSimpleNameExpression) {
|
if (variable instanceof JetSimpleNameExpression) {
|
||||||
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) variable;
|
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) variable;
|
||||||
if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) {
|
if (simpleNameExpression.getReferencedNameElementType() != JetTokens.FIELD_IDENTIFIER) {
|
||||||
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD.on(simpleNameExpression, expression, variableDescriptor));
|
if (((PropertyDescriptor) variableDescriptor).getModality() != Modality.FINAL) {
|
||||||
|
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER.on(simpleNameExpression, expression, variableDescriptor));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
trace.report(Errors.INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER.on(simpleNameExpression, expression, variableDescriptor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkBackingField(@NotNull VariableDescriptor variableDescriptor, @NotNull JetElement element) {
|
||||||
|
boolean[] error = new boolean[1];
|
||||||
|
if (isBackingFieldReference((JetElement) element.getParent(), error, false)) return false; // this expression has been already checked
|
||||||
|
if (!isBackingFieldReference(element, error, true)) return false;
|
||||||
|
if (error[0]) return true;
|
||||||
|
if (!(variableDescriptor instanceof PropertyDescriptor)) {
|
||||||
|
trace.report(Errors.NOT_PROPERTY_BACKING_FIELD.on(element));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
PsiElement property = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
||||||
|
if (!trace.get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) variableDescriptor) &&
|
||||||
|
!PsiTreeUtil.isAncestor(property, element, false)) { // not to generate error in accessors of abstract properties, there is one: declared accessor of abstract property
|
||||||
|
if (((PropertyDescriptor) variableDescriptor).getModality() == Modality.ABSTRACT) {
|
||||||
|
trace.report(NO_BACKING_FIELD_ABSTRACT_PROPERTY.on(element));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
trace.report(NO_BACKING_FIELD_CUSTOM_ACCESSORS.on(element));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JetClassOrObject propertyClassOrObject = PsiTreeUtil.getParentOfType(property, JetClassOrObject.class);
|
||||||
|
if (propertyClassOrObject == null || !PsiTreeUtil.isAncestor(propertyClassOrObject, element, false)) {
|
||||||
|
trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBackingFieldReference(@Nullable JetElement element, boolean[] error, boolean reportError) {
|
||||||
|
error[0] = false;
|
||||||
|
if (element instanceof JetSimpleNameExpression && ((JetSimpleNameExpression) element).getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (element instanceof JetDotQualifiedExpression && isBackingFieldReference(((JetDotQualifiedExpression) element).getSelectorExpression(), error, false)) {
|
||||||
|
if (((JetDotQualifiedExpression) element).getReceiverExpression() instanceof JetThisExpression) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
error[0] = true;
|
||||||
|
if (reportError) {
|
||||||
|
trace.report(Errors.INACCESSIBLE_BACKING_FIELD.on(element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void recordInitializedVariables(Collection<VariableDescriptor> declaredVariables, Map<VariableDescriptor, VariableInitializers> resultInfo) {
|
private void recordInitializedVariables(Collection<VariableDescriptor> declaredVariables, Map<VariableDescriptor, VariableInitializers> resultInfo) {
|
||||||
for (Map.Entry<VariableDescriptor, VariableInitializers> entry : resultInfo.entrySet()) {
|
for (Map.Entry<VariableDescriptor, VariableInitializers> entry : resultInfo.entrySet()) {
|
||||||
VariableDescriptor variable = entry.getKey();
|
VariableDescriptor variable = entry.getKey();
|
||||||
@@ -456,58 +516,55 @@ public class JetFlowInformationProvider {
|
|||||||
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, VariableStatus> enterData, @Nullable Map<VariableDescriptor, VariableStatus> exitData) {
|
public void execute(Instruction instruction, @Nullable Map<VariableDescriptor, VariableStatus> enterData, @Nullable Map<VariableDescriptor, VariableStatus> exitData) {
|
||||||
assert enterData != null && exitData != null;
|
assert enterData != null && exitData != null;
|
||||||
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
VariableDescriptor variableDescriptor = extractVariableDescriptorIfAny(instruction, false);
|
||||||
if (variableDescriptor != null && declaredVariables.contains(variableDescriptor)) {
|
if (variableDescriptor == null || !declaredVariables.contains(variableDescriptor)) return;
|
||||||
PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
PsiElement variableDeclarationElement = trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, variableDescriptor);
|
||||||
assert variableDeclarationElement instanceof JetDeclaration;
|
assert variableDeclarationElement instanceof JetDeclaration;
|
||||||
boolean isLocal = JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement);
|
if (!JetPsiUtil.isLocal((JetDeclaration) variableDeclarationElement)) return;
|
||||||
if (isLocal) {
|
if (instruction instanceof WriteValueInstruction) {
|
||||||
if (instruction instanceof WriteValueInstruction) {
|
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
||||||
JetElement element = ((WriteValueInstruction) instruction).getElement();
|
if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN || enterData.get(variableDescriptor) == VariableStatus.UNUSED) {
|
||||||
if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN || enterData.get(variableDescriptor) == VariableStatus.UNUSED) {
|
if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
|
||||||
if (element instanceof JetBinaryExpression && ((JetBinaryExpression) element).getOperationToken() == JetTokens.EQ) {
|
JetExpression right = ((JetBinaryExpression) element).getRight();
|
||||||
JetExpression right = ((JetBinaryExpression) element).getRight();
|
if (right != null) {
|
||||||
if (right != null) {
|
trace.report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor));
|
||||||
trace.report(Errors.UNUSED_VALUE.on(right, right, variableDescriptor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (element instanceof JetPostfixExpression) {
|
|
||||||
IElementType operationToken = ((JetPostfixExpression) element).getOperationSign().getReferencedNameElementType();
|
|
||||||
if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) {
|
|
||||||
trace.report(Errors.UNUSED_CHANGED_VALUE.on(element, element));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (instruction instanceof VariableDeclarationInstruction) {
|
else if (element instanceof JetPostfixExpression) {
|
||||||
JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
IElementType operationToken = ((JetPostfixExpression) element).getOperationSign().getReferencedNameElementType();
|
||||||
if (element instanceof JetNamedDeclaration) {
|
if (operationToken == JetTokens.PLUSPLUS || operationToken == JetTokens.MINUSMINUS) {
|
||||||
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
|
trace.report(Errors.UNUSED_CHANGED_VALUE.on(element, element));
|
||||||
PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element;
|
|
||||||
if (enterData.get(variableDescriptor) == VariableStatus.UNUSED) {
|
|
||||||
if (element instanceof JetProperty) {
|
|
||||||
trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, elementToMark, variableDescriptor));
|
|
||||||
}
|
|
||||||
else if (element instanceof JetParameter) {
|
|
||||||
PsiElement psiElement = element.getParent().getParent();
|
|
||||||
if (psiElement instanceof JetFunction) {
|
|
||||||
boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement);
|
|
||||||
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
|
|
||||||
assert descriptor instanceof FunctionDescriptor;
|
|
||||||
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
|
||||||
if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) {
|
|
||||||
trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, elementToMark, variableDescriptor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN && element instanceof JetProperty) {
|
|
||||||
trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, elementToMark, variableDescriptor));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (instruction instanceof VariableDeclarationInstruction) {
|
||||||
|
JetDeclaration element = ((VariableDeclarationInstruction) instruction).getVariableDeclarationElement();
|
||||||
|
if (element instanceof JetNamedDeclaration) {
|
||||||
|
PsiElement nameIdentifier = ((JetNamedDeclaration) element).getNameIdentifier();
|
||||||
|
PsiElement elementToMark = nameIdentifier != null ? nameIdentifier : element;
|
||||||
|
if (enterData.get(variableDescriptor) == VariableStatus.UNUSED) {
|
||||||
|
if (element instanceof JetProperty) {
|
||||||
|
trace.report(Errors.UNUSED_VARIABLE.on((JetProperty) element, elementToMark, variableDescriptor));
|
||||||
|
}
|
||||||
|
else if (element instanceof JetParameter) {
|
||||||
|
PsiElement psiElement = element.getParent().getParent();
|
||||||
|
if (psiElement instanceof JetFunction) {
|
||||||
|
boolean isMain = (psiElement instanceof JetNamedFunction) && JetMainDetector.isMain((JetNamedFunction) psiElement);
|
||||||
|
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, psiElement);
|
||||||
|
assert descriptor instanceof FunctionDescriptor;
|
||||||
|
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
|
||||||
|
if (!isMain && !functionDescriptor.getModality().isOverridable() && functionDescriptor.getOverriddenDescriptors().isEmpty()) {
|
||||||
|
trace.report(Errors.UNUSED_PARAMETER.on((JetParameter) element, elementToMark, variableDescriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (enterData.get(variableDescriptor) == VariableStatus.WRITTEN && element instanceof JetProperty) {
|
||||||
|
trace.report(Errors.ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE.on((JetNamedDeclaration) element, elementToMark, variableDescriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -52,7 +52,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
|||||||
this.scopeForMemberLookup = new WritableScopeImpl(JetScope.EMPTY, this, redeclarationHandler).setDebugName("MemberLookup").changeLockLevel(WritableScope.LockLevel.BOTH);
|
this.scopeForMemberLookup = new WritableScopeImpl(JetScope.EMPTY, this, redeclarationHandler).setDebugName("MemberLookup").changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||||
this.scopeForSupertypeResolution = new WritableScopeImpl(outerScope, this, redeclarationHandler).setDebugName("SupertypeResolution").changeLockLevel(WritableScope.LockLevel.BOTH);
|
this.scopeForSupertypeResolution = new WritableScopeImpl(outerScope, this, redeclarationHandler).setDebugName("SupertypeResolution").changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||||
this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler).setDebugName("MemberResolution").changeLockLevel(WritableScope.LockLevel.BOTH);
|
this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler).setDebugName("MemberResolution").changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||||
this.scopeForInitializers = new WritableScopeImpl(scopeForMemberResolution, this, redeclarationHandler).setDebugName("PropertyInitializers").changeLockLevel(WritableScope.LockLevel.BOTH);
|
this.scopeForInitializers = new WritableScopeImpl(scopeForMemberResolution, this, redeclarationHandler).setDebugName("Initializers").changeLockLevel(WritableScope.LockLevel.BOTH);
|
||||||
this.kind = kind;
|
this.kind = kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +137,6 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
|
|||||||
callableMembers.add(propertyDescriptor);
|
callableMembers.add(propertyDescriptor);
|
||||||
scopeForMemberLookup.addVariableDescriptor(propertyDescriptor);
|
scopeForMemberLookup.addVariableDescriptor(propertyDescriptor);
|
||||||
scopeForMemberResolution.addVariableDescriptor(propertyDescriptor);
|
scopeForMemberResolution.addVariableDescriptor(propertyDescriptor);
|
||||||
scopeForInitializers.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -84,7 +84,11 @@ public interface Errors {
|
|||||||
|
|
||||||
SimpleDiagnosticFactory CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation");
|
SimpleDiagnosticFactory CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation");
|
||||||
|
|
||||||
SimpleDiagnosticFactory NO_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "This property does not have a backing field");
|
SimpleDiagnosticFactory NO_BACKING_FIELD_ABSTRACT_PROPERTY = SimpleDiagnosticFactory.create(ERROR, "This property doesn't have a backing field, because it's abstract");
|
||||||
|
SimpleDiagnosticFactory NO_BACKING_FIELD_CUSTOM_ACCESSORS = SimpleDiagnosticFactory.create(ERROR, "This property doesn't have a backing field, because it has custom accessors without reference to the backing field");
|
||||||
|
SimpleDiagnosticFactory INACCESSIBLE_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "The backing field is not accessible here");
|
||||||
|
SimpleDiagnosticFactory NOT_PROPERTY_BACKING_FIELD = SimpleDiagnosticFactory.create(ERROR, "The referenced variable is not a property and doesn't have backing field");
|
||||||
|
|
||||||
SimpleDiagnosticFactory MIXING_NAMED_AND_POSITIONED_ARGUMENTS = SimpleDiagnosticFactory.create(ERROR, "Mixing named and positioned arguments in not allowed");
|
SimpleDiagnosticFactory MIXING_NAMED_AND_POSITIONED_ARGUMENTS = SimpleDiagnosticFactory.create(ERROR, "Mixing named and positioned arguments in not allowed");
|
||||||
SimpleDiagnosticFactory ARGUMENT_PASSED_TWICE = SimpleDiagnosticFactory.create(ERROR, "An argument is already passed for this parameter");
|
SimpleDiagnosticFactory ARGUMENT_PASSED_TWICE = SimpleDiagnosticFactory.create(ERROR, "An argument is already passed for this parameter");
|
||||||
UnresolvedReferenceDiagnosticFactory NAMED_PARAMETER_NOT_FOUND = new UnresolvedReferenceDiagnosticFactory("Cannot find a parameter with this name");//SimpleDiagnosticFactory.create(ERROR, "Cannot find a parameter with this name");
|
UnresolvedReferenceDiagnosticFactory NAMED_PARAMETER_NOT_FOUND = new UnresolvedReferenceDiagnosticFactory("Cannot find a parameter with this name");//SimpleDiagnosticFactory.create(ERROR, "Cannot find a parameter with this name");
|
||||||
@@ -166,7 +170,8 @@ public interface Errors {
|
|||||||
PsiElementOnlyDiagnosticFactory1<JetExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
|
PsiElementOnlyDiagnosticFactory1<JetExpression, DeclarationDescriptor> VAL_REASSIGNMENT = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Val can not be reassigned", NAME);
|
||||||
SimplePsiElementOnlyDiagnosticFactory<JetExpression> VARIABLE_EXPECTED = new SimplePsiElementOnlyDiagnosticFactory<JetExpression>(ERROR, "Variable expected");
|
SimplePsiElementOnlyDiagnosticFactory<JetExpression> VARIABLE_EXPECTED = new SimplePsiElementOnlyDiagnosticFactory<JetExpression>(ERROR, "Variable expected");
|
||||||
|
|
||||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> INITIALIZATION_USING_BACKING_FIELD = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Initialization using backing field required", NAME);
|
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER = PsiElementOnlyDiagnosticFactory1.create(ERROR, "This property has a custom setter, so initialization using backing field required", NAME);
|
||||||
|
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Setter of this property can be overridden, so initialization using backing field required", NAME);
|
||||||
|
|
||||||
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> FUNCTION_PARAMETERS_OF_INLINE_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function parameters of inline function can only be invoked", NAME);
|
PsiElementOnlyDiagnosticFactory1<JetSimpleNameExpression, DeclarationDescriptor> FUNCTION_PARAMETERS_OF_INLINE_FUNCTION = PsiElementOnlyDiagnosticFactory1.create(ERROR, "Function parameters of inline function can only be invoked", NAME);
|
||||||
|
|
||||||
|
|||||||
@@ -104,9 +104,9 @@ public class JetPsiUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isLocal(@NotNull JetDeclaration declaration) {
|
public static boolean isLocal(@NotNull JetElement element) {
|
||||||
JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(declaration, JetClassOrObject.class);
|
JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(element, JetClassOrObject.class);
|
||||||
JetDeclarationWithBody function = PsiTreeUtil.getParentOfType(declaration, JetDeclarationWithBody.class);
|
JetDeclarationWithBody function = PsiTreeUtil.getParentOfType(element, JetDeclarationWithBody.class);
|
||||||
if (function != null && PsiTreeUtil.isAncestor(classOrObject, function, false)) {
|
if (function != null && PsiTreeUtil.isAncestor(classOrObject, function, false)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,41 +34,11 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
|||||||
public class BodyResolver {
|
public class BodyResolver {
|
||||||
private final TopDownAnalysisContext context;
|
private final TopDownAnalysisContext context;
|
||||||
|
|
||||||
private final ObservableBindingTrace traceForConstructors;
|
private final ObservableBindingTrace trace;
|
||||||
private final ObservableBindingTrace traceForMembers;
|
|
||||||
|
|
||||||
public BodyResolver(TopDownAnalysisContext context) {
|
public BodyResolver(TopDownAnalysisContext context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
this.trace = context.getTrace();
|
||||||
// This allows access to backing fields
|
|
||||||
this.traceForConstructors = new ObservableBindingTrace(context.getTrace()).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() {
|
|
||||||
@Override
|
|
||||||
public void handleRecord(WritableSlice<JetReferenceExpression, DeclarationDescriptor> slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) {
|
|
||||||
if (expression instanceof JetSimpleNameExpression) {
|
|
||||||
JetSimpleNameExpression simpleNameExpression = (JetSimpleNameExpression) expression;
|
|
||||||
if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
|
||||||
if (!BodyResolver.this.context.getTrace().getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, (PropertyDescriptor) descriptor)) {
|
|
||||||
BodyResolver.this.context.getTrace().report(NO_BACKING_FIELD.on(expression));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// This tracks access to properties in order to register primary constructor parameters that yield real fields (JET-9)
|
|
||||||
// NOTE!!! This code is not used, because we do not allow constructor parameter access in member bodies
|
|
||||||
this.traceForMembers = new ObservableBindingTrace(context.getTrace()).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() {
|
|
||||||
@Override
|
|
||||||
public void handleRecord(WritableSlice<JetReferenceExpression, DeclarationDescriptor> slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) {
|
|
||||||
if (descriptor instanceof PropertyDescriptor) {
|
|
||||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
|
||||||
if (BodyResolver.this.context.getPrimaryConstructorParameterProperties().contains(propertyDescriptor)) {
|
|
||||||
traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resolveBehaviorDeclarationBodies() {
|
public void resolveBehaviorDeclarationBodies() {
|
||||||
@@ -100,8 +70,8 @@ public class BodyResolver {
|
|||||||
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
|
final ConstructorDescriptor primaryConstructor = descriptor.getUnsubstitutedPrimaryConstructor();
|
||||||
final JetScope scopeForConstructor = primaryConstructor == null
|
final JetScope scopeForConstructor = primaryConstructor == null
|
||||||
? null
|
? null
|
||||||
: FunctionDescriptorUtil.getFunctionInnerScope(descriptor.getScopeForSupertypeResolution(), primaryConstructor, traceForConstructors);
|
: FunctionDescriptorUtil.getFunctionInnerScope(descriptor.getScopeForSupertypeResolution(), primaryConstructor, trace);
|
||||||
final ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow
|
final ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace); // TODO : flow
|
||||||
|
|
||||||
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
|
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
|
||||||
JetVisitorVoid visitor = new JetVisitorVoid() {
|
JetVisitorVoid visitor = new JetVisitorVoid() {
|
||||||
@@ -268,7 +238,7 @@ public class BodyResolver {
|
|||||||
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
|
||||||
assert primaryConstructor != null;
|
assert primaryConstructor != null;
|
||||||
final JetScope scopeForInitializers = classDescriptor.getScopeForInitializers();
|
final JetScope scopeForInitializers = classDescriptor.getScopeForInitializers();
|
||||||
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
|
||||||
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
|
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
|
||||||
typeInferrer.getType(scopeForInitializers, anonymousInitializer.getBody(), NO_EXPECTED_TYPE);
|
typeInferrer.getType(scopeForInitializers, anonymousInitializer.getBody(), NO_EXPECTED_TYPE);
|
||||||
}
|
}
|
||||||
@@ -294,9 +264,9 @@ public class BodyResolver {
|
|||||||
private void resolveSecondaryConstructorBody(JetSecondaryConstructor declaration, final ConstructorDescriptor descriptor) {
|
private void resolveSecondaryConstructorBody(JetSecondaryConstructor declaration, final ConstructorDescriptor descriptor) {
|
||||||
if (!context.completeAnalysisNeeded(declaration)) return;
|
if (!context.completeAnalysisNeeded(declaration)) return;
|
||||||
MutableClassDescriptor classDescriptor = (MutableClassDescriptor) descriptor.getContainingDeclaration();
|
MutableClassDescriptor classDescriptor = (MutableClassDescriptor) descriptor.getContainingDeclaration();
|
||||||
final JetScope scopeForSupertypeInitializers = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForSupertypeResolution(), descriptor, traceForConstructors);
|
final JetScope scopeForSupertypeInitializers = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForSupertypeResolution(), descriptor, trace);
|
||||||
//contains only constructor parameters
|
//contains only constructor parameters
|
||||||
final JetScope scopeForConstructorBody = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForInitializers(), descriptor, traceForConstructors);
|
final JetScope scopeForConstructorBody = FunctionDescriptorUtil.getFunctionInnerScope(classDescriptor.getScopeForInitializers(), descriptor, trace);
|
||||||
//contains members & backing fields
|
//contains members & backing fields
|
||||||
|
|
||||||
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo
|
final CallResolver callResolver = new CallResolver(context.getSemanticServices(), DataFlowInfo.EMPTY); // TODO: dataFlowInfo
|
||||||
@@ -360,7 +330,7 @@ public class BodyResolver {
|
|||||||
}
|
}
|
||||||
JetExpression bodyExpression = declaration.getBodyExpression();
|
JetExpression bodyExpression = declaration.getBodyExpression();
|
||||||
if (bodyExpression != null) {
|
if (bodyExpression != null) {
|
||||||
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
|
||||||
|
|
||||||
typeInferrer.checkFunctionReturnType(scopeForConstructorBody, declaration, JetStandardClasses.getUnitType());
|
typeInferrer.checkFunctionReturnType(scopeForConstructorBody, declaration, JetStandardClasses.getUnitType());
|
||||||
}
|
}
|
||||||
@@ -417,7 +387,6 @@ public class BodyResolver {
|
|||||||
JetScope propertyDeclarationInnerScope = context.getDescriptorResolver().getPropertyDeclarationInnerScope(
|
JetScope propertyDeclarationInnerScope = context.getDescriptorResolver().getPropertyDeclarationInnerScope(
|
||||||
declaringScope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter());
|
declaringScope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter());
|
||||||
WritableScope accessorScope = new WritableScopeImpl(propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Accessor scope");
|
WritableScope accessorScope = new WritableScopeImpl(propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(context.getTrace())).setDebugName("Accessor scope");
|
||||||
accessorScope.addPropertyDescriptorByFieldName("$" + propertyDescriptor.getName(), propertyDescriptor);
|
|
||||||
accessorScope.changeLockLevel(WritableScope.LockLevel.READING);
|
accessorScope.changeLockLevel(WritableScope.LockLevel.READING);
|
||||||
|
|
||||||
return accessorScope;
|
return accessorScope;
|
||||||
@@ -442,7 +411,7 @@ public class BodyResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ObservableBindingTrace createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) {
|
private ObservableBindingTrace createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) {
|
||||||
return new ObservableBindingTrace(traceForMembers).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() {
|
return new ObservableBindingTrace(trace).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler<JetReferenceExpression, DeclarationDescriptor>() {
|
||||||
@Override
|
@Override
|
||||||
public void handleRecord(WritableSlice<JetReferenceExpression, DeclarationDescriptor> slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) {
|
public void handleRecord(WritableSlice<JetReferenceExpression, DeclarationDescriptor> slice, JetReferenceExpression expression, DeclarationDescriptor descriptor) {
|
||||||
if (expression instanceof JetSimpleNameExpression) {
|
if (expression instanceof JetSimpleNameExpression) {
|
||||||
@@ -450,7 +419,7 @@ public class BodyResolver {
|
|||||||
if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
if (simpleNameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
||||||
// This check may be considered redundant as long as $x is only accessible from accessors to $x
|
// This check may be considered redundant as long as $x is only accessible from accessors to $x
|
||||||
if (descriptor == propertyDescriptor) { // TODO : original?
|
if (descriptor == propertyDescriptor) { // TODO : original?
|
||||||
traceForMembers.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this context.getTrace()?
|
trace.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this context.getTrace()?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,7 +429,7 @@ public class BodyResolver {
|
|||||||
|
|
||||||
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
|
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
|
||||||
//JetFlowInformationProvider flowInformationProvider = context.getDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
|
//JetFlowInformationProvider flowInformationProvider = context.getDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
|
||||||
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
|
ExpressionTypingServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
|
||||||
JetType expectedTypeForInitializer = property.getPropertyTypeRef() != null ? propertyDescriptor.getOutType() : NO_EXPECTED_TYPE;
|
JetType expectedTypeForInitializer = property.getPropertyTypeRef() != null ? propertyDescriptor.getOutType() : NO_EXPECTED_TYPE;
|
||||||
JetType type = typeInferrer.getType(context.getDescriptorResolver().getPropertyDeclarationInnerScope(scope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter()), initializer, expectedTypeForInitializer);
|
JetType type = typeInferrer.getType(context.getDescriptorResolver().getPropertyDeclarationInnerScope(scope, propertyDescriptor, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter()), initializer, expectedTypeForInitializer);
|
||||||
//
|
//
|
||||||
@@ -494,7 +463,7 @@ public class BodyResolver {
|
|||||||
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
|
JetScope declaringScope = this.context.getDeclaringScopes().get(declaration);
|
||||||
assert declaringScope != null;
|
assert declaringScope != null;
|
||||||
|
|
||||||
resolveFunctionBody(traceForMembers, declaration, descriptor, declaringScope);
|
resolveFunctionBody(trace, declaration, descriptor, declaringScope);
|
||||||
|
|
||||||
assert descriptor.getReturnType() != null;
|
assert descriptor.getReturnType() != null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,8 @@ public class DeclarationsChecker {
|
|||||||
if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
|
if (!(classDescriptor.getModality() == Modality.ABSTRACT) && classDescriptor.getKind() != ClassKind.ENUM_CLASS) {
|
||||||
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
|
PsiElement classElement = context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, classDescriptor);
|
||||||
assert classElement instanceof JetClass;
|
assert classElement instanceof JetClass;
|
||||||
context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, property.getName(), classDescriptor, (JetClass) classElement));
|
String name = property.getName();
|
||||||
|
context.getTrace().report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, abstractNode, name != null ? name : "", classDescriptor, (JetClass) classElement));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (classDescriptor.getKind() == ClassKind.TRAIT) {
|
if (classDescriptor.getKind() == ClassKind.TRAIT) {
|
||||||
|
|||||||
@@ -64,7 +64,15 @@ public class CallResolver {
|
|||||||
if (referencedName == null) {
|
if (referencedName == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
List<ResolutionTask<VariableDescriptor>> prioritizedTasks = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo);
|
TaskPrioritizer<VariableDescriptor> task_prioritizer;
|
||||||
|
if (nameExpression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER) {
|
||||||
|
referencedName = referencedName.substring(1);
|
||||||
|
task_prioritizer = TaskPrioritizers.PROPERTY_TASK_PRIORITIZER;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
task_prioritizer = TaskPrioritizers.VARIABLE_TASK_PRIORITIZER;
|
||||||
|
}
|
||||||
|
List<ResolutionTask<VariableDescriptor>> prioritizedTasks = task_prioritizer.computePrioritizedTasks(scope, call, referencedName, trace.getBindingContext(), dataFlowInfo);
|
||||||
return resolveCallToDescriptor(trace, scope, call, expectedType, prioritizedTasks, nameExpression);
|
return resolveCallToDescriptor(trace, scope, call, expectedType, prioritizedTasks, nameExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.calls;
|
package org.jetbrains.jet.lang.resolve.calls;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
@@ -8,10 +9,7 @@ import org.jetbrains.jet.lang.types.ErrorUtils;
|
|||||||
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
import org.jetbrains.jet.lang.types.JetStandardClasses;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author abreslav
|
* @author abreslav
|
||||||
@@ -83,7 +81,7 @@ public class TaskPrioritizers {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*package*/ static TaskPrioritizer<VariableDescriptor> PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer<VariableDescriptor>() {
|
/*package*/ static TaskPrioritizer<VariableDescriptor> VARIABLE_TASK_PRIORITIZER = new TaskPrioritizer<VariableDescriptor>() {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
@@ -115,4 +113,34 @@ public class TaskPrioritizers {
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*package*/ static TaskPrioritizer<VariableDescriptor> PROPERTY_TASK_PRIORITIZER = new TaskPrioritizer<VariableDescriptor>() {
|
||||||
|
private Collection<VariableDescriptor> filterProperties(Collection<VariableDescriptor> variableDescriptors) {
|
||||||
|
ArrayList<VariableDescriptor> properties = Lists.newArrayList();
|
||||||
|
for (VariableDescriptor descriptor : variableDescriptors) {
|
||||||
|
if (descriptor instanceof PropertyDescriptor) {
|
||||||
|
properties.add(descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected Collection<VariableDescriptor> getNonExtensionsByName(JetScope scope, String name) {
|
||||||
|
return filterProperties(VARIABLE_TASK_PRIORITIZER.getNonExtensionsByName(scope, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected Collection<VariableDescriptor> getMembersByName(@NotNull JetType receiver, String name) {
|
||||||
|
return filterProperties(VARIABLE_TASK_PRIORITIZER.getMembersByName(receiver, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
protected Collection<VariableDescriptor> getExtensionsByName(JetScope scope, String name) {
|
||||||
|
return filterProperties(VARIABLE_TASK_PRIORITIZER.getExtensionsByName(scope, name));
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ public interface WritableScope extends JetScope {
|
|||||||
@Nullable
|
@Nullable
|
||||||
NamespaceDescriptor getDeclaredNamespace(@NotNull String name);
|
NamespaceDescriptor getDeclaredNamespace(@NotNull String name);
|
||||||
|
|
||||||
void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor);
|
|
||||||
|
|
||||||
void importScope(@NotNull JetScope imported);
|
void importScope(@NotNull JetScope imported);
|
||||||
|
|
||||||
void setImplicitReceiver(@NotNull ReceiverDescriptor implicitReceiver);
|
void setImplicitReceiver(@NotNull ReceiverDescriptor implicitReceiver);
|
||||||
|
|||||||
@@ -338,17 +338,6 @@ public class WritableScopeImpl extends WritableScopeWithImports {
|
|||||||
return propertyDescriptorsByFieldNames;
|
return propertyDescriptorsByFieldNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) {
|
|
||||||
checkMayWrite();
|
|
||||||
|
|
||||||
if (!fieldName.startsWith("$")) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPropertyDescriptorsByFieldNames().put(fieldName, propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) {
|
public PropertyDescriptor getPropertyByFieldReference(@NotNull String fieldName) {
|
||||||
checkMayRead();
|
checkMayRead();
|
||||||
|
|||||||
@@ -176,13 +176,6 @@ public class WriteThroughScope extends WritableScopeWithImports {
|
|||||||
return writableWorker.getDeclaredNamespace(name);
|
return writableWorker.getDeclaredNamespace(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addPropertyDescriptorByFieldName(@NotNull String fieldName, @NotNull PropertyDescriptor propertyDescriptor) {
|
|
||||||
checkMayWrite();
|
|
||||||
|
|
||||||
writableWorker.addPropertyDescriptorByFieldName(fieldName, propertyDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void importScope(@NotNull JetScope imported) {
|
public void importScope(@NotNull JetScope imported) {
|
||||||
checkMayWrite();
|
checkMayWrite();
|
||||||
|
|||||||
+1
-16
@@ -47,22 +47,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
public JetType visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) {
|
public JetType visitSimpleNameExpression(JetSimpleNameExpression expression, ExpressionTypingContext context) {
|
||||||
// TODO : other members
|
// TODO : other members
|
||||||
// TODO : type substitutions???
|
// TODO : type substitutions???
|
||||||
String referencedName = expression.getReferencedName();
|
return DataFlowUtils.checkType(getSelectorReturnType(NO_RECEIVER, null, expression, context), expression, context); // TODO : Extensions to this
|
||||||
if (expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER
|
|
||||||
&& referencedName != null) {
|
|
||||||
PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName);
|
|
||||||
if (property == null) {
|
|
||||||
context.trace.report(UNRESOLVED_REFERENCE.on(expression));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context.trace.record(REFERENCE_TARGET, expression, property);
|
|
||||||
return DataFlowUtils.checkType(property.getOutType(), expression, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return DataFlowUtils.checkType(getSelectorReturnType(NO_RECEIVER, null, expression, context), expression, context); // TODO : Extensions to this
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetType lookupNamespaceOrClassObject(JetSimpleNameExpression expression, String referencedName, ExpressionTypingContext context) {
|
private JetType lookupNamespaceOrClassObject(JetSimpleNameExpression expression, String referencedName, ExpressionTypingContext context) {
|
||||||
|
|||||||
+1
-10
@@ -213,16 +213,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
|
|||||||
basic.checkLValue(context.trace, expression.getLeft());
|
basic.checkLValue(context.trace, expression.getLeft());
|
||||||
}
|
}
|
||||||
if (left instanceof JetSimpleNameExpression) {
|
if (left instanceof JetSimpleNameExpression) {
|
||||||
JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left;
|
ExpressionTypingUtils.checkWrappingInRef(left, context);
|
||||||
String referencedName = simpleName.getReferencedName();
|
|
||||||
if (simpleName.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER
|
|
||||||
&& referencedName != null) {
|
|
||||||
PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName);
|
|
||||||
if (property != null) {
|
|
||||||
context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, simpleName, property);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ExpressionTypingUtils.checkWrappingInRef(simpleName, context);
|
|
||||||
}
|
}
|
||||||
return checkExpectedType(expression, contextWithExpectedType);
|
return checkExpectedType(expression, contextWithExpectedType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class WithC() {
|
|||||||
{
|
{
|
||||||
val z = <!UNRESOLVED_REFERENCE!>b<!>
|
val z = <!UNRESOLVED_REFERENCE!>b<!>
|
||||||
val zz = x
|
val zz = x
|
||||||
val zzz = <!NO_BACKING_FIELD!>$a<!>
|
val zzz = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$a<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
this(a : Int) : this() {
|
this(a : Int) : this() {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
var x : Int = 1 + x
|
var x : Int = 1 + x
|
||||||
get() : Int = 1
|
get() : Int = 1
|
||||||
set(<!REF_SETTER_PARAMETER!>ref<!> value : <!WRONG_SETTER_PARAMETER_TYPE!>Long<!>) {
|
set(<!REF_SETTER_PARAMETER!>ref<!> value : <!WRONG_SETTER_PARAMETER_TYPE!>Long<!>) {
|
||||||
$x = value.int
|
$x = value.int
|
||||||
@@ -14,16 +14,16 @@
|
|||||||
|
|
||||||
class Test() {
|
class Test() {
|
||||||
var a : Int = 111
|
var a : Int = 111
|
||||||
var b : Int get() = <!UNRESOLVED_REFERENCE!>$a<!>; set(x) {a = x; <!UNRESOLVED_REFERENCE!>$a<!> = x}
|
var b : Int get() = $a; set(x) {a = x; $a = x}
|
||||||
|
|
||||||
this(i : Int) : this() {
|
this(i : Int) : this() {
|
||||||
<!NO_BACKING_FIELD!>$b<!> = $a
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$b<!> = $a
|
||||||
$a = <!NO_BACKING_FIELD!>$b<!>
|
$a = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$b<!>
|
||||||
a = <!NO_BACKING_FIELD!>$b<!>
|
a = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$b<!>
|
||||||
}
|
}
|
||||||
fun f() {
|
fun f() {
|
||||||
<!UNRESOLVED_REFERENCE!>$b<!> = <!UNRESOLVED_REFERENCE!>$a<!>
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$b<!> = $a
|
||||||
a = <!UNRESOLVED_REFERENCE!>$b<!>
|
a = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$b<!>
|
||||||
}
|
}
|
||||||
public val <!PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE!>i<!> = 1
|
public val <!PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE!>i<!> = 1
|
||||||
}
|
}
|
||||||
@@ -137,14 +137,14 @@ class AnonymousInitializers(var a: String, val b: String) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
<!VAL_REASSIGNMENT!>$i<!> = 13
|
<!VAL_REASSIGNMENT!>$i<!> = 13
|
||||||
<!NO_BACKING_FIELD, VAL_REASSIGNMENT!>$j<!> = 30
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$j<!> = 30
|
||||||
j = 34
|
<!VAL_REASSIGNMENT!>j<!> = 34
|
||||||
}
|
}
|
||||||
|
|
||||||
val k: String
|
val k: String
|
||||||
{
|
{
|
||||||
if (1 < 3) {
|
if (1 < 3) {
|
||||||
<!INITIALIZATION_USING_BACKING_FIELD!>k<!> = "a"
|
k = "a"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$k = "b"
|
$k = "b"
|
||||||
@@ -288,7 +288,7 @@ class TestObjectExpression() {
|
|||||||
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>y<!> : Int
|
val <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>y<!> : Int
|
||||||
{
|
{
|
||||||
if (true)
|
if (true)
|
||||||
<!INITIALIZATION_USING_BACKING_FIELD!>x<!> = 12
|
x = 12
|
||||||
else
|
else
|
||||||
$x = 1
|
$x = 1
|
||||||
}
|
}
|
||||||
@@ -349,4 +349,4 @@ fun test(m : M) {
|
|||||||
fun test1(m : M) {
|
fun test1(m : M) {
|
||||||
<!VAL_REASSIGNMENT!>m.x<!>++
|
<!VAL_REASSIGNMENT!>m.x<!>++
|
||||||
m.y--
|
m.y--
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
class ReadByAnotherPropertyInitializer() {
|
class ReadByAnotherPropertyInitializer() {
|
||||||
val a = 1
|
val a = 1
|
||||||
fun ff() = <!UNRESOLVED_REFERENCE!>$a<!>
|
fun ff() = $a
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -2,6 +2,6 @@ abstract class ReadNonexistent() {
|
|||||||
abstract val aa: Int
|
abstract val aa: Int
|
||||||
|
|
||||||
{
|
{
|
||||||
val x = <!NO_BACKING_FIELD!>$aa<!>
|
val x = <!NO_BACKING_FIELD_ABSTRACT_PROPERTY!>$aa<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
abstract class ReadNonexistent {
|
abstract class ReadNonexistent {
|
||||||
abstract val aa: Int
|
abstract val aa: Int
|
||||||
|
|
||||||
fun ff() = <!UNRESOLVED_REFERENCE!>$aa<!>
|
fun ff() = <!NO_BACKING_FIELD_ABSTRACT_PROPERTY!>$aa<!>
|
||||||
}
|
}
|
||||||
+2
-2
@@ -3,6 +3,6 @@ class ReadNonexistent() {
|
|||||||
get() = 1
|
get() = 1
|
||||||
|
|
||||||
{
|
{
|
||||||
val x = <!NO_BACKING_FIELD!>$a<!>
|
val x = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$a<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-2
@@ -2,5 +2,5 @@ class CustomValNoBackingField() {
|
|||||||
val a: Int
|
val a: Int
|
||||||
get() = 1
|
get() = 1
|
||||||
|
|
||||||
val b = <!NO_BACKING_FIELD!>$a<!>
|
val b = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$a<!>
|
||||||
}
|
}
|
||||||
+6
-7
@@ -1,7 +1,6 @@
|
|||||||
val y = 1
|
class CustomValNoBackingField() {
|
||||||
|
val a: Int
|
||||||
class A() {
|
get() = 1
|
||||||
{
|
|
||||||
val x = <!UNRESOLVED_REFERENCE!>$y<!>
|
val b = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$a<!>
|
||||||
}
|
}
|
||||||
}
|
|
||||||
+2
-2
@@ -2,6 +2,6 @@ val y = 1
|
|||||||
|
|
||||||
class A() {
|
class A() {
|
||||||
{
|
{
|
||||||
<!UNRESOLVED_REFERENCE!>$y<!> = 1
|
<!INACCESSIBLE_BACKING_FIELD!>$y<!> = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
//KT-462 Consider allowing initializing properties via property names when it is safe
|
||||||
|
//KT-598 Allow to use backing fields after this expression
|
||||||
|
|
||||||
|
namespace kt462
|
||||||
|
|
||||||
|
abstract class TestInitializationWithoutBackingField() {
|
||||||
|
val valWithBackingField : Int
|
||||||
|
{
|
||||||
|
valWithBackingField = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
val valWithoutBackingField : Int
|
||||||
|
get() = 42
|
||||||
|
{
|
||||||
|
<!VAL_REASSIGNMENT!>valWithoutBackingField<!> = 45
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalDefaultVar : Int
|
||||||
|
{
|
||||||
|
finalDefaultVar = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
open var openVar : Int
|
||||||
|
{
|
||||||
|
<!INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER!>openVar<!> = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
var varWithCustomSetter : Int
|
||||||
|
set(v: Int) {
|
||||||
|
$varWithCustomSetter = v
|
||||||
|
}
|
||||||
|
{
|
||||||
|
<!INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER!>varWithCustomSetter<!> = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
var varWithoutBackingField : Int
|
||||||
|
get() = 3
|
||||||
|
set(v: Int) {}
|
||||||
|
{
|
||||||
|
varWithoutBackingField = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract var abstractVar : Int
|
||||||
|
{
|
||||||
|
abstractVar = 34
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TestInitializationThroughBackingField() {
|
||||||
|
val valWithBackingField : Int
|
||||||
|
{
|
||||||
|
$valWithBackingField = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
val valWithoutBackingField : Int
|
||||||
|
get() = 42
|
||||||
|
{
|
||||||
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$valWithoutBackingField<!> = 45
|
||||||
|
}
|
||||||
|
|
||||||
|
var finalDefaultVar : Int
|
||||||
|
{
|
||||||
|
$finalDefaultVar = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
open var openVar : Int
|
||||||
|
{
|
||||||
|
$openVar = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
var varWithCustomSetter : Int
|
||||||
|
set(v: Int) {
|
||||||
|
$varWithCustomSetter = v
|
||||||
|
}
|
||||||
|
{
|
||||||
|
$varWithCustomSetter = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
var varWithoutBackingField : Int
|
||||||
|
get() = 3
|
||||||
|
set(v: Int) {}
|
||||||
|
{
|
||||||
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$varWithoutBackingField<!> = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract var abstractVar : Int
|
||||||
|
{
|
||||||
|
<!NO_BACKING_FIELD_ABSTRACT_PROPERTY!>$abstractVar<!> = 34
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestBackingFieldsVisibility() {
|
||||||
|
var a : Int = 712
|
||||||
|
{
|
||||||
|
$a = 37
|
||||||
|
this.$a = 357
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
$a = 334
|
||||||
|
this.$a = 347
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(a: TestBackingFieldsVisibility) {
|
||||||
|
val <!UNUSED_VARIABLE!>b<!> : Int = 3
|
||||||
|
<!UNRESOLVED_REFERENCE!>$b<!> = 342
|
||||||
|
<!INACCESSIBLE_BACKING_FIELD!>a.$a<!> = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
val x = <!INACCESSIBLE_BACKING_FIELD!>$namespaceLevelVar<!>
|
||||||
|
|
||||||
|
class Inner() {
|
||||||
|
val z = this@TestBackingFieldsVisibility.$x
|
||||||
|
}
|
||||||
|
|
||||||
|
<!ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS!>abstract<!> val w = 11
|
||||||
|
get() = $w //test there is no second error here
|
||||||
|
}
|
||||||
|
|
||||||
|
val namespaceLevelVar = 11
|
||||||
|
|
||||||
|
class T() {
|
||||||
|
val z : Int get() = 42
|
||||||
|
|
||||||
|
{
|
||||||
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>this.$z<!> = 34
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>this.$z<!> = 343
|
||||||
|
}
|
||||||
|
|
||||||
|
val a = object {
|
||||||
|
val x = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS, NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$z<!>
|
||||||
|
{
|
||||||
|
<!NO_BACKING_FIELD_CUSTOM_ACCESSORS, NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$z<!> = 23
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var x: Int = 2
|
||||||
|
get() {
|
||||||
|
val <!UNUSED_VARIABLE!>o<!> = object {
|
||||||
|
{
|
||||||
|
$x = 34
|
||||||
|
}
|
||||||
|
fun foo() {
|
||||||
|
$x = 23
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var r: Int = $x
|
||||||
|
set(v: Int) {
|
||||||
|
if (true) {
|
||||||
|
$r = 33
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$r = 35
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
$x = 34
|
||||||
|
val <!UNUSED_VARIABLE!>o<!> = object {
|
||||||
|
val y = $x
|
||||||
|
{
|
||||||
|
$x = 422
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace kt510
|
|||||||
public open class Identifier1() {
|
public open class Identifier1() {
|
||||||
var field : Boolean
|
var field : Boolean
|
||||||
{
|
{
|
||||||
<!INITIALIZATION_USING_BACKING_FIELD!>field<!> = false; // error
|
field = false; // error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,6 +13,6 @@ public open class Identifier1() {
|
|||||||
public open class Identifier2() {
|
public open class Identifier2() {
|
||||||
var field : Boolean
|
var field : Boolean
|
||||||
{
|
{
|
||||||
<!INITIALIZATION_USING_BACKING_FIELD!>this.field<!> = false;
|
this.field = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ public class AddModifierFix extends JetIntentionAction<JetModifierListOwner> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
/*package*/ static String getElementName(JetModifierListOwner modifierListOwner) {
|
/*package*/ static String getElementName(@NotNull JetModifierListOwner modifierListOwner) {
|
||||||
String name = null;
|
String name = null;
|
||||||
if (modifierListOwner instanceof PsiNameIdentifierOwner) {
|
if (modifierListOwner instanceof PsiNameIdentifierOwner) {
|
||||||
PsiElement nameIdentifier = ((PsiNameIdentifierOwner) modifierListOwner).getNameIdentifier();
|
PsiElement nameIdentifier = ((PsiNameIdentifierOwner) modifierListOwner).getNameIdentifier();
|
||||||
|
|||||||
@@ -36,12 +36,7 @@ public class ChangeToBackingFieldFix extends JetIntentionAction<JetSimpleNameExp
|
|||||||
@Override
|
@Override
|
||||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||||
JetSimpleNameExpression backingField = (JetSimpleNameExpression) JetPsiFactory.createExpression(project, "$" + element.getText());
|
JetSimpleNameExpression backingField = (JetSimpleNameExpression) JetPsiFactory.createExpression(project, "$" + element.getText());
|
||||||
if (element.getParent() instanceof JetDotQualifiedExpression && ((JetDotQualifiedExpression) element.getParent()).getReceiverExpression() instanceof JetThisExpression) {
|
element.replace(backingField);
|
||||||
element.getParent().replace(backingField);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
element.replace(backingField);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JetIntentionActionFactory<JetSimpleNameExpression> createFactory() {
|
public static JetIntentionActionFactory<JetSimpleNameExpression> createFactory() {
|
||||||
|
|||||||
@@ -78,8 +78,9 @@ public class ChangeVariableMutabilityFix implements IntentionAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
|
||||||
JetProperty element = getCorrespondingProperty(editor, (JetFile)file);
|
JetProperty property = getCorrespondingProperty(editor, (JetFile)file);
|
||||||
JetProperty newElement = (JetProperty) element.copy();
|
assert property != null && !property.isVar();
|
||||||
|
JetProperty newElement = (JetProperty) property.copy();
|
||||||
if (newElement.isVar()) {
|
if (newElement.isVar()) {
|
||||||
PsiElement varElement = newElement.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi();
|
PsiElement varElement = newElement.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi();
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ public class ChangeVariableMutabilityFix implements IntentionAction {
|
|||||||
PsiElement varElement = varProperty.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi();
|
PsiElement varElement = varProperty.getNode().findChildByType(JetTokens.VAR_KEYWORD).getPsi();
|
||||||
CodeEditUtil.replaceChild(newElement.getNode(), valElement.getNode(), varElement.getNode());
|
CodeEditUtil.replaceChild(newElement.getNode(), valElement.getNode(), varElement.getNode());
|
||||||
}
|
}
|
||||||
element.replace(newElement);
|
property.replace(newElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -111,8 +111,10 @@ public class QuickFixes {
|
|||||||
add(Errors.ILLEGAL_MODIFIER, removeModifierFactory);
|
add(Errors.ILLEGAL_MODIFIER, removeModifierFactory);
|
||||||
|
|
||||||
add(Errors.PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE, AddReturnTypeFix.createFactory());
|
add(Errors.PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE, AddReturnTypeFix.createFactory());
|
||||||
|
|
||||||
add(Errors.INITIALIZATION_USING_BACKING_FIELD, ChangeToBackingFieldFix.createFactory());
|
JetIntentionActionFactory<JetSimpleNameExpression> changeToBackingFieldFactory = ChangeToBackingFieldFix.createFactory();
|
||||||
|
add(Errors.INITIALIZATION_USING_BACKING_FIELD_CUSTOM_SETTER, changeToBackingFieldFactory);
|
||||||
|
add(Errors.INITIALIZATION_USING_BACKING_FIELD_OPEN_SETTER, changeToBackingFieldFactory);
|
||||||
|
|
||||||
ImplementMethodsHandler implementMethodsHandler = new ImplementMethodsHandler();
|
ImplementMethodsHandler implementMethodsHandler = new ImplementMethodsHandler();
|
||||||
actionMap.put(Errors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, implementMethodsHandler);
|
actionMap.put(Errors.ABSTRACT_MEMBER_NOT_IMPLEMENTED, implementMethodsHandler);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public class RemoveModifierFix {
|
|||||||
if (isRedundant) {
|
if (isRedundant) {
|
||||||
return JetBundle.message("remove.redundant.modifier", modifier.getValue());
|
return JetBundle.message("remove.redundant.modifier", modifier.getValue());
|
||||||
}
|
}
|
||||||
if (element != null && modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD) {
|
if (element != null && (modifier == JetTokens.ABSTRACT_KEYWORD || modifier == JetTokens.OPEN_KEYWORD)) {
|
||||||
return JetBundle.message("make.element.not.modifier", AddModifierFix.getElementName(element), modifier.getValue());
|
return JetBundle.message("make.element.not.modifier", AddModifierFix.getElementName(element), modifier.getValue());
|
||||||
}
|
}
|
||||||
return JetBundle.message("remove.modifier", modifier.getValue());
|
return JetBundle.message("remove.modifier", modifier.getValue());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
class Test() {
|
class Test() {
|
||||||
var a : Int = 111
|
var a : Int = 111
|
||||||
var b : Int get() = <error>$a</error>; set(x) {a = x; <error>$a</error> = x}
|
var b : Int get() = $a; set(x) {a = x; $a = x}
|
||||||
|
|
||||||
this(i : Int) : this() {
|
this(i : Int) : this() {
|
||||||
<error>$b</error> = $a
|
<error>$b</error> = $a
|
||||||
@@ -22,7 +22,7 @@ class Test() {
|
|||||||
a = <error>$b</error>
|
a = <error>$b</error>
|
||||||
}
|
}
|
||||||
fun f() {
|
fun f() {
|
||||||
<error>$b</error> = <error>$a</error>
|
<error>$b</error> = $a
|
||||||
a = <error>$b</error>
|
a = <error>$b</error>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// "Change reference to backing field" "true"
|
// "Change reference to backing field" "true"
|
||||||
class A() {
|
class A() {
|
||||||
val a : Int
|
var a : Int
|
||||||
|
set(v) {}
|
||||||
{
|
{
|
||||||
<caret>$a = 1
|
<caret>$a = 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// "Change reference to backing field" "true"
|
// "Change reference to backing field" "true"
|
||||||
public open class Identifier() {
|
public open class Identifier() {
|
||||||
var field : Boolean
|
var field : Boolean
|
||||||
|
set(v) {}
|
||||||
{
|
{
|
||||||
<caret>$field = false;
|
<caret>this.$field = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// "Change reference to backing field" "true"
|
// "Change reference to backing field" "true"
|
||||||
class A() {
|
class A() {
|
||||||
val a : Int
|
var a : Int
|
||||||
|
set(v) {}
|
||||||
{
|
{
|
||||||
<caret>a = 1
|
<caret>a = 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// "Change reference to backing field" "true"
|
// "Change reference to backing field" "true"
|
||||||
public open class Identifier() {
|
public open class Identifier() {
|
||||||
var field : Boolean
|
var field : Boolean
|
||||||
|
set(v) {}
|
||||||
{
|
{
|
||||||
<caret>this.field = false;
|
<caret>this.field = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user