ClassGen.java 11.9 KB
Newer Older
S
Skylot 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
package jadx.core.codegen;

import jadx.core.Consts;
import jadx.core.dex.attributes.AttrNode;
import jadx.core.dex.attributes.AttributeFlag;
import jadx.core.dex.attributes.AttributeType;
import jadx.core.dex.attributes.EnumClassAttr;
import jadx.core.dex.attributes.EnumClassAttr.EnumField;
import jadx.core.dex.attributes.IAttribute;
import jadx.core.dex.attributes.SourceFileAttr;
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.nodes.ClassNode;
S
Skylot 已提交
16
import jadx.core.dex.nodes.DexNode;
S
Skylot 已提交
17 18 19 20 21 22
import jadx.core.dex.nodes.FieldNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.nodes.parser.FieldValueAttr;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.CodegenException;
S
Skylot 已提交
23 24 25 26 27 28

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
29 30
import java.util.Map;
import java.util.Map.Entry;
S
Skylot 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
import java.util.Set;

import com.android.dx.rop.code.AccessFlags;

public class ClassGen {
	private final ClassNode cls;
	private final ClassGen parentGen;
	private final AnnotationGen annotationGen;
	private final boolean fallback;

	private final Set<ClassInfo> imports = new HashSet<ClassInfo>();

	public ClassGen(ClassNode cls, ClassGen parentClsGen, boolean fallback) {
		this.cls = cls;
		this.parentGen = parentClsGen;
		this.fallback = fallback;

		this.annotationGen = new AnnotationGen(cls, this);
	}

	public ClassNode getClassNode() {
		return cls;
	}

	public CodeWriter makeClass() throws CodegenException {
		CodeWriter clsBody = new CodeWriter();
		addClassCode(clsBody);

		CodeWriter clsCode = new CodeWriter();

		if (!"".equals(cls.getPackage())) {
62
			clsCode.add("package ").add(cls.getPackage()).add(';');
63
			clsCode.newLine();
S
Skylot 已提交
64 65
		}

S
Skylot 已提交
66 67 68 69
		int importsCount = imports.size();
		if (importsCount != 0) {
			List<String> sortImports = new ArrayList<String>(importsCount);
			for (ClassInfo ic : imports) {
S
Skylot 已提交
70
				sortImports.add(ic.getFullName());
S
Skylot 已提交
71
			}
S
Skylot 已提交
72 73 74
			Collections.sort(sortImports);

			for (String imp : sortImports) {
75
				clsCode.startLine("import ").add(imp).add(';');
S
Skylot 已提交
76
			}
77
			clsCode.newLine();
S
Skylot 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90

			sortImports.clear();
			imports.clear();
		}

		clsCode.add(clsBody);
		return clsCode;
	}

	public void addClassCode(CodeWriter code) throws CodegenException {
		if (cls.getAttributes().contains(AttributeFlag.DONT_GENERATE))
			return;

S
Skylot 已提交
91 92 93
		if (cls.getAttributes().contains(AttributeFlag.INCONSISTENT_CODE))
			code.startLine("// jadx: inconsistent code");

S
Skylot 已提交
94 95
		makeClassDeclaration(code);
		makeClassBody(code);
96
		code.newLine();
S
Skylot 已提交
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
	}

	public void makeClassDeclaration(CodeWriter clsCode) {
		AccessInfo af = cls.getAccessFlags();
		if (af.isInterface()) {
			af = af.remove(AccessFlags.ACC_ABSTRACT);
		} else if (af.isEnum()) {
			af = af.remove(AccessFlags.ACC_FINAL).remove(AccessFlags.ACC_ABSTRACT);
		}

		annotationGen.addForClass(clsCode);
		clsCode.startLine(af.makeString());
		if (af.isInterface()) {
			if (af.isAnnotation())
				clsCode.add('@');
			clsCode.add("interface ");
		} else if (af.isEnum()) {
			clsCode.add("enum ");
		} else {
			clsCode.add("class ");
		}
		clsCode.add(cls.getShortName());

120 121 122 123
		makeGenericMap(clsCode, cls.getGenericMap());
		clsCode.add(' ');

		ClassInfo sup = cls.getSuperClass();
S
Skylot 已提交
124 125 126
		if (sup != null
				&& !sup.getFullName().equals(Consts.CLASS_OBJECT)
				&& !sup.getFullName().equals(Consts.CLASS_ENUM)) {
127
			clsCode.add("extends ").add(useClass(sup)).add(' ');
S
Skylot 已提交
128 129 130 131
		}

		if (cls.getInterfaces().size() > 0 && !af.isAnnotation()) {
			if (cls.getAccessFlags().isInterface())
132
				clsCode.add("extends ");
S
Skylot 已提交
133
			else
134
				clsCode.add("implements ");
S
Skylot 已提交
135

S
Skylot 已提交
136
			for (Iterator<ClassInfo> it = cls.getInterfaces().iterator(); it.hasNext(); ) {
S
Skylot 已提交
137 138 139 140 141
				ClassInfo interf = it.next();
				clsCode.add(useClass(interf));
				if (it.hasNext())
					clsCode.add(", ");
			}
142 143 144
			if (!cls.getInterfaces().isEmpty())
				clsCode.add(' ');
		}
145 146

		clsCode.attachAnnotation(cls);
147 148
	}

S
Skylot 已提交
149
	public boolean makeGenericMap(CodeWriter code, Map<ArgType, List<ArgType>> gmap) {
150
		if (gmap == null || gmap.isEmpty())
S
Skylot 已提交
151
			return false;
152 153 154 155 156 157 158 159 160 161 162 163

		code.add('<');
		int i = 0;
		for (Entry<ArgType, List<ArgType>> e : gmap.entrySet()) {
			ArgType type = e.getKey();
			List<ArgType> list = e.getValue();
			if (i != 0) {
				code.add(", ");
			}
			code.add(useClass(type));
			if (list != null && !list.isEmpty()) {
				code.add(" extends ");
S
Skylot 已提交
164
				for (Iterator<ArgType> it = list.iterator(); it.hasNext(); ) {
165 166 167 168 169 170 171 172
					ArgType g = it.next();
					code.add(useClass(g));
					if (it.hasNext()) {
						code.add(" & ");
					}
				}
			}
			i++;
S
Skylot 已提交
173
		}
174
		code.add('>');
S
Skylot 已提交
175
		return true;
S
Skylot 已提交
176 177 178
	}

	public void makeClassBody(CodeWriter clsCode) throws CodegenException {
179
		clsCode.add('{');
180 181
		insertSourceFileInfo(clsCode, cls);

S
Skylot 已提交
182
		CodeWriter mthsCode = makeMethods(clsCode, cls.getMethods());
S
Skylot 已提交
183 184 185
		CodeWriter fieldsCode = makeFields(clsCode, cls, cls.getFields());
		clsCode.add(fieldsCode);
		if (fieldsCode.notEmpty() && mthsCode.notEmpty())
186
			clsCode.newLine();
S
Skylot 已提交
187 188 189 190

		// insert inner classes code
		if (cls.getInnerClasses().size() != 0) {
			clsCode.add(makeInnerClasses(cls, clsCode.getIndent()));
S
Skylot 已提交
191
			if (mthsCode.notEmpty())
192
				clsCode.newLine();
S
Skylot 已提交
193 194
		}
		clsCode.add(mthsCode);
195
		clsCode.startLine('}');
S
Skylot 已提交
196 197
	}

S
Skylot 已提交
198
	private CodeWriter makeInnerClasses(ClassNode cls, int indent) throws CodegenException {
S
Skylot 已提交
199 200 201 202 203 204 205 206 207 208 209 210
		CodeWriter innerClsCode = new CodeWriter(indent + 1);
		for (ClassNode inCls : cls.getInnerClasses()) {
			if (inCls.isAnonymous())
				continue;

			ClassGen inClGen = new ClassGen(inCls, parentGen == null ? this : parentGen, fallback);
			inClGen.addClassCode(innerClsCode);
			imports.addAll(inClGen.getImports());
		}
		return innerClsCode;
	}

211
	private CodeWriter makeMethods(CodeWriter clsCode, List<MethodNode> mthList) {
S
Skylot 已提交
212
		CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);
S
Skylot 已提交
213
		for (Iterator<MethodNode> it = mthList.iterator(); it.hasNext(); ) {
S
Skylot 已提交
214
			MethodNode mth = it.next();
S
Skylot 已提交
215 216 217
			if (mth.getAttributes().contains(AttributeFlag.DONT_GENERATE))
				continue;

S
Skylot 已提交
218 219 220 221 222 223 224 225 226 227 228
			try {
				if (mth.getAccessFlags().isAbstract() || mth.getAccessFlags().isNative()) {
					MethodGen mthGen = new MethodGen(this, mth);
					mthGen.addDefinition(code);
					if (cls.getAccessFlags().isAnnotation()) {
						Object def = annotationGen.getAnnotationDefaultValue(mth.getName());
						if (def != null) {
							String v = annotationGen.encValueToString(def);
							code.add(" default ").add(v);
						}
					}
229
					code.add(';');
S
Skylot 已提交
230 231 232 233 234 235 236
				} else {
					if (mth.isNoCode())
						continue;

					MethodGen mthGen = new MethodGen(this, mth);
					mthGen.addDefinition(code);
					code.add(" {");
237
					insertSourceFileInfo(code, mth);
S
Skylot 已提交
238
					code.add(mthGen.makeInstructions(code.getIndent()));
239
					code.startLine('}');
S
Skylot 已提交
240 241 242 243 244 245 246
				}
			} catch (Throwable e) {
				String msg = ErrorsCounter.methodError(mth, "Method generation error", e);
				code.startLine("/* " + msg + CodeWriter.NL + Utils.getStackTrace(e) + "*/");
			}

			if (it.hasNext())
247
				code.newLine();
S
Skylot 已提交
248 249 250 251 252 253 254 255 256
		}
		return code;
	}

	private CodeWriter makeFields(CodeWriter clsCode, ClassNode cls, List<FieldNode> fields) throws CodegenException {
		CodeWriter code = new CodeWriter(clsCode.getIndent() + 1);

		EnumClassAttr enumFields = (EnumClassAttr) cls.getAttributes().get(AttributeType.ENUM_CLASS);
		if (enumFields != null) {
S
Skylot 已提交
257 258
			InsnGen igen = null;
			for (Iterator<EnumField> it = enumFields.getFields().iterator(); it.hasNext(); ) {
S
Skylot 已提交
259 260 261 262
				EnumField f = it.next();
				code.startLine(f.getName());
				if (f.getArgs().size() != 0) {
					code.add('(');
S
Skylot 已提交
263
					for (Iterator<InsnArg> aIt = f.getArgs().iterator(); aIt.hasNext(); ) {
S
Skylot 已提交
264
						InsnArg arg = aIt.next();
S
Skylot 已提交
265 266 267 268 269
						if (igen == null) {
							// don't init mth gen if this is simple enum
							MethodGen mthGen = new MethodGen(this, enumFields.getStaticMethod());
							igen = new InsnGen(mthGen, enumFields.getStaticMethod(), false);
						}
S
Skylot 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
						code.add(igen.arg(arg));
						if (aIt.hasNext())
							code.add(", ");
					}
					code.add(')');
				}
				if (f.getCls() != null) {
					new ClassGen(f.getCls(), this, fallback).makeClassBody(code);
				}
				if (it.hasNext())
					code.add(',');
			}
			if (enumFields.getFields().isEmpty())
				code.startLine();

			code.add(';');
286
			code.newLine();
S
Skylot 已提交
287 288 289 290 291 292
		}

		for (FieldNode f : fields) {
			annotationGen.addForField(code, f);
			code.startLine(f.getAccessFlags().makeString());
			code.add(TypeGen.translate(this, f.getType()));
293
			code.add(' ');
S
Skylot 已提交
294 295 296 297 298 299 300 301 302 303
			code.add(f.getName());
			FieldValueAttr fv = (FieldValueAttr) f.getAttributes().get(AttributeType.FIELD_VALUE);
			if (fv != null) {
				code.add(" = ");
				if (fv.getValue() == null) {
					code.add(TypeGen.literalToString(0, f.getType()));
				} else {
					code.add(annotationGen.encValueToString(fv.getValue()));
				}
			}
304
			code.add(';');
305
			code.attachAnnotation(f);
S
Skylot 已提交
306 307 308 309 310
		}
		return code;
	}

	public String useClass(ArgType clsType) {
311 312 313
		if (clsType.isGenericType()) {
			return clsType.getObject();
		}
S
Skylot 已提交
314
		return useClass(ClassInfo.fromType(clsType));
315
	}
316

317
	public String useClass(ClassInfo classInfo) {
S
Skylot 已提交
318
		String baseClass = useClassInternal(cls.getClassInfo(), classInfo);
319
		ArgType[] generics = classInfo.getType().getGenericTypes();
320 321 322
		if (generics != null) {
			StringBuilder sb = new StringBuilder();
			sb.append(baseClass);
323
			sb.append('<');
324 325 326 327 328 329 330
			int len = generics.length;
			for (int i = 0; i < len; i++) {
				if (i != 0) {
					sb.append(", ");
				}
				ArgType gt = generics[i];
				if (gt.isTypeKnown())
331
					sb.append(TypeGen.translate(this, gt));
332 333 334
				else
					sb.append('?');
			}
335
			sb.append('>');
336 337 338 339
			return sb.toString();
		} else {
			return baseClass;
		}
S
Skylot 已提交
340 341
	}

S
Skylot 已提交
342
	private String useClassInternal(ClassInfo useCls, ClassInfo classInfo) {
S
Skylot 已提交
343
		String clsStr = classInfo.getFullName();
S
Skylot 已提交
344
		if (fallback) {
S
Skylot 已提交
345
			return clsStr;
S
Skylot 已提交
346
		}
S
Skylot 已提交
347 348 349 350 351
		String shortName = classInfo.getShortName();
		if (classInfo.getPackage().equals("java.lang") && classInfo.getParentClass() == null) {
			return shortName;
		} else {
			// don't add import if this class inner for current class
S
Skylot 已提交
352
			if (isClassInnerFor(classInfo, useCls)) {
S
Skylot 已提交
353
				return shortName;
S
Skylot 已提交
354
			}
355
			// don't add import if this class from same package
S
Skylot 已提交
356
			if (classInfo.getPackage().equals(useCls.getPackage()) && !classInfo.isInner()) {
357
				return shortName;
S
Skylot 已提交
358 359 360 361 362 363 364
			}
			if (classInfo.getPackage().equals(useCls.getPackage())) {
				clsStr = classInfo.getNameWithoutPackage();
			}
			if (searchCollision(cls.dex(), useCls, shortName)) {
				return clsStr;
			}
S
Skylot 已提交
365 366
			for (ClassInfo cls : imports) {
				if (!cls.equals(classInfo)) {
S
Skylot 已提交
367
					if (cls.getShortName().equals(shortName)) {
S
Skylot 已提交
368
						return clsStr;
S
Skylot 已提交
369
					}
S
Skylot 已提交
370 371
				}
			}
372
			addImport(classInfo);
S
Skylot 已提交
373 374 375 376
			return shortName;
		}
	}

377 378 379 380 381 382 383 384
	private void addImport(ClassInfo classInfo) {
		if (parentGen != null) {
			parentGen.addImport(classInfo);
		} else {
			imports.add(classInfo);
		}
	}

S
Skylot 已提交
385
	private static boolean isClassInnerFor(ClassInfo inner, ClassInfo parent) {
S
Skylot 已提交
386 387
		if (inner.isInner()) {
			ClassInfo p = inner.getParentClass();
S
Skylot 已提交
388
			return p.equals(parent) || isClassInnerFor(p, parent);
S
Skylot 已提交
389 390 391 392
		}
		return false;
	}

S
Skylot 已提交
393 394 395 396 397 398 399 400
	private static boolean searchCollision(DexNode dex, ClassInfo useCls, String shortName) {
		if (useCls == null) {
			return false;
		}
		if (useCls.getShortName().equals(shortName)) {
			return true;
		}
		ClassNode classNode = dex.resolveClass(useCls);
401 402 403 404 405
		if (classNode != null) {
			for (ClassNode inner : classNode.getInnerClasses()) {
				if (inner.getShortName().equals(shortName)) {
					return true;
				}
S
Skylot 已提交
406 407 408 409 410
			}
		}
		return searchCollision(dex, useCls.getParentClass(), shortName);
	}

411 412
	private void insertSourceFileInfo(CodeWriter code, AttrNode node) {
		IAttribute sourceFileAttr = node.getAttributes().get(AttributeType.SOURCE_FILE);
413
		if (sourceFileAttr != null) {
414
			code.startLine(1, "// compiled from: ");
415
			code.add(((SourceFileAttr) sourceFileAttr).getFileName());
416 417 418
		}
	}

S
Skylot 已提交
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
	public Set<ClassInfo> getImports() {
		return imports;
	}

	public ClassGen getParentGen() {
		return parentGen;
	}

	public AnnotationGen getAnnotationGen() {
		return annotationGen;
	}

	public boolean isFallbackMode() {
		return fallback;
	}
}