1 /*
  2  * Copyright (c) 2020, 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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.asmtools.jasm;
 24 
 25 import java.io.IOException;
 26 import java.io.PrintWriter;
 27 import java.util.ArrayList;
 28 
 29 /**
 30  * TargetInfo (4.7.20.1. The target_info union)
 31  *
 32  * BaseClass for any Type Annotation Target-Info.
 33  */
 34 public abstract class TypeAnnotationTargetInfoData implements Data {
 35 
 36     protected TypeAnnotationTypes.ETargetType targettype = null;
 37 
 38     public TypeAnnotationTargetInfoData(TypeAnnotationTypes.ETargetType tt) {
 39         targettype = tt;
 40     }
 41 
 42     public TypeAnnotationTypes.ETargetType getTargetType() {
 43         return targettype;
 44     }
 45 
 46     public void print(PrintWriter out, String tab) {
 47         // print the TargetType and TargetInfo
 48         out.print(tab + " {");
 49         targettype.print(out);
 50         _print(out, tab);
 51         out.print(tab + "} ");
 52     }
 53 
 54     public abstract void _print(PrintWriter out, String tab);
 55 
 56     public abstract void write(CheckedDataOutputStream out) throws IOException;
 57 
 58     @Override
 59     public String toString() {
 60         return toString(0);
 61     }
 62 
 63     protected abstract void _toString(StringBuilder sb, int tabLevel);
 64 
 65     public  String toString(int tabLevel)  {
 66         StringBuilder sb = new StringBuilder(tabString(tabLevel));
 67         // first print the target info name (
 68         sb.append(targettype.targetInfo().printValue()).append("_target ");
 69         // get the sub-classes parts
 70         _toString(sb, tabLevel);
 71         return sb.toString();
 72     }
 73 
 74     /**
 75      * type_parameter_target (4.7.20.1. The target_info union)
 76      *
 77      * The type_parameter_target item indicates that an annotation appears on the declaration of the i'th type parameter
 78      * of a generic class, generic interface, generic method, or generic constructor.
 79      *
 80      * type_parameter_target {
 81      *     u1 type_parameter_index;
 82      * }
 83      */
 84     public static class type_parameter_target extends TypeAnnotationTargetInfoData {
 85 
 86         int typeParamIndex;
 87 
 88         public type_parameter_target(TypeAnnotationTypes.ETargetType tt, int index) {
 89             super(tt);
 90             typeParamIndex = index;
 91         }
 92 
 93         @Override
 94         public void write(CheckedDataOutputStream out) throws IOException {
 95             out.writeByte(typeParamIndex);
 96         }
 97 
 98         @Override
 99         public void _print(PrintWriter out, String tab) {
100             out.print(" ");
101             out.print(typeParamIndex);
102         }
103 
104         @Override
105         public int getLength() {
106             return 1;
107         }
108 
109         @Override
110         protected void _toString(StringBuilder sb, int tabLevel) {
111             sb.append(tabString(tabLevel)).append(String.format("{ type_parameter_index: %d; }",typeParamIndex));
112         }
113     }
114 
115     /**
116      * supertype_target (4.7.20.1. The target_info union)
117      *
118      * The supertype_target item indicates that an annotation appears on a type in the extends or implements clause of
119      * a class or interface declaration.
120      *
121      * supertype_target {
122      *     u2 supertype_index;
123      * }
124      */
125     public static class supertype_target extends TypeAnnotationTargetInfoData {
126 
127         int superTypeIndex;
128 
129         public supertype_target(TypeAnnotationTypes.ETargetType tt, int index) {
130             super(tt);
131             superTypeIndex = index;
132         }
133 
134         @Override
135         public void write(CheckedDataOutputStream out) throws IOException {
136             out.writeShort(superTypeIndex);
137         }
138 
139         @Override
140         public void _print(PrintWriter out, String tab) {
141             out.print(" ");
142             out.print(superTypeIndex);
143         }
144 
145         @Override
146         public int getLength() {
147             return 2;
148         }
149 
150         @Override
151         protected void _toString(StringBuilder sb, int tabLevel) {
152             sb.append(tabString(tabLevel)).append(String.format("{ supertype_index: %d; }",superTypeIndex));
153         }
154     }
155 
156     /**
157      * type_parameter_bound_target (4.7.20.1. The target_info union)
158      *
159      * The type_parameter_bound_target item indicates that an annotation appears on the i'th bound of the j'th type parameter
160      * declaration of a generic class, interface, method, or constructor.
161      *
162      * type_parameter_bound_target {
163      *     u1 type_parameter_index;
164      *     u1 bound_index;
165      * }
166      */
167     public static class type_parameter_bound_target extends TypeAnnotationTargetInfoData {
168 
169         int typeParamIndex;
170         int boundIndex;
171 
172         public type_parameter_bound_target(TypeAnnotationTypes.ETargetType tt, int pindx, int bindx) {
173             super(tt);
174             typeParamIndex = pindx;
175             boundIndex = bindx;
176         }
177 
178         @Override
179         public void write(CheckedDataOutputStream out) throws IOException {
180             out.writeByte(typeParamIndex);
181             out.writeByte(boundIndex);
182         }
183 
184         @Override
185         public void _print(PrintWriter out, String tab) {
186             out.print(" ");
187             out.print(typeParamIndex);
188             out.print(" ");
189             out.print(boundIndex);
190         }
191 
192         @Override
193         public int getLength() {
194             return 2;
195         }
196 
197         @Override
198         protected void _toString(StringBuilder sb, int tabLevel) {
199             sb.append(tabString(tabLevel)).append(String.format("{ type_parameter_index: %d; bound_index: %d; }",
200                     typeParamIndex, boundIndex));
201         }
202     }
203 
204     /**
205      * empty_target (4.7.20.1. The target_info union)
206      *
207      * The empty_target item indicates that an annotation appears on either the type in a field declaration,
208      * the return type of a method, the type of a newly constructed object, or the receiver type of a method or constructor.
209      *
210      * empty_target {
211      * }
212      */
213     public static class empty_target extends TypeAnnotationTargetInfoData {
214 
215         public empty_target(TypeAnnotationTypes.ETargetType tt) {
216             super(tt);
217         }
218 
219         @Override
220         public void _print(PrintWriter out, String tab) {
221             // do nothing
222         }
223 
224         @Override
225         public void write(CheckedDataOutputStream out) throws IOException {
226             // do nothing
227         }
228 
229         @Override
230         public int getLength() { return 0; }
231 
232         @Override
233         protected void _toString(StringBuilder sb, int tabLevel) {
234             sb.append(tabString(tabLevel)).append("{ }");
235         }
236     }
237 
238     /**
239      * formal_parameter_target (4.7.20.1. The target_info union)
240      *
241      * The formal_parameter_target item indicates that an annotation appears on the type in a formal parameter
242      * declaration of a method, constructor, or lambda expression.
243      *
244      * formal_parameter_target {
245      *     u1 formal_parameter_index;
246      * }
247      */
248     public static class formal_parameter_target extends TypeAnnotationTargetInfoData {
249 
250         int formalParamIndex;
251 
252         public formal_parameter_target(TypeAnnotationTypes.ETargetType tt, int index) {
253             super(tt);
254             formalParamIndex = index;
255         }
256 
257         @Override
258         public void write(CheckedDataOutputStream out) throws IOException {
259             out.writeByte(formalParamIndex);
260         }
261 
262         @Override
263         public void _print(PrintWriter out, String tab) {
264             out.print(" ");
265             out.print(formalParamIndex);
266         }
267 
268         @Override
269         public int getLength() {
270             return 1;
271         }
272 
273         @Override
274         protected void _toString(StringBuilder sb, int tabLevel) {
275             sb.append(tabString(tabLevel)).append(String.format("{ formal_parameter_index: %d; }",formalParamIndex));
276         }
277     }
278 
279     /**
280      * throws_target (4.7.20.1. The target_info union)
281      *
282      * The throws_target item indicates that an annotation appears on the i'th type in the throws clause of a method or
283      * constructor declaration.
284      *
285      * throws_target {
286      *     u2 throws_type_index;
287      * }
288      */
289     public static class throws_target extends TypeAnnotationTargetInfoData {
290 
291         int throwsTypeIndex;
292 
293         public throws_target(TypeAnnotationTypes.ETargetType tt, int index) {
294             super(tt);
295             throwsTypeIndex = index;
296         }
297 
298         @Override
299         public void write(CheckedDataOutputStream out) throws IOException {
300             out.writeShort(throwsTypeIndex);
301         }
302 
303         @Override
304         public void _print(PrintWriter out, String tab) {
305             out.print(" ");
306             out.print(throwsTypeIndex);
307         }
308 
309         @Override
310         public int getLength() {
311             return 2;
312         }
313 
314         @Override
315         protected void _toString(StringBuilder sb, int tabLevel) {
316             sb.append(tabString(tabLevel)).append(String.format("{ throws_type_index: %d; }",throwsTypeIndex));
317         }
318     }
319 
320     /**
321      * localvar_target (4.7.20.1. The target_info union)
322      *
323      * The localvar_target item indicates that an annotation appears on the type in a local variable declaration,
324      * including a variable declared as a resource in a try-with-resources statement.
325      *
326      * localvar_target {
327      *     u2 table_length;
328      *     {   u2 start_pc;
329      *         u2 length;
330      *         u2 index;
331      *     } table[table_length];
332      * }
333      */
334     public static class localvar_target extends TypeAnnotationTargetInfoData {
335 
336         public class LocalVar_Entry {
337 
338             public int startPC;
339             public int length;
340             public int cpx;
341 
342             public LocalVar_Entry(int st, int len, int index) {
343                 startPC = st;
344                 length = len;
345                 cpx = index;
346             }
347 
348             void write(CheckedDataOutputStream out) throws IOException {
349                 out.writeShort(startPC);
350                 out.writeShort(length);
351                 out.writeShort(cpx);
352             }
353 
354             public void _print(PrintWriter out, String tab) {
355                 out.print(tab + "{");
356                 out.print(startPC);
357                 out.print(" ");
358                 out.print(length);
359                 out.print(" ");
360                 out.print(cpx);
361                 out.print("}");
362             }
363 
364             public String toString() {
365                 return String.format("start_pc: %d, length: %d, index: %d", startPC, length, cpx);
366             }
367         }
368 
369         ArrayList<LocalVar_Entry> table = null;
370 
371         public localvar_target(TypeAnnotationTypes.ETargetType tt, int size) {
372             super(tt);
373             table = new ArrayList<>(size);
374         }
375 
376         public void addEntry(int startPC, int length, int cpx) {
377             LocalVar_Entry entry = new LocalVar_Entry(startPC, length, cpx);
378             table.add(entry);
379         }
380 
381         @Override
382         public void write(CheckedDataOutputStream out) throws IOException {
383             out.writeShort(table.size());
384             for (LocalVar_Entry entry : table) {
385                 entry.write(out);
386             }
387         }
388 
389         @Override
390         public void _print(PrintWriter out, String tab) {
391             String innerTab = tab + " ";
392             for (LocalVar_Entry entry : table) {
393                 entry._print(out, innerTab);
394             }
395             out.print(tab);
396         }
397 
398         @Override
399         public int getLength() {
400             return 2 + // U2 for table size
401                     (6 * table.size()); // (3 * U2) for each table entry
402         }
403 
404         @Override
405         protected void _toString(StringBuilder sb, int tabLevel) {
406             int i = 0;
407             sb.append(tabString(tabLevel)).append(String.format("{ %d  {", table.size()));
408             for (LocalVar_Entry entry : table) {
409                 sb.append(String.format(" [%d]: %s;", i++, entry.toString()));
410             }
411             sb.append(" } }");
412         }
413     }
414 
415     /**
416      * catch_target (4.7.20.1. The target_info union)
417      *
418      * The catch_target item indicates that an annotation appears on the i'th type in an exception parameter declaration.
419      *
420      * catch_target {
421      *     u2 exception_table_index;
422      * }
423      */
424     public static class catch_target extends TypeAnnotationTargetInfoData {
425 
426         int exceptionTableIndex;
427 
428         public catch_target(TypeAnnotationTypes.ETargetType tt, int index) {
429             super(tt);
430             exceptionTableIndex = index;
431         }
432 
433         @Override
434         public void write(CheckedDataOutputStream out) throws IOException {
435             out.writeShort(exceptionTableIndex);
436         }
437 
438         @Override
439         public void _print(PrintWriter out, String tab) {
440             out.print(" ");
441             out.print(exceptionTableIndex);
442         }
443 
444         @Override
445         public int getLength() {
446             return 2;
447         }
448 
449         @Override
450         protected void _toString(StringBuilder sb, int tabLevel) {
451             sb.append(tabString(tabLevel)).append(String.format("{ exception_table_index: %d; }",exceptionTableIndex));
452         }
453     }
454 
455     /**
456      * offset_target (4.7.20.1. The target_info union)
457      *
458      *  The offset_target item indicates that an annotation appears on either the type in an instanceof expression or
459      *  a new expression, or the type before the :: in a method reference expression.
460      *
461      *  offset_target {
462      *     u2 offset;
463      * }
464      */
465     public static class offset_target extends TypeAnnotationTargetInfoData {
466 
467         int offset;
468 
469         public offset_target(TypeAnnotationTypes.ETargetType tt, int offset) {
470             super(tt);
471             this.offset = offset;
472         }
473 
474         @Override
475         public void write(CheckedDataOutputStream out) throws IOException {
476             out.writeShort(offset);
477         }
478 
479         @Override
480         public void _print(PrintWriter out, String tab) {
481             out.print(" ");
482             out.print(offset);
483         }
484 
485         @Override
486         public int getLength() {
487             return 2;
488         }
489 
490         @Override
491         protected void _toString(StringBuilder sb, int tabLevel) {
492             sb.append(tabString(tabLevel)).append(String.format("{ offset: %d; }", offset));
493         }
494     }
495 
496     /**
497      * type_argument_target (4.7.20.1. The target_info union)
498      *
499      *  The type_argument_target item indicates that an annotation appears either on the i'th type in a cast expression,
500      *  or on the i'th type argument in the explicit type argument list for any of the following: a new expression,
501      *  an explicit constructor invocation statement, a method invocation expression, or a method reference expression
502      *
503      *  type_argument_target {
504      *     u2 offset;
505      *     u1 type_argument_index;
506      * }
507      */
508     public static class type_argument_target extends TypeAnnotationTargetInfoData {
509 
510         int offset;
511         int typeArgumentIndex;
512 
513         public type_argument_target(TypeAnnotationTypes.ETargetType tt, int offset, int index) {
514             super(tt);
515             this.offset = offset;
516             typeArgumentIndex = index;
517         }
518 
519         @Override
520         public void write(CheckedDataOutputStream out) throws IOException {
521             out.writeShort(offset);
522             out.writeByte(typeArgumentIndex);
523         }
524 
525         @Override
526         public void _print(PrintWriter out, String tab) {
527             out.print(" ");
528             out.print(offset);
529             out.print(" ");
530             out.print(typeArgumentIndex);
531         }
532 
533         @Override
534         public int getLength() {
535             return 3;
536         }
537 
538         @Override
539         protected void _toString(StringBuilder sb, int tabLevel) {
540             sb.append(tabString(tabLevel)).append(String.format("{ offset: %d; type_argument_index: %d; }",
541                     offset, typeArgumentIndex));
542         }
543     }
544 
545 }
546