Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java
58461 views
1
/*
2
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.tools.javap;
27
28
import java.net.URI;
29
import java.text.DateFormat;
30
import java.util.Collection;
31
import java.util.Date;
32
import java.util.List;
33
import java.util.Set;
34
35
import com.sun.tools.classfile.AccessFlags;
36
import com.sun.tools.classfile.Attribute;
37
import com.sun.tools.classfile.Attributes;
38
import com.sun.tools.classfile.ClassFile;
39
import com.sun.tools.classfile.Code_attribute;
40
import com.sun.tools.classfile.ConstantPool;
41
import com.sun.tools.classfile.ConstantPoolException;
42
import com.sun.tools.classfile.ConstantValue_attribute;
43
import com.sun.tools.classfile.Descriptor;
44
import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
45
import com.sun.tools.classfile.Exceptions_attribute;
46
import com.sun.tools.classfile.Field;
47
import com.sun.tools.classfile.Method;
48
import com.sun.tools.classfile.Module_attribute;
49
import com.sun.tools.classfile.Signature;
50
import com.sun.tools.classfile.Signature_attribute;
51
import com.sun.tools.classfile.SourceFile_attribute;
52
import com.sun.tools.classfile.Type;
53
import com.sun.tools.classfile.Type.ArrayType;
54
import com.sun.tools.classfile.Type.ClassSigType;
55
import com.sun.tools.classfile.Type.ClassType;
56
import com.sun.tools.classfile.Type.MethodType;
57
import com.sun.tools.classfile.Type.SimpleType;
58
import com.sun.tools.classfile.Type.TypeParamType;
59
import com.sun.tools.classfile.Type.WildcardType;
60
61
import static com.sun.tools.classfile.AccessFlags.*;
62
import static com.sun.tools.classfile.ConstantPool.CONSTANT_Module;
63
import static com.sun.tools.classfile.ConstantPool.CONSTANT_Package;
64
65
/*
66
* The main javap class to write the contents of a class file as text.
67
*
68
* <p><b>This is NOT part of any supported API.
69
* If you write code that depends on this, you do so at your own risk.
70
* This code and its internal interfaces are subject to change or
71
* deletion without notice.</b>
72
*/
73
public class ClassWriter extends BasicWriter {
74
static ClassWriter instance(Context context) {
75
ClassWriter instance = context.get(ClassWriter.class);
76
if (instance == null)
77
instance = new ClassWriter(context);
78
return instance;
79
}
80
81
protected ClassWriter(Context context) {
82
super(context);
83
context.put(ClassWriter.class, this);
84
options = Options.instance(context);
85
attrWriter = AttributeWriter.instance(context);
86
codeWriter = CodeWriter.instance(context);
87
constantWriter = ConstantWriter.instance(context);
88
}
89
90
void setDigest(String name, byte[] digest) {
91
this.digestName = name;
92
this.digest = digest;
93
}
94
95
void setFile(URI uri) {
96
this.uri = uri;
97
}
98
99
void setFileSize(int size) {
100
this.size = size;
101
}
102
103
void setLastModified(long lastModified) {
104
this.lastModified = lastModified;
105
}
106
107
protected ClassFile getClassFile() {
108
return classFile;
109
}
110
111
protected void setClassFile(ClassFile cf) {
112
classFile = cf;
113
constant_pool = classFile.constant_pool;
114
}
115
116
protected Method getMethod() {
117
return method;
118
}
119
120
protected void setMethod(Method m) {
121
method = m;
122
}
123
124
public void write(ClassFile cf) {
125
setClassFile(cf);
126
127
if (options.sysInfo || options.verbose) {
128
if (uri != null) {
129
if (uri.getScheme().equals("file"))
130
println("Classfile " + uri.getPath());
131
else
132
println("Classfile " + uri);
133
}
134
indent(+1);
135
if (lastModified != -1) {
136
Date lm = new Date(lastModified);
137
DateFormat df = DateFormat.getDateInstance();
138
if (size > 0) {
139
println("Last modified " + df.format(lm) + "; size " + size + " bytes");
140
} else {
141
println("Last modified " + df.format(lm));
142
}
143
} else if (size > 0) {
144
println("Size " + size + " bytes");
145
}
146
if (digestName != null && digest != null) {
147
StringBuilder sb = new StringBuilder();
148
for (byte b: digest)
149
sb.append(String.format("%02x", b));
150
println(digestName + " checksum " + sb);
151
}
152
}
153
154
Attribute sfa = cf.getAttribute(Attribute.SourceFile);
155
if (sfa instanceof SourceFile_attribute) {
156
println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
157
}
158
159
if (options.sysInfo || options.verbose) {
160
indent(-1);
161
}
162
163
AccessFlags flags = cf.access_flags;
164
writeModifiers(flags.getClassModifiers());
165
166
if (classFile.access_flags.is(AccessFlags.ACC_MODULE)) {
167
Attribute attr = classFile.attributes.get(Attribute.Module);
168
if (attr instanceof Module_attribute) {
169
Module_attribute modAttr = (Module_attribute) attr;
170
String name;
171
try {
172
// FIXME: compatibility code
173
if (constant_pool.get(modAttr.module_name).getTag() == CONSTANT_Module) {
174
name = getJavaName(constant_pool.getModuleInfo(modAttr.module_name).getName());
175
} else {
176
name = getJavaName(constant_pool.getUTF8Value(modAttr.module_name));
177
}
178
} catch (ConstantPoolException e) {
179
name = report(e);
180
}
181
if ((modAttr.module_flags & Module_attribute.ACC_OPEN) != 0) {
182
print("open ");
183
}
184
print("module ");
185
print(name);
186
if (modAttr.module_version_index != 0) {
187
print("@");
188
print(getUTF8Value(modAttr.module_version_index));
189
}
190
} else {
191
// fallback for malformed class files
192
print("class ");
193
print(getJavaName(classFile));
194
}
195
} else {
196
if (classFile.isClass())
197
print("class ");
198
else if (classFile.isInterface())
199
print("interface ");
200
201
print(getJavaName(classFile));
202
}
203
204
Signature_attribute sigAttr = getSignature(cf.attributes);
205
if (sigAttr == null) {
206
// use info from class file header
207
if (classFile.isClass() && classFile.super_class != 0 ) {
208
String sn = getJavaSuperclassName(cf);
209
if (!sn.equals("java.lang.Object")) {
210
print(" extends ");
211
print(sn);
212
}
213
}
214
for (int i = 0; i < classFile.interfaces.length; i++) {
215
print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
216
print(getJavaInterfaceName(classFile, i));
217
}
218
} else {
219
try {
220
Type t = sigAttr.getParsedSignature().getType(constant_pool);
221
JavaTypePrinter p = new JavaTypePrinter(classFile.isInterface());
222
// The signature parser cannot disambiguate between a
223
// FieldType and a ClassSignatureType that only contains a superclass type.
224
if (t instanceof Type.ClassSigType) {
225
print(p.print(t));
226
} else if (options.verbose || !t.isObject()) {
227
print(" extends ");
228
print(p.print(t));
229
}
230
} catch (ConstantPoolException e) {
231
print(report(e));
232
} catch (IllegalStateException e) {
233
report("Invalid value for Signature attribute: " + e.getMessage());
234
}
235
}
236
237
if (options.verbose) {
238
println();
239
indent(+1);
240
println("minor version: " + cf.minor_version);
241
println("major version: " + cf.major_version);
242
writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getClassFlags(), "\n");
243
print("this_class: #" + cf.this_class);
244
if (cf.this_class != 0) {
245
tab();
246
print("// " + constantWriter.stringValue(cf.this_class));
247
}
248
println();
249
print("super_class: #" + cf.super_class);
250
if (cf.super_class != 0) {
251
tab();
252
print("// " + constantWriter.stringValue(cf.super_class));
253
}
254
println();
255
print("interfaces: " + cf.interfaces.length);
256
print(", fields: " + cf.fields.length);
257
print(", methods: " + cf.methods.length);
258
println(", attributes: " + cf.attributes.attrs.length);
259
indent(-1);
260
constantWriter.writeConstantPool();
261
} else {
262
print(" ");
263
}
264
265
println("{");
266
indent(+1);
267
if (flags.is(AccessFlags.ACC_MODULE) && !options.verbose) {
268
writeDirectives();
269
}
270
writeFields();
271
writeMethods();
272
indent(-1);
273
println("}");
274
275
if (options.verbose) {
276
attrWriter.write(cf, cf.attributes, constant_pool);
277
}
278
}
279
// where
280
class JavaTypePrinter implements Type.Visitor<StringBuilder,StringBuilder> {
281
boolean isInterface;
282
283
JavaTypePrinter(boolean isInterface) {
284
this.isInterface = isInterface;
285
}
286
287
String print(Type t) {
288
return t.accept(this, new StringBuilder()).toString();
289
}
290
291
String printTypeArgs(List<? extends TypeParamType> typeParamTypes) {
292
StringBuilder builder = new StringBuilder();
293
appendIfNotEmpty(builder, "<", typeParamTypes, "> ");
294
return builder.toString();
295
}
296
297
@Override
298
public StringBuilder visitSimpleType(SimpleType type, StringBuilder sb) {
299
sb.append(getJavaName(type.name));
300
return sb;
301
}
302
303
@Override
304
public StringBuilder visitArrayType(ArrayType type, StringBuilder sb) {
305
append(sb, type.elemType);
306
sb.append("[]");
307
return sb;
308
}
309
310
@Override
311
public StringBuilder visitMethodType(MethodType type, StringBuilder sb) {
312
appendIfNotEmpty(sb, "<", type.typeParamTypes, "> ");
313
append(sb, type.returnType);
314
append(sb, " (", type.paramTypes, ")");
315
appendIfNotEmpty(sb, " throws ", type.throwsTypes, "");
316
return sb;
317
}
318
319
@Override
320
public StringBuilder visitClassSigType(ClassSigType type, StringBuilder sb) {
321
appendIfNotEmpty(sb, "<", type.typeParamTypes, ">");
322
if (isInterface) {
323
appendIfNotEmpty(sb, " extends ", type.superinterfaceTypes, "");
324
} else {
325
if (type.superclassType != null
326
&& (options.verbose || !type.superclassType.isObject())) {
327
sb.append(" extends ");
328
append(sb, type.superclassType);
329
}
330
appendIfNotEmpty(sb, " implements ", type.superinterfaceTypes, "");
331
}
332
return sb;
333
}
334
335
@Override
336
public StringBuilder visitClassType(ClassType type, StringBuilder sb) {
337
if (type.outerType != null) {
338
append(sb, type.outerType);
339
sb.append(".");
340
}
341
sb.append(getJavaName(type.name));
342
appendIfNotEmpty(sb, "<", type.typeArgs, ">");
343
return sb;
344
}
345
346
@Override
347
public StringBuilder visitTypeParamType(TypeParamType type, StringBuilder sb) {
348
sb.append(type.name);
349
String sep = " extends ";
350
if (type.classBound != null
351
&& (options.verbose || !type.classBound.isObject())) {
352
sb.append(sep);
353
append(sb, type.classBound);
354
sep = " & ";
355
}
356
if (type.interfaceBounds != null) {
357
for (Type bound: type.interfaceBounds) {
358
sb.append(sep);
359
append(sb, bound);
360
sep = " & ";
361
}
362
}
363
return sb;
364
}
365
366
@Override
367
public StringBuilder visitWildcardType(WildcardType type, StringBuilder sb) {
368
switch (type.kind) {
369
case UNBOUNDED:
370
sb.append("?");
371
break;
372
case EXTENDS:
373
sb.append("? extends ");
374
append(sb, type.boundType);
375
break;
376
case SUPER:
377
sb.append("? super ");
378
append(sb, type.boundType);
379
break;
380
default:
381
throw new AssertionError();
382
}
383
return sb;
384
}
385
386
private void append(StringBuilder sb, Type t) {
387
t.accept(this, sb);
388
}
389
390
private void append(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {
391
sb.append(prefix);
392
String sep = "";
393
for (Type t: list) {
394
sb.append(sep);
395
append(sb, t);
396
sep = ", ";
397
}
398
sb.append(suffix);
399
}
400
401
private void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {
402
if (!isEmpty(list))
403
append(sb, prefix, list, suffix);
404
}
405
406
private boolean isEmpty(List<? extends Type> list) {
407
return (list == null || list.isEmpty());
408
}
409
}
410
411
protected void writeFields() {
412
for (Field f: classFile.fields) {
413
writeField(f);
414
}
415
}
416
417
protected void writeField(Field f) {
418
if (!options.checkAccess(f.access_flags))
419
return;
420
421
AccessFlags flags = f.access_flags;
422
writeModifiers(flags.getFieldModifiers());
423
Signature_attribute sigAttr = getSignature(f.attributes);
424
if (sigAttr == null)
425
print(getJavaFieldType(f.descriptor));
426
else {
427
try {
428
Type t = sigAttr.getParsedSignature().getType(constant_pool);
429
print(getJavaName(t.toString()));
430
} catch (ConstantPoolException e) {
431
// report error?
432
// fall back on non-generic descriptor
433
print(getJavaFieldType(f.descriptor));
434
}
435
}
436
print(" ");
437
print(getFieldName(f));
438
if (options.showConstants) {
439
Attribute a = f.attributes.get(Attribute.ConstantValue);
440
if (a instanceof ConstantValue_attribute) {
441
print(" = ");
442
ConstantValue_attribute cv = (ConstantValue_attribute) a;
443
print(getConstantValue(f.descriptor, cv.constantvalue_index));
444
}
445
}
446
print(";");
447
println();
448
449
indent(+1);
450
451
boolean showBlank = false;
452
453
if (options.showDescriptors)
454
println("descriptor: " + getValue(f.descriptor));
455
456
if (options.verbose)
457
writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getFieldFlags(), "\n");
458
459
if (options.showAllAttrs) {
460
for (Attribute attr: f.attributes)
461
attrWriter.write(f, attr, constant_pool);
462
showBlank = true;
463
}
464
465
indent(-1);
466
467
if (showBlank || options.showDisassembled || options.showLineAndLocalVariableTables)
468
println();
469
}
470
471
protected void writeMethods() {
472
for (Method m: classFile.methods)
473
writeMethod(m);
474
setPendingNewline(false);
475
}
476
477
private static final int DEFAULT_ALLOWED_MAJOR_VERSION = 52;
478
private static final int DEFAULT_ALLOWED_MINOR_VERSION = 0;
479
480
protected void writeMethod(Method m) {
481
if (!options.checkAccess(m.access_flags))
482
return;
483
484
method = m;
485
486
AccessFlags flags = m.access_flags;
487
488
Descriptor d;
489
Type.MethodType methodType;
490
List<? extends Type> methodExceptions;
491
492
Signature_attribute sigAttr = getSignature(m.attributes);
493
if (sigAttr == null) {
494
d = m.descriptor;
495
methodType = null;
496
methodExceptions = null;
497
} else {
498
Signature methodSig = sigAttr.getParsedSignature();
499
d = methodSig;
500
try {
501
methodType = (Type.MethodType) methodSig.getType(constant_pool);
502
methodExceptions = methodType.throwsTypes;
503
if (methodExceptions != null && methodExceptions.isEmpty())
504
methodExceptions = null;
505
} catch (ConstantPoolException | IllegalStateException e) {
506
// report error?
507
// fall back on standard descriptor
508
methodType = null;
509
methodExceptions = null;
510
}
511
}
512
513
Set<String> modifiers = flags.getMethodModifiers();
514
515
String name = getName(m);
516
if (classFile.isInterface() &&
517
(!flags.is(AccessFlags.ACC_ABSTRACT)) && !name.equals("<clinit>")) {
518
if (classFile.major_version > DEFAULT_ALLOWED_MAJOR_VERSION ||
519
(classFile.major_version == DEFAULT_ALLOWED_MAJOR_VERSION && classFile.minor_version >= DEFAULT_ALLOWED_MINOR_VERSION)) {
520
if (!flags.is(AccessFlags.ACC_STATIC | AccessFlags.ACC_PRIVATE)) {
521
modifiers.add("default");
522
}
523
}
524
}
525
526
writeModifiers(modifiers);
527
if (methodType != null) {
528
print(new JavaTypePrinter(false).printTypeArgs(methodType.typeParamTypes));
529
}
530
switch (name) {
531
case "<init>":
532
print(getJavaName(classFile));
533
print(getJavaParameterTypes(d, flags));
534
break;
535
case "<clinit>":
536
print("{}");
537
break;
538
default:
539
print(getJavaReturnType(d));
540
print(" ");
541
print(name);
542
print(getJavaParameterTypes(d, flags));
543
break;
544
}
545
546
Attribute e_attr = m.attributes.get(Attribute.Exceptions);
547
if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
548
if (e_attr instanceof Exceptions_attribute) {
549
Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
550
print(" throws ");
551
if (methodExceptions != null) { // use generic list if available
552
writeList("", methodExceptions, "");
553
} else {
554
for (int i = 0; i < exceptions.number_of_exceptions; i++) {
555
if (i > 0)
556
print(", ");
557
print(getJavaException(exceptions, i));
558
}
559
}
560
} else {
561
report("Unexpected or invalid value for Exceptions attribute");
562
}
563
}
564
565
println(";");
566
567
indent(+1);
568
569
if (options.showDescriptors) {
570
println("descriptor: " + getValue(m.descriptor));
571
}
572
573
if (options.verbose) {
574
writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getMethodFlags(), "\n");
575
}
576
577
Code_attribute code = null;
578
Attribute c_attr = m.attributes.get(Attribute.Code);
579
if (c_attr != null) {
580
if (c_attr instanceof Code_attribute)
581
code = (Code_attribute) c_attr;
582
else
583
report("Unexpected or invalid value for Code attribute");
584
}
585
586
if (options.showAllAttrs) {
587
Attribute[] attrs = m.attributes.attrs;
588
for (Attribute attr: attrs)
589
attrWriter.write(m, attr, constant_pool);
590
} else if (code != null) {
591
if (options.showDisassembled) {
592
println("Code:");
593
codeWriter.writeInstrs(code);
594
codeWriter.writeExceptionTable(code);
595
}
596
597
if (options.showLineAndLocalVariableTables) {
598
attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
599
attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
600
}
601
}
602
603
indent(-1);
604
605
// set pendingNewline to write a newline before the next method (if any)
606
// if a separator is desired
607
setPendingNewline(
608
options.showDisassembled ||
609
options.showAllAttrs ||
610
options.showDescriptors ||
611
options.showLineAndLocalVariableTables ||
612
options.verbose);
613
}
614
615
void writeModifiers(Collection<String> items) {
616
for (Object item: items) {
617
print(item);
618
print(" ");
619
}
620
}
621
622
void writeDirectives() {
623
Attribute attr = classFile.attributes.get(Attribute.Module);
624
if (!(attr instanceof Module_attribute))
625
return;
626
627
Module_attribute m = (Module_attribute) attr;
628
for (Module_attribute.RequiresEntry entry: m.requires) {
629
print("requires");
630
if ((entry.requires_flags & Module_attribute.ACC_STATIC_PHASE) != 0)
631
print(" static");
632
if ((entry.requires_flags & Module_attribute.ACC_TRANSITIVE) != 0)
633
print(" transitive");
634
print(" ");
635
String mname;
636
try {
637
mname = getModuleName(entry.requires_index);
638
} catch (ConstantPoolException e) {
639
mname = report(e);
640
}
641
print(mname);
642
println(";");
643
}
644
645
for (Module_attribute.ExportsEntry entry: m.exports) {
646
print("exports");
647
print(" ");
648
String pname;
649
try {
650
pname = getPackageName(entry.exports_index).replace('/', '.');
651
} catch (ConstantPoolException e) {
652
pname = report(e);
653
}
654
print(pname);
655
boolean first = true;
656
for (int i: entry.exports_to_index) {
657
String mname;
658
try {
659
mname = getModuleName(i);
660
} catch (ConstantPoolException e) {
661
mname = report(e);
662
}
663
if (first) {
664
println(" to");
665
indent(+1);
666
first = false;
667
} else {
668
println(",");
669
}
670
print(mname);
671
}
672
println(";");
673
if (!first)
674
indent(-1);
675
}
676
677
for (Module_attribute.OpensEntry entry: m.opens) {
678
print("opens");
679
print(" ");
680
String pname;
681
try {
682
pname = getPackageName(entry.opens_index).replace('/', '.');
683
} catch (ConstantPoolException e) {
684
pname = report(e);
685
}
686
print(pname);
687
boolean first = true;
688
for (int i: entry.opens_to_index) {
689
String mname;
690
try {
691
mname = getModuleName(i);
692
} catch (ConstantPoolException e) {
693
mname = report(e);
694
}
695
if (first) {
696
println(" to");
697
indent(+1);
698
first = false;
699
} else {
700
println(",");
701
}
702
print(mname);
703
}
704
println(";");
705
if (!first)
706
indent(-1);
707
}
708
709
for (int entry: m.uses_index) {
710
print("uses ");
711
print(getClassName(entry).replace('/', '.'));
712
println(";");
713
}
714
715
for (Module_attribute.ProvidesEntry entry: m.provides) {
716
print("provides ");
717
print(getClassName(entry.provides_index).replace('/', '.'));
718
boolean first = true;
719
for (int i: entry.with_index) {
720
if (first) {
721
println(" with");
722
indent(+1);
723
first = false;
724
} else {
725
println(",");
726
}
727
print(getClassName(i).replace('/', '.'));
728
}
729
println(";");
730
if (!first)
731
indent(-1);
732
}
733
}
734
735
String getModuleName(int index) throws ConstantPoolException {
736
if (constant_pool.get(index).getTag() == CONSTANT_Module) {
737
return constant_pool.getModuleInfo(index).getName();
738
} else {
739
return constant_pool.getUTF8Value(index);
740
}
741
}
742
743
String getPackageName(int index) throws ConstantPoolException {
744
if (constant_pool.get(index).getTag() == CONSTANT_Package) {
745
return constant_pool.getPackageInfo(index).getName();
746
} else {
747
return constant_pool.getUTF8Value(index);
748
}
749
}
750
751
String getUTF8Value(int index) {
752
try {
753
return classFile.constant_pool.getUTF8Value(index);
754
} catch (ConstantPoolException e) {
755
return report(e);
756
}
757
}
758
759
String getClassName(int index) {
760
try {
761
return classFile.constant_pool.getClassInfo(index).getName();
762
} catch (ConstantPoolException e) {
763
return report(e);
764
}
765
}
766
767
void writeList(String prefix, Collection<?> items, String suffix) {
768
print(prefix);
769
String sep = "";
770
for (Object item: items) {
771
print(sep);
772
print(item);
773
sep = ", ";
774
}
775
print(suffix);
776
}
777
778
void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
779
if (items != null && items.size() > 0)
780
writeList(prefix, items, suffix);
781
}
782
783
Signature_attribute getSignature(Attributes attributes) {
784
return (Signature_attribute) attributes.get(Attribute.Signature);
785
}
786
787
String adjustVarargs(AccessFlags flags, String params) {
788
if (flags.is(ACC_VARARGS)) {
789
int i = params.lastIndexOf("[]");
790
if (i > 0)
791
return params.substring(0, i) + "..." + params.substring(i+2);
792
}
793
794
return params;
795
}
796
797
String getJavaName(ClassFile cf) {
798
try {
799
return getJavaName(cf.getName());
800
} catch (ConstantPoolException e) {
801
return report(e);
802
}
803
}
804
805
String getJavaSuperclassName(ClassFile cf) {
806
try {
807
return getJavaName(cf.getSuperclassName());
808
} catch (ConstantPoolException e) {
809
return report(e);
810
}
811
}
812
813
String getJavaInterfaceName(ClassFile cf, int index) {
814
try {
815
return getJavaName(cf.getInterfaceName(index));
816
} catch (ConstantPoolException e) {
817
return report(e);
818
}
819
}
820
821
String getJavaFieldType(Descriptor d) {
822
try {
823
return getJavaName(d.getFieldType(constant_pool));
824
} catch (ConstantPoolException e) {
825
return report(e);
826
} catch (InvalidDescriptor e) {
827
return report(e);
828
}
829
}
830
831
String getJavaReturnType(Descriptor d) {
832
try {
833
return getJavaName(d.getReturnType(constant_pool));
834
} catch (ConstantPoolException e) {
835
return report(e);
836
} catch (InvalidDescriptor e) {
837
return report(e);
838
}
839
}
840
841
String getJavaParameterTypes(Descriptor d, AccessFlags flags) {
842
try {
843
return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool)));
844
} catch (ConstantPoolException e) {
845
return report(e);
846
} catch (InvalidDescriptor e) {
847
return report(e);
848
}
849
}
850
851
String getJavaException(Exceptions_attribute attr, int index) {
852
try {
853
return getJavaName(attr.getException(index, constant_pool));
854
} catch (ConstantPoolException e) {
855
return report(e);
856
}
857
}
858
859
String getValue(Descriptor d) {
860
try {
861
return d.getValue(constant_pool);
862
} catch (ConstantPoolException e) {
863
return report(e);
864
}
865
}
866
867
String getFieldName(Field f) {
868
try {
869
return f.getName(constant_pool);
870
} catch (ConstantPoolException e) {
871
return report(e);
872
}
873
}
874
875
String getName(Method m) {
876
try {
877
return m.getName(constant_pool);
878
} catch (ConstantPoolException e) {
879
return report(e);
880
}
881
}
882
883
static String getJavaName(String name) {
884
return name.replace('/', '.');
885
}
886
887
String getSourceFile(SourceFile_attribute attr) {
888
try {
889
return attr.getSourceFile(constant_pool);
890
} catch (ConstantPoolException e) {
891
return report(e);
892
}
893
}
894
895
/**
896
* Get the value of an entry in the constant pool as a Java constant.
897
* Characters and booleans are represented by CONSTANT_Intgere entries.
898
* Character and string values are processed to escape characters outside
899
* the basic printable ASCII set.
900
* @param d the descriptor, giving the expected type of the constant
901
* @param index the index of the value in the constant pool
902
* @return a printable string containing the value of the constant.
903
*/
904
String getConstantValue(Descriptor d, int index) {
905
try {
906
ConstantPool.CPInfo cpInfo = constant_pool.get(index);
907
908
switch (cpInfo.getTag()) {
909
case ConstantPool.CONSTANT_Integer: {
910
ConstantPool.CONSTANT_Integer_info info =
911
(ConstantPool.CONSTANT_Integer_info) cpInfo;
912
String t = d.getValue(constant_pool);
913
switch (t) {
914
case "C":
915
// character
916
return getConstantCharValue((char) info.value);
917
case "Z":
918
// boolean
919
return String.valueOf(info.value == 1);
920
default:
921
// other: assume integer
922
return String.valueOf(info.value);
923
}
924
}
925
926
case ConstantPool.CONSTANT_String: {
927
ConstantPool.CONSTANT_String_info info =
928
(ConstantPool.CONSTANT_String_info) cpInfo;
929
return getConstantStringValue(info.getString());
930
}
931
932
default:
933
return constantWriter.stringValue(cpInfo);
934
}
935
} catch (ConstantPoolException e) {
936
return "#" + index;
937
}
938
}
939
940
private String getConstantCharValue(char c) {
941
StringBuilder sb = new StringBuilder();
942
sb.append('\'');
943
sb.append(esc(c, '\''));
944
sb.append('\'');
945
return sb.toString();
946
}
947
948
private String getConstantStringValue(String s) {
949
StringBuilder sb = new StringBuilder();
950
sb.append("\"");
951
for (int i = 0; i < s.length(); i++) {
952
sb.append(esc(s.charAt(i), '"'));
953
}
954
sb.append("\"");
955
return sb.toString();
956
}
957
958
private String esc(char c, char quote) {
959
if (32 <= c && c <= 126 && c != quote && c != '\\')
960
return String.valueOf(c);
961
else switch (c) {
962
case '\b': return "\\b";
963
case '\n': return "\\n";
964
case '\t': return "\\t";
965
case '\f': return "\\f";
966
case '\r': return "\\r";
967
case '\\': return "\\\\";
968
case '\'': return "\\'";
969
case '\"': return "\\\"";
970
default: return String.format("\\u%04x", (int) c);
971
}
972
}
973
974
private final Options options;
975
private final AttributeWriter attrWriter;
976
private final CodeWriter codeWriter;
977
private final ConstantWriter constantWriter;
978
private ClassFile classFile;
979
private URI uri;
980
private long lastModified;
981
private String digestName;
982
private byte[] digest;
983
private int size;
984
private ConstantPool constant_pool;
985
private Method method;
986
}
987
988