ClassNode.java 21.9 KB
Newer Older
S
Skylot 已提交
1 2
package jadx.core.dex.nodes;

3 4 5
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
6
import java.util.LinkedHashSet;
7 8
import java.util.List;
import java.util.Map;
9
import java.util.Set;
10
import java.util.function.BiConsumer;
11
import java.util.function.Consumer;
12
import java.util.stream.Collectors;
13

14
import org.jetbrains.annotations.NotNull;
15 16 17 18
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

S
Skylot 已提交
19
import jadx.api.DecompilationMode;
20
import jadx.api.ICodeCache;
S
Skylot 已提交
21
import jadx.api.ICodeInfo;
S
Skylot 已提交
22
import jadx.api.ICodeWriter;
S
Skylot 已提交
23
import jadx.api.JadxArgs;
24
import jadx.api.plugins.input.data.IClassData;
25 26
import jadx.api.plugins.input.data.IFieldData;
import jadx.api.plugins.input.data.IMethodData;
27
import jadx.api.plugins.input.data.annotations.EncodedValue;
S
Skylot 已提交
28 29 30 31 32 33
import jadx.api.plugins.input.data.attributes.JadxAttrType;
import jadx.api.plugins.input.data.attributes.types.AnnotationDefaultAttr;
import jadx.api.plugins.input.data.attributes.types.AnnotationDefaultClassAttr;
import jadx.api.plugins.input.data.attributes.types.InnerClassesAttr;
import jadx.api.plugins.input.data.attributes.types.InnerClsInfo;
import jadx.api.plugins.input.data.attributes.types.SourceFileAttr;
34
import jadx.api.plugins.input.data.impl.ListConsumer;
S
Skylot 已提交
35
import jadx.core.Consts;
S
Skylot 已提交
36
import jadx.core.ProcessClass;
37
import jadx.core.dex.attributes.AFlag;
38
import jadx.core.dex.attributes.AType;
39
import jadx.core.dex.attributes.nodes.NotificationAttrNode;
S
Skylot 已提交
40 41 42 43 44 45
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.AccessInfo.AFType;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.info.FieldInfo;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType;
1
13.beta2 已提交
46
import jadx.core.dex.instructions.args.LiteralArg;
47
import jadx.core.dex.nodes.utils.TypeUtils;
48
import jadx.core.utils.ListUtils;
49
import jadx.core.utils.Utils;
S
Skylot 已提交
50
import jadx.core.utils.exceptions.JadxRuntimeException;
S
Skylot 已提交
51

S
Skylot 已提交
52
import static jadx.core.dex.nodes.ProcessState.LOADED;
53
import static jadx.core.dex.nodes.ProcessState.NOT_LOADED;
54

55
public class ClassNode extends NotificationAttrNode implements ILoadable, ICodeNode, Comparable<ClassNode> {
S
Skylot 已提交
56
	private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class);
S
Skylot 已提交
57

58
	private final RootNode root;
59
	private final IClassData clsData;
60

S
Skylot 已提交
61
	private final ClassInfo clsInfo;
62
	private AccessInfo accessFlags;
S
Skylot 已提交
63 64
	private ArgType superClass;
	private List<ArgType> interfaces;
65
	private List<ArgType> generics = Collections.emptyList();
S
Skylot 已提交
66

67 68
	private List<MethodNode> methods;
	private List<FieldNode> fields;
69
	private List<ClassNode> innerClasses = Collections.emptyList();
S
Skylot 已提交
70

71 72
	private List<ClassNode> inlinedClasses = Collections.emptyList();

73 74
	// store smali
	private String smali;
75 76
	// store parent for inner classes or 'this' otherwise
	private ClassNode parentClass;
S
Skylot 已提交
77

S
Skylot 已提交
78
	private volatile ProcessState state = ProcessState.NOT_LOADED;
79
	private LoadStage loadStage = LoadStage.NONE;
80

81 82 83
	/**
	 * Top level classes used in this class (only for top level classes, empty for inners)
	 */
S
Skylot 已提交
84
	private List<ClassNode> dependencies = Collections.emptyList();
85 86 87 88
	/**
	 * Top level classes needed for code generation stage
	 */
	private List<ClassNode> codegenDeps = Collections.emptyList();
89 90 91
	/**
	 * Classes which uses this class
	 */
92
	private List<ClassNode> useIn = Collections.emptyList();
93 94 95
	/**
	 * Methods which uses this class (by instructions only, definition is excluded)
	 */
96
	private List<MethodNode> useInMth = Collections.emptyList();
97

S
Skylot 已提交
98 99 100
	// cache maps
	private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();

101 102 103
	public ClassNode(RootNode root, IClassData cls) {
		this.root = root;
		this.clsInfo = ClassInfo.fromType(root, ArgType.object(cls.getType()));
104
		this.clsData = cls.copy();
105
		initialLoad(clsData);
106 107
	}

S
Skylot 已提交
108
	private void initialLoad(IClassData cls) {
S
Skylot 已提交
109
		try {
110 111 112
			addAttrs(cls.getAttributes());
			this.accessFlags = new AccessInfo(getAccessFlags(cls), AFType.CLASS);
			this.superClass = checkSuperType(cls);
113
			this.interfaces = Utils.collectionMap(cls.getInterfacesTypes(), ArgType::object);
S
Skylot 已提交
114

115 116 117
			ListConsumer<IFieldData, FieldNode> fieldsConsumer = new ListConsumer<>(fld -> FieldNode.build(this, fld));
			ListConsumer<IMethodData, MethodNode> methodsConsumer = new ListConsumer<>(mth -> MethodNode.build(this, mth));
			cls.visitFieldsAndMethods(fieldsConsumer, methodsConsumer);
118 119 120 121
			if (this.fields != null && this.methods != null) {
				// TODO: temporary solution for restore usage info in reloaded methods and fields
				restoreUsageData(this.fields, this.methods, fieldsConsumer.getResult(), methodsConsumer.getResult());
			}
122 123
			this.fields = fieldsConsumer.getResult();
			this.methods = methodsConsumer.getResult();
S
Skylot 已提交
124

S
Skylot 已提交
125 126
			initStaticValues(fields);
			processAttributes(this);
S
Skylot 已提交
127
			buildCache();
128 129 130 131 132

			// TODO: implement module attribute parsing
			if (this.accessFlags.isModuleInfo()) {
				this.addWarnComment("Modules not supported yet");
			}
S
Skylot 已提交
133
		} catch (Exception e) {
134
			throw new JadxRuntimeException("Error decode class: " + clsInfo, e);
S
Skylot 已提交
135 136 137
		}
	}

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	private void restoreUsageData(List<FieldNode> oldFields, List<MethodNode> oldMethods,
			List<FieldNode> newFields, List<MethodNode> newMethods) {
		Map<FieldInfo, FieldNode> oldFieldMap = Utils.groupBy(oldFields, FieldNode::getFieldInfo);
		for (FieldNode newField : newFields) {
			FieldNode oldField = oldFieldMap.get(newField.getFieldInfo());
			if (oldField != null) {
				newField.setUseIn(oldField.getUseIn());
			}
		}
		Map<MethodInfo, MethodNode> oldMethodsMap = Utils.groupBy(oldMethods, MethodNode::getMethodInfo);
		for (MethodNode newMethod : newMethods) {
			MethodNode oldMethod = oldMethodsMap.get(newMethod.getMethodInfo());
			if (oldMethod != null) {
				newMethod.setUseIn(oldMethod.getUseIn());
			}
		}
	}

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	private ArgType checkSuperType(IClassData cls) {
		String superType = cls.getSuperType();
		if (superType == null) {
			if (clsInfo.getType().getObject().equals(Consts.CLASS_OBJECT)) {
				// java.lang.Object don't have super class
				return null;
			}
			if (this.accessFlags.isModuleInfo()) {
				// module-info also don't have super class
				return null;
			}
			throw new JadxRuntimeException("No super class in " + clsInfo.getType());
		}
		return ArgType.object(superType);
	}

172 173 174 175 176 177
	public void updateGenericClsData(ArgType superClass, List<ArgType> interfaces, List<ArgType> generics) {
		this.superClass = superClass;
		this.interfaces = interfaces;
		this.generics = generics;
	}

S
Skylot 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
	private static void processAttributes(ClassNode cls) {
		// move AnnotationDefault from cls to methods (dex specific)
		AnnotationDefaultClassAttr defAttr = cls.get(JadxAttrType.ANNOTATION_DEFAULT_CLASS);
		if (defAttr != null) {
			cls.remove(JadxAttrType.ANNOTATION_DEFAULT_CLASS);
			for (Map.Entry<String, EncodedValue> entry : defAttr.getValues().entrySet()) {
				MethodNode mth = cls.searchMethodByShortName(entry.getKey());
				if (mth != null) {
					mth.addAttr(new AnnotationDefaultAttr(entry.getValue()));
				} else {
					cls.addWarnComment("Method from annotation default annotation not found: " + entry.getKey());
				}
			}
		}

		// check source file attribute
		if (!cls.checkSourceFilenameAttr()) {
			cls.remove(JadxAttrType.SOURCE_FILE);
		}
	}

	private int getAccessFlags(IClassData cls) {
		InnerClassesAttr innerClassesAttr = get(JadxAttrType.INNER_CLASSES);
		if (innerClassesAttr != null) {
			InnerClsInfo innerClsInfo = innerClassesAttr.getMap().get(cls.getType());
			if (innerClsInfo != null) {
				return innerClsInfo.getAccessFlags();
			}
206
		}
S
Skylot 已提交
207
		return cls.getAccessFlags();
208 209
	}

210
	public static ClassNode addSyntheticClass(RootNode root, String name, int accessFlags) {
211 212 213 214 215 216 217 218 219 220
		ClassInfo clsInfo = ClassInfo.fromName(root, name);
		ClassNode existCls = root.resolveClass(clsInfo);
		if (existCls != null) {
			throw new JadxRuntimeException("Class already exist: " + name);
		}
		return addSyntheticClass(root, clsInfo, accessFlags);
	}

	public static ClassNode addSyntheticClass(RootNode root, ClassInfo clsInfo, int accessFlags) {
		ClassNode cls = new ClassNode(root, clsInfo, accessFlags);
221 222 223 224 225 226 227
		cls.add(AFlag.SYNTHETIC);
		cls.setState(ProcessState.PROCESS_COMPLETE);
		root.addClassNode(cls);
		return cls;
	}

	// Create empty class
228
	private ClassNode(RootNode root, ClassInfo clsInfo, int accessFlags) {
229
		this.root = root;
230
		this.clsData = null;
231
		this.clsInfo = clsInfo;
232 233 234 235
		this.interfaces = new ArrayList<>();
		this.methods = new ArrayList<>();
		this.fields = new ArrayList<>();
		this.accessFlags = new AccessInfo(accessFlags, AFType.CLASS);
236 237 238
		this.parentClass = this;
	}

S
Skylot 已提交
239
	private void initStaticValues(List<FieldNode> fields) {
240 241
		if (fields.isEmpty()) {
			return;
S
Skylot 已提交
242
		}
243
		List<FieldNode> staticFields = fields.stream().filter(FieldNode::isStatic).collect(Collectors.toList());
S
Skylot 已提交
244
		for (FieldNode f : staticFields) {
S
Skylot 已提交
245
			if (f.getAccessFlags().isFinal() && f.get(JadxAttrType.CONSTANT_VALUE) == null) {
246
				// incorrect initialization will be removed if assign found in constructor
S
Skylot 已提交
247
				f.addAttr(EncodedValue.NULL);
S
Skylot 已提交
248 249
			}
		}
250 251 252 253 254
		try {
			// process const fields
			root().getConstValues().processConstFields(this, staticFields);
		} catch (Exception e) {
			this.addWarnComment("Failed to load initial values for static fields", e);
255
		}
S
Skylot 已提交
256 257
	}

S
Skylot 已提交
258 259 260 261
	private boolean checkSourceFilenameAttr() {
		SourceFileAttr sourceFileAttr = get(JadxAttrType.SOURCE_FILE);
		if (sourceFileAttr == null) {
			return true;
262
		}
S
Skylot 已提交
263
		String fileName = sourceFileAttr.getFileName();
264 265 266
		if (fileName.endsWith(".java")) {
			fileName = fileName.substring(0, fileName.length() - 5);
		}
267
		if (fileName.isEmpty() || fileName.equals("SourceFile")) {
S
Skylot 已提交
268
			return false;
269 270 271 272
		}
		if (clsInfo != null) {
			String name = clsInfo.getShortName();
			if (fileName.equals(name)) {
S
Skylot 已提交
273 274 275 276 277 278 279 280 281
				return false;
			}
			ClassInfo parentCls = clsInfo.getParentClass();
			while (parentCls != null) {
				String parentName = parentCls.getShortName();
				if (parentName.equals(fileName) || parentName.startsWith(fileName + '$')) {
					return false;
				}
				parentCls = parentCls.getParentClass();
282
			}
283
			if (fileName.contains("$") && fileName.endsWith('$' + name)) {
S
Skylot 已提交
284 285 286 287
				return false;
			}
			if (name.contains("$") && name.startsWith(fileName)) {
				return false;
S
Skylot 已提交
288
			}
289
		}
S
Skylot 已提交
290
		return true;
291 292
	}

293 294 295 296
	public boolean checkProcessed() {
		return getTopParentClass().getState().isProcessComplete();
	}

297
	public void ensureProcessed() {
298 299
		if (!checkProcessed()) {
			ClassNode topParentClass = getTopParentClass();
300
			throw new JadxRuntimeException("Expected class to be processed at this point,"
301
					+ " class: " + topParentClass + ", state: " + topParentClass.getState());
302
		}
S
Skylot 已提交
303 304
	}

305 306 307 308
	public ICodeInfo decompile() {
		return decompile(true);
	}

S
Skylot 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
	/**
	 * WARNING: Slow operation! Use with caution!
	 */
	public ICodeInfo decompileWithMode(DecompilationMode mode) {
		DecompilationMode baseMode = root.getArgs().getDecompilationMode();
		if (mode == baseMode) {
			return decompile(true);
		}
		JadxArgs args = root.getArgs();
		try {
			unload();
			args.setDecompilationMode(mode);
			ProcessClass process = new ProcessClass(args);
			process.initPasses(root);
			return process.generateCode(this);
		} finally {
			args.setDecompilationMode(baseMode);
		}
	}

329 330 331 332
	public ICodeInfo getCode() {
		return decompile(true);
	}

333 334
	public ICodeInfo reloadCode() {
		add(AFlag.CLASS_DEEP_RELOAD);
335 336 337
		return decompile(false);
	}

338 339 340 341 342 343 344 345 346
	public void unloadCode() {
		if (state == NOT_LOADED) {
			return;
		}
		add(AFlag.CLASS_UNLOADED);
		unloadFromCache();
		deepUnload();
	}

S
Skylot 已提交
347
	public void deepUnload() {
348
		if (clsData == null) {
S
Skylot 已提交
349 350 351
			// manually added class
			return;
		}
352
		unload();
353
		clearAttributes();
354
		root().getConstValues().removeForClass(this);
355
		initialLoad(clsData);
356

357
		innerClasses.forEach(ClassNode::deepUnload);
358 359
	}

360 361 362 363 364 365 366 367
	private void unloadFromCache() {
		if (isInner()) {
			return;
		}
		ICodeCache codeCache = root().getCodeCache();
		codeCache.remove(getRawName());
	}

368
	private synchronized ICodeInfo decompile(boolean searchInCache) {
369 370 371
		if (isInner()) {
			return ICodeInfo.EMPTY;
		}
372
		ICodeCache codeCache = root().getCodeCache();
373
		String clsRawName = getRawName();
374 375
		if (searchInCache) {
			ICodeInfo code = codeCache.get(clsRawName);
376
			if (code != null && code != ICodeInfo.EMPTY) {
377 378
				return code;
			}
S
Skylot 已提交
379
		}
S
Skylot 已提交
380
		ICodeInfo codeInfo = root.getProcessClasses().generateCode(this);
381
		codeCache.add(clsRawName, codeInfo);
S
Skylot 已提交
382 383 384
		return codeInfo;
	}

385 386 387 388 389 390 391 392 393 394 395
	@Nullable
	public ICodeInfo getCodeFromCache() {
		ICodeCache codeCache = root().getCodeCache();
		String clsRawName = getRawName();
		ICodeInfo codeInfo = codeCache.get(clsRawName);
		if (codeInfo == ICodeInfo.EMPTY) {
			return null;
		}
		return codeInfo;
	}

S
Skylot 已提交
396
	@Override
S
Skylot 已提交
397
	public void load() {
S
Skylot 已提交
398
		for (MethodNode mth : getMethods()) {
S
Skylot 已提交
399 400
			try {
				mth.load();
401
			} catch (Exception e) {
402
				mth.addError("Method load error", e);
S
Skylot 已提交
403
			}
S
Skylot 已提交
404 405 406 407
		}
		for (ClassNode innerCls : getInnerClasses()) {
			innerCls.load();
		}
S
Skylot 已提交
408
		setState(LOADED);
S
Skylot 已提交
409 410 411 412
	}

	@Override
	public void unload() {
413 414 415
		if (state == NOT_LOADED) {
			return;
		}
416 417 418 419
		methods.forEach(MethodNode::unload);
		innerClasses.forEach(ClassNode::unload);
		fields.forEach(FieldNode::unloadAttributes);
		unloadAttributes();
420
		setState(NOT_LOADED);
421
		this.loadStage = LoadStage.NONE;
422
		this.smali = null;
S
Skylot 已提交
423 424
	}

S
Skylot 已提交
425
	private void buildCache() {
S
Skylot 已提交
426
		mthInfoMap = new HashMap<>(methods.size());
S
Skylot 已提交
427 428 429 430 431
		for (MethodNode mth : methods) {
			mthInfoMap.put(mth.getMethodInfo(), mth);
		}
	}

S
Skylot 已提交
432 433
	@Nullable
	public ArgType getSuperClass() {
S
Skylot 已提交
434 435 436
		return superClass;
	}

S
Skylot 已提交
437
	public List<ArgType> getInterfaces() {
S
Skylot 已提交
438 439 440
		return interfaces;
	}

441
	public List<ArgType> getGenericTypeParameters() {
442
		return generics;
443 444
	}

445 446 447 448 449 450 451 452
	public ArgType getType() {
		ArgType clsType = clsInfo.getType();
		if (Utils.notEmpty(generics)) {
			return ArgType.generic(clsType, generics);
		}
		return clsType;
	}

S
Skylot 已提交
453 454 455 456 457 458 459 460
	public List<MethodNode> getMethods() {
		return methods;
	}

	public List<FieldNode> getFields() {
		return fields;
	}

461 462 463 464
	public void addField(FieldNode fld) {
		fields.add(fld);
	}

465 466 467 468
	public FieldNode getConstField(Object obj) {
		return getConstField(obj, true);
	}

469
	@Nullable
470
	public FieldNode getConstField(Object obj, boolean searchGlobal) {
471
		return root().getConstValues().getConstField(this, obj, searchGlobal);
472 473
	}

474
	@Nullable
1
13.beta2 已提交
475
	public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
476
		return root().getConstValues().getConstFieldByLiteralArg(this, arg);
1
13.beta2 已提交
477 478
	}

479
	public FieldNode searchField(FieldInfo field) {
S
Skylot 已提交
480
		for (FieldNode f : fields) {
481
			if (f.getFieldInfo().equals(field)) {
S
Skylot 已提交
482
				return f;
S
Skylot 已提交
483
			}
S
Skylot 已提交
484 485 486 487
		}
		return null;
	}

488 489 490 491 492 493 494 495 496
	public FieldNode searchFieldByNameAndType(FieldInfo field) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().equalsNameAndType(field)) {
				return f;
			}
		}
		return null;
	}

S
Skylot 已提交
497
	public FieldNode searchFieldByName(String name) {
S
Skylot 已提交
498
		for (FieldNode f : fields) {
S
Skylot 已提交
499
			if (f.getName().equals(name)) {
S
Skylot 已提交
500
				return f;
S
Skylot 已提交
501
			}
S
Skylot 已提交
502 503 504 505
		}
		return null;
	}

506 507 508 509 510 511 512 513 514
	public FieldNode searchFieldByShortId(String shortId) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().getShortId().equals(shortId)) {
				return f;
			}
		}
		return null;
	}

S
Skylot 已提交
515
	public MethodNode searchMethod(MethodInfo mth) {
S
Skylot 已提交
516
		return mthInfoMap.get(mth);
S
Skylot 已提交
517 518
	}

519
	public MethodNode searchMethodByShortId(String shortId) {
S
Skylot 已提交
520
		for (MethodNode m : methods) {
S
Skylot 已提交
521
			if (m.getMethodInfo().getShortId().equals(shortId)) {
S
Skylot 已提交
522
				return m;
S
Skylot 已提交
523
			}
S
Skylot 已提交
524 525 526 527
		}
		return null;
	}

528 529
	/**
	 * Return first method by original short name
530 531
	 * Note: methods are not unique by name (class can have several methods with same name but different
	 * signature)
532 533 534 535 536 537 538 539 540 541 542
	 */
	@Nullable
	public MethodNode searchMethodByShortName(String name) {
		for (MethodNode m : methods) {
			if (m.getMethodInfo().getName().equals(name)) {
				return m;
			}
		}
		return null;
	}

543
	public ClassNode getParentClass() {
544 545 546 547 548 549 550 551 552
		return parentClass;
	}

	public void updateParentClass() {
		if (clsInfo.isInner()) {
			ClassNode parent = root.resolveClass(clsInfo.getParentClass());
			if (parent != null) {
				parentClass = parent;
				return;
553 554
			}
		}
555
		parentClass = this;
556 557
	}

558 559
	public ClassNode getTopParentClass() {
		ClassNode parent = getParentClass();
560
		return parent == this ? this : parent.getTopParentClass();
561 562
	}

563 564 565 566 567 568 569 570 571 572
	public void visitParentClasses(Consumer<ClassNode> consumer) {
		ClassNode currentCls = this;
		ClassNode parentCls = currentCls.getParentClass();
		while (parentCls != currentCls) {
			consumer.accept(parentCls);
			currentCls = parentCls;
			parentCls = currentCls.getParentClass();
		}
	}

573 574 575 576 577 578 579 580 581 582 583 584 585
	public void visitSuperTypes(BiConsumer<ArgType, ArgType> consumer) {
		TypeUtils typeUtils = root.getTypeUtils();
		ArgType thisType = this.getType();
		if (!superClass.equals(ArgType.OBJECT)) {
			consumer.accept(thisType, superClass);
			typeUtils.visitSuperTypes(superClass, consumer);
		}
		for (ArgType iface : interfaces) {
			consumer.accept(thisType, iface);
			typeUtils.visitSuperTypes(iface, consumer);
		}
	}

586 587 588 589 590 591 592 593 594 595 596
	public boolean hasNotGeneratedParent() {
		if (contains(AFlag.DONT_GENERATE)) {
			return true;
		}
		ClassNode parent = getParentClass();
		if (parent == this) {
			return false;
		}
		return parent.hasNotGeneratedParent();
	}

S
Skylot 已提交
597 598 599 600
	public List<ClassNode> getInnerClasses() {
		return innerClasses;
	}

601 602 603 604
	public List<ClassNode> getInlinedClasses() {
		return inlinedClasses;
	}

605
	/**
606
	 * Get all inner and inlined classes recursively
607
	 *
608 609
	 * @param resultClassesSet
	 *                         all identified inner and inlined classes are added to this set
610
	 */
611 612 613 614 615 616 617 618 619 620
	public void getInnerAndInlinedClassesRecursive(Set<ClassNode> resultClassesSet) {
		for (ClassNode innerCls : innerClasses) {
			if (resultClassesSet.add(innerCls)) {
				innerCls.getInnerAndInlinedClassesRecursive(resultClassesSet);
			}
		}
		for (ClassNode inlinedCls : inlinedClasses) {
			if (resultClassesSet.add(inlinedCls)) {
				inlinedCls.getInnerAndInlinedClassesRecursive(resultClassesSet);
			}
621 622 623
		}
	}

S
Skylot 已提交
624
	public void addInnerClass(ClassNode cls) {
625 626 627
		if (innerClasses.isEmpty()) {
			innerClasses = new ArrayList<>(5);
		}
S
Skylot 已提交
628
		innerClasses.add(cls);
629
		cls.parentClass = this;
S
Skylot 已提交
630 631
	}

632 633 634 635 636 637 638
	public void addInlinedClass(ClassNode cls) {
		if (inlinedClasses.isEmpty()) {
			inlinedClasses = new ArrayList<>(5);
		}
		inlinedClasses.add(cls);
	}

639
	public boolean isEnum() {
S
Skylot 已提交
640 641 642
		return getAccessFlags().isEnum()
				&& getSuperClass() != null
				&& getSuperClass().getObject().equals(ArgType.ENUM.getObject());
643 644
	}

S
Skylot 已提交
645
	public boolean isAnonymous() {
646
		return contains(AType.ANONYMOUS_CLASS);
647 648
	}

649
	public boolean isInner() {
650
		return parentClass != this;
651 652
	}

653 654 655 656
	public boolean isTopClass() {
		return parentClass == this;
	}

657 658
	@Nullable
	public MethodNode getClassInitMth() {
659
		return searchMethodByShortId("<clinit>()V");
660 661 662
	}

	@Nullable
S
Skylot 已提交
663 664
	public MethodNode getDefaultConstructor() {
		for (MethodNode mth : methods) {
665
			if (mth.isDefaultConstructor()) {
S
Skylot 已提交
666
				return mth;
S
Skylot 已提交
667 668
			}
		}
S
Skylot 已提交
669
		return null;
S
Skylot 已提交
670 671
	}

672
	@Override
S
Skylot 已提交
673 674 675 676
	public AccessInfo getAccessFlags() {
		return accessFlags;
	}

677 678 679 680 681
	@Override
	public void setAccessFlags(AccessInfo accessFlags) {
		this.accessFlags = accessFlags;
	}

682 683
	@Override
	public RootNode root() {
684
		return root;
685 686
	}

687 688 689 690 691
	@Override
	public String typeName() {
		return "class";
	}

S
Skylot 已提交
692 693 694 695 696 697 698
	public String getRawName() {
		return clsInfo.getRawName();
	}

	/**
	 * Internal class info (don't use in code generation and external api).
	 */
S
Skylot 已提交
699 700 701 702 703
	public ClassInfo getClassInfo() {
		return clsInfo;
	}

	public String getShortName() {
704
		return clsInfo.getAliasShortName();
S
Skylot 已提交
705 706 707
	}

	public String getFullName() {
708
		return clsInfo.getAliasFullName();
S
Skylot 已提交
709 710 711
	}

	public String getPackage() {
712
		return clsInfo.getAliasPkg();
713 714
	}

S
Skylot 已提交
715
	public String getDisassembledCode() {
716
		if (smali == null) {
717
			StringBuilder sb = new StringBuilder();
S
Skylot 已提交
718 719
			getDisassembledCode(sb);
			sb.append(ICodeWriter.NL);
720 721 722
			Set<ClassNode> allInlinedClasses = new LinkedHashSet<>();
			getInnerAndInlinedClassesRecursive(allInlinedClasses);
			for (ClassNode innerClass : allInlinedClasses) {
S
Skylot 已提交
723 724
				innerClass.getDisassembledCode(sb);
				sb.append(ICodeWriter.NL);
725
			}
726
			smali = sb.toString();
727
		}
728 729 730
		return smali;
	}

S
Skylot 已提交
731 732
	protected void getDisassembledCode(StringBuilder sb) {
		if (clsData == null) {
733 734
			sb.append(String.format("###### Class %s is created by jadx", getFullName()));
			return;
735
		}
736
		sb.append(String.format("###### Class %s (%s)", getFullName(), getRawName()));
S
Skylot 已提交
737 738
		sb.append(ICodeWriter.NL);
		sb.append(clsData.getDisassembledCode());
739 740
	}

741 742
	public IClassData getClsData() {
		return clsData;
743 744
	}

745 746 747 748 749 750 751 752
	public ProcessState getState() {
		return state;
	}

	public void setState(ProcessState state) {
		this.state = state;
	}

753 754 755 756
	public LoadStage getLoadStage() {
		return loadStage;
	}

757 758
	public void setLoadStage(LoadStage loadStage) {
		this.loadStage = loadStage;
759 760 761 762 763
	}

	public void reloadAtCodegenStage() {
		ClassNode topCls = this.getTopParentClass();
		if (topCls.getLoadStage() == LoadStage.CODEGEN_STAGE) {
764
			throw new JadxRuntimeException("Class not yet loaded at codegen stage: " + topCls);
765 766 767 768
		}
		topCls.add(AFlag.RELOAD_AT_CODEGEN_STAGE);
	}

S
Skylot 已提交
769
	public List<ClassNode> getDependencies() {
770 771 772
		return dependencies;
	}

S
Skylot 已提交
773 774 775 776
	public void setDependencies(List<ClassNode> dependencies) {
		this.dependencies = dependencies;
	}

777 778 779 780
	public void removeDependency(ClassNode dep) {
		this.dependencies = ListUtils.safeRemoveAndTrim(this.dependencies, dep);
	}

781 782 783 784 785 786 787 788
	public List<ClassNode> getCodegenDeps() {
		return codegenDeps;
	}

	public void setCodegenDeps(List<ClassNode> codegenDeps) {
		this.codegenDeps = codegenDeps;
	}

789 790 791 792
	public void addCodegenDep(ClassNode dep) {
		this.codegenDeps = ListUtils.safeAdd(this.codegenDeps, dep);
	}

793 794 795 796
	public int getTotalDepsCount() {
		return dependencies.size() + codegenDeps.size();
	}

797 798 799 800 801 802 803 804 805 806
	public List<ClassNode> getUseIn() {
		return useIn;
	}

	public void setUseIn(List<ClassNode> useIn) {
		this.useIn = useIn;
	}

	public List<MethodNode> getUseInMth() {
		return useInMth;
807 808
	}

809 810
	public void setUseInMth(List<MethodNode> useInMth) {
		this.useInMth = useInMth;
811 812
	}

813
	@Override
814 815
	public String getInputFileName() {
		return clsData == null ? "synthetic" : clsData.getInputFileName();
816 817
	}

818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
	@Override
	public int hashCode() {
		return clsInfo.hashCode();
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) {
			return true;
		}
		if (o instanceof ClassNode) {
			ClassNode other = (ClassNode) o;
			return clsInfo.equals(other.clsInfo);
		}
		return false;
	}

835 836 837 838 839
	@Override
	public int compareTo(@NotNull ClassNode o) {
		return this.getFullName().compareTo(o.getFullName());
	}

S
Skylot 已提交
840 841
	@Override
	public String toString() {
S
Skylot 已提交
842
		return clsInfo.getFullName();
S
Skylot 已提交
843 844
	}
}