ClassNode.java 20.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;

19
import jadx.api.ICodeCache;
S
Skylot 已提交
20
import jadx.api.ICodeInfo;
S
Skylot 已提交
21
import jadx.api.ICodeWriter;
22
import jadx.api.plugins.input.data.IClassData;
23 24
import jadx.api.plugins.input.data.IFieldData;
import jadx.api.plugins.input.data.IMethodData;
25
import jadx.api.plugins.input.data.annotations.EncodedValue;
S
Skylot 已提交
26 27 28 29 30 31
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;
32
import jadx.api.plugins.input.data.impl.ListConsumer;
S
Skylot 已提交
33
import jadx.core.Consts;
S
Skylot 已提交
34
import jadx.core.ProcessClass;
35
import jadx.core.dex.attributes.AFlag;
36
import jadx.core.dex.attributes.nodes.NotificationAttrNode;
S
Skylot 已提交
37 38 39 40 41 42
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 已提交
43
import jadx.core.dex.instructions.args.LiteralArg;
44
import jadx.core.dex.nodes.utils.TypeUtils;
45
import jadx.core.utils.Utils;
S
Skylot 已提交
46
import jadx.core.utils.exceptions.JadxRuntimeException;
S
Skylot 已提交
47

S
Skylot 已提交
48
import static jadx.core.dex.nodes.ProcessState.LOADED;
49
import static jadx.core.dex.nodes.ProcessState.NOT_LOADED;
50

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

54
	private final RootNode root;
55
	private final IClassData clsData;
56

S
Skylot 已提交
57
	private final ClassInfo clsInfo;
58
	private AccessInfo accessFlags;
S
Skylot 已提交
59 60
	private ArgType superClass;
	private List<ArgType> interfaces;
61
	private List<ArgType> generics = Collections.emptyList();
S
Skylot 已提交
62

63 64
	private List<MethodNode> methods;
	private List<FieldNode> fields;
65
	private List<ClassNode> innerClasses = Collections.emptyList();
S
Skylot 已提交
66

67 68
	private List<ClassNode> inlinedClasses = Collections.emptyList();

69 70
	// store smali
	private String smali;
71 72
	// store parent for inner classes or 'this' otherwise
	private ClassNode parentClass;
S
Skylot 已提交
73

S
Skylot 已提交
74
	private volatile ProcessState state = ProcessState.NOT_LOADED;
75
	private LoadStage loadStage = LoadStage.NONE;
76

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

S
Skylot 已提交
94 95 96
	// cache maps
	private Map<MethodInfo, MethodNode> mthInfoMap = Collections.emptyMap();

97 98 99
	public ClassNode(RootNode root, IClassData cls) {
		this.root = root;
		this.clsInfo = ClassInfo.fromType(root, ArgType.object(cls.getType()));
100
		this.clsData = cls.copy();
101
		initialLoad(clsData);
102 103
	}

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

111 112 113
			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);
114 115 116 117
			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());
			}
118 119
			this.fields = fieldsConsumer.getResult();
			this.methods = methodsConsumer.getResult();
S
Skylot 已提交
120

S
Skylot 已提交
121 122
			initStaticValues(fields);
			processAttributes(this);
S
Skylot 已提交
123
			buildCache();
124 125 126 127 128

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

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	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());
			}
		}
	}

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	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);
	}

168 169 170 171 172 173
	public void updateGenericClsData(ArgType superClass, List<ArgType> interfaces, List<ArgType> generics) {
		this.superClass = superClass;
		this.interfaces = interfaces;
		this.generics = generics;
	}

S
Skylot 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
	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();
			}
202
		}
S
Skylot 已提交
203
		return cls.getAccessFlags();
204 205
	}

206
	public static ClassNode addSyntheticClass(RootNode root, String name, int accessFlags) {
207 208 209 210 211 212 213 214 215 216
		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);
217 218 219 220 221 222 223
		cls.add(AFlag.SYNTHETIC);
		cls.setState(ProcessState.PROCESS_COMPLETE);
		root.addClassNode(cls);
		return cls;
	}

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

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

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

289 290 291 292
	public boolean checkProcessed() {
		return getTopParentClass().getState().isProcessComplete();
	}

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

301 302 303 304 305 306 307 308
	public ICodeInfo decompile() {
		return decompile(true);
	}

	public ICodeInfo getCode() {
		return decompile(true);
	}

309 310
	public ICodeInfo reloadCode() {
		add(AFlag.CLASS_DEEP_RELOAD);
311 312 313
		return decompile(false);
	}

314 315 316 317 318 319 320 321 322
	public void unloadCode() {
		if (state == NOT_LOADED) {
			return;
		}
		add(AFlag.CLASS_UNLOADED);
		unloadFromCache();
		deepUnload();
	}

S
Skylot 已提交
323
	public void deepUnload() {
324
		if (clsData == null) {
S
Skylot 已提交
325 326 327
			// manually added class
			return;
		}
328
		unload();
329
		clearAttributes();
330
		root().getConstValues().removeForClass(this);
331
		initialLoad(clsData);
332

333
		innerClasses.forEach(ClassNode::deepUnload);
334 335
	}

336 337 338 339 340 341 342 343
	private void unloadFromCache() {
		if (isInner()) {
			return;
		}
		ICodeCache codeCache = root().getCodeCache();
		codeCache.remove(getRawName());
	}

344
	private synchronized ICodeInfo decompile(boolean searchInCache) {
345 346 347
		if (isInner()) {
			return ICodeInfo.EMPTY;
		}
348
		ICodeCache codeCache = root().getCodeCache();
349
		String clsRawName = getRawName();
350 351
		if (searchInCache) {
			ICodeInfo code = codeCache.get(clsRawName);
352
			if (code != null && code != ICodeInfo.EMPTY) {
353 354
				return code;
			}
S
Skylot 已提交
355
		}
356
		ICodeInfo codeInfo = ProcessClass.generateCode(this);
357
		codeCache.add(clsRawName, codeInfo);
S
Skylot 已提交
358 359 360
		return codeInfo;
	}

361 362 363 364 365 366 367 368 369 370 371
	@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 已提交
372
	@Override
S
Skylot 已提交
373
	public void load() {
S
Skylot 已提交
374
		for (MethodNode mth : getMethods()) {
S
Skylot 已提交
375 376
			try {
				mth.load();
377
			} catch (Exception e) {
378
				mth.addError("Method load error", e);
S
Skylot 已提交
379
			}
S
Skylot 已提交
380 381 382 383
		}
		for (ClassNode innerCls : getInnerClasses()) {
			innerCls.load();
		}
S
Skylot 已提交
384
		setState(LOADED);
S
Skylot 已提交
385 386 387 388
	}

	@Override
	public void unload() {
389 390 391
		if (state == NOT_LOADED) {
			return;
		}
392 393 394 395
		methods.forEach(MethodNode::unload);
		innerClasses.forEach(ClassNode::unload);
		fields.forEach(FieldNode::unloadAttributes);
		unloadAttributes();
396
		setState(NOT_LOADED);
397
		this.loadStage = LoadStage.NONE;
398
		this.smali = null;
S
Skylot 已提交
399 400
	}

S
Skylot 已提交
401
	private void buildCache() {
S
Skylot 已提交
402
		mthInfoMap = new HashMap<>(methods.size());
S
Skylot 已提交
403 404 405 406 407
		for (MethodNode mth : methods) {
			mthInfoMap.put(mth.getMethodInfo(), mth);
		}
	}

S
Skylot 已提交
408 409
	@Nullable
	public ArgType getSuperClass() {
S
Skylot 已提交
410 411 412
		return superClass;
	}

S
Skylot 已提交
413
	public List<ArgType> getInterfaces() {
S
Skylot 已提交
414 415 416
		return interfaces;
	}

417
	public List<ArgType> getGenericTypeParameters() {
418
		return generics;
419 420
	}

421 422 423 424 425 426 427 428
	public ArgType getType() {
		ArgType clsType = clsInfo.getType();
		if (Utils.notEmpty(generics)) {
			return ArgType.generic(clsType, generics);
		}
		return clsType;
	}

S
Skylot 已提交
429 430 431 432 433 434 435 436
	public List<MethodNode> getMethods() {
		return methods;
	}

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

437 438 439 440
	public void addField(FieldNode fld) {
		fields.add(fld);
	}

441 442 443 444
	public FieldNode getConstField(Object obj) {
		return getConstField(obj, true);
	}

445
	@Nullable
446
	public FieldNode getConstField(Object obj, boolean searchGlobal) {
447
		return root().getConstValues().getConstField(this, obj, searchGlobal);
448 449
	}

450
	@Nullable
1
13.beta2 已提交
451
	public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
452
		return root().getConstValues().getConstFieldByLiteralArg(this, arg);
1
13.beta2 已提交
453 454
	}

455
	public FieldNode searchField(FieldInfo field) {
S
Skylot 已提交
456
		for (FieldNode f : fields) {
457
			if (f.getFieldInfo().equals(field)) {
S
Skylot 已提交
458
				return f;
S
Skylot 已提交
459
			}
S
Skylot 已提交
460 461 462 463
		}
		return null;
	}

464 465 466 467 468 469 470 471 472
	public FieldNode searchFieldByNameAndType(FieldInfo field) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().equalsNameAndType(field)) {
				return f;
			}
		}
		return null;
	}

S
Skylot 已提交
473
	public FieldNode searchFieldByName(String name) {
S
Skylot 已提交
474
		for (FieldNode f : fields) {
S
Skylot 已提交
475
			if (f.getName().equals(name)) {
S
Skylot 已提交
476
				return f;
S
Skylot 已提交
477
			}
S
Skylot 已提交
478 479 480 481
		}
		return null;
	}

482 483 484 485 486 487 488 489 490
	public FieldNode searchFieldByShortId(String shortId) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().getShortId().equals(shortId)) {
				return f;
			}
		}
		return null;
	}

S
Skylot 已提交
491
	public MethodNode searchMethod(MethodInfo mth) {
S
Skylot 已提交
492
		return mthInfoMap.get(mth);
S
Skylot 已提交
493 494
	}

495
	public MethodNode searchMethodByShortId(String shortId) {
S
Skylot 已提交
496
		for (MethodNode m : methods) {
S
Skylot 已提交
497
			if (m.getMethodInfo().getShortId().equals(shortId)) {
S
Skylot 已提交
498
				return m;
S
Skylot 已提交
499
			}
S
Skylot 已提交
500 501 502 503
		}
		return null;
	}

504 505
	/**
	 * Return first method by original short name
506 507
	 * Note: methods are not unique by name (class can have several methods with same name but different
	 * signature)
508 509 510 511 512 513 514 515 516 517 518
	 */
	@Nullable
	public MethodNode searchMethodByShortName(String name) {
		for (MethodNode m : methods) {
			if (m.getMethodInfo().getName().equals(name)) {
				return m;
			}
		}
		return null;
	}

519
	public ClassNode getParentClass() {
520 521 522 523 524 525 526 527 528
		return parentClass;
	}

	public void updateParentClass() {
		if (clsInfo.isInner()) {
			ClassNode parent = root.resolveClass(clsInfo.getParentClass());
			if (parent != null) {
				parentClass = parent;
				return;
529 530
			}
		}
531
		parentClass = this;
532 533
	}

534 535
	public ClassNode getTopParentClass() {
		ClassNode parent = getParentClass();
536
		return parent == this ? this : parent.getTopParentClass();
537 538
	}

539 540 541 542 543 544 545 546 547 548
	public void visitParentClasses(Consumer<ClassNode> consumer) {
		ClassNode currentCls = this;
		ClassNode parentCls = currentCls.getParentClass();
		while (parentCls != currentCls) {
			consumer.accept(parentCls);
			currentCls = parentCls;
			parentCls = currentCls.getParentClass();
		}
	}

549 550 551 552 553 554 555 556 557 558 559 560 561
	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);
		}
	}

562 563 564 565 566 567 568 569 570 571 572
	public boolean hasNotGeneratedParent() {
		if (contains(AFlag.DONT_GENERATE)) {
			return true;
		}
		ClassNode parent = getParentClass();
		if (parent == this) {
			return false;
		}
		return parent.hasNotGeneratedParent();
	}

S
Skylot 已提交
573 574 575 576
	public List<ClassNode> getInnerClasses() {
		return innerClasses;
	}

577 578 579 580
	public List<ClassNode> getInlinedClasses() {
		return inlinedClasses;
	}

581
	/**
582
	 * Get all inner and inlined classes recursively
583
	 *
584 585
	 * @param resultClassesSet
	 *                         all identified inner and inlined classes are added to this set
586
	 */
587 588 589 590 591 592 593 594 595 596
	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);
			}
597 598 599
		}
	}

S
Skylot 已提交
600
	public void addInnerClass(ClassNode cls) {
601 602 603
		if (innerClasses.isEmpty()) {
			innerClasses = new ArrayList<>(5);
		}
S
Skylot 已提交
604
		innerClasses.add(cls);
605
		cls.parentClass = this;
S
Skylot 已提交
606 607
	}

608 609 610 611 612 613 614
	public void addInlinedClass(ClassNode cls) {
		if (inlinedClasses.isEmpty()) {
			inlinedClasses = new ArrayList<>(5);
		}
		inlinedClasses.add(cls);
	}

615
	public boolean isEnum() {
S
Skylot 已提交
616 617 618
		return getAccessFlags().isEnum()
				&& getSuperClass() != null
				&& getSuperClass().getObject().equals(ArgType.ENUM.getObject());
619 620
	}

S
Skylot 已提交
621
	public boolean isAnonymous() {
622
		return contains(AFlag.ANONYMOUS_CLASS);
623 624
	}

625
	public boolean isInner() {
626
		return parentClass != this;
627 628
	}

629 630 631 632
	public boolean isTopClass() {
		return parentClass == this;
	}

633 634
	@Nullable
	public MethodNode getClassInitMth() {
635
		return searchMethodByShortId("<clinit>()V");
636 637 638
	}

	@Nullable
S
Skylot 已提交
639 640
	public MethodNode getDefaultConstructor() {
		for (MethodNode mth : methods) {
641
			if (mth.isDefaultConstructor()) {
S
Skylot 已提交
642
				return mth;
S
Skylot 已提交
643 644
			}
		}
S
Skylot 已提交
645
		return null;
S
Skylot 已提交
646 647
	}

648
	@Override
S
Skylot 已提交
649 650 651 652
	public AccessInfo getAccessFlags() {
		return accessFlags;
	}

653 654 655 656 657
	@Override
	public void setAccessFlags(AccessInfo accessFlags) {
		this.accessFlags = accessFlags;
	}

658 659
	@Override
	public RootNode root() {
660
		return root;
661 662
	}

663 664 665 666 667
	@Override
	public String typeName() {
		return "class";
	}

S
Skylot 已提交
668 669 670 671 672 673 674
	public String getRawName() {
		return clsInfo.getRawName();
	}

	/**
	 * Internal class info (don't use in code generation and external api).
	 */
S
Skylot 已提交
675 676 677 678 679
	public ClassInfo getClassInfo() {
		return clsInfo;
	}

	public String getShortName() {
680
		return clsInfo.getAliasShortName();
S
Skylot 已提交
681 682 683
	}

	public String getFullName() {
684
		return clsInfo.getAliasFullName();
S
Skylot 已提交
685 686 687
	}

	public String getPackage() {
688
		return clsInfo.getAliasPkg();
689 690
	}

S
Skylot 已提交
691
	public String getDisassembledCode() {
692
		if (smali == null) {
693
			StringBuilder sb = new StringBuilder();
S
Skylot 已提交
694 695
			getDisassembledCode(sb);
			sb.append(ICodeWriter.NL);
696 697 698
			Set<ClassNode> allInlinedClasses = new LinkedHashSet<>();
			getInnerAndInlinedClassesRecursive(allInlinedClasses);
			for (ClassNode innerClass : allInlinedClasses) {
S
Skylot 已提交
699 700
				innerClass.getDisassembledCode(sb);
				sb.append(ICodeWriter.NL);
701
			}
702
			smali = sb.toString();
703
		}
704 705 706
		return smali;
	}

S
Skylot 已提交
707 708
	protected void getDisassembledCode(StringBuilder sb) {
		if (clsData == null) {
709 710
			sb.append(String.format("###### Class %s is created by jadx", getFullName()));
			return;
711
		}
712
		sb.append(String.format("###### Class %s (%s)", getFullName(), getRawName()));
S
Skylot 已提交
713 714
		sb.append(ICodeWriter.NL);
		sb.append(clsData.getDisassembledCode());
715 716
	}

717 718
	public IClassData getClsData() {
		return clsData;
719 720
	}

721 722 723 724 725 726 727 728
	public ProcessState getState() {
		return state;
	}

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

729 730 731 732
	public LoadStage getLoadStage() {
		return loadStage;
	}

733 734
	public void setLoadStage(LoadStage loadStage) {
		this.loadStage = loadStage;
735 736 737 738 739
	}

	public void reloadAtCodegenStage() {
		ClassNode topCls = this.getTopParentClass();
		if (topCls.getLoadStage() == LoadStage.CODEGEN_STAGE) {
740
			throw new JadxRuntimeException("Class not yet loaded at codegen stage: " + topCls);
741 742 743 744
		}
		topCls.add(AFlag.RELOAD_AT_CODEGEN_STAGE);
	}

S
Skylot 已提交
745
	public List<ClassNode> getDependencies() {
746 747 748
		return dependencies;
	}

S
Skylot 已提交
749 750 751 752
	public void setDependencies(List<ClassNode> dependencies) {
		this.dependencies = dependencies;
	}

753 754 755 756 757 758 759 760
	public List<ClassNode> getCodegenDeps() {
		return codegenDeps;
	}

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

761 762 763 764 765 766 767 768 769 770
	public List<ClassNode> getUseIn() {
		return useIn;
	}

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

	public List<MethodNode> getUseInMth() {
		return useInMth;
771 772
	}

773 774
	public void setUseInMth(List<MethodNode> useInMth) {
		this.useInMth = useInMth;
775 776
	}

777
	@Override
778 779
	public String getInputFileName() {
		return clsData == null ? "synthetic" : clsData.getInputFileName();
780 781
	}

782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
	@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;
	}

799 800 801 802 803
	@Override
	public int compareTo(@NotNull ClassNode o) {
		return this.getFullName().compareTo(o.getFullName());
	}

S
Skylot 已提交
804 805
	@Override
	public String toString() {
S
Skylot 已提交
806
		return clsInfo.getFullName();
S
Skylot 已提交
807 808
	}
}