Modify analysis for property initializer. Add errors about delegated property accessors.

This commit is contained in:
Natalia.Ukhorskaya
2013-04-26 10:52:20 +04:00
parent 171144e641
commit e7bf3b141f
16 changed files with 246 additions and 15 deletions
@@ -241,6 +241,11 @@ public interface Errors {
DiagnosticFactory0<JetPropertyAccessor> ABSTRACT_PROPERTY_WITH_GETTER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyAccessor> ABSTRACT_PROPERTY_WITH_SETTER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyDelegate> ABSTRACT_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyAccessor> ACCESSOR_FOR_DELEGATED_PROPERTY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyDelegate> DELEGATED_PROPERTY_IN_TRAIT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetPropertyDelegate> LOCAL_VARIABLE_WITH_DELEGATE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetProperty> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, NAMED_ELEMENT);
DiagnosticFactory0<JetProperty> MUST_BE_INITIALIZED = DiagnosticFactory0.create(ERROR, NAMED_ELEMENT);
@@ -109,7 +109,7 @@ public class DefaultErrorMessages {
MAP.put(NON_VARARG_SPREAD, "The spread operator (*foo) may only be applied in a vararg position");
MAP.put(MANY_FUNCTION_LITERAL_ARGUMENTS, "Only one function literal is allowed outside a parenthesized argument list");
MAP.put(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, "This property must either have a type annotation or be initialized");
MAP.put(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER, "This property must either have a type annotation, be initialized or be delegated");
MAP.put(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER, "This variable must either have a type annotation or be initialized");
MAP.put(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION, "Initializer required for multi-declaration");
@@ -123,6 +123,11 @@ public class DefaultErrorMessages {
MAP.put(ABSTRACT_PROPERTY_WITH_GETTER, "Property with getter implementation cannot be abstract");
MAP.put(ABSTRACT_PROPERTY_WITH_SETTER, "Property with setter implementation cannot be abstract");
MAP.put(ABSTRACT_DELEGATED_PROPERTY, "Delegated property cannot be abstract");
MAP.put(ACCESSOR_FOR_DELEGATED_PROPERTY, "Delegated property cannot have accessor");
MAP.put(DELEGATED_PROPERTY_IN_TRAIT, "Delegated properties are not allowed in traits");
MAP.put(LOCAL_VARIABLE_WITH_DELEGATE, "Local variables are not allowed to have delegates");
MAP.put(PACKAGE_MEMBER_CANNOT_BE_PROTECTED, "Package member cannot be protected");
MAP.put(GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, "Getter visibility must be the same as property visibility");
@@ -123,6 +123,7 @@ public class BodyResolver {
resolveDelegationSpecifierLists();
resolveClassAnnotations();
resolvePropertyDelegates();
resolvePropertyDeclarationBodies();
resolveAnonymousInitializers();
resolvePrimaryConstructorParameters();
@@ -152,6 +153,27 @@ public class BodyResolver {
}
}
private void resolvePropertyDelegates() {
for (Map.Entry<JetProperty, PropertyDescriptor> entry : context.getProperties().entrySet()) {
JetProperty jetProperty = entry.getKey();
JetExpression delegateExpression = jetProperty.getDelegateExpression();
if (delegateExpression == null) continue;
JetPropertyAccessor getter = jetProperty.getGetter();
if (getter != null) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter));
}
JetPropertyAccessor setter = jetProperty.getSetter();
if (setter != null) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter));
}
//todo resolve delegate expression
}
}
private void resolveDelegationSpecifierList(JetClassOrObject jetClass, MutableClassDescriptor descriptor) {
resolveDelegationSpecifierList(jetClass, descriptor,
descriptor.getUnsubstitutedPrimaryConstructor(),
@@ -422,7 +444,8 @@ public class BodyResolver {
JetScope declaringScope = context.getDeclaringScopes().apply(accessor);
JetScope propertyDeclarationInnerScope = descriptorResolver.getPropertyDeclarationInnerScope(
propertyDescriptor, declaringScope, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter(), trace);
propertyDescriptor, declaringScope, propertyDescriptor.getTypeParameters(), propertyDescriptor.getReceiverParameter(),
trace);
WritableScope accessorScope = new WritableScopeImpl(
propertyDeclarationInnerScope, declaringScope.getContainingDeclaration(), new TraceBasedRedeclarationHandler(trace), "Accessor scope");
accessorScope.changeLockLevel(WritableScope.LockLevel.READING);
@@ -521,7 +544,7 @@ public class BodyResolver {
}
}
}
private static void computeDeferredType(JetType type) {
// handle type inference loop: function or property body contains a reference to itself
// fun f() = { f() }
@@ -199,6 +199,10 @@ public class DeclarationsChecker {
if (initializer != null) {
trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer));
}
JetPropertyDelegate delegate = property.getDelegate();
if (delegate != null) {
trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate));
}
if (getter != null && getter.getBodyExpression() != null) {
trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter));
}
@@ -218,7 +222,7 @@ public class DeclarationsChecker {
(setter != null && setter.getBodyExpression() != null);
if (propertyDescriptor.getModality() == Modality.ABSTRACT) {
if (property.getInitializer() == null && property.getTypeRef() == null) {
if (property.getDelegateExpressionOrInitializer() == null && property.getTypeRef() == null) {
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property));
}
return;
@@ -226,12 +230,13 @@ public class DeclarationsChecker {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor)containingDeclaration).getKind() == ClassKind.TRAIT;
JetExpression initializer = property.getInitializer();
JetPropertyDelegate delegate = property.getDelegate();
boolean backingFieldRequired = trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
if (inTrait && backingFieldRequired && hasAccessorImplementation) {
trace.report(BACKING_FIELD_IN_TRAIT.on(property));
}
if (initializer == null) {
if (initializer == null && delegate == null) {
boolean error = false;
if (backingFieldRequired && !inTrait && !trace.getBindingContext().get(BindingContext.IS_INITIALIZED, propertyDescriptor)) {
if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) {
@@ -252,9 +257,14 @@ public class DeclarationsChecker {
return;
}
if (inTrait) {
trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
if (delegate != null) {
trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate));
}
else {
trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer));
}
}
else if (!backingFieldRequired) {
else if (!backingFieldRequired && delegate == null) {
trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer));
}
}
@@ -964,7 +964,7 @@ public class DescriptorResolver {
/*package*/
static boolean hasBody(JetProperty property) {
boolean hasBody = property.getInitializer() != null;
boolean hasBody = property.getDelegateExpressionOrInitializer() != null;
if (!hasBody) {
JetPropertyAccessor getter = property.getGetter();
if (getter != null && getter.getBodyExpression() != null) {
@@ -989,9 +989,14 @@ public class DescriptorResolver {
) {
JetTypeReference propertyTypeRef = variable.getTypeRef();
boolean hasDelegate = variable instanceof JetProperty && ((JetProperty) variable).getDelegateExpression() != null;
if (propertyTypeRef == null) {
final JetExpression initializer = variable.getInitializer();
if (initializer == null) {
if (hasDelegate) {
// todo resolve type from delegate
return ErrorUtils.createErrorType("Type from delegate");
}
if (!notLocal) {
trace.report(VARIABLE_WITH_NO_TYPE_NO_INITIALIZER.on(variable));
}
@@ -1112,7 +1117,12 @@ public class DescriptorResolver {
trace.record(BindingContext.PROPERTY_ACCESSOR, setter, setterDescriptor);
}
else if (property.isVar()) {
setterDescriptor = createDefaultSetter(propertyDescriptor);
if (property.getDelegateExpression() != null) {
setterDescriptor = createSetterForDelegatedProperty(propertyDescriptor);
}
else {
setterDescriptor = createDefaultSetter(propertyDescriptor);
}
}
if (!property.isVar()) {
@@ -1124,12 +1134,23 @@ public class DescriptorResolver {
return setterDescriptor;
}
public static PropertySetterDescriptorImpl createDefaultSetter(PropertyDescriptor propertyDescriptor) {
@NotNull
public static PropertySetterDescriptorImpl createDefaultSetter(@NotNull PropertyDescriptor propertyDescriptor) {
return createSetter(propertyDescriptor, false, true);
}
@NotNull
public static PropertySetterDescriptorImpl createSetterForDelegatedProperty(@NotNull PropertyDescriptor propertyDescriptor) {
return createSetter(propertyDescriptor, true, false);
}
@NotNull
private static PropertySetterDescriptorImpl createSetter(@NotNull PropertyDescriptor propertyDescriptor, boolean hasBody, boolean isDefault) {
PropertySetterDescriptorImpl setterDescriptor;
setterDescriptor = new PropertySetterDescriptorImpl(
propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), propertyDescriptor.getModality(),
propertyDescriptor.getVisibility(),
false, true, CallableMemberDescriptor.Kind.DECLARATION);
hasBody, isDefault, CallableMemberDescriptor.Kind.DECLARATION);
setterDescriptor.initializeDefault();
return setterDescriptor;
}
@@ -1165,18 +1186,33 @@ public class DescriptorResolver {
trace.record(BindingContext.PROPERTY_ACCESSOR, getter, getterDescriptor);
}
else {
getterDescriptor = createDefaultGetter(propertyDescriptor);
if (property.getDelegateExpression() != null) {
getterDescriptor = createGetterForDelegatedProperty(propertyDescriptor);
}
else {
getterDescriptor = createDefaultGetter(propertyDescriptor);
}
getterDescriptor.initialize(propertyDescriptor.getType());
}
return getterDescriptor;
}
public static PropertyGetterDescriptorImpl createDefaultGetter(PropertyDescriptor propertyDescriptor) {
@NotNull
public static PropertyGetterDescriptorImpl createDefaultGetter(@NotNull PropertyDescriptor propertyDescriptor) {
return createGetter(propertyDescriptor, false, true);
}
@NotNull
public static PropertyGetterDescriptorImpl createGetterForDelegatedProperty(@NotNull PropertyDescriptor propertyDescriptor) {
return createGetter(propertyDescriptor, true, false);
}
private static PropertyGetterDescriptorImpl createGetter(@NotNull PropertyDescriptor propertyDescriptor, boolean hasBody, boolean isDefault) {
PropertyGetterDescriptorImpl getterDescriptor;
getterDescriptor = new PropertyGetterDescriptorImpl(
propertyDescriptor, Collections.<AnnotationDescriptor>emptyList(), propertyDescriptor.getModality(),
propertyDescriptor.getVisibility(),
false, true, CallableMemberDescriptor.Kind.DECLARATION);
hasBody, isDefault, CallableMemberDescriptor.Kind.DECLARATION);
return getterDescriptor;
}
@@ -112,6 +112,12 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
}
JetExpression delegateExpression = property.getDelegateExpression();
if (delegateExpression != null) {
context.expressionTypingServices.getType(scope, delegateExpression, TypeUtils.NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate()));
}
VariableDescriptor propertyDescriptor = context.expressionTypingServices.getDescriptorResolver().
resolveLocalVariableDescriptor(scope.getContainingDeclaration(), scope, property, context.dataFlowInfo, context.trace);
JetExpression initializer = property.getInitializer();
@@ -0,0 +1,8 @@
val a: Int by Delegate()
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,8 @@
val a by Delegate()
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,10 @@
abstract class A {
abstract val a: Int <!ABSTRACT_DELEGATED_PROPERTY!>by Delegate()<!>
}
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,13 @@
class B {
val a: Int by Delegate()
fun foo() = <!NO_BACKING_FIELD_CUSTOM_ACCESSORS!>$a<!>
}
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,10 @@
trait T {
val a: Int <!DELEGATED_PROPERTY_IN_TRAIT!>by Delegate()<!>
}
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,12 @@
class Local {
fun foo() {
val <!UNUSED_VARIABLE!>a<!>: Int <!LOCAL_VARIABLE_WITH_DELEGATE!>by Delegate()<!>
}
}
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,8 @@
<!PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE!>public val a<!> by Delegate()
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,9 @@
val a: Int by Delegate()
<!ACCESSOR_FOR_DELEGATED_PROPERTY!>get() = 1<!>
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
}
@@ -0,0 +1,14 @@
var a: Int by Delegate()
<!ACCESSOR_FOR_DELEGATED_PROPERTY!>get() = 1<!>
<!ACCESSOR_FOR_DELEGATED_PROPERTY!>set(i) {}<!>
class Delegate {
fun get(t: Any?, p: String): Int {
t.equals(p) // to avoid UNUSED_PARAMETER warning
return 1
}
fun set(t: Any?, p: String, i: Int) {
t.equals(p) || i.equals(null) // to avoid UNUSED_PARAMETER warning
}
}
@@ -33,7 +33,7 @@ import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve;
@InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class})
public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve {
@TestMetadata("compiler/testData/diagnostics/tests")
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.ThisAndSuper.class, Tests.Varargs.class})
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.ThisAndSuper.class, Tests.Varargs.class})
public static class Tests extends AbstractDiagnosticsTestWithEagerResolve {
@TestMetadata("Abstract.kt")
public void testAbstract() throws Exception {
@@ -1887,6 +1887,59 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
}
}
@TestMetadata("compiler/testData/diagnostics/tests/delegatedProperty")
public static class DelegatedProperty extends AbstractDiagnosticsTestWithEagerResolve {
@TestMetadata("absentErrorAboutInitializer.kt")
public void testAbsentErrorAboutInitializer() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/absentErrorAboutInitializer.kt");
}
@TestMetadata("absentErrorAboutType.kt")
public void testAbsentErrorAboutType() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/absentErrorAboutType.kt");
}
@TestMetadata("abstractDelegatedProperty.kt")
public void testAbstractDelegatedProperty() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/abstractDelegatedProperty.kt");
}
public void testAllFilesPresentInDelegatedProperty() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/delegatedProperty"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("backingField.kt")
public void testBackingField() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/backingField.kt");
}
@TestMetadata("inTrait.kt")
public void testInTrait() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/inTrait.kt");
}
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/localVariable.kt");
}
@TestMetadata("publicDelegatedProperty.kt")
public void testPublicDelegatedProperty() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/publicDelegatedProperty.kt");
}
@TestMetadata("redundantGetter.kt")
public void testRedundantGetter() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/redundantGetter.kt");
}
@TestMetadata("redundantSetter.kt")
public void testRedundantSetter() throws Exception {
doTest("compiler/testData/diagnostics/tests/delegatedProperty/redundantSetter.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/tests/deparenthesize")
public static class Deparenthesize extends AbstractDiagnosticsTestWithEagerResolve {
public void testAllFilesPresentInDeparenthesize() throws Exception {
@@ -4757,6 +4810,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
suite.addTestSuite(DataFlow.class);
suite.addTestSuite(DataFlowInfoTraversal.class);
suite.addTest(DeclarationChecks.innerSuite());
suite.addTestSuite(DelegatedProperty.class);
suite.addTestSuite(Deparenthesize.class);
suite.addTest(Enum.innerSuite());
suite.addTestSuite(Extensions.class);