Test & fix for Bug 370273 - [compiler][otjld] consider allowing base
imported types as the return type of a team method
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedSingleTypeReference.java
index 08acfc2..0af1cb8 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnParameterizedSingleTypeReference.java
@@ -34,8 +34,8 @@
 	}
 //{ObjectTeams: one more method to override:
 	@Override
-	public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
-		TypeBinding result = super.checkResolveUsingBaseImportScope(scope);
+	public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
+		TypeBinding result = super.checkResolveUsingBaseImportScope(scope, tolerate);
 		if (this.resolvedType != null)
 			throw new SelectionNodeFound(this.resolvedType);
 		return result;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 771e687..31ce927 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -110,7 +110,9 @@
 		ALLOWED   { public boolean isAllowed() { return true;  }},
 		/** This node is either a playedBy reference for which decapsulation has been reported,
 		 *  or some other (generated) base reference for which decapsulation shall not be reported. */
-		REPORTED  { public boolean isAllowed() { return true;  }};
+		REPORTED  { public boolean isAllowed() { return true;  }},
+		/** This mode is for team method return types: prefer local resolution, but tolerate base class as a fallback. */
+		TOLERATED { public boolean isAllowed() { return false; }};
 		abstract public boolean isAllowed();
 	}
 	public DecapsulationState getBaseclassDecapsulation() {return DecapsulationState.NONE;}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index 4c92765..c0e16b8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -449,9 +449,10 @@
 //{ObjectTeams: resolve helpers
 	// for base-imported types (only single is supported):
 	@Override
-	public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
+	public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
 		// same as in SingleTypeReference:
 		if (   this.getBaseclassDecapsulation().isAllowed()
+			|| tolerate
 			|| scope.isBaseGuard())
 		{
 			TypeBinding problem = this.resolvedType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
index 0e5b6be..5f8c0e1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
@@ -107,8 +107,9 @@
 
 //{ObjectTeams: for base-imported types (only single is supported):
 	@Override
-	public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
+	public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
 		if (   this.getBaseclassDecapsulation().isAllowed()
+			|| tolerate
 			|| scope.isBaseGuard())
 		{
 			TypeBinding problem = this.resolvedType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
index 89eba30..0a30535 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
@@ -167,7 +167,7 @@
 	CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult();
 	CompilationResult.CheckPoint cp = compilationResult.getCheckPoint(scope.referenceContext());
 	try {
-	  type = checkResolveUsingBaseImportScope(scope);
+	  type = checkResolveUsingBaseImportScope(scope, false); // apply TOLERATE strategy only as a last resort below
 	  // copied from below:
 	  if (type != null && type.isValidBinding()) {
 		type = scope.environment().convertToRawType(type, false /*do not force conversion of enclosing types*/);
@@ -199,8 +199,8 @@
 		throw snf; // found a valid node.
 	caughtException = snf;
   }
-  try {
 // a third chance trying an anchored type:
+  try {
     if (   (caughtException != null)
     	|| (this.resolvedType.problemId() == ProblemReasons.NotFound))
 	{
@@ -211,11 +211,25 @@
     }
   } catch (SelectionNodeFound snf2) {
 	  caughtException = snf2; // throw the newer exception instead.
-  } finally {
+  }
+//a forth chance trying a TOLERATED base imported type:
+ try {
+   if (   (caughtException != null)
+	   || (this.resolvedType.problemId() == ProblemReasons.NotFound))
+	{
+   		if (this.baseclassDecapsulation == DecapsulationState.TOLERATED) {
+   			TypeBinding result = checkResolveUsingBaseImportScope(scope, true);
+   			if (result != null)             // did we do any better than before?
+   				type = this.resolvedType = result; // if non-null but ProblemBinding report below.
+   		}
+   }
+ } catch (SelectionNodeFound snf2) {
+	  caughtException = snf2; // throw the newer exception instead.
+ } finally {
 	  // the attempt to prevent an exception failed:
 	  if (caughtException != null)
 		  throw caughtException;
-  }
+ }
 // SH}
 	if ((hasError = !type.isValidBinding()) == true) {
 		reportInvalidType(scope);
@@ -258,7 +272,7 @@
 
 //{ObjectTeams: alternative strategies for resolving:
 /** Try to resolve this reference from base imports. */
-public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
+public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
 	return null; // override to do something useful (only in SingleTypeReference).
 }
 /**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index 5a69310..b82025b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -2369,7 +2369,7 @@
  */
 			typeReference.deprecationProblemId = IProblem.DeprecatedBaseclass;
 			ReferenceBinding superType;
-			if (typeReference.checkResolveUsingBaseImportScope(this) != null) {
+			if (typeReference.checkResolveUsingBaseImportScope(this, false) != null) {
 				superType = (ReferenceBinding)typeReference.resolvedType;
 			} else {
 				superType = (ReferenceBinding) typeReference.resolveSuperType(this);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 46f0bf1..07d1434 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -2268,6 +2268,8 @@
 		} else {
 //{ObjectTeams: option to roll back problems:
 			CheckPoint cp = this.scope.referenceContext.compilationResult.getCheckPoint(methodDecl);
+			if (this.isTeam() && !method.isPrivate() && returnType.getBaseclassDecapsulation() == DecapsulationState.NONE)
+				returnType.setBaseclassDecapsulation(DecapsulationState.TOLERATED);
 //	 SH}
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=322817
 			boolean deferRawTypeCheck = !reportUnavoidableGenericTypeProblems && (returnType.bits & ASTNode.IgnoreRawTypeCheck) == 0;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java
index 7d2ccb5..15be70e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/util/IAlienScopeTypeReference.java
@@ -51,8 +51,8 @@
 		}
 		public Scope getAlienScope() { return this.alienScope; }
 		@Override
-		public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
-			return super.checkResolveUsingBaseImportScope(this.alienScope);
+		public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
+			return super.checkResolveUsingBaseImportScope(this.alienScope, tolerate);
 		}
 		@Override
 		public TypeBinding resolveType(ClassScope scope) {
@@ -87,8 +87,8 @@
 		}
 		public Scope getAlienScope() { return this.alienScope; }
 		@Override
-		public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
-			return super.checkResolveUsingBaseImportScope(this.alienScope);
+		public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
+			return super.checkResolveUsingBaseImportScope(this.alienScope, tolerate);
 		}
 		@Override
 		public TypeBinding resolveType(ClassScope scope) {
@@ -124,15 +124,15 @@
 		}
 		public Scope getAlienScope() { return this.alienScope; }
 		@Override
-		public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
+		public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
 			// `scope` may be stronger then `alienScope`, try it first:
 			// (see 1.1.22-otjld-layered-teams-5)
-			TypeBinding result= super.checkResolveUsingBaseImportScope(scope);
+			TypeBinding result= super.checkResolveUsingBaseImportScope(scope, tolerate);
 			if (result != null && result.isValidBinding())
 				return result;
 			// remove problem binding if any:
 			this.resolvedType = null;
-			return super.checkResolveUsingBaseImportScope(this.alienScope);
+			return super.checkResolveUsingBaseImportScope(this.alienScope, tolerate);
 		}
 		@Override
 		public TypeBinding resolveType(ClassScope scope) {
@@ -168,8 +168,8 @@
 		}
 		public Scope getAlienScope() { return this.alienScope; }
 		@Override
-		public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
-			return super.checkResolveUsingBaseImportScope(this.alienScope);
+		public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
+			return super.checkResolveUsingBaseImportScope(this.alienScope, tolerate);
 		}
 		@Override
 		public TypeBinding resolveType(ClassScope scope) {
@@ -208,8 +208,8 @@
 		}
 		public Scope getAlienScope() { return this.alienScope; }
 		@Override
-		public TypeBinding checkResolveUsingBaseImportScope(Scope scope) {
-			return super.checkResolveUsingBaseImportScope(this.alienScope);
+		public TypeBinding checkResolveUsingBaseImportScope(Scope scope, boolean tolerate) {
+			return super.checkResolveUsingBaseImportScope(this.alienScope, tolerate);
 		}
 		@Override
 		public TypeBinding resolveType(ClassScope scope) {
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java
index e762d52..d846bfe 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/roleplaying/BaseClassVisibility.java
@@ -30,7 +30,7 @@
 	// Static initializer to specify tests subset using TESTS_* static variables
 	// All specified tests which does not belong to the class are skipped...
 	static {
-//		TESTS_NAMES = new String[] { "test242_inaccessibleBaseClass"};
+//		TESTS_NAMES = new String[] { "test247_baseImportScope"};
 //		TESTS_NUMBERS = new int[] { 1459 };
 //		TESTS_RANGE = new int[] { 1097, -1 };
 	}
@@ -2128,4 +2128,106 @@
             },
             "Syntax error");
     }
+
+    // a team uses a base-imported class as a return type for one of its methods
+    public void test247_baseImportScope4() {
+        runConformTest(
+            new String[] {
+        "T247bis4Main.java",
+        		"public class T247bis4Main {\n" +
+        		"    public static void main(String... args) {\n" +
+        		"         System.out.print(new p2.Team247bis4().getR());\n" +
+        		"    }\n" +
+        		"}\n",
+		"p2/Team247bis4.java",
+			    "package p2;\n" +
+			    "import base p1.T247bis4_1;\n" +
+			    "public team class Team247bis4 {\n" +
+			    "    protected class R playedBy T247bis4_1 {\n" +
+			    "        protected R() {\n" +
+			    "            base();\n" +
+			    "        }\n" +
+			    "    }\n" +
+			    "    public T247bis4_1 getR() {\n" +
+			    "        return new R();\n" +
+			    "    }\n" +
+			    "}\n",
+		"p1/T247bis4_1.java",
+			    "\n" +
+			    "package p1;\n" +
+			    "public class T247bis4_1 {\n" +
+			    "    @Override public String toString() { return \"Base\"; }\n" +
+			    "}\n"
+            },
+            "Base");
+    }
+    // resolving team method return type prefers role over base class
+    public void test247_baseImportScope5() {
+        runConformTest(
+            new String[] {
+        "T247bis5Main.java",
+        		"public class T247bis5Main {\n" +
+        		"    public static void main(String... args) {\n" +
+        		"         new p2.Team247bis5().test();\n" +
+        		"    }\n" +
+        		"}\n",
+		"p2/Team247bis5.java",
+			    "package p2;\n" +
+			    "import base p1.T247bis5_1;\n" +
+			    "public team class Team247bis5 {\n" +
+			    "    protected class T247bis5_1 playedBy T247bis5_1 {\n" +
+			    "         protected T247bis5_1() { base(); }\n" +
+			    "         @Override public String toString() { return \"Role\"; }\n" +
+			    "    }\n" +
+			    "    T247bis5_1 getR() {\n" +
+			    "        return new T247bis5_1();\n" +
+			    "    }\n" +
+			    "    public void test() {\n" +
+			    "         System.out.print(getR());\n" +
+			    "    }\n" +
+			    "}\n",
+		"p1/T247bis5_1.java",
+			    "\n" +
+			    "package p1;\n" +
+			    "public class T247bis5_1 {\n" +
+			    "    @Override public String toString() { return \"Base\"; }\n" +
+			    "}\n"
+            },
+            "Role");
+    }
+
+    // a team uses a base-imported class as a return type for one of its methods
+    // also: Bug 372391 - [compiler] creating bound role in field declaration throws NPE on role cache
+    public void _test247_baseImportScope6() {
+        runConformTest(
+            new String[] {
+        "T247bis6Main.java",
+        		"public class T247bis6Main {\n" +
+        		"    public static void main(String... args) {\n" +
+        		"         System.out.print(new p2.Team247bis6().getR());\n" +
+        		"    }\n" +
+        		"}\n",
+		"p2/Team247bis6.java",
+			    "package p2;\n" +
+			    "import base p1.T247bis6_1;\n" +
+			    "public team class Team247bis6 {\n" +
+			    "    protected class R playedBy T247bis6_1 {\n" +
+			    "        protected R() {\n" +
+			    "            base();\n" +
+			    "        }\n" +
+			    "    }\n" +
+			    "    R r = new R();\n" +
+			    "    public T247bis6_1 getR() {\n" +
+			    "        return this.r;\n" +
+			    "    }\n" +
+			    "}\n",
+		"p1/T247bis6_1.java",
+			    "\n" +
+			    "package p1;\n" +
+			    "public class T247bis6_1 {\n" +
+			    "    @Override public String toString() { return \"Base\"; }\n" +
+			    "}\n"
+            },
+            "Base");
+    }
 }