ClassGen.java 23.8 KB
Newer Older
S
Skylot 已提交
1 2
package jadx.core.codegen;

S
Skylot 已提交
3
import java.util.ArrayList;
S
Skylot 已提交
4
import java.util.Collection;
5
import java.util.Collections;
S
Skylot 已提交
6 7 8 9
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
10
import java.util.Objects;
S
Skylot 已提交
11
import java.util.Set;
12
import java.util.stream.Collectors;
S
Skylot 已提交
13
import java.util.stream.Stream;
S
Skylot 已提交
14

15
import org.jetbrains.annotations.NotNull;
16 17
import org.jetbrains.annotations.Nullable;

18
import jadx.api.CommentsLevel;
19
import jadx.api.ICodeInfo;
S
Skylot 已提交
20
import jadx.api.ICodeWriter;
21
import jadx.api.JadxArgs;
22
import jadx.api.metadata.annotations.NodeEnd;
23 24 25
import jadx.api.plugins.input.data.AccessFlags;
import jadx.api.plugins.input.data.annotations.EncodedType;
import jadx.api.plugins.input.data.annotations.EncodedValue;
S
Skylot 已提交
26
import jadx.api.plugins.input.data.attributes.JadxAttrType;
27
import jadx.core.Consts;
S
Skylot 已提交
28 29
import jadx.core.dex.attributes.AFlag;
import jadx.core.dex.attributes.AType;
S
Skylot 已提交
30
import jadx.core.dex.attributes.FieldInitInsnAttr;
S
Skylot 已提交
31 32
import jadx.core.dex.attributes.nodes.EnumClassAttr;
import jadx.core.dex.attributes.nodes.EnumClassAttr.EnumField;
S
Skylot 已提交
33
import jadx.core.dex.attributes.nodes.LineAttrNode;
34
import jadx.core.dex.attributes.nodes.MethodInlineAttr;
35
import jadx.core.dex.attributes.nodes.SkipMethodArgsAttr;
S
Skylot 已提交
36 37 38
import jadx.core.dex.info.AccessInfo;
import jadx.core.dex.info.ClassInfo;
import jadx.core.dex.instructions.args.ArgType;
S
Skylot 已提交
39
import jadx.core.dex.instructions.args.LiteralArg;
40
import jadx.core.dex.instructions.args.PrimitiveType;
41
import jadx.core.dex.instructions.mods.ConstructorInsn;
S
Skylot 已提交
42 43
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.FieldNode;
44
import jadx.core.dex.nodes.InsnNode;
S
Skylot 已提交
45
import jadx.core.dex.nodes.MethodNode;
46
import jadx.core.dex.nodes.RootNode;
47
import jadx.core.utils.CodeGenUtils;
S
Skylot 已提交
48
import jadx.core.utils.EncodedValueUtils;
S
Skylot 已提交
49
import jadx.core.utils.Utils;
50
import jadx.core.utils.android.AndroidResourcesUtils;
S
Skylot 已提交
51
import jadx.core.utils.exceptions.CodegenException;
52
import jadx.core.utils.exceptions.JadxRuntimeException;
S
Skylot 已提交
53 54

public class ClassGen {
S
Skylot 已提交
55

S
Skylot 已提交
56 57 58 59
	private final ClassNode cls;
	private final ClassGen parentGen;
	private final AnnotationGen annotationGen;
	private final boolean fallback;
S
Sergey Toshin 已提交
60
	private final boolean useImports;
S
Skylot 已提交
61
	private final boolean showInconsistentCode;
62

S
Skylot 已提交
63
	private final Set<ClassInfo> imports = new HashSet<>();
S
Skylot 已提交
64
	private int clsDeclOffset;
S
Skylot 已提交
65

66 67
	private boolean bodyGenStarted;

68 69 70
	@Nullable
	private NameGen outerNameGen;

71 72
	public ClassGen(ClassNode cls, JadxArgs jadxArgs) {
		this(cls, null, jadxArgs.isUseImports(), jadxArgs.isFallbackMode(), jadxArgs.isShowInconsistentCode());
S
Skylot 已提交
73 74 75
	}

	public ClassGen(ClassNode cls, ClassGen parentClsGen) {
S
Sergey Toshin 已提交
76
		this(cls, parentClsGen, parentClsGen.useImports, parentClsGen.fallback, parentClsGen.showInconsistentCode);
77 78
	}

S
Sergey Toshin 已提交
79
	public ClassGen(ClassNode cls, ClassGen parentClsGen, boolean useImports, boolean fallback, boolean showBadCode) {
S
Skylot 已提交
80 81 82
		this.cls = cls;
		this.parentGen = parentClsGen;
		this.fallback = fallback;
S
Sergey Toshin 已提交
83
		this.useImports = useImports;
S
Skylot 已提交
84
		this.showInconsistentCode = showBadCode;
S
Skylot 已提交
85 86 87 88 89 90 91 92

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

	public ClassNode getClassNode() {
		return cls;
	}

93
	public ICodeInfo makeClass() throws CodegenException {
S
Skylot 已提交
94
		ICodeWriter clsBody = cls.root().makeCodeWriter();
S
Skylot 已提交
95 96
		addClassCode(clsBody);

S
Skylot 已提交
97
		ICodeWriter clsCode = cls.root().makeCodeWriter();
S
Skylot 已提交
98
		if (!"".equals(cls.getPackage())) {
S
Skylot 已提交
99
			clsCode.add("package ").add(cls.getPackage()).add(';');
100
			clsCode.newLine();
S
Skylot 已提交
101
		}
S
Skylot 已提交
102 103
		int importsCount = imports.size();
		if (importsCount != 0) {
104
			List<ClassInfo> sortedImports = new ArrayList<>(imports);
105
			sortedImports.sort(Comparator.comparing(ClassInfo::getAliasFullName));
106
			sortedImports.forEach(classInfo -> {
107
				clsCode.startLine("import ");
108
				ClassNode classNode = cls.root().resolveClass(classInfo);
109 110 111
				if (classNode != null) {
					clsCode.attachAnnotation(classNode);
				}
112
				clsCode.add(classInfo.getAliasFullName());
113
				clsCode.add(';');
114
			});
115
			clsCode.newLine();
S
Skylot 已提交
116 117 118
			imports.clear();
		}
		clsCode.add(clsBody);
119
		return clsCode.finish();
S
Skylot 已提交
120 121
	}

S
Skylot 已提交
122
	public void addClassCode(ICodeWriter code) throws CodegenException {
S
Skylot 已提交
123
		if (cls.contains(AFlag.DONT_GENERATE)) {
S
Skylot 已提交
124
			return;
S
Skylot 已提交
125
		}
126 127 128
		if (Consts.DEBUG_USAGE) {
			addClassUsageInfo(code, cls);
		}
129
		CodeGenUtils.addErrorsAndComments(code, cls);
130
		CodeGenUtils.addSourceFileInfo(code, cls);
S
Skylot 已提交
131 132
		addClassDeclaration(code);
		addClassBody(code);
S
Skylot 已提交
133 134
	}

S
Skylot 已提交
135
	public void addClassDeclaration(ICodeWriter clsCode) {
S
Skylot 已提交
136 137
		AccessInfo af = cls.getAccessFlags();
		if (af.isInterface()) {
138 139
			af = af.remove(AccessFlags.ABSTRACT)
					.remove(AccessFlags.STATIC);
S
Skylot 已提交
140
		} else if (af.isEnum()) {
141 142 143
			af = af.remove(AccessFlags.FINAL)
					.remove(AccessFlags.ABSTRACT)
					.remove(AccessFlags.STATIC);
S
Skylot 已提交
144 145
		}

146
		// 'static' and 'private' modifier not allowed for top classes (not inner)
147
		if (!cls.getClassInfo().isInner()) {
148
			af = af.remove(AccessFlags.STATIC).remove(AccessFlags.PRIVATE);
S
Skylot 已提交
149 150
		}

S
Skylot 已提交
151
		annotationGen.addForClass(clsCode);
152
		insertRenameInfo(clsCode, cls);
153
		CodeGenUtils.addInputFileInfo(clsCode, cls);
154
		clsCode.startLineWithNum(cls.getSourceLine()).add(af.makeString(cls.checkCommentsLevel(CommentsLevel.INFO)));
S
Skylot 已提交
155
		if (af.isInterface()) {
S
Skylot 已提交
156
			if (af.isAnnotation()) {
S
Skylot 已提交
157
				clsCode.add('@');
S
Skylot 已提交
158
			}
S
Skylot 已提交
159 160 161 162 163 164
			clsCode.add("interface ");
		} else if (af.isEnum()) {
			clsCode.add("enum ");
		} else {
			clsCode.add("class ");
		}
165
		clsCode.attachDefinition(cls);
166
		clsCode.add(cls.getClassInfo().getAliasShortName());
S
Skylot 已提交
167

168
		addGenericTypeParameters(clsCode, cls.getGenericTypeParameters(), true);
169 170
		clsCode.add(' ');

S
Skylot 已提交
171
		ArgType sup = cls.getSuperClass();
S
Skylot 已提交
172
		if (sup != null
S
Skylot 已提交
173
				&& !sup.equals(ArgType.OBJECT)
174
				&& !cls.isEnum()) {
175 176 177
			clsCode.add("extends ");
			useClass(clsCode, sup);
			clsCode.add(' ');
S
Skylot 已提交
178 179
		}

S
Skylot 已提交
180
		if (!cls.getInterfaces().isEmpty() && !af.isAnnotation()) {
S
Skylot 已提交
181
			if (cls.getAccessFlags().isInterface()) {
182
				clsCode.add("extends ");
S
Skylot 已提交
183
			} else {
184
				clsCode.add("implements ");
S
Skylot 已提交
185
			}
186
			for (Iterator<ArgType> it = cls.getInterfaces().iterator(); it.hasNext();) {
S
Skylot 已提交
187
				ArgType interf = it.next();
188
				useClass(clsCode, interf);
S
Skylot 已提交
189
				if (it.hasNext()) {
S
Skylot 已提交
190
					clsCode.add(", ");
S
Skylot 已提交
191
				}
S
Skylot 已提交
192
			}
S
Skylot 已提交
193
			if (!cls.getInterfaces().isEmpty()) {
194
				clsCode.add(' ');
S
Skylot 已提交
195
			}
196 197 198
		}
	}

S
Skylot 已提交
199
	public boolean addGenericTypeParameters(ICodeWriter code, List<ArgType> generics, boolean classDeclaration) {
200
		if (generics == null || generics.isEmpty()) {
S
Skylot 已提交
201
			return false;
S
Skylot 已提交
202
		}
203 204
		code.add('<');
		int i = 0;
205
		for (ArgType genericInfo : generics) {
206 207 208
			if (i != 0) {
				code.add(", ");
			}
209 210
			if (genericInfo.isGenericType()) {
				code.add(genericInfo.getObject());
211
			} else {
212
				useClass(code, genericInfo);
213
			}
214
			List<ArgType> list = genericInfo.getExtendTypes();
215 216
			if (list != null && !list.isEmpty()) {
				code.add(" extends ");
217
				for (Iterator<ArgType> it = list.iterator(); it.hasNext();) {
218
					ArgType g = it.next();
219 220 221
					if (g.isGenericType()) {
						code.add(g.getObject());
					} else {
S
Skylot 已提交
222
						useClass(code, g);
223 224 225
						if (classDeclaration
								&& !cls.getClassInfo().isInner()
								&& cls.root().getArgs().isUseImports()) {
226
							addImport(ClassInfo.fromType(cls.root(), g));
227
						}
228
					}
229 230 231 232 233 234
					if (it.hasNext()) {
						code.add(" & ");
					}
				}
			}
			i++;
S
Skylot 已提交
235
		}
236
		code.add('>');
S
Skylot 已提交
237
		return true;
S
Skylot 已提交
238 239
	}

S
Skylot 已提交
240
	public void addClassBody(ICodeWriter clsCode) throws CodegenException {
241 242 243 244 245 246 247
		addClassBody(clsCode, false);
	}

	/**
	 * @param printClassName allows to print the original class name as comment (e.g. for inlined
	 *                       classes)
	 */
S
Skylot 已提交
248
	public void addClassBody(ICodeWriter clsCode, boolean printClassName) throws CodegenException {
249
		clsCode.add('{');
250
		if (printClassName && cls.checkCommentsLevel(CommentsLevel.INFO)) {
251 252
			clsCode.add(" // from class: " + cls.getClassInfo().getFullName());
		}
253
		setBodyGenStarted(true);
S
Skylot 已提交
254
		clsDeclOffset = clsCode.getLength();
S
Skylot 已提交
255 256
		clsCode.incIndent();
		addFields(clsCode);
257
		addInnerClsAndMethods(clsCode);
S
Skylot 已提交
258
		clsCode.decIndent();
259
		clsCode.startLine('}');
260
		clsCode.attachAnnotation(NodeEnd.VALUE);
S
Skylot 已提交
261 262
	}

S
Skylot 已提交
263
	private void addInnerClsAndMethods(ICodeWriter clsCode) {
S
Skylot 已提交
264 265
		Stream.of(cls.getInnerClasses(), cls.getMethods())
				.flatMap(Collection::stream)
266
				.filter(node -> !node.contains(AFlag.DONT_GENERATE) || fallback)
267 268 269 270 271 272 273 274 275 276
				.sorted(Comparator.comparingInt(LineAttrNode::getSourceLine))
				.forEach(node -> {
					if (node instanceof ClassNode) {
						addInnerClass(clsCode, (ClassNode) node);
					} else {
						addMethod(clsCode, (MethodNode) node);
					}
				});
	}

S
Skylot 已提交
277
	private void addInnerClass(ICodeWriter code, ClassNode innerCls) {
278
		try {
S
Skylot 已提交
279
			ClassGen inClGen = new ClassGen(innerCls, getParentGen());
S
Skylot 已提交
280 281 282
			code.newLine();
			inClGen.addClassCode(code);
			imports.addAll(inClGen.getImports());
283
		} catch (Exception e) {
284
			innerCls.addError("Inner class code generation error", e);
S
Skylot 已提交
285 286 287 288
		}
	}

	private boolean isInnerClassesPresents() {
S
Skylot 已提交
289
		for (ClassNode innerCls : cls.getInnerClasses()) {
290
			if (!innerCls.contains(AType.ANONYMOUS_CLASS)) {
S
Skylot 已提交
291
				return true;
S
Skylot 已提交
292
			}
S
Skylot 已提交
293
		}
S
Skylot 已提交
294
		return false;
S
Skylot 已提交
295 296
	}

S
Skylot 已提交
297
	private void addMethod(ICodeWriter code, MethodNode mth) {
298 299 300
		if (skipMethod(mth)) {
			return;
		}
S
Skylot 已提交
301
		if (code.getLength() != clsDeclOffset) {
302 303 304 305 306 307 308 309
			code.newLine();
		}
		int savedIndent = code.getIndent();
		try {
			addMethodCode(code, mth);
		} catch (Exception e) {
			if (mth.getParentClass().getTopParentClass().contains(AFlag.RESTART_CODEGEN)) {
				throw new JadxRuntimeException("Method generation error", e);
S
Skylot 已提交
310
			}
311 312
			mth.addError("Method generation error", e);
			CodeGenUtils.addErrors(code, mth);
313
			code.setIndent(savedIndent);
S
Skylot 已提交
314 315 316
		}
	}

317 318 319 320 321 322 323 324
	/**
	 * Additional checks for inlined methods
	 */
	private boolean skipMethod(MethodNode mth) {
		MethodInlineAttr inlineAttr = mth.get(AType.METHOD_INLINE);
		if (inlineAttr == null || inlineAttr.notNeeded()) {
			return false;
		}
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
		try {
			if (mth.getUseIn().isEmpty()) {
				mth.add(AFlag.DONT_GENERATE);
				return true;
			}
			List<MethodNode> useInCompleted = mth.getUseIn().stream()
					.filter(m -> m.getTopParentClass().getState().isProcessComplete())
					.collect(Collectors.toList());
			if (useInCompleted.isEmpty()) {
				mth.add(AFlag.DONT_GENERATE);
				return true;
			}
			mth.addDebugComment("Method not inlined, still used in: " + useInCompleted);
			return false;
		} catch (Exception e) {
			// check failed => keep method
			mth.addWarnComment("Failed to check method usage", e);
			return false;
343 344 345
		}
	}

S
Skylot 已提交
346
	private boolean isMethodsPresents() {
S
Skylot 已提交
347
		for (MethodNode mth : cls.getMethods()) {
S
Skylot 已提交
348
			if (!mth.contains(AFlag.DONT_GENERATE)) {
S
Skylot 已提交
349
				return true;
350
			}
S
Skylot 已提交
351
		}
S
Skylot 已提交
352
		return false;
S
Skylot 已提交
353 354
	}

S
Skylot 已提交
355
	public void addMethodCode(ICodeWriter code, MethodNode mth) throws CodegenException {
356
		CodeGenUtils.addErrorsAndComments(code, mth);
357
		if (mth.isNoCode()) {
S
Skylot 已提交
358
			MethodGen mthGen = new MethodGen(this, mth);
S
Skylot 已提交
359 360 361
			mthGen.addDefinition(code);
			code.add(';');
		} else {
S
Skylot 已提交
362
			boolean badCode = mth.contains(AFlag.INCONSISTENT_CODE);
S
Skylot 已提交
363 364
			if (badCode && showInconsistentCode) {
				badCode = false;
S
Skylot 已提交
365
			}
S
Skylot 已提交
366
			MethodGen mthGen;
S
Skylot 已提交
367
			if (badCode || fallback || mth.contains(AType.JADX_ERROR)) {
S
Skylot 已提交
368 369 370 371
				mthGen = MethodGen.getFallbackMethodGen(mth);
			} else {
				mthGen = new MethodGen(this, mth);
			}
S
Skylot 已提交
372 373 374 375 376
			if (mthGen.addDefinition(code)) {
				code.add(' ');
			}
			code.add('{');
			code.incIndent();
377
			mthGen.addInstructions(code);
S
Skylot 已提交
378 379
			code.decIndent();
			code.startLine('}');
380
			code.attachAnnotation(NodeEnd.VALUE);
S
Skylot 已提交
381 382
		}
	}
383

S
Skylot 已提交
384
	private void addFields(ICodeWriter code) throws CodegenException {
S
Skylot 已提交
385 386
		addEnumFields(code);
		for (FieldNode f : cls.getFields()) {
387 388 389
			addField(code, f);
		}
	}
390

S
Skylot 已提交
391
	public void addField(ICodeWriter code, FieldNode f) {
392 393 394
		if (f.contains(AFlag.DONT_GENERATE)) {
			return;
		}
395 396 397
		if (Consts.DEBUG_USAGE) {
			addFieldUsageInfo(code, f);
		}
398 399 400
		CodeGenUtils.addComments(code, f);
		annotationGen.addForField(code, f);

401 402
		boolean addInfoComments = f.checkCommentsLevel(CommentsLevel.INFO);
		if (f.getFieldInfo().isRenamed() && addInfoComments) {
403 404 405
			code.newLine();
			CodeGenUtils.addRenamedComment(code, f, f.getName());
		}
406
		code.startLine(f.getAccessFlags().makeString(addInfoComments));
407 408 409 410
		useType(code, f.getType());
		code.add(' ');
		code.attachDefinition(f);
		code.add(f.getAlias());
S
Skylot 已提交
411 412 413 414

		FieldInitInsnAttr initInsnAttr = f.get(AType.FIELD_INIT_INSN);
		if (initInsnAttr != null) {
			InsnGen insnGen = makeInsnGen(initInsnAttr.getInsnMth());
415
			code.add(" = ");
S
Skylot 已提交
416 417 418 419 420 421
			addInsnBody(insnGen, code, initInsnAttr.getInsn());
		} else {
			EncodedValue constVal = f.get(JadxAttrType.CONSTANT_VALUE);
			if (constVal != null) {
				code.add(" = ");
				if (constVal.getType() == EncodedType.ENCODED_NULL) {
422 423
					code.add(TypeGen.literalToString(0, f.getType(), cls, fallback));
				} else {
S
Skylot 已提交
424 425 426 427 428 429 430 431 432
					Object val = EncodedValueUtils.convertToConstValue(constVal);
					if (val instanceof LiteralArg) {
						long lit = ((LiteralArg) val).getLiteral();
						if (!AndroidResourcesUtils.handleResourceFieldValue(cls, code, lit, f.getType())) {
							// force literal type to be same as field (java bytecode can use different type)
							code.add(TypeGen.literalToString(lit, f.getType(), cls, fallback));
						}
					} else {
						annotationGen.encodeValue(cls.root(), code, constVal);
433
					}
434 435 436
				}
			}
		}
437
		code.add(';');
438 439
	}

S
Skylot 已提交
440 441 442 443 444 445 446 447 448
	private boolean isFieldsPresents() {
		for (FieldNode field : cls.getFields()) {
			if (!field.contains(AFlag.DONT_GENERATE)) {
				return true;
			}
		}
		return false;
	}

S
Skylot 已提交
449
	private void addEnumFields(ICodeWriter code) throws CodegenException {
S
Skylot 已提交
450
		EnumClassAttr enumFields = cls.get(AType.ENUM_CLASS);
451 452 453 454
		if (enumFields == null) {
			return;
		}
		InsnGen igen = null;
455
		for (Iterator<EnumField> it = enumFields.getFields().iterator(); it.hasNext();) {
456
			EnumField f = it.next();
457 458

			CodeGenUtils.addComments(code, f.getField());
459
			code.startLine(f.getField().getAlias());
460
			ConstructorInsn constrInsn = f.getConstrInsn();
461
			MethodNode callMth = cls.root().resolveMethod(constrInsn.getCallMth());
462 463
			int skipCount = getEnumCtrSkipArgsCount(callMth);
			if (constrInsn.getArgsCount() > skipCount) {
464
				if (igen == null) {
465
					igen = makeInsnGen(enumFields.getStaticMethod());
S
Skylot 已提交
466
				}
467
				igen.generateMethodArguments(code, constrInsn, 0, callMth);
S
Skylot 已提交
468
			}
469
			if (f.getCls() != null) {
S
Skylot 已提交
470
				code.add(' ');
471
				new ClassGen(f.getCls(), this).addClassBody(code, true);
S
Skylot 已提交
472
			}
473 474 475 476
			if (it.hasNext()) {
				code.add(',');
			}
		}
S
Skylot 已提交
477 478 479 480 481
		if (isMethodsPresents() || isFieldsPresents() || isInnerClassesPresents()) {
			if (enumFields.getFields().isEmpty()) {
				code.startLine();
			}
			code.add(';');
482 483 484
			if (isFieldsPresents()) {
				code.startLine();
			}
S
Skylot 已提交
485 486 487
		}
	}

488 489 490 491 492 493 494 495 496 497
	private int getEnumCtrSkipArgsCount(@Nullable MethodNode callMth) {
		if (callMth != null) {
			SkipMethodArgsAttr skipArgsAttr = callMth.get(AType.SKIP_MTH_ARGS);
			if (skipArgsAttr != null) {
				return skipArgsAttr.getSkipCount();
			}
		}
		return 0;
	}

498 499 500 501 502
	private InsnGen makeInsnGen(MethodNode mth) {
		MethodGen mthGen = new MethodGen(this, mth);
		return new InsnGen(mthGen, false);
	}

S
Skylot 已提交
503
	private void addInsnBody(InsnGen insnGen, ICodeWriter code, InsnNode insn) {
504 505 506
		try {
			insnGen.makeInsn(insn, code, InsnGen.Flags.BODY_ONLY_NOWRAP);
		} catch (Exception e) {
507
			cls.addError("Failed to generate init code", e);
508 509 510
		}
	}

S
Skylot 已提交
511
	public void useType(ICodeWriter code, ArgType type) {
S
Skylot 已提交
512
		PrimitiveType stype = type.getPrimitiveType();
513 514 515 516 517 518
		if (stype == null) {
			code.add(type.toString());
		} else if (stype == PrimitiveType.OBJECT) {
			if (type.isGenericType()) {
				code.add(type.getObject());
			} else {
S
Skylot 已提交
519
				useClass(code, type);
520 521 522 523 524 525
			}
		} else if (stype == PrimitiveType.ARRAY) {
			useType(code, type.getArrayElement());
			code.add("[]");
		} else {
			code.add(stype.getLongName());
526 527
		}
	}
528

S
Skylot 已提交
529
	public void useClass(ICodeWriter code, String rawCls) {
530 531 532
		useClass(code, ArgType.object(rawCls));
	}

S
Skylot 已提交
533
	public void useClass(ICodeWriter code, ArgType type) {
534 535 536 537
		ArgType outerType = type.getOuterType();
		if (outerType != null) {
			useClass(code, outerType);
			code.add('.');
538
			addInnerType(code, type);
539 540
			return;
		}
541
		useClass(code, ClassInfo.fromType(cls.root(), type));
542 543 544 545 546 547 548
		addGenerics(code, type);
	}

	private void addInnerType(ICodeWriter code, ArgType baseType) {
		ArgType innerType = baseType.getInnerType();
		ArgType outerType = innerType.getOuterType();
		if (outerType != null) {
549
			useClassWithShortName(code, baseType, outerType);
550 551 552 553
			code.add('.');
			addInnerType(code, innerType);
			return;
		}
554 555 556 557
		useClassWithShortName(code, baseType, innerType);
	}

	private void useClassWithShortName(ICodeWriter code, ArgType baseType, ArgType type) {
558
		String fullNameObj;
559 560
		if (type.getObject().contains(".")) {
			fullNameObj = type.getObject();
561 562 563 564 565 566 567 568 569
		} else {
			fullNameObj = baseType.getObject();
		}
		ClassInfo classInfo = ClassInfo.fromName(cls.root(), fullNameObj);
		ClassNode classNode = cls.root().resolveClass(classInfo);
		if (classNode != null) {
			code.attachAnnotation(classNode);
		}
		code.add(classInfo.getAliasShortName());
570
		addGenerics(code, type);
571 572 573
	}

	private void addGenerics(ICodeWriter code, ArgType type) {
574
		List<ArgType> generics = type.getGenericTypes();
575 576
		if (generics != null) {
			code.add('<');
577
			int len = generics.size();
578 579 580 581
			for (int i = 0; i < len; i++) {
				if (i != 0) {
					code.add(", ");
				}
582
				ArgType gt = generics.get(i);
583 584
				ArgType wt = gt.getWildcardType();
				if (wt != null) {
585 586 587
					ArgType.WildcardBound bound = gt.getWildcardBound();
					code.add(bound.getStr());
					if (bound != ArgType.WildcardBound.UNBOUND) {
588 589 590 591
						useType(code, wt);
					}
				} else {
					useType(code, gt);
S
Skylot 已提交
592
				}
593
			}
594
			code.add('>');
595
		}
S
Skylot 已提交
596 597
	}

S
Skylot 已提交
598
	public void useClass(ICodeWriter code, ClassInfo classInfo) {
599
		ClassNode classNode = cls.root().resolveClass(classInfo);
S
Skylot 已提交
600
		if (classNode != null) {
601 602 603
			useClass(code, classNode);
		} else {
			addClsName(code, classInfo);
S
Skylot 已提交
604
		}
605 606
	}

S
Skylot 已提交
607
	public void useClass(ICodeWriter code, ClassNode classNode) {
608 609 610 611
		code.attachAnnotation(classNode);
		addClsName(code, classNode.getClassInfo());
	}

612
	public void addClsName(ICodeWriter code, ClassInfo classInfo) {
613
		String clsName = useClassInternal(cls.getClassInfo(), classInfo);
614
		code.add(clsName);
S
Skylot 已提交
615 616 617
	}

	private String useClassInternal(ClassInfo useCls, ClassInfo extClsInfo) {
618
		String fullName = extClsInfo.getAliasFullName();
S
Sergey Toshin 已提交
619
		if (fallback || !useImports) {
620
			return fullName;
S
Skylot 已提交
621
		}
622
		String shortName = extClsInfo.getAliasShortName();
623 624 625
		if (useCls.equals(extClsInfo)) {
			return shortName;
		}
S
Skylot 已提交
626 627 628
		if (isClassInnerFor(useCls, extClsInfo)) {
			return shortName;
		}
629 630 631
		if (extClsInfo.isInner()) {
			return expandInnerClassName(useCls, extClsInfo);
		}
632 633
		if (checkInnerCollision(cls.root(), useCls, extClsInfo)
				|| checkInPackageCollision(cls.root(), useCls, extClsInfo)) {
634 635
			return fullName;
		}
S
Skylot 已提交
636 637 638
		if (isBothClassesInOneTopClass(useCls, extClsInfo)) {
			return shortName;
		}
639 640 641 642
		// don't add import for top classes from 'java.lang' package (subpackages excluded)
		if (extClsInfo.getPackage().equals("java.lang") && extClsInfo.getParentClass() == null) {
			return shortName;
		}
S
Skylot 已提交
643 644 645 646
		// don't add import if this class from same package
		if (extClsInfo.getPackage().equals(useCls.getPackage()) && !extClsInfo.isInner()) {
			return shortName;
		}
647 648 649 650
		// ignore classes from default package
		if (extClsInfo.isDefaultPackage()) {
			return shortName;
		}
651 652
		if (extClsInfo.getAliasPkg().equals(useCls.getAliasPkg())) {
			fullName = extClsInfo.getAliasNameWithoutPackage();
S
Skylot 已提交
653 654 655
		}
		for (ClassInfo importCls : getImports()) {
			if (!importCls.equals(extClsInfo)
656
					&& importCls.getAliasShortName().equals(shortName)) {
S
Skylot 已提交
657
				if (extClsInfo.isInner()) {
658
					String parent = useClassInternal(useCls, extClsInfo.getParentClass());
659
					return parent + '.' + shortName;
S
Skylot 已提交
660 661
				} else {
					return fullName;
S
Skylot 已提交
662 663 664
				}
			}
		}
S
Skylot 已提交
665 666
		addImport(extClsInfo);
		return shortName;
S
Skylot 已提交
667 668
	}

669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688
	private String expandInnerClassName(ClassInfo useCls, ClassInfo extClsInfo) {
		List<ClassInfo> clsList = new ArrayList<>();
		clsList.add(extClsInfo);
		ClassInfo parentCls = extClsInfo.getParentClass();
		boolean addImport = true;
		while (parentCls != null) {
			if (parentCls == useCls || isClassInnerFor(useCls, parentCls)) {
				addImport = false;
				break;
			}
			clsList.add(parentCls);
			parentCls = parentCls.getParentClass();
		}
		Collections.reverse(clsList);
		if (addImport) {
			addImport(clsList.get(0));
		}
		return Utils.listToString(clsList, ".", ClassInfo::getAliasShortName);
	}

689 690
	private void addImport(ClassInfo classInfo) {
		if (parentGen != null) {
691
			parentGen.addImport(classInfo);
692 693 694 695 696
		} else {
			imports.add(classInfo);
		}
	}

697
	public Set<ClassInfo> getImports() {
698 699 700 701 702 703 704
		if (parentGen != null) {
			return parentGen.getImports();
		} else {
			return imports;
		}
	}

S
Skylot 已提交
705 706 707 708 709 710 711 712 713 714
	private static boolean isBothClassesInOneTopClass(ClassInfo useCls, ClassInfo extClsInfo) {
		ClassInfo a = useCls.getTopParentClass();
		ClassInfo b = extClsInfo.getTopParentClass();
		if (a != null) {
			return a.equals(b);
		}
		// useCls - is a top class
		return useCls.equals(b);
	}

S
Skylot 已提交
715
	private static boolean isClassInnerFor(ClassInfo inner, ClassInfo parent) {
S
Skylot 已提交
716 717
		if (inner.isInner()) {
			ClassInfo p = inner.getParentClass();
718
			return Objects.equals(p, parent) || isClassInnerFor(p, parent);
S
Skylot 已提交
719 720 721 722
		}
		return false;
	}

723
	private static boolean checkInnerCollision(RootNode root, @Nullable ClassInfo useCls, ClassInfo searchCls) {
S
Skylot 已提交
724 725 726
		if (useCls == null) {
			return false;
		}
727 728
		String shortName = searchCls.getAliasShortName();
		if (useCls.getAliasShortName().equals(shortName)) {
S
Skylot 已提交
729 730
			return true;
		}
731
		ClassNode classNode = root.resolveClass(useCls);
732 733
		if (classNode != null) {
			for (ClassNode inner : classNode.getInnerClasses()) {
734 735
				if (inner.getShortName().equals(shortName)
						&& !inner.getFullName().equals(searchCls.getAliasFullName())) {
736 737
					return true;
				}
S
Skylot 已提交
738 739
			}
		}
740 741 742 743 744 745 746 747 748 749 750 751 752 753
		return checkInnerCollision(root, useCls.getParentClass(), searchCls);
	}

	/**
	 * Check if class with same name exists in current package
	 */
	private static boolean checkInPackageCollision(RootNode root, ClassInfo useCls, ClassInfo searchCls) {
		String currentPkg = useCls.getAliasPkg();
		if (currentPkg.equals(searchCls.getAliasPkg())) {
			// search class already from current package
			return false;
		}
		String shortName = searchCls.getAliasShortName();
		return root.getClsp().isClsKnown(currentPkg + '.' + shortName);
S
Skylot 已提交
754 755
	}

S
Skylot 已提交
756
	private void insertRenameInfo(ICodeWriter code, ClassNode cls) {
757
		ClassInfo classInfo = cls.getClassInfo();
758
		if (classInfo.hasAlias() && cls.checkCommentsLevel(CommentsLevel.INFO)) {
759
			CodeGenUtils.addRenamedComment(code, cls, classInfo.getType().getObject());
760 761 762
		}
	}

S
Skylot 已提交
763
	private static void addClassUsageInfo(ICodeWriter code, ClassNode cls) {
764 765 766
		List<ClassNode> deps = cls.getDependencies();
		code.startLine("// deps - ").add(Integer.toString(deps.size()));
		for (ClassNode depCls : deps) {
767
			code.startLine("//  ").add(depCls.getClassInfo().getFullName());
768 769 770 771
		}
		List<ClassNode> useIn = cls.getUseIn();
		code.startLine("// use in - ").add(Integer.toString(useIn.size()));
		for (ClassNode useCls : useIn) {
772
			code.startLine("//  ").add(useCls.getClassInfo().getFullName());
773 774 775 776 777 778 779 780
		}
		List<MethodNode> useInMths = cls.getUseInMth();
		code.startLine("// use in methods - ").add(Integer.toString(useInMths.size()));
		for (MethodNode useMth : useInMths) {
			code.startLine("//  ").add(useMth.toString());
		}
	}

S
Skylot 已提交
781
	static void addMthUsageInfo(ICodeWriter code, MethodNode mth) {
782 783 784 785 786 787 788
		List<MethodNode> useInMths = mth.getUseIn();
		code.startLine("// use in methods - ").add(Integer.toString(useInMths.size()));
		for (MethodNode useMth : useInMths) {
			code.startLine("//  ").add(useMth.toString());
		}
	}

S
Skylot 已提交
789
	private static void addFieldUsageInfo(ICodeWriter code, FieldNode fieldNode) {
790 791 792 793 794 795 796
		List<MethodNode> useInMths = fieldNode.getUseIn();
		code.startLine("// use in methods - ").add(Integer.toString(useInMths.size()));
		for (MethodNode useMth : useInMths) {
			code.startLine("//  ").add(useMth.toString());
		}
	}

S
Skylot 已提交
797
	public ClassGen getParentGen() {
798
		return parentGen == null ? this : parentGen;
S
Skylot 已提交
799 800 801 802 803 804 805 806 807
	}

	public AnnotationGen getAnnotationGen() {
		return annotationGen;
	}

	public boolean isFallbackMode() {
		return fallback;
	}
808 809 810 811 812 813 814 815

	public boolean isBodyGenStarted() {
		return bodyGenStarted;
	}

	public void setBodyGenStarted(boolean bodyGenStarted) {
		this.bodyGenStarted = bodyGenStarted;
	}
816 817 818 819 820 821 822 823 824

	@Nullable
	public NameGen getOuterNameGen() {
		return outerNameGen;
	}

	public void setOuterNameGen(@NotNull NameGen outerNameGen) {
		this.outerNameGen = outerNameGen;
	}
S
Skylot 已提交
825
}