Test & fix for Bug 355259 - Cannot declare role-typed field in an
enum-as-team-member
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index a3c2f5d..ec46137 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -161,6 +161,7 @@
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TypeModel;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.CopyInheritance;
+import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.copyinheritance.CopyInheritance.RoleConstructorCall;
import org.eclipse.objectteams.otdt.internal.core.compiler.statemachine.transformer.MethodSignatureEnhancer;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstEdit;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.AstGenerator;
@@ -3494,10 +3495,14 @@
break;
//{ObjectTeams: for roles we detect this earlier than JDT
case ProblemReasons.NonStaticReferenceInConstructorInvocation:
+ case ProblemReasons.NonStaticReferenceInStaticContext:
if ( targetConstructor.declaringClass != null
&& targetConstructor.declaringClass.isRole())
{
- noSuchEnclosingInstance(targetConstructor.declaringClass.enclosingType(), statement, true);
+ if (statement instanceof CopyInheritance.RoleConstructorCall)
+ statement = ((RoleConstructorCall)statement).allocationOrig;
+ noSuchEnclosingInstance(targetConstructor.declaringClass.enclosingType(), statement,
+ targetConstructor.problemId() == ProblemReasons.NonStaticReferenceInConstructorInvocation);
return;
}
break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java
index 61ec1ac..63af192 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/copyinheritance/CopyInheritance.java
@@ -66,6 +66,7 @@
import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier;
import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
@@ -91,6 +92,7 @@
import org.eclipse.objectteams.otdt.internal.core.compiler.control.StateHelper;
import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config.NotConfiguredException;
import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.Lifting;
+import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.AnchorMapping;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.RoleTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.SyntheticBaseCallSurrogate;
@@ -1613,6 +1615,63 @@
}
}
}
+
+ public static class RoleConstructorCall extends MessageSend {
+ public AllocationExpression allocationOrig;
+
+ public RoleConstructorCall(AllocationExpression allocationExpr) {
+ this.allocationOrig = allocationExpr;
+ }
+
+ // specialized MessageSend to perform analysis for unsafe role instantiation:
+ @Override
+ public TypeBinding resolveType(BlockScope blockScope) {
+ TypeBinding result = super.resolveType(blockScope);
+ ReferenceBinding roleType = (ReferenceBinding)this.resolvedType;
+ if (roleType != null && roleType.isValidBinding()) {
+ MethodBinding ctor = roleType.getExactConstructor(this.binding.parameters);
+ if (Lifting.isLiftToConstructor(ctor, roleType)) // implies role is bound
+ {
+ if (this.arguments != null && this.arguments.length > 0) {
+ Expression currentArg = this.arguments[0];
+ while (currentArg instanceof CastExpression)
+ currentArg = ((CastExpression)currentArg).expression; // unwrap
+ if ( (currentArg instanceof AllocationExpression)
+ || ( (currentArg instanceof MessageSend)
+ && isCreator(((MessageSend)currentArg).binding)))
+ {
+ // need to check if arg is compatible without lowering
+ TypeBinding allocType = currentArg.resolvedType;
+ Config confBak = Config.createOrResetConfig(this);
+ try {
+ if ( allocType.isCompatibleWith(roleType.baseclass())
+ && !Config.getLoweringRequired()) // TODO(SH): could potentially ask the expression if conversions were involved?
+ return result; // we're clean
+ } finally {
+ Config.removeOrRestore(confBak, this);
+ }
+ }
+ blockScope.problemReporter().liftCtorArgNotAllocation(ctor, this, roleType.baseclass());
+ this.binding.roleCreatorRequiringRuntimeCheck = true;
+ }
+ }
+ }
+ return result;
+ }
+ @Override
+ protected TypeBinding afterMethodLookup(Scope scope, AnchorMapping anchorMapping, TypeBinding[] argumentTypes,
+ TypeBinding returnType) {
+ this.allocationOrig.binding = this.binding; // secure this for error reporting
+ if (this.binding instanceof ProblemMethodBinding)
+ this.allocationOrig.binding = ((ProblemMethodBinding)this.binding).closestMatch;
+ if (this.allocationOrig.binding != null) {
+ MethodModel model = this.allocationOrig.binding.model;
+ if (model != null && model._srcCtor != null)
+ this.allocationOrig.binding = model._srcCtor;
+ }
+ return super.afterMethodLookup(scope, anchorMapping, argumentTypes, returnType);
+ }
+ }
/**
* Create an invocation of a creation method, which will replace a given
* allocation expression, i.e.,
@@ -1674,43 +1733,7 @@
} else {
receiver = ThisReference.implicitThis();
}
- MessageSend message = new MessageSend() {
- // specialized MessageSend to perform analysis for unsafe role instantiation:
- @Override
- public TypeBinding resolveType(BlockScope blockScope) {
- TypeBinding result = super.resolveType(blockScope);
- ReferenceBinding roleType = (ReferenceBinding)this.resolvedType;
- if (roleType != null && roleType.isValidBinding()) {
- MethodBinding ctor = roleType.getExactConstructor(this.binding.parameters);
- if (Lifting.isLiftToConstructor(ctor, roleType)) // implies role is bound
- {
- if (this.arguments != null && this.arguments.length > 0) {
- Expression currentArg = this.arguments[0];
- while (currentArg instanceof CastExpression)
- currentArg = ((CastExpression)currentArg).expression; // unwrap
- if ( (currentArg instanceof AllocationExpression)
- || ( (currentArg instanceof MessageSend)
- && isCreator(((MessageSend)currentArg).binding)))
- {
- // need to check if arg is compatible without lowering
- TypeBinding allocType = currentArg.resolvedType;
- Config confBak = Config.createOrResetConfig(this);
- try {
- if ( allocType.isCompatibleWith(roleType.baseclass())
- && !Config.getLoweringRequired()) // TODO(SH): could potentially ask the expression if conversions were involved?
- return result; // we're clean
- } finally {
- Config.removeOrRestore(confBak, this);
- }
- }
- blockScope.problemReporter().liftCtorArgNotAllocation(ctor, this, roleType.baseclass());
- this.binding.roleCreatorRequiringRuntimeCheck = true;
- }
- }
- }
- return result;
- }
- };
+ MessageSend message = new RoleConstructorCall(allocationExpr);
gen.setPos(message);
message.nameSourcePosition = gen.pos;
message.selector = selector;
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
index 0a402d1..23bb407 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/Java5.java
@@ -5041,6 +5041,32 @@
null/*requestor*/);
}
+ // An enum-in-a-team tries to refer to a role
+ // Bug 355259 - Cannot declare role-typed field in an enum-as-team-member
+ public void testA120_enumInTeam5() {
+ runConformTest(
+ new String[] {
+ "TeamA120eit5.java",
+ "public team class TeamA120eit5 {\n" +
+ " protected class R {}\n" +
+ " protected enum Values {\n" +
+ " V1, V2;\n" +
+ " public R r = new R();\n" +
+ " }\n" +
+ " public static void main(String[] args) {\n" +
+ " for (Values v : Values.values())\n" +
+ " System.out.print(v);\n" +
+ " }\n" +
+ "}"
+ },
+ "----------\n" +
+ "1. ERROR in TeamA120eit5.java (at line 5)\n" +
+ " public R r = new R();\n" +
+ " ^^^^^^^\n" +
+ "No enclosing instance of type TeamA120eit5 is accessible. Must qualify the allocation with an enclosing instance of type TeamA120eit5 (e.g. x.new A() where x is an instance of TeamA120eit5).\n" +
+ "----------\n");
+ }
+
public void testA121_genericNestedTeam1() {
runConformTest(
new String[] {