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

S
Skylot 已提交
361
	@Override
S
Skylot 已提交
362
	public void load() {
S
Skylot 已提交
363
		for (MethodNode mth : getMethods()) {
S
Skylot 已提交
364 365
			try {
				mth.load();
366
			} catch (Exception e) {
367
				mth.addError("Method load error", e);
S
Skylot 已提交
368
			}
S
Skylot 已提交
369 370 371 372
		}
		for (ClassNode innerCls : getInnerClasses()) {
			innerCls.load();
		}
S
Skylot 已提交
373
		setState(LOADED);
S
Skylot 已提交
374 375 376 377
	}

	@Override
	public void unload() {
378 379 380
		if (state == NOT_LOADED) {
			return;
		}
381 382 383 384
		methods.forEach(MethodNode::unload);
		innerClasses.forEach(ClassNode::unload);
		fields.forEach(FieldNode::unloadAttributes);
		unloadAttributes();
385
		setState(NOT_LOADED);
386
		this.loadStage = LoadStage.NONE;
387
		this.smali = null;
S
Skylot 已提交
388 389
	}

S
Skylot 已提交
390
	private void buildCache() {
S
Skylot 已提交
391
		mthInfoMap = new HashMap<>(methods.size());
S
Skylot 已提交
392 393 394 395 396
		for (MethodNode mth : methods) {
			mthInfoMap.put(mth.getMethodInfo(), mth);
		}
	}

S
Skylot 已提交
397 398
	@Nullable
	public ArgType getSuperClass() {
S
Skylot 已提交
399 400 401
		return superClass;
	}

S
Skylot 已提交
402
	public List<ArgType> getInterfaces() {
S
Skylot 已提交
403 404 405
		return interfaces;
	}

406
	public List<ArgType> getGenericTypeParameters() {
407
		return generics;
408 409
	}

410 411 412 413 414 415 416 417
	public ArgType getType() {
		ArgType clsType = clsInfo.getType();
		if (Utils.notEmpty(generics)) {
			return ArgType.generic(clsType, generics);
		}
		return clsType;
	}

S
Skylot 已提交
418 419 420 421 422 423 424 425
	public List<MethodNode> getMethods() {
		return methods;
	}

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

426 427 428 429
	public void addField(FieldNode fld) {
		fields.add(fld);
	}

430 431 432 433
	public FieldNode getConstField(Object obj) {
		return getConstField(obj, true);
	}

434
	@Nullable
435
	public FieldNode getConstField(Object obj, boolean searchGlobal) {
436
		return root().getConstValues().getConstField(this, obj, searchGlobal);
437 438
	}

439
	@Nullable
1
13.beta2 已提交
440
	public FieldNode getConstFieldByLiteralArg(LiteralArg arg) {
441
		return root().getConstValues().getConstFieldByLiteralArg(this, arg);
1
13.beta2 已提交
442 443
	}

444
	public FieldNode searchField(FieldInfo field) {
S
Skylot 已提交
445
		for (FieldNode f : fields) {
446
			if (f.getFieldInfo().equals(field)) {
S
Skylot 已提交
447
				return f;
S
Skylot 已提交
448
			}
S
Skylot 已提交
449 450 451 452
		}
		return null;
	}

453 454 455 456 457 458 459 460 461
	public FieldNode searchFieldByNameAndType(FieldInfo field) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().equalsNameAndType(field)) {
				return f;
			}
		}
		return null;
	}

S
Skylot 已提交
462
	public FieldNode searchFieldByName(String name) {
S
Skylot 已提交
463
		for (FieldNode f : fields) {
S
Skylot 已提交
464
			if (f.getName().equals(name)) {
S
Skylot 已提交
465
				return f;
S
Skylot 已提交
466
			}
S
Skylot 已提交
467 468 469 470
		}
		return null;
	}

471 472 473 474 475 476 477 478 479
	public FieldNode searchFieldByShortId(String shortId) {
		for (FieldNode f : fields) {
			if (f.getFieldInfo().getShortId().equals(shortId)) {
				return f;
			}
		}
		return null;
	}

S
Skylot 已提交
480
	public MethodNode searchMethod(MethodInfo mth) {
S
Skylot 已提交
481
		return mthInfoMap.get(mth);
S
Skylot 已提交
482 483
	}

484
	public MethodNode searchMethodByShortId(String shortId) {
S
Skylot 已提交
485
		for (MethodNode m : methods) {
S
Skylot 已提交
486
			if (m.getMethodInfo().getShortId().equals(shortId)) {
S
Skylot 已提交
487
				return m;
S
Skylot 已提交
488
			}
S
Skylot 已提交
489 490 491 492
		}
		return null;
	}

493 494
	/**
	 * Return first method by original short name
495 496
	 * Note: methods are not unique by name (class can have several methods with same name but different
	 * signature)
497 498 499 500 501 502 503 504 505 506 507
	 */
	@Nullable
	public MethodNode searchMethodByShortName(String name) {
		for (MethodNode m : methods) {
			if (m.getMethodInfo().getName().equals(name)) {
				return m;
			}
		}
		return null;
	}

508
	public ClassNode getParentClass() {
509 510 511 512 513 514 515 516 517
		return parentClass;
	}

	public void updateParentClass() {
		if (clsInfo.isInner()) {
			ClassNode parent = root.resolveClass(clsInfo.getParentClass());
			if (parent != null) {
				parentClass = parent;
				return;
518 519
			}
		}
520
		parentClass = this;
521 522
	}

523 524
	public ClassNode getTopParentClass() {
		ClassNode parent = getParentClass();
525
		return parent == this ? this : parent.getTopParentClass();
526 527
	}

528 529 530 531 532 533 534 535 536 537
	public void visitParentClasses(Consumer<ClassNode> consumer) {
		ClassNode currentCls = this;
		ClassNode parentCls = currentCls.getParentClass();
		while (parentCls != currentCls) {
			consumer.accept(parentCls);
			currentCls = parentCls;
			parentCls = currentCls.getParentClass();
		}
	}

538 539 540 541 542 543 544 545 546 547 548 549 550
	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);
		}
	}

551 552 553 554 555 556 557 558 559 560 561
	public boolean hasNotGeneratedParent() {
		if (contains(AFlag.DONT_GENERATE)) {
			return true;
		}
		ClassNode parent = getParentClass();
		if (parent == this) {
			return false;
		}
		return parent.hasNotGeneratedParent();
	}

S
Skylot 已提交
562 563 564 565
	public List<ClassNode> getInnerClasses() {
		return innerClasses;
	}

566 567 568 569
	public List<ClassNode> getInlinedClasses() {
		return inlinedClasses;
	}

570
	/**
571
	 * Get all inner and inlined classes recursively
572
	 *
573 574
	 * @param resultClassesSet
	 *                         all identified inner and inlined classes are added to this set
575
	 */
576 577 578 579 580 581 582 583 584 585
	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);
			}
586 587 588
		}
	}

S
Skylot 已提交
589
	public void addInnerClass(ClassNode cls) {
590 591 592
		if (innerClasses.isEmpty()) {
			innerClasses = new ArrayList<>(5);
		}
S
Skylot 已提交
593
		innerClasses.add(cls);
594
		cls.parentClass = this;
S
Skylot 已提交
595 596
	}

597 598 599 600 601 602 603
	public void addInlinedClass(ClassNode cls) {
		if (inlinedClasses.isEmpty()) {
			inlinedClasses = new ArrayList<>(5);
		}
		inlinedClasses.add(cls);
	}

604
	public boolean isEnum() {
S
Skylot 已提交
605 606 607
		return getAccessFlags().isEnum()
				&& getSuperClass() != null
				&& getSuperClass().getObject().equals(ArgType.ENUM.getObject());
608 609
	}

S
Skylot 已提交
610
	public boolean isAnonymous() {
611
		return contains(AFlag.ANONYMOUS_CLASS);
612 613
	}

614
	public boolean isInner() {
615
		return parentClass != this;
616 617
	}

618 619 620 621
	public boolean isTopClass() {
		return parentClass == this;
	}

622 623
	@Nullable
	public MethodNode getClassInitMth() {
624
		return searchMethodByShortId("<clinit>()V");
625 626 627
	}

	@Nullable
S
Skylot 已提交
628 629
	public MethodNode getDefaultConstructor() {
		for (MethodNode mth : methods) {
630
			if (mth.isDefaultConstructor()) {
S
Skylot 已提交
631
				return mth;
S
Skylot 已提交
632 633
			}
		}
S
Skylot 已提交
634
		return null;
S
Skylot 已提交
635 636
	}

637
	@Override
S
Skylot 已提交
638 639 640 641
	public AccessInfo getAccessFlags() {
		return accessFlags;
	}

642 643 644 645 646
	@Override
	public void setAccessFlags(AccessInfo accessFlags) {
		this.accessFlags = accessFlags;
	}

647 648
	@Override
	public RootNode root() {
649
		return root;
650 651
	}

652 653 654 655 656
	@Override
	public String typeName() {
		return "class";
	}

S
Skylot 已提交
657 658 659 660 661 662 663
	public String getRawName() {
		return clsInfo.getRawName();
	}

	/**
	 * Internal class info (don't use in code generation and external api).
	 */
S
Skylot 已提交
664 665 666 667 668
	public ClassInfo getClassInfo() {
		return clsInfo;
	}

	public String getShortName() {
669
		return clsInfo.getAliasShortName();
S
Skylot 已提交
670 671 672
	}

	public String getFullName() {
673
		return clsInfo.getAliasFullName();
S
Skylot 已提交
674 675 676
	}

	public String getPackage() {
677
		return clsInfo.getAliasPkg();
678 679
	}

S
Skylot 已提交
680
	public String getDisassembledCode() {
681
		if (smali == null) {
682
			StringBuilder sb = new StringBuilder();
S
Skylot 已提交
683 684
			getDisassembledCode(sb);
			sb.append(ICodeWriter.NL);
685 686 687
			Set<ClassNode> allInlinedClasses = new LinkedHashSet<>();
			getInnerAndInlinedClassesRecursive(allInlinedClasses);
			for (ClassNode innerClass : allInlinedClasses) {
S
Skylot 已提交
688 689
				innerClass.getDisassembledCode(sb);
				sb.append(ICodeWriter.NL);
690
			}
691
			smali = sb.toString();
692
		}
693 694 695
		return smali;
	}

S
Skylot 已提交
696 697
	protected void getDisassembledCode(StringBuilder sb) {
		if (clsData == null) {
698 699
			sb.append(String.format("###### Class %s is created by jadx", getFullName()));
			return;
700
		}
701
		sb.append(String.format("###### Class %s (%s)", getFullName(), getRawName()));
S
Skylot 已提交
702 703
		sb.append(ICodeWriter.NL);
		sb.append(clsData.getDisassembledCode());
704 705
	}

706 707
	public IClassData getClsData() {
		return clsData;
708 709
	}

710 711 712 713 714 715 716 717
	public ProcessState getState() {
		return state;
	}

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

718 719 720 721
	public LoadStage getLoadStage() {
		return loadStage;
	}

722 723
	public void setLoadStage(LoadStage loadStage) {
		this.loadStage = loadStage;
724 725 726 727 728
	}

	public void reloadAtCodegenStage() {
		ClassNode topCls = this.getTopParentClass();
		if (topCls.getLoadStage() == LoadStage.CODEGEN_STAGE) {
729
			throw new JadxRuntimeException("Class not yet loaded at codegen stage: " + topCls);
730 731 732 733
		}
		topCls.add(AFlag.RELOAD_AT_CODEGEN_STAGE);
	}

S
Skylot 已提交
734
	public List<ClassNode> getDependencies() {
735 736 737
		return dependencies;
	}

S
Skylot 已提交
738 739 740 741
	public void setDependencies(List<ClassNode> dependencies) {
		this.dependencies = dependencies;
	}

742 743 744 745 746 747 748 749
	public List<ClassNode> getCodegenDeps() {
		return codegenDeps;
	}

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

750 751 752 753 754 755 756 757 758 759
	public List<ClassNode> getUseIn() {
		return useIn;
	}

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

	public List<MethodNode> getUseInMth() {
		return useInMth;
760 761
	}

762 763
	public void setUseInMth(List<MethodNode> useInMth) {
		this.useInMth = useInMth;
764 765
	}

766
	@Override
767 768
	public String getInputFileName() {
		return clsData == null ? "synthetic" : clsData.getInputFileName();
769 770
	}

771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
	@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;
	}

788 789 790 791 792
	@Override
	public int compareTo(@NotNull ClassNode o) {
		return this.getFullName().compareTo(o.getFullName());
	}

S
Skylot 已提交
793 794
	@Override
	public String toString() {
S
Skylot 已提交
795
		return clsInfo.getFullName();
S
Skylot 已提交
796 797
	}
}