001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    aspect AnnotationsCodegen {
032      refine Attributes eq TypeDecl.attributes() {
033        Collection c = refined();
034        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
035        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
036        return c;
037      }
038      refine Attributes eq FieldDeclaration.attributes() {
039        Collection c = refined();
040        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
041        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
042        return c;
043      }
044      refine Attributes eq MethodDecl.attributes() {
045        Collection c = refined();
046        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
047        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
048        addRuntimeVisibleParameterAnnotationsAttribute(c);
049        addRuntimeInvisibleParameterAnnotationsAttribute(c);
050        return c;
051      }
052      refine Attributes eq ConstructorDecl.attributes() {
053        Collection c = refined();
054        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
055        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
056        return c;
057      }
058    
059      // 4.8.15
060      public void Modifiers.addRuntimeVisibleAnnotationsAttribute(Collection c) {
061        ConstantPool cp = hostType().constantPool();
062        Collection annotations = runtimeVisibleAnnotations();
063        if (!annotations.isEmpty()) {
064          c.add(new AnnotationsAttribute(cp, annotations, "RuntimeVisibleAnnotations"));
065        }
066      }
067    
068      // 4.8.16
069      public void Modifiers.addRuntimeInvisibleAnnotationsAttribute(Collection c) {
070        ConstantPool cp = hostType().constantPool();
071        Collection annotations = runtimeInvisibleAnnotations();
072        if (!annotations.isEmpty()) {
073          c.add(new AnnotationsAttribute(cp, annotations, "RuntimeInvisibleAnnotations"));
074        }
075      }
076    
077      class AnnotationsAttribute extends Attribute {
078        public AnnotationsAttribute(ConstantPool cp, Collection annotations, String name) {
079          super(cp, name);
080          u2(annotations.size());
081          for (Iterator iter = annotations.iterator(); iter.hasNext(); ) {
082            ((Annotation) iter.next()).appendAsAttributeTo(this);
083          }
084        }
085      }
086    
087      // 4.8.15
088      syn boolean Modifier.isRuntimeVisible() = false;
089      eq Annotation.isRuntimeVisible() {
090        Annotation a = decl().annotation(lookupType("java.lang.annotation", "Retention"));
091        if (a == null) {
092          return false;
093        }
094        ElementConstantValue value = (ElementConstantValue) a.getElementValuePair(0).getElementValue();
095        Variable v = value.getExpr().varDecl();
096        return v != null && v.name().equals("RUNTIME");
097      }
098    
099      // 4.8.16
100      syn boolean Modifier.isRuntimeInvisible() = false;
101      eq Annotation.isRuntimeInvisible() {
102        Annotation a = decl().annotation(lookupType("java.lang.annotation", "Retention"));
103        if (a == null) return true; // default bahavior if not annotated
104        ElementConstantValue value = (ElementConstantValue) a.getElementValuePair(0).getElementValue();
105        Variable v = value.getExpr().varDecl();
106        return v != null &&  v.name().equals("CLASS");
107      }
108    
109      // 4.8.17
110      public void MethodDecl.addRuntimeVisibleParameterAnnotationsAttribute(Collection c) {
111        boolean foundVisibleAnnotations = false;
112        Collection annotations = new ArrayList(getNumParameter());
113        for (int i = 0; i < getNumParameter(); i++) {
114          Collection a = getParameter(i).getModifiers().runtimeVisibleAnnotations();
115          if (!a.isEmpty()) {
116            foundVisibleAnnotations = true;
117          }
118          annotations.add(a);
119        }
120        if (foundVisibleAnnotations) {
121          c.add(new ParameterAnnotationsAttribute(hostType().constantPool(), annotations, "RuntimeVisibleParameterAnnotations"));
122        }
123      }
124    
125      public Collection Modifiers.runtimeVisibleAnnotations() {
126        Collection annotations = new ArrayList();
127        for (int i = 0; i < getNumModifier(); i++) {
128          if (getModifier(i).isRuntimeVisible()) {
129            annotations.add(getModifier(i));
130          }
131        }
132        return annotations;
133      }
134    
135      // 4.8.18
136      public void MethodDecl.addRuntimeInvisibleParameterAnnotationsAttribute(Collection c) {
137        boolean foundInvisibleAnnotations = false;
138        Collection annotations = new ArrayList(getNumParameter());
139        for (int i = 0; i < getNumParameter(); i++) {
140          Collection a = getParameter(i).getModifiers().runtimeInvisibleAnnotations();
141          if (!a.isEmpty()) {
142            foundInvisibleAnnotations = true;
143          }
144          annotations.add(a);
145        }
146        if (foundInvisibleAnnotations) {
147          c.add(new ParameterAnnotationsAttribute(hostType().constantPool(), annotations, "RuntimeInvisibleParameterAnnotations"));
148        }
149      }
150    
151      public Collection Modifiers.runtimeInvisibleAnnotations() {
152        Collection annotations = new ArrayList();
153        for (int i = 0; i < getNumModifier(); i++) {
154          if (getModifier(i).isRuntimeInvisible()) {
155            annotations.add(getModifier(i));
156          }
157        }
158        return annotations;
159      }
160    
161      class ParameterAnnotationsAttribute extends Attribute {
162        public ParameterAnnotationsAttribute(ConstantPool cp, Collection annotations, String name) {
163          super(cp, name);
164          u1(annotations.size());
165          for (Iterator iter = annotations.iterator(); iter.hasNext(); ) {
166            Collection c = (Collection) iter.next();
167            for (Iterator inner = c.iterator(); inner.hasNext(); ) {
168              Annotation a = (Annotation) inner.next();
169              a.appendAsAttributeTo(this);
170            }
171          }
172        }
173      }
174    
175      // Add ACC_ANNOTATION flag to generated class file
176      public static final int Modifiers.ACC_ANNOTATION = 0x2000;
177      eq AnnotationDecl.flags() = super.flags() | Modifiers.ACC_ANNOTATION;
178    
179      eq AnnotationMethodDecl.attributes() {
180        Collection c = super.attributes();
181        // 4.8.19
182        if (hasDefaultValue()) {
183          Attribute attribute = new Attribute(hostType().constantPool(), "AnnotationDefault");
184          getDefaultValue().appendAsAttributeTo(attribute);
185          c.add(attribute);
186        }
187        return c;
188      }
189    
190      // 4.8.15
191      public void Annotation.appendAsAttributeTo(Attribute buf) {
192        ConstantPool cp = hostType().constantPool();
193        String typeDescriptor = decl().typeDescriptor();
194        int type_index = cp.addUtf8(typeDescriptor);
195        buf.u2(type_index);
196        buf.u2(getNumElementValuePair());
197        for (int i = 0; i < getNumElementValuePair(); i++) {
198          int name_index = cp.addUtf8(getElementValuePair(i).getName());
199          buf.u2(name_index);
200          getElementValuePair(i).getElementValue().appendAsAttributeTo(buf);
201        }
202      }
203    
204      /**
205       * Add an annotation parameter constant to the constant pool.
206       * @see AST.TypeDecl#addConstant(ConstantPool, Constant) TypeDecl.addConstant(ConstantPool, Constant)
207       */
208      public int TypeDecl.addAnnotConstant(ConstantPool p, Constant c)     {
209        if (isString()) {
210          return p.addUtf8(c.stringValue());
211        }
212        throw new Error("Not supported");
213      }
214      public int BooleanType.addAnnotConstant(ConstantPool p, Constant c)  {
215        return addConstant(p, c);
216      }
217      public int IntegralType.addAnnotConstant(ConstantPool p, Constant c) {
218        return addConstant(p, c);
219      }
220      public int LongType.addAnnotConstant(ConstantPool p, Constant c) {
221        return addConstant(p, c);
222      }
223      public int FloatType.addAnnotConstant(ConstantPool p, Constant c) {
224        return addConstant(p, c);
225      }
226      public int DoubleType.addAnnotConstant(ConstantPool p, Constant c) {
227        return addConstant(p, c);
228      }
229    
230      // 4.8.15.1
231      public void ElementValue.appendAsAttributeTo(Attribute buf) {
232        throw new Error(getClass().getName() + " does not support appendAsAttributeTo(Attribute buf)");
233      }
234    
235      /**
236       * Finds the host type declaration of a class access.
237       * Call this attribute only on expressions that return true for
238       * isClassAccess or it may throw an error!
239       * @return The TypeDecl corresponding to the accesssed class
240       */
241      syn TypeDecl Expr.classAccess() {
242        throw new Error(
243            "Class access can only be computed for class access expressions");
244      }
245    
246      eq AbstractDot.classAccess() {
247        if (getRight() instanceof ClassAccess) {
248          return getLeft().classAccess();
249        } else {
250          return getRight().classAccess();
251        }
252      }
253    
254      eq TypeAccess.classAccess() = type();
255    
256      public void ElementConstantValue.appendAsAttributeTo(Attribute buf) {
257        if (getExpr().isConstant() && !getExpr().type().isEnumDecl()) {
258          TypeDecl targetType = declType();
259          char tag = targetType.isString() ? 's' : targetType.typeDescriptor().charAt(0);
260          int const_value_index = targetType.addAnnotConstant(hostType().constantPool(), getExpr().constant());
261          buf.u1(tag);
262          buf.u2(const_value_index);
263        } else if (getExpr().isClassAccess()) {
264          int const_class_index = hostType().constantPool().addUtf8(getExpr().classAccess().typeDescriptor());
265          buf.u1('c');
266          buf.u2(const_class_index);
267        } else {
268          Variable v = getExpr().varDecl();
269          if (v == null) {
270            throw new Error("Expected Enumeration constant");
271          }
272    
273          int type_name_index = hostType().constantPool().addUtf8(v.type().typeDescriptor());
274          int const_name_index = hostType().constantPool().addUtf8(v.name());
275          buf.u1('e');
276          buf.u2(type_name_index);
277          buf.u2(const_name_index);
278        }
279      }
280      public void ElementAnnotationValue.appendAsAttributeTo(Attribute buf) {
281        buf.u1('@');
282        getAnnotation().appendAsAttributeTo(buf);
283      }
284      public void ElementArrayValue.appendAsAttributeTo(Attribute buf) {
285        buf.u1('[');
286        buf.u2(getNumElementValue());
287        for (int i = 0; i < getNumElementValue(); i++) {
288          getElementValue(i).appendAsAttributeTo(buf);
289        }
290      }
291    
292      inh TypeDecl ElementValue.hostType();
293    }