Java, typeres: add basic method type inference
This commit is contained in:
@ -22,25 +22,25 @@ public class ASTExpression extends AbstractJavaTypeNode {
|
||||
}
|
||||
|
||||
public boolean isStandAlonePrimitive() {
|
||||
if(jjtGetNumChildren() != 1) {
|
||||
if (jjtGetNumChildren() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTPrimaryExpression primaryExpression = getFirstChildOfType(ASTPrimaryExpression.class);
|
||||
|
||||
if(primaryExpression == null || primaryExpression.jjtGetNumChildren() != 1) {
|
||||
if (primaryExpression == null || primaryExpression.jjtGetNumChildren() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTPrimaryPrefix primaryPrefix = primaryExpression.getFirstChildOfType(ASTPrimaryPrefix.class);
|
||||
|
||||
if(primaryPrefix == null || primaryPrefix.jjtGetNumChildren() != 1) {
|
||||
if (primaryPrefix == null || primaryPrefix.jjtGetNumChildren() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ASTLiteral literal = primaryPrefix.getFirstChildOfType(ASTLiteral.class);
|
||||
|
||||
if(literal == null || literal.jjtGetNumChildren() != 0) {
|
||||
if (literal == null || literal.jjtGetNumChildren() != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
|
||||
// First try: com.package.SomeClass.staticField.otherField
|
||||
// Second try: com.package.SomeClass.staticField
|
||||
// Third try: com.package.SomeClass <- found a class!
|
||||
for (String reducedImage = node.getImage(); ; ) {
|
||||
for (String reducedImage = node.getImage();;) {
|
||||
populateType(node, reducedImage);
|
||||
if (node.getType() != null) {
|
||||
break; // we found a class!
|
||||
@ -422,7 +422,13 @@ public class ClassTypeResolver extends JavaParserVisitorAdapter {
|
||||
Collections.<JavaTypeDefinition>emptyList(),
|
||||
methodArgsArity, accessingClass);
|
||||
|
||||
previousType = getBestMethodReturnType(node.getTypeDefinition(), methods, astArgumentList);
|
||||
TypeNode enclosingType = getEnclosingTypeDeclaration(node);
|
||||
if (enclosingType == null) {
|
||||
return data; // we can't proceed, probably uncompiled sources
|
||||
}
|
||||
|
||||
previousType = getBestMethodReturnType(enclosingType.getTypeDefinition(),
|
||||
methods, astArgumentList);
|
||||
} else { // field
|
||||
previousType = getTypeDefinitionOfVariableFromScope(node.getScope(), dotSplitImage[0],
|
||||
accessingClass);
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.typeresolution;
|
||||
|
||||
import static net.sourceforge.pmd.lang.java.typeresolution.typeinference.InferenceRuleType.LOOSE_INVOCATION;
|
||||
import static net.sourceforge.pmd.lang.java.typeresolution.typeinference.InferenceRuleType.SUBTYPE;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
@ -12,7 +15,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.xml.internal.bind.v2.runtime.reflect.opt.Const;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
@ -22,11 +24,10 @@ import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Bound;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Constraint;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.TypeInferenceResolver;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.TypeInferenceResolver.ResolutionFailedException;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Variable;
|
||||
|
||||
import static net.sourceforge.pmd.lang.java.typeresolution.typeinference.InferenceRuleType.LOOSE_INVOCATION;
|
||||
import static net.sourceforge.pmd.lang.java.typeresolution.typeinference.InferenceRuleType.SUBTYPE;
|
||||
|
||||
public final class MethodTypeResolution {
|
||||
private MethodTypeResolution() {}
|
||||
@ -134,7 +135,7 @@ public final class MethodTypeResolution {
|
||||
}
|
||||
}
|
||||
|
||||
methodType = parameterizeStrictInvocation(context, methodType.getMethod(), argList);
|
||||
methodType = parameterizeInvocation(context, methodType.getMethod(), argList);
|
||||
}
|
||||
|
||||
// check subtypeability of each argument to the corresponding parameter
|
||||
@ -162,17 +163,18 @@ public final class MethodTypeResolution {
|
||||
}
|
||||
|
||||
|
||||
public static MethodType parameterizeStrictInvocation(JavaTypeDefinition context, Method method,
|
||||
ASTArgumentList argList) {
|
||||
public static MethodType parameterizeInvocation(JavaTypeDefinition context, Method method,
|
||||
ASTArgumentList argList) {
|
||||
|
||||
// variables are set up by the call to produceInitialBounds
|
||||
List<Variable> variables = new ArrayList<>();
|
||||
List<Bound> initialBounds = new ArrayList<>();
|
||||
produceInitialBounds(method, context, variables, initialBounds);
|
||||
|
||||
List<Constraint> initialConstraints = produceInitialConstraints(method, argList, variables);
|
||||
List<JavaTypeDefinition> resolvedTypeParameters = TypeInferenceResolver
|
||||
.inferTypes(produceInitialConstraints(method, argList, variables), initialBounds, variables);
|
||||
|
||||
return null;
|
||||
return getTypeDefOfMethod(context, method, resolvedTypeParameters);
|
||||
}
|
||||
|
||||
public static List<Constraint> produceInitialConstraints(Method method, ASTArgumentList argList,
|
||||
@ -184,14 +186,16 @@ public final class MethodTypeResolution {
|
||||
|
||||
// TODO: add support for variable arity methods
|
||||
for (int i = 0; i < methodParameters.length; i++) {
|
||||
int typeParamIndex;
|
||||
if (methodParameters[i] instanceof TypeVariable
|
||||
&& (typeParamIndex = JavaTypeDefinition
|
||||
.getGenericTypeIndex(methodTypeParameters, ((TypeVariable) methodParameters[i]).getName())) != -1) {
|
||||
int typeParamIndex = -1;
|
||||
if (methodParameters[i] instanceof TypeVariable) {
|
||||
typeParamIndex = JavaTypeDefinition
|
||||
.getGenericTypeIndex(methodTypeParameters, ((TypeVariable) methodParameters[i]).getName());
|
||||
}
|
||||
|
||||
if (typeParamIndex != -1) {
|
||||
// TODO: we are cheating here, it should be a contraint of the form 'var -> expression' not 'var->type'
|
||||
result.add(new Constraint(variables.get(typeParamIndex),
|
||||
((TypeNode) argList.jjtGetChild(i)).getTypeDefinition(), LOOSE_INVOCATION));
|
||||
result.add(new Constraint(((TypeNode) argList.jjtGetChild(i)).getTypeDefinition(),
|
||||
variables.get(typeParamIndex), LOOSE_INVOCATION));
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,10 +226,13 @@ public final class MethodTypeResolution {
|
||||
// appears in the set; if this results in no proper upper bounds for αl (only dependencies), then the
|
||||
// bound α <: Object also appears in the set.
|
||||
|
||||
int boundVarIndex;
|
||||
if (bound instanceof TypeVariable
|
||||
&& (boundVarIndex = JavaTypeDefinition
|
||||
.getGenericTypeIndex(typeVariables, ((TypeVariable) bound).getName())) != -1) {
|
||||
int boundVarIndex = -1;
|
||||
if (bound instanceof TypeVariable) {
|
||||
boundVarIndex =
|
||||
JavaTypeDefinition.getGenericTypeIndex(typeVariables, ((TypeVariable) bound).getName());
|
||||
}
|
||||
|
||||
if (boundVarIndex != -1) {
|
||||
initialBounds.add(new Bound(variables.get(currVarIndex), variables.get(boundVarIndex), SUBTYPE));
|
||||
} else {
|
||||
currVarHasNoProperUpperBound = false;
|
||||
@ -436,13 +443,6 @@ public final class MethodTypeResolution {
|
||||
// search the class
|
||||
for (Method method : contextClass.getDeclaredMethods()) {
|
||||
if (isMethodApplicable(method, methodName, argArity, accessingClass, typeArguments)) {
|
||||
if (isGeneric(method) && typeArguments.size() == 0) {
|
||||
// TODO: do generic implicit methods
|
||||
// this disables invocations which could match generic methods and have no explicit type args
|
||||
result.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
result.add(getTypeDefOfMethod(context, method, typeArguments));
|
||||
}
|
||||
}
|
||||
@ -496,7 +496,7 @@ public final class MethodTypeResolution {
|
||||
// if the method isn't vararg, then arity matches
|
||||
&& (method.isVarArgs() || (argArity == getArity(method)))
|
||||
// isn't generic or arity of type arguments matches that of parameters
|
||||
&& (!isGeneric(method) || typeArguments == null
|
||||
&& (!isGeneric(method) || typeArguments.isEmpty()
|
||||
|| method.getTypeParameters().length == typeArguments.size())) {
|
||||
|
||||
return true;
|
||||
|
@ -23,6 +23,7 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin
|
||||
|
||||
public final class TypeInferenceResolver {
|
||||
|
||||
|
||||
public static class ResolutionFailedException extends RuntimeException {
|
||||
|
||||
}
|
||||
@ -31,6 +32,38 @@ public final class TypeInferenceResolver {
|
||||
|
||||
}
|
||||
|
||||
public static List<JavaTypeDefinition> inferTypes(List<Constraint> constraints, List<Bound> bounds,
|
||||
List<Variable> variables) {
|
||||
|
||||
List<Bound> newBounds = new ArrayList<>();
|
||||
while (!constraints.isEmpty()) {
|
||||
List<BoundOrConstraint> reduceResult = constraints.get(constraints.size() - 1).reduce();
|
||||
constraints.remove(constraints.size() - 1);
|
||||
|
||||
for (BoundOrConstraint boundOrConstraint : reduceResult) {
|
||||
if (boundOrConstraint instanceof Bound) {
|
||||
newBounds.add((Bound) boundOrConstraint);
|
||||
} else if (boundOrConstraint instanceof Constraint) {
|
||||
constraints.add((Constraint) boundOrConstraint);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown BoundOrConstraint subclass");
|
||||
}
|
||||
}
|
||||
|
||||
constraints.addAll(incorporateBounds(bounds, newBounds));
|
||||
newBounds.clear();
|
||||
}
|
||||
|
||||
Map<Variable, JavaTypeDefinition> resolutionResult = resolveVariables(bounds);
|
||||
List<JavaTypeDefinition> result = new ArrayList<>();
|
||||
|
||||
for (Variable variable : variables) {
|
||||
result.add(resolutionResult.get(variable));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static JavaTypeDefinition lub(List<JavaTypeDefinition> types) {
|
||||
for (JavaTypeDefinition type : types) {
|
||||
if (type.isArrayType()) {
|
||||
@ -510,6 +543,8 @@ public final class TypeInferenceResolver {
|
||||
}
|
||||
}
|
||||
|
||||
currentBounds.addAll(newBounds);
|
||||
|
||||
return newConstraints;
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
|
||||
import net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.MethodTypeResolution;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Bound;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Constraint;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Variable;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.GenericMethods;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther2;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jaxen.JaxenException;
|
||||
|
||||
@ -43,6 +35,7 @@ import net.sourceforge.pmd.lang.LanguageVersionHandler;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
@ -62,11 +55,17 @@ import net.sourceforge.pmd.lang.java.ast.ASTType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.AbstractJavaTypeNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.ClassTypeResolver;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.MethodType;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.MethodTypeResolution;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Bound;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Constraint;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Variable;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.AnonymousClassFromInterface;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.AnonymousInnerClass;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.AnoymousExtendingObject;
|
||||
@ -85,6 +84,7 @@ import net.sourceforge.pmd.typeresolution.testdata.FieldAccessPrimaryGenericSimp
|
||||
import net.sourceforge.pmd.typeresolution.testdata.FieldAccessShadow;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.FieldAccessStatic;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.FieldAccessSuper;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.GenericMethodsImplicit;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.InnerClass;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.Literals;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.MethodAccessibility;
|
||||
@ -106,6 +106,8 @@ import net.sourceforge.pmd.typeresolution.testdata.dummytypes.JavaTypeDefinition
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.StaticMembers;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA2;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther2;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassB;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassB2;
|
||||
|
||||
@ -1489,6 +1491,26 @@ public class ClassTypeResolverTest {
|
||||
assertEquals("All expressions not tested", index, expressions.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMethodTypeInference() throws JaxenException {
|
||||
ASTCompilationUnit acu = parseAndTypeResolveForClass15(GenericMethodsImplicit.class);
|
||||
|
||||
List<AbstractJavaTypeNode> expressions = convertList(
|
||||
acu.findChildNodesWithXPath("//VariableInitializer/Expression/PrimaryExpression"),
|
||||
AbstractJavaTypeNode.class);
|
||||
|
||||
int index = 0;
|
||||
|
||||
// SuperClassA2 a = bar((SuperClassA) null, (SuperClassAOther) null, null, (SuperClassAOther2) null);
|
||||
assertEquals(SuperClassA2.class, expressions.get(index).getType());
|
||||
assertEquals(SuperClassA2.class, getChildType(expressions.get(index), 0));
|
||||
assertEquals(SuperClassA2.class, getChildType(expressions.get(index++), 1));
|
||||
|
||||
// Make sure we got them all
|
||||
assertEquals("All expressions not tested", index, expressions.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJavaTypeDefinitionEquals() {
|
||||
JavaTypeDefinition a = JavaTypeDefinition.forClass(Integer.class);
|
||||
@ -1545,11 +1567,11 @@ public class ClassTypeResolverTest {
|
||||
|
||||
@Test
|
||||
public void testMethodInitialBounds() throws NoSuchMethodException {
|
||||
JavaTypeDefinition context = JavaTypeDefinition.forClass(GenericMethods.class,
|
||||
JavaTypeDefinition context = JavaTypeDefinition.forClass(GenericMethodsImplicit.class,
|
||||
JavaTypeDefinition.forClass(Thread.class));
|
||||
List<Variable> variables = new ArrayList<>();
|
||||
List<Bound> initialBounds = new ArrayList<>();
|
||||
Method method = GenericMethods.class.getMethod("foo");
|
||||
Method method = GenericMethodsImplicit.class.getMethod("foo");
|
||||
MethodTypeResolution.produceInitialBounds(method, context, variables, initialBounds);
|
||||
|
||||
assertEquals(initialBounds.size(), 6);
|
||||
@ -1572,38 +1594,61 @@ public class ClassTypeResolverTest {
|
||||
|
||||
@Test
|
||||
public void testMethodInitialConstraints() throws NoSuchMethodException, JaxenException {
|
||||
ASTCompilationUnit acu = parseAndTypeResolveForClass15(GenericMethods.class);
|
||||
ASTCompilationUnit acu = parseAndTypeResolveForClass15(GenericMethodsImplicit.class);
|
||||
|
||||
List<AbstractJavaNode> expressions = convertList(
|
||||
acu.findChildNodesWithXPath("//ArgumentList"),
|
||||
AbstractJavaNode.class);
|
||||
|
||||
assertEquals(expressions.size(), 1);
|
||||
|
||||
List<Variable> variables = new ArrayList<>();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
variables.add(new Variable());
|
||||
}
|
||||
Method method = GenericMethods.class.getMethod("bar", Object.class, Object.class,
|
||||
Integer.class, Object.class);
|
||||
Method method = GenericMethodsImplicit.class.getMethod("bar", Object.class, Object.class,
|
||||
Integer.class, Object.class);
|
||||
ASTArgumentList argList = (ASTArgumentList) expressions.get(0);
|
||||
|
||||
List<Constraint> constraints = MethodTypeResolution.produceInitialConstraints(method, argList, variables);
|
||||
|
||||
assertEquals(constraints.size(), 3);
|
||||
// A
|
||||
assertTrue(constraints.contains(new Constraint(variables.get(0),
|
||||
JavaTypeDefinition.forClass(SuperClassA.class),
|
||||
LOOSE_INVOCATION)));
|
||||
assertTrue(constraints.contains(new Constraint(variables.get(0),
|
||||
JavaTypeDefinition.forClass(SuperClassAOther.class),
|
||||
assertTrue(constraints.contains(new Constraint(JavaTypeDefinition.forClass(SuperClassA.class),
|
||||
variables.get(0), LOOSE_INVOCATION)));
|
||||
assertTrue(constraints.contains(new Constraint(JavaTypeDefinition.forClass(SuperClassAOther.class),
|
||||
variables.get(0),
|
||||
LOOSE_INVOCATION)));
|
||||
// B
|
||||
assertTrue(constraints.contains(new Constraint(variables.get(1),
|
||||
JavaTypeDefinition.forClass(SuperClassAOther2.class),
|
||||
assertTrue(constraints.contains(new Constraint(JavaTypeDefinition.forClass(SuperClassAOther2.class),
|
||||
variables.get(1),
|
||||
LOOSE_INVOCATION)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodParameterization() throws JaxenException, NoSuchMethodException {
|
||||
ASTCompilationUnit acu = parseAndTypeResolveForClass15(GenericMethodsImplicit.class);
|
||||
|
||||
List<AbstractJavaNode> expressions = convertList(
|
||||
acu.findChildNodesWithXPath("//ArgumentList"),
|
||||
AbstractJavaNode.class);
|
||||
|
||||
JavaTypeDefinition context = JavaTypeDefinition.forClass(GenericMethodsImplicit.class,
|
||||
JavaTypeDefinition.forClass(Thread.class));
|
||||
Method method = GenericMethodsImplicit.class.getMethod("bar", Object.class, Object.class,
|
||||
Integer.class, Object.class);
|
||||
ASTArgumentList argList = (ASTArgumentList) expressions.get(0);
|
||||
|
||||
MethodType inferedMethod = MethodTypeResolution.parameterizeInvocation(context, method, argList);
|
||||
|
||||
assertEquals(inferedMethod.getParameterTypes().get(0),
|
||||
JavaTypeDefinition.forClass(SuperClassA2.class));
|
||||
assertEquals(inferedMethod.getParameterTypes().get(1),
|
||||
JavaTypeDefinition.forClass(SuperClassA2.class));
|
||||
assertEquals(inferedMethod.getParameterTypes().get(2),
|
||||
JavaTypeDefinition.forClass(Integer.class));
|
||||
assertEquals(inferedMethod.getParameterTypes().get(3),
|
||||
JavaTypeDefinition.forClass(SuperClassAOther2.class));
|
||||
}
|
||||
|
||||
|
||||
private Class<?> getChildType(Node node, int childIndex) {
|
||||
return ((TypeNode) node.jjtGetChild(childIndex)).getType();
|
||||
|
@ -1,14 +0,0 @@
|
||||
package net.sourceforge.pmd.typeresolution.testdata;
|
||||
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther2;
|
||||
|
||||
public class GenericMethods<T> {
|
||||
public <A, B extends Number & Runnable, C extends D, D extends T> void foo() {
|
||||
}
|
||||
|
||||
public <A, B> void bar(A a, A b, Integer c, B d) {
|
||||
bar((SuperClassA) null, (SuperClassAOther) null, null, (SuperClassAOther2) null);
|
||||
}
|
||||
}
|
23
pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/GenericMethodsImplicit.java
vendored
Normal file
23
pmd-java/src/test/java/net/sourceforge/pmd/typeresolution/testdata/GenericMethodsImplicit.java
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.typeresolution.testdata;
|
||||
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassA2;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther;
|
||||
import net.sourceforge.pmd.typeresolution.testdata.dummytypes.SuperClassAOther2;
|
||||
|
||||
public class GenericMethodsImplicit<T> {
|
||||
public <A, B extends Number & Runnable, C extends D, D extends T> void foo() {
|
||||
}
|
||||
|
||||
public <A, B> A bar(A a, A b, Integer c, B d) {
|
||||
return null;
|
||||
}
|
||||
|
||||
void test() {
|
||||
SuperClassA2 a = bar((SuperClassA) null, (SuperClassAOther) null, (Integer) null, (SuperClassAOther2) null);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user