/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * 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)); } }