### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java,v retrieving revision 1.5 diff -u -r1.5 TypeConverter.java --- model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java 8 Sep 2010 12:55:49 -0000 1.5 +++ model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java 20 Sep 2010 06:21:44 -0000 @@ -401,7 +401,7 @@ result.sourceEnd = end; return result; case '[' : - if (dim == 0) nameFragmentEnd = this.namePos-1; + if (dim == 0 && nameFragmentEnd < 0) nameFragmentEnd = this.namePos-1; dim++; break; case ']' : @@ -414,19 +414,28 @@ identCount ++; break; case '<' : - // convert 1.5 specific constructs only if compliance is 1.5 or above - if (!this.has1_5Compliance) - break typeLoop; - if (fragments == null) fragments = new ArrayList(2); + /* We need to convert and preserve 1.5 specific constructs only if compliance is 1.5 or above, + but in all cases, we must skip over them to see if there are any applicable type fragments + after the type parameters: i.e we just aren't done having seen a '<' in 1.4 mode. Because of + the way type signatures are encoded, TypeConverter.decodeType(String, int, int, int) is immune + to this problem. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=325633 + */ + if (this.has1_5Compliance) { + if (fragments == null) fragments = new ArrayList(2); + } nameFragmentEnd = this.namePos-1; - char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, this.namePos); - fragments.add(identifiers); + if (this.has1_5Compliance) { + char[][] identifiers = CharOperation.splitOn('.', typeName, nameFragmentStart, this.namePos); + fragments.add(identifiers); + } this.namePos++; // skip '<' TypeReference[] arguments = decodeTypeArguments(typeName, length, start, end); // positionned on '>' at end - fragments.add(arguments); - identCount = 0; - nameFragmentStart = -1; - nameFragmentEnd = -1; + if (this.has1_5Compliance) { + fragments.add(arguments); + identCount = 0; + nameFragmentStart = -1; + nameFragmentEnd = -1; + } // next increment will skip '>' break; } #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java,v retrieving revision 1.155 diff -u -r1.155 ReconcilerTests.java --- src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java 8 Sep 2010 12:55:45 -0000 1.155 +++ src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java 20 Sep 2010 06:21:49 -0000 @@ -4807,4 +4807,73 @@ deleteProject(project15); } } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=325633 +public void testGenericAPIUsageFromA14Project5() throws CoreException { + IJavaProject project14 = null; + IJavaProject project15 = null; + try { + project15 = createJavaProject("Reconciler15API", new String[] {"src"}, new String[] {"JCL15_LIB"}, "bin"); + createFolder("/Reconciler15API/src/p2"); + createFile( + "/Reconciler15API/src/p2/List.java", + "package p2;\n" + + "public class List {}\n" + + " public static List [] getArray() {\n" + + " return null;\n" + + " }\n" + + " public static List [] getBackArray(List[] p) {\n" + + " return p;\n" + + " }\n" + + "}" + ); + project15.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_5); + project15.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_5); + project15.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_5); + + project14 = createJavaProject("Reconciler1415", new String[] {"src"}, new String[] {"JCL_LIB"}, "bin"); + project14.setOption(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_4); + project14.setOption(JavaCore.COMPILER_COMPLIANCE, JavaCore.VERSION_1_4); + project14.setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_4); + + IClasspathEntry[] oldClasspath = project14.getRawClasspath(); + int oldLength = oldClasspath.length; + IClasspathEntry[] newClasspath = new IClasspathEntry[oldLength+1]; + System.arraycopy(oldClasspath, 0, newClasspath, 0, oldLength); + newClasspath[oldLength] = JavaCore.newProjectEntry(new Path("/Reconciler15API")); + project14.setRawClasspath(newClasspath, null); + + createFolder("/Reconciler1415/src/p1"); + String source = + "package p1;\n" + + "import p2.List;\n" + + "public class X {\n" + + " private List [] l = List.getArray();\n" + + " private List [] l2 = List.getBackArray(l);\n" + + "}"; + + createFile( + "/Reconciler1415/src/p1/X.java", + source + ); + + this.workingCopies = new ICompilationUnit[1]; + char[] sourceChars = source.toCharArray(); + this.problemRequestor.initialize(sourceChars); + this.workingCopies[0] = getCompilationUnit("/Reconciler1415/src/p1/X.java").getWorkingCopy(this.wcOwner, null); + assertProblems( + "Unexpected problems", + "----------\n" + + "1. WARNING in /Reconciler1415/src/p1/X.java (at line 5)\n" + + " private List [] l2 = List.getBackArray(l);\n" + + " ^^\n" + + "The field X.l2 is never read locally\n" + + "----------\n" + ); + } finally { + if (project14 != null) + deleteProject(project14); + if (project15 != null) + deleteProject(project15); + } +} }