/** * Copyright (c) 2014 Codetrails GmbH. * 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: * Andreas Sewe - Initial API and implementation */ package org.eclipse.recommenders.rcp.utils; import static org.eclipse.recommenders.testing.CodeBuilder.*; import static org.eclipse.recommenders.utils.names.VmMethodName.get; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; import java.util.Collection; import java.util.LinkedList; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.recommenders.utils.names.IMethodName; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import com.google.common.collect.Lists; @RunWith(Parameterized.class) @SuppressWarnings("restriction") public class CompilerBindingsToMethodNameTest { private final CharSequence code; private final IMethodName expected; public CompilerBindingsToMethodNameTest(String description, CharSequence code, IMethodName expected) { this.code = code; this.expected = expected; } @Parameters(name = "{index}: {0}") public static Collection<Object[]> scenarios() { LinkedList<Object[]> scenarios = Lists.newLinkedList(); // Real-world scenarios scenarios.add(scenario("Method without arguments, void return type", method("$wait();"), get("Ljava/lang/Object.wait()V"))); scenarios.add(scenario("Primitive argument, void return type", method("$wait(0L);"), get("Ljava/lang/Object.wait(J)V"))); scenarios.add(scenario("Method with reference argument, void return type", method("System.out.$println(\"\");"), get("Ljava/io/PrintStream.println(Ljava/lang/String;)V"))); scenarios.add(scenario("Method without arguments, primitive return type", method("$hashCode();"), get("Ljava/lang/Object.hashCode()I"))); scenarios.add(scenario("Method withoutarguments, reference return type", method("$toString();"), get("Ljava/lang/Object.toString()Ljava/lang/String;"))); scenarios.add(scenario("Constructor without arguments", method("$new String();"), get("Ljava/lang/String.<init>()V"))); // Synthetic scenarios scenarios.add(scenario("Method argument is array of primitives", classbody("Example", "void method(int[] is) { $method(null); }"), get("LExample.method([I)V"))); scenarios.add(scenario("Method argument is array of objects", classbody("Example", "void method(Object[] os) { $method(null); }"), get("LExample.method([Ljava/lang/Object;)V"))); scenarios.add(scenario("Method argument is array of arrays of objects", classbody("Example", "void method(Object[][] os) { $method(null); }"), get("LExample.method([[Ljava/lang/Object;)V"))); scenarios.add(scenario("Method argument is parameterized type (invariant)", classbody("Example", "void method(Collection<Number> c) { $method(null); }"), get("LExample.method(Ljava/util/Collection;)V"))); scenarios.add(scenario("Method argument is parameterized type (wildcard)", classbody("Example", "void method(Collection<?> c) { $method(null); }"), get("LExample.method(Ljava/util/Collection;)V"))); scenarios.add(scenario("Method argument is parameterized type (upper-bounded wildcard)", classbody("Example", "void method(Collection<? extends Number> c) { $method(null); }"), get("LExample.method(Ljava/util/Collection;)V"))); scenarios.add(scenario("Method argument is parameterized type (lower-bounded wildcard)", classbody("Example", "void method(Collection<? super Number> c) { $method(null); }"), get("LExample.method(Ljava/util/Collection;)V"))); scenarios.add(scenario("Method argument is type parameter of declaring class", classbody("Example<T>", "void method(T t) { $method(null); }"), get("LExample.method(Ljava/lang/Object;)V"))); scenarios.add(scenario("Method argument is upper-bounded type parameter of declaring class", classbody("Example<N extends Number>", "void method(N n) { $method(null); }"), get("LExample.method(Ljava/lang/Number;)V"))); scenarios.add(scenario( "Method argument is upper-bounded type parameter of declaring class (superfluous bound of Object)", classbody("Example<O extends Object>", "void method(O o) { $method(null); }"), get("LExample.method(Ljava/lang/Object;)V"))); scenarios.add(scenario("Method argument is upper-bounded type parameter of declaring class (multiple bounds)", classbody("Example<N extends Number & Comparable>", "void method(N n) { $method(null); }"), get("LExample.method(Ljava/lang/Number;)V"))); scenarios.add(scenario( "Method argument is upper-bounded type parameter of declaring class (bound is parameterized itself)", classbody("Example<L extends List<String>>", "void method(L l) { $method(null); }"), get("LExample.method(Ljava/util/List;)V"))); scenarios.add(scenario("Method argument is type parameter of method", classbody("Example", "<T> void method(T t) { $method(null); }"), get("LExample.method(Ljava/lang/Object;)V"))); scenarios.add(scenario("Method argument is upper-bounded type parameter of method", classbody("Example", "<N extends Number> void method(N n) { $method(null); }"), get("LExample.method(Ljava/lang/Number;)V"))); scenarios.add(scenario( "Method argument is upper-bounded type parameter of method (superfluous bound of Object)", classbody("Example", "<O extends Object> void method(O o) { $method(null); }"), get("LExample.method(Ljava/lang/Object;)V"))); scenarios.add(scenario("Method argument is upper-bounded type parameter of method (multiple bounds)", classbody("Example", "<N extends Number & Comparable> void method(N n) { $method(null); }"), get("LExample.method(Ljava/lang/Number;)V"))); scenarios.add(scenario( "Method argument is upper-bounded type parameter of method (bound is parameterized itself)", classbody("Example", "<L extends List<String>> void method(L l) { $method(null); }"), get("LExample.method(Ljava/util/List;)V"))); scenarios.add(scenario("Method argument is type parameter of implemented interface", classbody("Example implements Comparable<Number>", "int compareTo(Number n) { $compareTo(null); }"), get("LExample.compareTo(Ljava/lang/Number;)I"))); scenarios.add(scenario("Constructor argument is type parameter of declaring class (raw)", classbody("Example<T>", "Example(T t) { $new Example(null); }"), get("LExample.<init>(Ljava/lang/Object;)V"))); scenarios.add(scenario("Constructor argument is type parameter of declaring class", classbody("Example<T>", "Example(T t) { $new Example<Number>(null); }"), get("LExample.<init>(Ljava/lang/Object;)V"))); scenarios.add(scenario("Constructor argument is upper-bounded type parameter of declaring class", classbody("Example<N extends Number>", "Example(N n) { $new Example<Integer>(null); }"), get("LExample.<init>(Ljava/lang/Number;)V"))); scenarios.add(scenario("Constructor argument is parameterized by type parameter of declaring class", classbody("Example<T>", "Example(Collection<T> ts) { $new Example<Integer>(null); }"), get("LExample.<init>(Ljava/util/Collection;)V"))); return scenarios; } private static Object[] scenario(String description, CharSequence code, IMethodName expected) { return new Object[] { description, code, expected }; } @Test public void test() throws Exception { MethodBinding binding = getBinding(code); IMethodName actual = CompilerBindings.toMethodName(binding).get(); assertThat(actual, is(equalTo(expected))); } private static MethodBinding getBinding(CharSequence code) throws Exception { return getBinding(CompilerBindingsTestUtils.getCompilerAstNode(code)); } private static MethodBinding getBinding(ASTNode node) { if (node instanceof MessageSend) { return ((MessageSend) node).binding; } else if (node instanceof AllocationExpression) { return ((AllocationExpression) node).binding; } else { throw new IllegalArgumentException(node.toString()); } } }