Add generic types to methods declarations
This commit is contained in:
@@ -62,11 +62,15 @@ public class AnnotationGen {
|
||||
String aCls = a.getAnnotationClass();
|
||||
if (aCls.startsWith("dalvik.annotation.")) {
|
||||
// skip
|
||||
if (aCls.equals("dalvik.annotation.Signature"))
|
||||
code.startLine("// signature: "
|
||||
+ Utils.mergeSignature((List<String>) a.getValues().get("value")));
|
||||
else if (Consts.DEBUG)
|
||||
if (aCls.equals("dalvik.annotation.Signature")) {
|
||||
if (!(node instanceof MethodNode)) {
|
||||
String sign = Utils.mergeSignature((List<String>) a.getValues().get("value"));
|
||||
List<ArgType> types = ArgType.parseSignatureList(sign);
|
||||
code.startLine("// signature: " + Utils.listToString(types));
|
||||
}
|
||||
} else if (Consts.DEBUG) {
|
||||
code.startLine("// " + a);
|
||||
}
|
||||
} else {
|
||||
code.startLine();
|
||||
code.add(formatAnnotation(a));
|
||||
|
||||
@@ -248,7 +248,29 @@ public class ClassGen {
|
||||
}
|
||||
|
||||
public String useClass(ArgType clsType) {
|
||||
return useClass(ClassInfo.fromType(cls.dex(), clsType));
|
||||
String baseClass = useClass(ClassInfo.fromType(cls.dex(), clsType));
|
||||
|
||||
ArgType[] generics = clsType.getGenericTypes();
|
||||
if (generics != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(baseClass);
|
||||
sb.append("<");
|
||||
int len = generics.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (i != 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
ArgType gt = generics[i];
|
||||
if (gt.isTypeKnown())
|
||||
sb.append(useClass(gt));
|
||||
else
|
||||
sb.append('?');
|
||||
}
|
||||
sb.append(">");
|
||||
return sb.toString();
|
||||
} else {
|
||||
return baseClass;
|
||||
}
|
||||
}
|
||||
|
||||
public String useClass(ClassInfo classInfo) {
|
||||
|
||||
@@ -94,19 +94,7 @@ public class InsnGen {
|
||||
}
|
||||
|
||||
public String declareVar(RegisterArg arg) throws CodegenException {
|
||||
String type = useType(arg.getType());
|
||||
ArgType[] generics = arg.getType().getGenericTypes();
|
||||
if (generics != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(type);
|
||||
sb.append("/*<");
|
||||
for (ArgType gt : generics) {
|
||||
sb.append(useType(gt));
|
||||
}
|
||||
sb.append(">*/");
|
||||
type = sb.toString();
|
||||
}
|
||||
return type + " " + arg(arg);
|
||||
return useType(arg.getType()) + " " + arg(arg);
|
||||
}
|
||||
|
||||
private String lit(LiteralArg arg) {
|
||||
@@ -144,13 +132,6 @@ public class InsnGen {
|
||||
}
|
||||
|
||||
private String useType(ArgType type) {
|
||||
if (type.isObject())
|
||||
return mgen.getClassGen().useClass(type);
|
||||
else
|
||||
return translate(type);
|
||||
}
|
||||
|
||||
private String translate(ArgType type) {
|
||||
return TypeGen.translate(mgen.getClassGen(), type);
|
||||
}
|
||||
|
||||
@@ -160,7 +141,6 @@ public class InsnGen {
|
||||
|
||||
private void makeInsn(InsnNode insn, CodeWriter code, boolean bodyOnly) throws CodegenException {
|
||||
try {
|
||||
// code.startLine("/* " + insn + "*/");
|
||||
EnumSet<InsnGenState> state = EnumSet.noneOf(InsnGenState.class);
|
||||
if (bodyOnly) {
|
||||
state.add(InsnGenState.BODY_ONLY);
|
||||
@@ -213,7 +193,7 @@ public class InsnGen {
|
||||
case CHECK_CAST:
|
||||
case CAST:
|
||||
code.add("((");
|
||||
code.add(translate(((ArgType) ((IndexInsnNode) insn).getIndex())));
|
||||
code.add(useType(((ArgType) ((IndexInsnNode) insn).getIndex())));
|
||||
code.add(") (");
|
||||
code.add(arg(insn.getArg(0)));
|
||||
code.add("))");
|
||||
@@ -445,7 +425,7 @@ public class InsnGen {
|
||||
}
|
||||
int len = str.length();
|
||||
str.delete(len - 2, len);
|
||||
code.add("new ").add(translate(elType)).add("[] { ").add(str.toString()).add(" }");
|
||||
code.add("new ").add(useType(elType)).add("[] { ").add(str.toString()).add(" }");
|
||||
}
|
||||
|
||||
private void makeConstructor(ConstructorInsn insn, CodeWriter code, EnumSet<InsnGenState> state)
|
||||
|
||||
@@ -81,13 +81,12 @@ public class MethodGen {
|
||||
if (mth.getAccessFlags().isConstructor()) {
|
||||
code.add(classGen.getClassNode().getShortName()); // constructor
|
||||
} else {
|
||||
code.add(TypeGen.translate(classGen, mth.getMethodInfo().getReturnType()));
|
||||
code.add(" ");
|
||||
code.add(TypeGen.translate(classGen, mth.getReturnType()));
|
||||
code.add(' ');
|
||||
code.add(mth.getName());
|
||||
}
|
||||
code.add("(");
|
||||
code.add('(');
|
||||
|
||||
mth.resetArgsTypes();
|
||||
List<RegisterArg> args = mth.getArguments(false);
|
||||
if (mth.getMethodInfo().isConstructor()
|
||||
&& mth.getParentClass().getAttributes().contains(AttributeType.ENUM_CLASS)) {
|
||||
|
||||
@@ -28,7 +28,7 @@ public class LocalVarInfo extends RegisterArg {
|
||||
|
||||
private void init(String name, ArgType type, String sign) {
|
||||
if (sign != null) {
|
||||
type = ArgType.generic(type.getObject(), sign);
|
||||
type = ArgType.generic(sign);
|
||||
}
|
||||
TypedVar tv = new TypedVar(type);
|
||||
tv.setName(name);
|
||||
|
||||
@@ -401,7 +401,7 @@ public class InsnDecoder {
|
||||
case Opcodes.RETURN_OBJECT:
|
||||
return insn(InsnType.RETURN,
|
||||
null,
|
||||
InsnArg.reg(insn, 0, method.getMethodInfo().getReturnType()));
|
||||
InsnArg.reg(insn, 0, method.getReturnType()));
|
||||
|
||||
case Opcodes.INSTANCE_OF: {
|
||||
InsnNode node = new IndexInsnNode(method, InsnType.INSTANCE_OF, dex.getType(insn.getIndex()), 1);
|
||||
|
||||
@@ -24,6 +24,7 @@ public abstract class ArgType {
|
||||
public static final ArgType THROWABLE = object(Consts.CLASS_THROWABLE);
|
||||
|
||||
public static final ArgType UNKNOWN = unknown(PrimitiveType.values());
|
||||
public static final ArgType UNKNOWN_OBJECT = unknown(PrimitiveType.OBJECT, PrimitiveType.ARRAY);
|
||||
|
||||
public static final ArgType NARROW = unknown(
|
||||
PrimitiveType.INT, PrimitiveType.FLOAT,
|
||||
@@ -32,8 +33,6 @@ public abstract class ArgType {
|
||||
|
||||
public static final ArgType WIDE = unknown(PrimitiveType.LONG, PrimitiveType.DOUBLE);
|
||||
|
||||
public static final ArgType UNKNOWN_OBJECT = unknown(PrimitiveType.OBJECT, PrimitiveType.ARRAY);
|
||||
|
||||
protected int hash;
|
||||
|
||||
private static ArgType primitive(PrimitiveType stype) {
|
||||
@@ -41,11 +40,15 @@ public abstract class ArgType {
|
||||
}
|
||||
|
||||
public static ArgType object(String obj) {
|
||||
return new ObjectArg(Utils.cleanObjectName(obj));
|
||||
return new ObjectArg(obj);
|
||||
}
|
||||
|
||||
public static ArgType generic(String obj, String signature) {
|
||||
return new GenericObjectArg(obj, signature);
|
||||
public static ArgType generic(String sign) {
|
||||
return parseSignature(sign);
|
||||
}
|
||||
|
||||
public static ArgType generic(String obj, ArgType[] generics) {
|
||||
return new GenericObjectArg(obj, generics);
|
||||
}
|
||||
|
||||
public static ArgType array(ArgType vtype) {
|
||||
@@ -91,7 +94,7 @@ public abstract class ArgType {
|
||||
private final String object;
|
||||
|
||||
public ObjectArg(String obj) {
|
||||
this.object = obj;
|
||||
this.object = Utils.cleanObjectName(obj);
|
||||
this.hash = obj.hashCode();
|
||||
}
|
||||
|
||||
@@ -119,9 +122,9 @@ public abstract class ArgType {
|
||||
private static final class GenericObjectArg extends ObjectArg {
|
||||
private final ArgType[] generics;
|
||||
|
||||
public GenericObjectArg(String obj, String signature) {
|
||||
public GenericObjectArg(String obj, ArgType[] generics) {
|
||||
super(obj);
|
||||
this.generics = parseSignature(signature);
|
||||
this.generics = generics;
|
||||
this.hash = obj.hashCode() + 31 * Arrays.hashCode(generics);
|
||||
}
|
||||
|
||||
@@ -132,7 +135,7 @@ public abstract class ArgType {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "<" + Arrays.toString(generics) + ">";
|
||||
return super.toString() + "<" + Utils.arrayToString(generics) + ">";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +180,7 @@ public abstract class ArgType {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return arrayElement.toString();
|
||||
return arrayElement.toString() + "[]";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +223,7 @@ public abstract class ArgType {
|
||||
@Override
|
||||
public String toString() {
|
||||
if (possibleTypes.length == PrimitiveType.values().length)
|
||||
return "*";
|
||||
return "?";
|
||||
else
|
||||
return "?" + Arrays.toString(possibleTypes);
|
||||
}
|
||||
@@ -363,30 +366,83 @@ public abstract class ArgType {
|
||||
}
|
||||
}
|
||||
|
||||
public static ArgType[] parseSignature(String signature) {
|
||||
int b = signature.indexOf('<') + 1;
|
||||
int e = signature.lastIndexOf('>');
|
||||
String gens = signature.substring(b, e);
|
||||
String[] split = gens.split(";");
|
||||
ArgType[] result = new ArgType[split.length];
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
String g = split[i];
|
||||
switch (g.charAt(0)) {
|
||||
public static ArgType parseSignature(String sign) {
|
||||
int b = sign.indexOf('<');
|
||||
if (b == -1)
|
||||
return parse(sign);
|
||||
|
||||
String obj = sign.substring(0, b);
|
||||
String genericsStr = sign.substring(b + 1, sign.length() - 2);
|
||||
List<ArgType> generics = parseSignatureList(genericsStr);
|
||||
ArgType res = generic(obj + ";", generics.toArray(new ArgType[generics.size()]));
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<ArgType> parseSignatureList(String str) {
|
||||
List<ArgType> signs = new ArrayList<ArgType>(3);
|
||||
if (str.equals("*")) {
|
||||
signs.add(UNKNOWN);
|
||||
return signs;
|
||||
}
|
||||
|
||||
int obj = 0;
|
||||
int objStart = 0;
|
||||
int gen = 0;
|
||||
int arr = 0;
|
||||
|
||||
int pos = 0;
|
||||
ArgType type = null;
|
||||
while (pos < str.length()) {
|
||||
char c = str.charAt(pos);
|
||||
switch (c) {
|
||||
case 'L':
|
||||
result[i] = object(g + ";");
|
||||
if (obj == 0 && gen == 0) {
|
||||
obj++;
|
||||
objStart = pos;
|
||||
}
|
||||
break;
|
||||
|
||||
case '*':
|
||||
case '?':
|
||||
result[i] = UNKNOWN;
|
||||
case ';':
|
||||
if (obj == 1 && gen == 0) {
|
||||
obj--;
|
||||
String o = str.substring(objStart, pos + 1);
|
||||
type = parseSignature(o);
|
||||
}
|
||||
break;
|
||||
|
||||
case '<':
|
||||
gen++;
|
||||
break;
|
||||
case '>':
|
||||
gen--;
|
||||
break;
|
||||
|
||||
case '[':
|
||||
arr++;
|
||||
break;
|
||||
|
||||
default:
|
||||
result[i] = UNKNOWN_OBJECT;
|
||||
if (obj == 0 && gen == 0) {
|
||||
type = parse(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
if (arr == 0) {
|
||||
signs.add(type);
|
||||
} else {
|
||||
for (int i = 0; i < arr; i++) {
|
||||
type = array(type);
|
||||
}
|
||||
signs.add(type);
|
||||
arr = 0;
|
||||
}
|
||||
type = null;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return result;
|
||||
return signs;
|
||||
}
|
||||
|
||||
private static ArgType parse(char f) {
|
||||
@@ -410,7 +466,7 @@ public abstract class ArgType {
|
||||
case 'V':
|
||||
return VOID;
|
||||
}
|
||||
throw new RuntimeException("Unknown type: " + f);
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getRegCount() {
|
||||
|
||||
@@ -2,7 +2,10 @@ package jadx.dex.nodes;
|
||||
|
||||
import jadx.dex.attributes.AttrNode;
|
||||
import jadx.dex.attributes.AttributeFlag;
|
||||
import jadx.dex.attributes.AttributeType;
|
||||
import jadx.dex.attributes.JumpAttribute;
|
||||
import jadx.dex.attributes.annotations.Annotation;
|
||||
import jadx.dex.attributes.annotations.AnnotationsList;
|
||||
import jadx.dex.info.AccessInfo;
|
||||
import jadx.dex.info.AccessInfo.AFType;
|
||||
import jadx.dex.info.ClassInfo;
|
||||
@@ -28,12 +31,16 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.android.dx.io.ClassData.Method;
|
||||
import com.android.dx.io.Code;
|
||||
import com.android.dx.io.Code.CatchHandler;
|
||||
import com.android.dx.io.Code.Try;
|
||||
|
||||
public class MethodNode extends AttrNode implements ILoadable {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MethodNode.class);
|
||||
|
||||
private final MethodInfo mthInfo;
|
||||
private final ClassNode parentClass;
|
||||
@@ -44,6 +51,7 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
private List<InsnNode> instructions;
|
||||
private boolean noCode;
|
||||
|
||||
private ArgType retType;
|
||||
private RegisterArg thisArg;
|
||||
private List<RegisterArg> argsList;
|
||||
|
||||
@@ -65,7 +73,8 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
if (methodData.getCodeOffset() == 0) {
|
||||
noCode = true;
|
||||
regsCount = 0;
|
||||
initArguments();
|
||||
retType = mthInfo.getReturnType();
|
||||
initArguments(mthInfo.getArgumentsTypes());
|
||||
} else {
|
||||
noCode = false;
|
||||
}
|
||||
@@ -81,6 +90,11 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
Code mthCode = dex.readCode(methodData);
|
||||
regsCount = mthCode.getRegistersSize();
|
||||
|
||||
if (!parseSignature()) {
|
||||
retType = mthInfo.getReturnType();
|
||||
initArguments(mthInfo.getArgumentsTypes());
|
||||
}
|
||||
|
||||
InsnDecoder decoder = new InsnDecoder(this, mthCode);
|
||||
InsnNode[] insnByOffset = decoder.run();
|
||||
instructions = new ArrayList<InsnNode>();
|
||||
@@ -90,7 +104,6 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
}
|
||||
((ArrayList<InsnNode>) instructions).trimToSize();
|
||||
|
||||
initArguments();
|
||||
initTryCatches(mthCode, insnByOffset);
|
||||
initJumps(insnByOffset);
|
||||
|
||||
@@ -116,8 +129,43 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
noCode = true;
|
||||
}
|
||||
|
||||
private void initArguments() {
|
||||
List<ArgType> args = mthInfo.getArgumentsTypes();
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean parseSignature() {
|
||||
AnnotationsList aList = (AnnotationsList) getAttributes().get(AttributeType.ANNOTATION_LIST);
|
||||
if (aList == null || aList.size() == 0)
|
||||
return false;
|
||||
|
||||
Annotation a = aList.get("dalvik.annotation.Signature");
|
||||
if (a == null)
|
||||
return false;
|
||||
|
||||
String sign = Utils.mergeSignature((List<String>) a.getValues().get("value"));
|
||||
int lastBracket = sign.indexOf(')');
|
||||
String argsTypesStr = sign.substring(1, lastBracket);
|
||||
String returnType = sign.substring(lastBracket + 1);
|
||||
|
||||
retType = ArgType.parseSignature(returnType);
|
||||
if (mthInfo.getArgumentsTypes().isEmpty()) {
|
||||
argsList = Collections.emptyList();
|
||||
return true;
|
||||
}
|
||||
|
||||
List<ArgType> argsTypes = ArgType.parseSignatureList(argsTypesStr);
|
||||
if (argsTypes.size() != mthInfo.getArgumentsTypes().size()) {
|
||||
if (!getParentClass().getAccessFlags().isEnum() && !mthInfo.isConstructor()) {
|
||||
// error parsing signature
|
||||
LOG.error("Wrong parse result: " + sign + " -> " + argsTypes
|
||||
+ " must be: " + mthInfo.getArgumentsTypes()
|
||||
// + " in method " + this
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
initArguments(argsTypes);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initArguments(List<ArgType> args) {
|
||||
int pos;
|
||||
if (!noCode) {
|
||||
pos = regsCount;
|
||||
@@ -134,6 +182,11 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
thisArg.getTypedVar().setName("this");
|
||||
}
|
||||
|
||||
if (args.isEmpty()) {
|
||||
argsList = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
|
||||
argsList = new ArrayList<RegisterArg>(args.size());
|
||||
for (ArgType arg : args) {
|
||||
argsList.add(InsnArg.reg(pos, arg));
|
||||
@@ -156,15 +209,8 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
return thisArg;
|
||||
}
|
||||
|
||||
// TODO: args types can change during type resolving => reset and copy back names
|
||||
@Deprecated
|
||||
public void resetArgsTypes() {
|
||||
List<InsnArg> modArgs = new ArrayList<InsnArg>(argsList);
|
||||
initArguments();
|
||||
|
||||
for (int i = 0; i < argsList.size(); i++) {
|
||||
argsList.get(i).getTypedVar().setName(modArgs.get(i).getTypedVar().getName());
|
||||
}
|
||||
public ArgType getReturnType() {
|
||||
return retType;
|
||||
}
|
||||
|
||||
// move to external class
|
||||
@@ -394,7 +440,7 @@ public class MethodNode extends AttrNode implements ILoadable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mthInfo.getReturnType()
|
||||
return retType
|
||||
+ " " + parentClass.getFullName() + "." + mthInfo.getName()
|
||||
+ "(" + Utils.listToString(mthInfo.getArgumentsTypes()) + ")";
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class ConstInlinerVisitor extends AbstractVisitor {
|
||||
|
||||
case RETURN:
|
||||
if (insn.getArgsCount() != 0) {
|
||||
insn.getArg(0).merge(mth.getMethodInfo().getReturnType());
|
||||
insn.getArg(0).merge(mth.getReturnType());
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ public class DotGraphVisitor extends AbstractVisitor {
|
||||
|
||||
dot.startLine("MethodNode[shape=record,label=\"{"
|
||||
+ escape(mth.getAccessFlags().makeString())
|
||||
+ escape(mth.getMethodInfo().getReturnType() + " "
|
||||
+ escape(mth.getReturnType() + " "
|
||||
+ mth.getParentClass().getFullName() + "." + mth.getName()
|
||||
+ "(" + Utils.listToString(mth.getArguments(true)) + ") ")
|
||||
+ (attrs.length() == 0 ? "" : " | " + attrs)
|
||||
|
||||
@@ -29,7 +29,7 @@ public class PostRegionVisitor extends AbstractVisitor {
|
||||
* Remove useless return at end
|
||||
*/
|
||||
private void removeReturn(MethodNode mth) {
|
||||
if (!mth.getMethodInfo().getReturnType().equals(ArgType.VOID))
|
||||
if (!mth.getReturnType().equals(ArgType.VOID))
|
||||
return;
|
||||
|
||||
if (!(mth.getRegion() instanceof Region))
|
||||
|
||||
@@ -28,8 +28,13 @@ public class Utils {
|
||||
}
|
||||
|
||||
public static String escape(String str) {
|
||||
return str.replace('.', '_').replace('/', '_').replace(';', '_')
|
||||
.replace('$', '_').replace("[]", "_A");
|
||||
return str.replace('.', '_')
|
||||
.replace('/', '_')
|
||||
.replace(';', '_')
|
||||
.replace('$', '_')
|
||||
.replace('<', '_')
|
||||
.replace('>', '_')
|
||||
.replace("[]", "_A");
|
||||
}
|
||||
|
||||
public static String listToString(Iterable<?> list) {
|
||||
@@ -46,6 +51,16 @@ public class Utils {
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static String arrayToString(Object[] array) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (i != 0)
|
||||
sb.append(", ");
|
||||
sb.append(array[i]);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String getStackTrace(Throwable throwable) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw, true);
|
||||
|
||||
@@ -68,6 +68,19 @@ public class TestCF3 extends AbstractTest {
|
||||
return l1.size() == 0;
|
||||
}
|
||||
|
||||
public boolean testNestedLoops2(List<String> list) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
while (i < list.size()) {
|
||||
String s = list.get(i);
|
||||
while (j < s.length()) {
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return j > 10;
|
||||
}
|
||||
|
||||
public static boolean testLabeledBreakContinue() {
|
||||
String searchMe = "Look for a substring in me";
|
||||
String substring = "sub";
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package jadx.samples;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TestGenerics extends AbstractTest {
|
||||
|
||||
private List<String> test1(Map<String, String> map) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
String str = map.get("key");
|
||||
list.add(str);
|
||||
return list;
|
||||
}
|
||||
|
||||
public void test2(Map<String, String> map, List<Object> list) {
|
||||
String str = map.get("key");
|
||||
list.add(str);
|
||||
}
|
||||
|
||||
public void test3(List<Object> list, int a, float[] b, String[] c, String[][][] d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testRun() throws Exception {
|
||||
assertTrue(test1(new HashMap<String, String>()) != null);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new TestGenerics().testRun();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user