| /******************************************************************************* |
| * Copyright (c) 2000, 2015 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.builder; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| |
| import junit.framework.*; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IRegion; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.ToolFactory; |
| import org.eclipse.jdt.core.compiler.CategorizedProblem; |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.core.tests.util.Util; |
| import org.eclipse.jdt.core.util.IClassFileReader; |
| import org.eclipse.jdt.core.util.IMethodInfo; |
| |
| @SuppressWarnings({"rawtypes", "unchecked"}) |
| public class AbstractMethodTests extends BuilderTests { |
| private static final Comparator COMPARATOR = new Comparator() { |
| public int compare(Object o1, Object o2) { |
| IResource resource1 = (IResource) o1; |
| IResource resource2 = (IResource) o2; |
| String path1 = resource1.getFullPath().toString(); |
| String path2 = resource2.getFullPath().toString(); |
| int length1 = path1.length(); |
| int length2 = path2.length(); |
| |
| if (length1 != length2) { |
| return length1 - length2; |
| } |
| return path1.toString().compareTo(path2.toString()); |
| } |
| }; |
| |
| public AbstractMethodTests(String name) { |
| super(name); |
| } |
| |
| public static Test suite() { |
| return buildTestSuite(AbstractMethodTests.class); |
| } |
| |
| /** |
| * Check behavior in 1.2 target mode (NO generated default abstract method) |
| */ |
| public void test001() throws JavaModelException { |
| //---------------------------- |
| // Step 1 |
| //---------------------------- |
| //---------------------------- |
| // Project1 |
| //---------------------------- |
| IPath project1Path = env.addProject("Project1"); //$NON-NLS-1$ |
| env.addExternalJars(project1Path, Util.getJavaClassLibs()); |
| |
| // remove old package fragment root so that names don't collide |
| env.removePackageFragmentRoot(project1Path, ""); //$NON-NLS-1$ |
| |
| env.setOutputFolder(project1Path, "bin"); //$NON-NLS-1$ |
| IPath root1 = env.addPackageFragmentRoot(project1Path, "src"); //$NON-NLS-1$ |
| |
| env.addClass(root1, "p1", "IX", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p1;\n" + //$NON-NLS-1$ |
| "public interface IX {\n" + //$NON-NLS-1$ |
| " public abstract void foo(IX x);\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| IPath classX = env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| " public void foo(IX x){}\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| //---------------------------- |
| // Project2 |
| //---------------------------- |
| IPath project2Path = env.addProject("Project2"); //$NON-NLS-1$ |
| env.addExternalJars(project2Path, Util.getJavaClassLibs()); |
| env.addRequiredProject(project2Path, project1Path); |
| |
| // remove old package fragment root so that names don't collide |
| env.removePackageFragmentRoot(project2Path, ""); //$NON-NLS-1$ |
| |
| IPath root2 = env.addPackageFragmentRoot(project2Path, "src"); //$NON-NLS-1$ |
| env.setOutputFolder(project2Path, "bin"); //$NON-NLS-1$ |
| |
| IPath classY =env.addClass(root2, "p3", "Y", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p3;\n" + //$NON-NLS-1$ |
| "import p2.*;\n" + //$NON-NLS-1$ |
| "public class Y extends X{\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| fullBuild(); |
| expectingNoProblems(); |
| |
| //---------------------------- |
| // Step 2 |
| //---------------------------- |
| env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| " public void foo(I__X x){}\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| incrementalBuild(); |
| expectingOnlySpecificProblemFor(classX, new Problem("X.foo(I__X)", "I__X cannot be resolved to a type", classX, 84, 88, CategorizedProblem.CAT_TYPE, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ |
| expectingOnlySpecificProblemFor(classY, new Problem("Y", "The type Y must implement the inherited abstract method IX.foo(IX)", classY, 38, 39, CategorizedProblem.CAT_MEMBER, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| //---------------------------- |
| // Step 3 |
| //---------------------------- |
| env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| " public void foo(IX x){}\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| incrementalBuild(); |
| expectingNoProblems(); |
| } |
| |
| /** |
| * Check behavior in 1.1 target mode (generated default abstract method) |
| */ |
| public void test002() throws JavaModelException { |
| //---------------------------- |
| // Step 1 |
| //---------------------------- |
| //---------------------------- |
| // Project1 |
| //---------------------------- |
| IPath project1Path = env.addProject("Project1"); //$NON-NLS-1$ |
| env.addExternalJars(project1Path, Util.getJavaClassLibs()); |
| env.getJavaProject(project1Path).setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_1); // need default abstract method |
| // remove old package fragment root so that names don't collide |
| env.removePackageFragmentRoot(project1Path, ""); //$NON-NLS-1$ |
| |
| env.setOutputFolder(project1Path, "bin"); //$NON-NLS-1$ |
| IPath root1 = env.addPackageFragmentRoot(project1Path, "src"); //$NON-NLS-1$ |
| |
| env.addClass(root1, "p1", "IX", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p1;\n" + //$NON-NLS-1$ |
| "public interface IX {\n" + //$NON-NLS-1$ |
| " public abstract void foo(IX x);\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| IPath classX = env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| " public void foo(IX x){}\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| //---------------------------- |
| // Project2 |
| //---------------------------- |
| IPath project2Path = env.addProject("Project2"); //$NON-NLS-1$ |
| env.addExternalJars(project2Path, Util.getJavaClassLibs()); |
| env.addRequiredProject(project2Path, project1Path); |
| |
| // remove old package fragment root so that names don't collide |
| env.removePackageFragmentRoot(project2Path, ""); //$NON-NLS-1$ |
| |
| IPath root2 = env.addPackageFragmentRoot(project2Path, "src"); //$NON-NLS-1$ |
| env.setOutputFolder(project2Path, "bin"); //$NON-NLS-1$ |
| |
| IPath classY =env.addClass(root2, "p3", "Y", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p3;\n" + //$NON-NLS-1$ |
| "import p2.*;\n" + //$NON-NLS-1$ |
| "public class Y extends X{\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| fullBuild(); |
| expectingNoProblems(); |
| |
| //---------------------------- |
| // Step 2 |
| //---------------------------- |
| env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| " public void foo(I__X x){}\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| incrementalBuild(); |
| expectingOnlySpecificProblemFor(classX, new Problem("X.foo(I__X)", "I__X cannot be resolved to a type", classX, 84, 88, CategorizedProblem.CAT_TYPE, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ |
| expectingOnlySpecificProblemFor(classY, new Problem("Y", "The type Y must implement the inherited abstract method IX.foo(IX)", classY, 38, 39, CategorizedProblem.CAT_MEMBER, IMarker.SEVERITY_ERROR)); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| //---------------------------- |
| // Step 3 |
| //---------------------------- |
| env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| " public void foo(IX x){}\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| incrementalBuild(); |
| expectingNoProblems(); |
| } |
| |
| /** |
| * Check behavior in 1.1 target mode (generated default abstract method) |
| */ |
| public void test003() throws JavaModelException { |
| //---------------------------- |
| // Step 1 |
| //---------------------------- |
| //---------------------------- |
| // Project1 |
| //---------------------------- |
| IPath project1Path = env.addProject("Project1"); //$NON-NLS-1$ |
| env.addExternalJars(project1Path, Util.getJavaClassLibs()); |
| env.getJavaProject(project1Path).setOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, JavaCore.VERSION_1_1); // need default abstract method |
| // remove old package fragment root so that names don't collide |
| env.removePackageFragmentRoot(project1Path, ""); //$NON-NLS-1$ |
| |
| env.setOutputFolder(project1Path, "bin"); //$NON-NLS-1$ |
| IPath root1 = env.addPackageFragmentRoot(project1Path, "src"); //$NON-NLS-1$ |
| |
| env.addClass(root1, "p1", "IX", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p1;\n" + //$NON-NLS-1$ |
| "public interface IX {\n" + //$NON-NLS-1$ |
| " public abstract void foo(IX x);\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| env.addClass(root1, "p2", "X", //$NON-NLS-1$ //$NON-NLS-2$ |
| "package p2;\n" + //$NON-NLS-1$ |
| "import p1.*;\n" + //$NON-NLS-1$ |
| "public abstract class X implements IX {\n" + //$NON-NLS-1$ |
| "}\n" //$NON-NLS-1$ |
| ); |
| |
| fullBuild(); |
| expectingNoProblems(); |
| |
| IJavaProject project = env.getJavaProject(project1Path); |
| IRegion region = JavaCore.newRegion(); |
| region.add(project); |
| IResource[] resources = JavaCore.getGeneratedResources(region, false); |
| assertEquals("Wrong size", 2, resources.length);//$NON-NLS-1$ |
| Arrays.sort(resources, COMPARATOR); |
| String actualOutput = getResourceOuput(resources); |
| String expectedOutput = "/Project1/bin/p2/X.class\n" + |
| "/Project1/bin/p1/IX.class\n"; |
| assertEquals("Wrong names", Util.convertToIndependantLineDelimiter(expectedOutput), actualOutput); |
| |
| assertEquals("Wrong type", IResource.FILE, resources[0].getType()); |
| IFile classFile = (IFile) resources[0]; |
| IClassFileReader classFileReader = null; |
| InputStream stream = null; |
| try { |
| stream = classFile.getContents(); |
| classFileReader = ToolFactory.createDefaultClassFileReader(stream, IClassFileReader.ALL); |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| } finally { |
| if (stream != null) { |
| try { |
| stream.close(); |
| } catch(IOException e) { |
| // ignore |
| } |
| } |
| } |
| assertNotNull("No class file reader", classFileReader); |
| IMethodInfo[] methodInfos = classFileReader.getMethodInfos(); |
| IMethodInfo found = null; |
| loop: for (int i = 0, max = methodInfos.length; i < max; i++) { |
| IMethodInfo methodInfo = methodInfos[i]; |
| if (CharOperation.equals(methodInfo.getName(), "foo".toCharArray())) { |
| found = methodInfo; |
| break loop; |
| } |
| } |
| assertNotNull("No method found", found); |
| assertTrue("Not a synthetic method", found.isSynthetic()); |
| } |
| |
| private String getResourceOuput(IResource[] resources) { |
| StringWriter stringWriter = new StringWriter(); |
| PrintWriter writer = new PrintWriter(stringWriter); |
| for (int i = 0, max = resources.length; i < max; i++) { |
| writer.println(resources[i].getFullPath().toString()); |
| } |
| writer.flush(); |
| writer.close(); |
| return Util.convertToIndependantLineDelimiter(String.valueOf(stringWriter)); |
| } |
| } |