ClassFile.java revision 4a9a664dd17b17d4ca4641f6267a59f644f20a07
1/*
2 * Copyright 2016 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.turbine.bytecode;
18
19import static java.util.Objects.requireNonNull;
20
21import com.google.common.collect.ImmutableList;
22import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
23import com.google.turbine.model.Const;
24import com.google.turbine.model.Const.Value;
25import java.util.ArrayDeque;
26import java.util.Deque;
27import java.util.List;
28import java.util.Map;
29import javax.annotation.Nullable;
30
31/** A JVMS §4.1 ClassFile. */
32public class ClassFile {
33
34  private final int access;
35  private final String name;
36  private final String signature;
37  private final String superClass;
38  private final List<String> interfaces;
39  private final List<MethodInfo> methods;
40  private final List<FieldInfo> fields;
41  private final List<AnnotationInfo> annotations;
42  private final List<InnerClass> innerClasses;
43  private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
44
45  public ClassFile(
46      int access,
47      String name,
48      String signature,
49      String superClass,
50      List<String> interfaces,
51      List<MethodInfo> methods,
52      List<FieldInfo> fields,
53      List<AnnotationInfo> annotations,
54      List<InnerClass> innerClasses,
55      ImmutableList<TypeAnnotationInfo> typeAnnotations) {
56    this.access = access;
57    this.name = name;
58    this.signature = signature;
59    this.superClass = superClass;
60    this.interfaces = interfaces;
61    this.methods = methods;
62    this.fields = fields;
63    this.annotations = annotations;
64    this.innerClasses = innerClasses;
65    this.typeAnnotations = typeAnnotations;
66  }
67
68  /** Class access and property flags. */
69  public int access() {
70    return access;
71  }
72
73  /** The name of the class or interface. */
74  public String name() {
75    return name;
76  }
77
78  /** The value of the Signature attribute. */
79  public String signature() {
80    return signature;
81  }
82
83  /** The super class. */
84  public String superName() {
85    return superClass;
86  }
87
88  /** The direct superinterfaces. */
89  public List<String> interfaces() {
90    return interfaces;
91  }
92
93  /** Methods declared by this class or interfaces type. */
94  public List<MethodInfo> methods() {
95    return methods;
96  }
97
98  /** Fields declared by this class or interfaces type. */
99  public List<FieldInfo> fields() {
100    return fields;
101  }
102
103  /** Declaration annotations of the class. */
104  public List<AnnotationInfo> annotations() {
105    return annotations;
106  }
107
108  /** Inner class information. */
109  public List<InnerClass> innerClasses() {
110    return innerClasses;
111  }
112
113  /** Type annotations. */
114  public ImmutableList<TypeAnnotationInfo> typeAnnotations() {
115    return typeAnnotations;
116  }
117
118  /** The contents of a JVMS §4.5 field_info structure. */
119  public static class FieldInfo {
120
121    private final int access;
122    private final String name;
123    private final String descriptor;
124    @Nullable private final String signature;
125    @Nullable private final Const.Value value;
126    private final List<AnnotationInfo> annotations;
127    private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
128
129    public FieldInfo(
130        int access,
131        String name,
132        String descriptor,
133        @Nullable String signature,
134        Value value,
135        List<AnnotationInfo> annotations,
136        ImmutableList<TypeAnnotationInfo> typeAnnotations) {
137      this.access = access;
138      this.name = name;
139      this.descriptor = descriptor;
140      this.signature = signature;
141      this.value = value;
142      this.annotations = annotations;
143      this.typeAnnotations = typeAnnotations;
144    }
145
146    /** Field access and property flags. */
147    public int access() {
148      return access;
149    }
150
151    /** The name of the field. */
152    public String name() {
153      return name;
154    }
155
156    /** The descriptor. */
157    public String descriptor() {
158      return descriptor;
159    }
160
161    /** The value of Signature attribute. */
162    @Nullable
163    public String signature() {
164      return signature;
165    }
166
167    /** The compile-time constant value. */
168    @Nullable
169    public Const.Value value() {
170      return value;
171    }
172
173    /** Declaration annotations of the field. */
174    public List<AnnotationInfo> annotations() {
175      return annotations;
176    }
177
178    /** Type annotations. */
179    public ImmutableList<TypeAnnotationInfo> typeAnnotations() {
180      return typeAnnotations;
181    }
182  }
183
184  /** A JVMS §4.7.6 InnerClasses attribute. */
185  public static class InnerClass {
186
187    private final String innerClass;
188    private final String outerClass;
189    private final String innerName;
190    private final int access;
191
192    public InnerClass(String innerClass, String outerClass, String innerName, int access) {
193      this.innerClass = requireNonNull(innerClass);
194      this.outerClass = requireNonNull(outerClass);
195      this.innerName = requireNonNull(innerName);
196      this.access = access;
197    }
198
199    /** The binary name of the inner class. */
200    public String innerClass() {
201      return innerClass;
202    }
203
204    /** The binary name of the enclosing class. */
205    public String outerClass() {
206      return outerClass;
207    }
208
209    /** The simple name of the inner class. */
210    public String innerName() {
211      return innerName;
212    }
213
214    /** Access and property flags of the inner class; see JVMS table 4.8. */
215    public int access() {
216      return access;
217    }
218  }
219
220  /** The contents of a JVMS §4.6 method_info structure. */
221  public static class MethodInfo {
222
223    private final int access;
224    private final String name;
225    private final String descriptor;
226    @Nullable private final String signature;
227    private final List<String> exceptions;
228    @Nullable private final AnnotationInfo.ElementValue defaultValue;
229    private final List<AnnotationInfo> annotations;
230    private final ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations;
231    private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
232    private final ImmutableList<ParameterInfo> parameters;
233
234    public MethodInfo(
235        int access,
236        String name,
237        String descriptor,
238        @Nullable String signature,
239        List<String> exceptions,
240        @Nullable ElementValue defaultValue,
241        List<AnnotationInfo> annotations,
242        ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations,
243        ImmutableList<TypeAnnotationInfo> typeAnnotations,
244        ImmutableList<ParameterInfo> parameters) {
245      this.access = access;
246      this.name = name;
247      this.descriptor = descriptor;
248      this.signature = signature;
249      this.exceptions = exceptions;
250      this.defaultValue = defaultValue;
251      this.annotations = annotations;
252      this.parameterAnnotations = parameterAnnotations;
253      this.typeAnnotations = typeAnnotations;
254      this.parameters = parameters;
255    }
256
257    /** Method access and property flags. */
258    public int access() {
259      return access;
260    }
261
262    /** The name of the method. */
263    public String name() {
264      return name;
265    }
266
267    /** The descriptor. */
268    public String descriptor() {
269      return descriptor;
270    }
271
272    /** The value of Signature attribute. */
273    @Nullable
274    public String signature() {
275      return signature;
276    }
277
278    /** The value of Exceptions attribute. */
279    public List<String> exceptions() {
280      return exceptions;
281    }
282
283    /** The value of the AnnotationDefault attribute. */
284    @Nullable
285    public AnnotationInfo.ElementValue defaultValue() {
286      return defaultValue;
287    }
288
289    /** Declaration annotations of the method. */
290    public List<AnnotationInfo> annotations() {
291      return annotations;
292    }
293
294    /** Declaration annotations of the formal parameters. */
295    public ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations() {
296      return parameterAnnotations;
297    }
298
299    /** Type annotations. */
300    public ImmutableList<TypeAnnotationInfo> typeAnnotations() {
301      return typeAnnotations;
302    }
303
304    /** Formal parameters. */
305    public ImmutableList<ParameterInfo> parameters() {
306      return parameters;
307    }
308
309    /** A formal parameter. */
310    public static class ParameterInfo {
311      private final String name;
312      private final int access;
313
314      public ParameterInfo(String name, int access) {
315        this.name = name;
316        this.access = access;
317      }
318
319      /** Returns the parameter's name. */
320      public String name() {
321        return name;
322      }
323
324      /** Returns the parameter's modifiers. */
325      public int access() {
326        return access;
327      }
328    }
329  }
330
331  /** The contents of a JVMS §4.7.16 annotation structure. */
332  public static class AnnotationInfo {
333
334    private final String typeName;
335    private final boolean runtimeVisible;
336    private final Map<String, ElementValue> elementValuePairs;
337
338    public AnnotationInfo(
339        String typeName, boolean runtimeVisible, Map<String, ElementValue> elementValuePairs) {
340      this.typeName = typeName;
341      this.runtimeVisible = runtimeVisible;
342      this.elementValuePairs = elementValuePairs;
343    }
344
345    /** The JVMS §4.3.2 field descriptor for the type of the annotation. */
346    public String typeName() {
347      return typeName;
348    }
349
350    /** Returns true if the annotation is visible at runtime. */
351    public boolean isRuntimeVisible() {
352      return runtimeVisible;
353    }
354
355    /** The element-value pairs of the annotation. */
356    public Map<String, ElementValue> elementValuePairs() {
357      return elementValuePairs;
358    }
359
360    /** A value of a JVMS §4.7.16.1 element-value pair. */
361    public interface ElementValue {
362
363      /** The value kind. */
364      Kind kind();
365
366      /** Element value kinds. */
367      enum Kind {
368        ENUM,
369        CONST,
370        ARRAY,
371        CLASS,
372        ANNOTATION
373      }
374
375      /** An enum constant value. */
376      class EnumConstValue implements ElementValue {
377
378        private final String typeName;
379        private final String constName;
380
381        public EnumConstValue(String typeName, String constName) {
382          this.typeName = typeName;
383          this.constName = constName;
384        }
385
386        @Override
387        public Kind kind() {
388          return Kind.ENUM;
389        }
390
391        /** The type of the enum. */
392        public String typeName() {
393          return typeName;
394        }
395
396        /** The name of the enum constant. */
397        public String constName() {
398          return constName;
399        }
400      }
401
402      /** A primitive or string constant value. */
403      class ConstValue implements ElementValue {
404
405        private final Const.Value value;
406
407        public ConstValue(Const.Value value) {
408
409          this.value = value;
410        }
411
412        @Override
413        public Kind kind() {
414          return Kind.CONST;
415        }
416
417        /** The constant value. */
418        public Const.Value value() {
419          return value;
420        }
421      }
422
423      /** A constant array value. */
424      class ArrayValue implements ElementValue {
425
426        private final List<ElementValue> elements;
427
428        public ArrayValue(List<ElementValue> elements) {
429          this.elements = elements;
430        }
431
432        @Override
433        public Kind kind() {
434          return Kind.ARRAY;
435        }
436
437        /** The elements of the array. */
438        public List<ElementValue> elements() {
439          return elements;
440        }
441      }
442
443      /** A constant class literal value. */
444      class ConstClassValue implements ElementValue {
445
446        private final String className;
447
448        public ConstClassValue(String className) {
449          this.className = className;
450        }
451
452        @Override
453        public Kind kind() {
454          return Kind.CLASS;
455        }
456
457        /** The class name. */
458        public String className() {
459          return className;
460        }
461      }
462
463      /** A nested annotation value. */
464      class AnnotationValue implements ElementValue {
465
466        private final AnnotationInfo annotation;
467
468        public AnnotationValue(AnnotationInfo annotation) {
469          this.annotation = annotation;
470        }
471
472        @Override
473        public Kind kind() {
474          return Kind.ANNOTATION;
475        }
476
477        /** The annotation. */
478        public AnnotationInfo annotation() {
479          return annotation;
480        }
481      }
482    }
483  }
484
485  /** The contents of a JVMS §4.7.20 type annotation structure. */
486  public static class TypeAnnotationInfo {
487    private final TargetType targetType;
488    private final Target target;
489    private final TypePath path;
490    private final AnnotationInfo anno;
491
492    public TypeAnnotationInfo(
493        TargetType targetType, Target target, TypePath path, AnnotationInfo anno) {
494      this.targetType = targetType;
495      this.target = target;
496      this.path = path;
497      this.anno = anno;
498    }
499
500    /**
501     * The underlying annotation info (type, visibility, element-value pairs); shared with
502     * declaration annotations.
503     */
504    public AnnotationInfo anno() {
505      return anno;
506    }
507
508    /** A JVMS 4.7.20 target_type kind, denotes the type context where the annotation appears. */
509    public TargetType targetType() {
510      return targetType;
511    }
512
513    /** A JVMS 4.7.20 target_info structure. */
514    public Target target() {
515      return target;
516    }
517
518    /**
519     * A JVMS 4.7.20 type_path structure, denotes which part of the type the annotation applies to.
520     */
521    public TypePath path() {
522      return path;
523    }
524
525    /** A JVMS 4.7.20 target_type kind. */
526    public enum TargetType {
527      CLASS_TYPE_PARAMETER(0x00),
528      METHOD_TYPE_PARAMETER(0x01),
529      SUPERTYPE(0x10),
530      CLASS_TYPE_PARAMETER_BOUND(0x11),
531      METHOD_TYPE_PARAMETER_BOUND(0x12),
532      FIELD(0x13),
533      METHOD_RETURN(0x14),
534      METHOD_RECEIVER_PARAMETER(0x15),
535      METHOD_FORMAL_PARAMETER(0x16),
536      METHOD_THROWS(0x17);
537
538      private final int tag;
539
540      TargetType(int tag) {
541        this.tag = tag;
542      }
543
544      public int tag() {
545        return tag;
546      }
547    }
548
549    /** A JVMS 4.7.20 target_info. */
550    public abstract static class Target {
551      /** Target info kind. */
552      public enum Kind {
553        TYPE_PARAMETER,
554        SUPERTYPE,
555        TYPE_PARAMETER_BOUND,
556        EMPTY,
557        FORMAL_PARAMETER,
558        THROWS;
559      }
560
561      /** Returns the target info kind. */
562      public abstract Kind kind();
563    }
564
565    /** A JVMS 4.7.20.1 type_parameter_target. */
566    public static class TypeParameterTarget extends Target {
567      private final int index;
568
569      public TypeParameterTarget(int index) {
570        this.index = index;
571      }
572
573      public int index() {
574        return index;
575      }
576
577      @Override
578      public Kind kind() {
579        return Kind.TYPE_PARAMETER;
580      }
581    }
582
583    /** A JVMS 4.7.20.1 supertype_target. */
584    public static class SuperTypeTarget extends Target {
585      private final int index;
586
587      public SuperTypeTarget(int index) {
588        this.index = index;
589      }
590
591      @Override
592      public Kind kind() {
593        return Kind.SUPERTYPE;
594      }
595
596      public int index() {
597        return index;
598      }
599    }
600
601    /** A JVMS 4.7.20.1 type_parameter_bound_target. */
602    public static class TypeParameterBoundTarget extends Target {
603      private final int typeParameterIndex;
604      private final int boundIndex;
605
606      public TypeParameterBoundTarget(int typeParameterIndex, int boundIndex) {
607        this.typeParameterIndex = typeParameterIndex;
608        this.boundIndex = boundIndex;
609      }
610
611      @Override
612      public Kind kind() {
613        return Kind.TYPE_PARAMETER_BOUND;
614      }
615
616      public int typeParameterIndex() {
617        return typeParameterIndex;
618      }
619
620      public int boundIndex() {
621        return boundIndex;
622      }
623    }
624
625    /** A JVMS 4.7.20.1 empty_target. */
626    public static final Target EMPTY_TARGET =
627        new Target() {
628          @Override
629          public Kind kind() {
630            return Kind.EMPTY;
631          }
632        };
633
634    /** A JVMS 4.7.20.1 formal_parameter_target. */
635    public static class FormalParameterTarget extends Target {
636      private final int index;
637
638      public FormalParameterTarget(int index) {
639        this.index = index;
640      }
641
642      @Override
643      public Kind kind() {
644        return Kind.FORMAL_PARAMETER;
645      }
646
647      public int index() {
648        return index;
649      }
650    }
651
652    /** A JVMS 4.7.20.1 throws_target. */
653    public static class ThrowsTarget extends Target {
654      private final int index;
655
656      public ThrowsTarget(int index) {
657        this.index = index;
658      }
659
660      @Override
661      public Kind kind() {
662        return Kind.THROWS;
663      }
664
665      public int index() {
666        return index;
667      }
668    }
669
670    /**
671     * A JVMS 4.7.20.2 type_path.
672     *
673     * <p>Represented as an immutable linked-list of nodes, which is built out by {@code Lower}
674     * while recursively searching for type annotations to process.
675     */
676    public static class TypePath {
677
678      /** The root type_path_kind, used for initialization. */
679      public static TypePath root() {
680        return new TypePath(null, null);
681      }
682
683      /** Adds an array type_path_kind entry. */
684      public TypePath array() {
685        return new TypePath(Kind.ARRAY, this);
686      }
687
688      /** Adds a nested type type_path_kind entry. */
689      public TypePath nested() {
690        return new TypePath(Kind.NESTED, this);
691      }
692
693      /** Adds a wildcard bound type_path_kind entry. */
694      public TypePath wild() {
695        return new TypePath(Kind.WILDCARD_BOUND, this);
696      }
697
698      /** Adds a type argument type_path_kind entry. */
699      public TypePath typeArgument(int idx) {
700        return new TypePath(idx, Kind.TYPE_ARGUMENT, this);
701      }
702
703      /** A type_path_kind. */
704      enum Kind {
705        ARRAY(0),
706        NESTED(1),
707        WILDCARD_BOUND(2),
708        TYPE_ARGUMENT(3);
709
710        final int tag;
711
712        Kind(int tag) {
713          this.tag = tag;
714        }
715      }
716
717      private final TypePath parent;
718      private final Kind kind;
719      private final int index;
720
721      private TypePath(Kind kind, TypePath parent) {
722        // JVMS 4.7.20.2: type_argument_index is 0 if the bound kind is not TYPE_ARGUMENT
723        this(0, kind, parent);
724      }
725
726      private TypePath(int index, Kind kind, TypePath parent) {
727        this.index = index;
728        this.kind = kind;
729        this.parent = parent;
730      }
731
732      /** The type argument index; set only if the kind is {@code TYPE_ARGUMENT}. */
733      public int typeArgumentIndex() {
734        return index;
735      }
736
737      /** The JVMS 4.7.20.2-A serialized value of the type_path_kind. */
738      public byte tag() {
739        return (byte) kind.tag;
740      }
741
742      /** Returns a flattened view of the type path. */
743      public ImmutableList<TypePath> flatten() {
744        Deque<TypePath> flat = new ArrayDeque<>();
745        for (TypePath curr = this; curr.kind != null; curr = curr.parent) {
746          flat.addFirst(curr);
747        }
748        return ImmutableList.copyOf(flat);
749      }
750    }
751  }
752}
753