Bug 505927: New IndexBinaryType is not sufficient for compilation of OT
types
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java
index dfd3ea1..24e069f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryType.java
@@ -167,4 +167,15 @@
  */
 ExternalAnnotationStatus getExternalAnnotationStatus();
 
+//{ObjectTeams:
+/**
+ * Answers the "real" binary type for the given binary type.
+ * By default this is an identity transformation.
+ * Only IndexBinaryType will retrieve the bytes from disk to answer a fresh ClassFileReader.
+ * @throws Exception 
+ */
+default IBinaryType withClassBytes() throws Exception {
+	return this;
+}
+// SH}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 185ff02..616c237 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -44,8 +44,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
-import java.io.File;
-import java.io.IOException;
 import java.util.ArrayList;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
@@ -54,7 +52,6 @@
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.classfmt.FieldInfo;
 import org.eclipse.jdt.internal.compiler.classfmt.MethodInfo;
 import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider.IMethodAnnotationWalker;
@@ -68,8 +65,6 @@
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.Util;
-import org.eclipse.jdt.internal.core.nd.java.model.IndexBinaryMethod;
-import org.eclipse.jdt.internal.core.nd.java.model.IndexBinaryType;
 import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
 import org.eclipse.objectteams.otdt.internal.core.compiler.bytecode.AbstractAttribute;
 import org.eclipse.objectteams.otdt.internal.core.compiler.control.Config;
@@ -572,17 +567,14 @@
 		    this._teamModel = new TeamModel(this);
 		// Note, 'model' is already set in ctor of superclass ReferenceBinding.
 
-		if (binaryType instanceof IndexBinaryType) {
-			// for roles and teams we need the bytes, retrieve them now:
-			if ((this.modifiers & (ExtraCompilerModifiers.AccRole|ClassFileConstants.AccTeam)) != 0) {
-	    		File file = new File(String.valueOf(binaryType.getFileName()));
-	    		try {
-					binaryType = ClassFileReader.read(file, true);
-				} catch (ClassFormatException | IOException e) {
-					if (this.environment.problemReporter != null) {
-						String errorMessage = "Cannot read class file for "+String.valueOf(binaryType.getName())+": "; //$NON-NLS-1$ //$NON-NLS-2$
-						this.environment.problemReporter.abortDueToInternalError(errorMessage+e.getMessage());
-					}
+		// for roles and teams we need the bytes, retrieve them now, if not already present:
+		if ((this.modifiers & (ExtraCompilerModifiers.AccRole|ClassFileConstants.AccTeam)) != 0) {
+    		try {
+    			binaryType = binaryType.withClassBytes();
+			} catch (Exception e) {
+				if (this.environment.problemReporter != null) {
+					String errorMessage = "Cannot read class file for "+String.valueOf(binaryType.getName())+": "; //$NON-NLS-1$ //$NON-NLS-2$
+					this.environment.problemReporter.abortDueToInternalError(errorMessage+e.getMessage());
 				}
 			}
 		}
@@ -1177,9 +1169,6 @@
 				this.environment.getTeamMethodGenerator().registerTeamMethod(method, result);
 			// Note, that maybeRegister() may reset the MethodInfo (nulling MethodInfo.reference):
 			((MethodInfo)method).maybeRegister(this, result, this.environment);
-		} else if (method instanceof IndexBinaryMethod) {
-			if (TypeAnalyzer.isOrgObjectteamsTeam(this))
-				this.environment.getTeamMethodGenerator().registerTeamMethodWithoutBytes(binaryType, method, result, this.environment);
 		}
 	}
   }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
index aaa7576..f011496 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
@@ -10,11 +10,19 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.nd.java.model;
 
+import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.zip.ZipFile;
 
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.classfmt.BinaryTypeFormatter;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.classfmt.ElementValuePairInfo;
 import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
 import org.eclipse.jdt.internal.compiler.env.ClassSignature;
@@ -26,10 +34,12 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
 import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IDependent;
 import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
 import org.eclipse.jdt.internal.core.nd.IReader;
 import org.eclipse.jdt.internal.core.nd.db.IString;
 import org.eclipse.jdt.internal.core.nd.java.JavaNames;
@@ -669,4 +679,23 @@
 	public ExternalAnnotationStatus getExternalAnnotationStatus() {
 		return ExternalAnnotationStatus.NOT_EEA_CONFIGURED;
 	}
+//{ObjectTeams: retrieve class file in workspace:
+	@Override
+	public IBinaryType withClassBytes() throws ClassFormatException, IOException, CoreException {
+		File file = new File(String.valueOf(this.fileName));
+		if (file.exists())
+			return ClassFileReader.read(file);
+		int pos = CharOperation.indexOf(IDependent.JAR_FILE_ENTRY_SEPARATOR, this.fileName);
+		if (pos != -1) {
+			String jarIdentifier = String.valueOf(CharOperation.subarray(this.fileName, 0, pos));
+			String fileInJarName = String.valueOf(CharOperation.subarray(this.fileName, pos+1, -1));
+			IJavaElement jJar = JavaCore.create(jarIdentifier);
+			if (jJar.exists()) {
+				ZipFile jarZip = ((JarPackageFragmentRoot) jJar).getJar();
+				return ClassFileReader.read(jarZip, fileInJarName);
+			}
+		}
+		return this; // could not improve
+	}
+// SH}
 }
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclFull1.8.jar b/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclFull1.8.jar
new file mode 100644
index 0000000..02238aa
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclFull1.8.jar
Binary files differ
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclMin1.8.jar b/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclMin1.8.jar
new file mode 100644
index 0000000..0e017da
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclMin1.8.jar
Binary files differ
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclMin1.8src.zip b/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclMin1.8src.zip
new file mode 100644
index 0000000..c85ea26
--- /dev/null
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/JCL/jclMin1.8src.zip
Binary files differ
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java b/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java
index 56159a1..1b1f346 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/model/org/eclipse/objectteams/otdt/tests/otmodel/OTReconcilerTests.java
@@ -30,6 +30,7 @@
 import org.eclipse.core.resources.IncrementalProjectBuilder;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaProject;
@@ -40,6 +41,7 @@
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.tests.model.ReconcilerTests;
+import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.Compiler;
 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
@@ -184,13 +186,48 @@
 	}
 	
 // ===== End COPY_AND_PASTE
+	// --- support OT libraries: ---
+	boolean addOTtoLibrary = false;
+	protected void addOTLibrary(IJavaProject javaProject, String jarName, String sourceZipName, String[] pathAndContents, String compliance) throws CoreException, IOException {
+		boolean prev = this.addOTtoLibrary;
+		try {
+			this.addOTtoLibrary = true;
+			addLibrary(javaProject, jarName, sourceZipName, pathAndContents, compliance);
+		} finally {
+			this.addOTtoLibrary = prev;
+		}
+	}
+	@Override
+	protected String[] getJCL15PlusLibraryIfNeeded(String compliance) throws JavaModelException, IOException {
+		if (compliance.charAt(compliance.length()-1) >= '8' && (AbstractCompilerTest.getPossibleComplianceLevels() & AbstractCompilerTest.F_1_8) != 0) {
+			// ensure that the JCL 18 lib is setup (i.e. that the jclMin18.jar is copied)
+			setUpJCLClasspathVariables("1.8");
+			if (addOTtoLibrary) {
+				IPath otreMinJarPath = OTREContainer.getOtreMinJarPath();
+				return new String[] {getExternalJCLPathString("1.8"), otreMinJarPath.toString() };
+			}
+			return new String[] {getExternalJCLPathString("1.8")};
+		}
+		if (compliance.charAt(compliance.length()-1) >= '5' && (AbstractCompilerTest.getPossibleComplianceLevels() & AbstractCompilerTest.F_1_5) != 0) {
+			// ensure that the JCL 15 lib is setup (i.e. that the jclMin15.jar is copied)
+			setUpJCLClasspathVariables("1.5");
+			if (addOTtoLibrary)
+				return new String[] {getExternalJCLPathString("1.5"), "OTRE" };
+			return new String[] {getExternalJCLPathString("1.5")};
+		}
+		return null;
+	}
+	// ---
 	
 	protected IJavaProject createOTJavaProject(String projectName, String[] sourceFolders, String[] libraries, String output) throws CoreException {
 		return createOTJavaProject(projectName, sourceFolders, libraries, "1.5", output);
 	}
 
 	protected IJavaProject createOTJavaProject(String projectName, String[] sourceFolders, String[] libraries, String compliance, String output) throws CoreException {
-		IJavaProject javaProject = createJavaProject(projectName, sourceFolders, libraries, output, compliance);
+		return createOTJavaProject(projectName, sourceFolders, libraries, compliance, output, false);
+	}
+	protected IJavaProject createOTJavaProject(String projectName, String[] sourceFolders, String[] libraries, String compliance, String output, boolean useFullJcl) throws CoreException {
+		IJavaProject javaProject = createJavaProject(projectName, sourceFolders, libraries, output, compliance, useFullJcl);
 		IProjectDescription description = javaProject.getProject().getDescription();
 		description.setNatureIds(OTDTPlugin.createProjectNatures(description));
 		javaProject.getProject().setDescription(description, null);
@@ -2043,4 +2080,52 @@
     		deleteProject("P");
     	}
     }
+
+    public void testTeamInJar1() throws CoreException, InterruptedException, IOException {
+    	try {
+			// Resources creation
+			IJavaProject p = createOTJavaProject("P", new String[] {"src"}, new String[] {"JCL18_FULL"}, "1.8", "bin", true/*fullJCL*/);
+			IProject project = p.getProject();
+			IProjectDescription prjDesc = project.getDescription();
+			prjDesc.setBuildSpec(OTDTPlugin.createProjectBuildCommands(prjDesc));
+			project.setDescription(prjDesc, null);
+
+			OTREContainer.initializeOTJProject(project);
+
+			addOTLibrary(p, "teams.jar", "teamsSrc.zip", new String[] {
+				"p/MyTeam.java",
+				"package p;\n" +
+				"public team class MyTeam {\n" +
+				"	protected class MyR {\n" +
+				"		void test() {}\n" +
+				"	}\n" +
+				"}\n"
+			}, "1.8");
+
+			this.createFolder("/P/src/p2");
+			String subTeamSourceString =	
+				"package p2;\n" +
+				"public team class SubTeam extends p.MyTeam {\n" +
+    			"	@Override\n" +
+    			"	protected class MyR {\n" +
+    			"		void test2() {\n" +
+    			"			test();\n" +
+    			"		}\n" +
+    			"	}\n" +
+				"}\n";
+			String teamFileName = "P/src/p2/SubTeam.java";
+			this.createFile(teamFileName, subTeamSourceString);
+
+			waitUntilIndexesReady();
+			this.workingCopies = new ICompilationUnit[1];
+
+			// Get first working copy and verify that there's no error
+			this.problemRequestor.initialize(subTeamSourceString.toCharArray());
+			this.workingCopies[0] = getCompilationUnit(teamFileName).getWorkingCopy(this.wcOwner, null);
+			assertNoProblem(subTeamSourceString.toCharArray(), this.workingCopies[0]);
+
+    	} finally {
+    		deleteProject("P");
+    	}
+    }
 }