001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     * All rights reserved.
008     */
009    
010    aspect AnnotationsCodegen {
011      refine Attributes eq TypeDecl.attributes() {
012        Collection c = refined();
013        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
014        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
015        return c;
016      }
017      refine Attributes eq FieldDeclaration.attributes() {
018        Collection c = refined();
019        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
020        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
021        return c;
022      }
023      refine Attributes eq MethodDecl.attributes() {
024        Collection c = refined();
025        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
026        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
027        addRuntimeVisibleParameterAnnotationsAttribute(c);
028        addRuntimeInvisibleParameterAnnotationsAttribute(c);
029        return c;
030      }
031      refine Attributes eq ConstructorDecl.attributes() {
032        Collection c = refined();
033        getModifiers().addRuntimeVisibleAnnotationsAttribute(c);
034        getModifiers().addRuntimeInvisibleAnnotationsAttribute(c);
035        return c;
036      }
037    
038      // 4.8.15
039      public void Modifiers.addRuntimeVisibleAnnotationsAttribute(Collection c) {
040        ConstantPool cp = hostType().constantPool();
041        Collection annotations = runtimeVisibleAnnotations();
042        if(!annotations.isEmpty())
043          c.add(new AnnotationsAttribute(cp, annotations, "RuntimeVisibleAnnotations"));
044      }
045    
046      // 4.8.16
047      public void Modifiers.addRuntimeInvisibleAnnotationsAttribute(Collection c) {
048        ConstantPool cp = hostType().constantPool();
049        Collection annotations = runtimeInvisibleAnnotations();
050        if(!annotations.isEmpty())
051          c.add(new AnnotationsAttribute(cp, annotations, "RuntimeInvisibleAnnotations"));
052      }
053    
054      class AnnotationsAttribute extends Attribute {
055        public AnnotationsAttribute(ConstantPool cp, Collection annotations, String name) {
056          super(cp, name);
057          u2(annotations.size());
058          for(Iterator iter = annotations.iterator(); iter.hasNext(); )
059            ((Annotation)iter.next()).appendAsAttributeTo(this);
060        }
061      }
062     
063      // 4.8.15
064      syn boolean Modifier.isRuntimeVisible() = false;
065      eq Annotation.isRuntimeVisible() {
066        Annotation a = decl().annotation(lookupType("java.lang.annotation", "Retention"));
067        if(a == null) return false;
068        ElementConstantValue value = (ElementConstantValue)a.getElementValuePair(0).getElementValue();
069        Variable v = value.getExpr().varDecl();
070        return v != null && v.name().equals("RUNTIME");
071      }
072    
073      // 4.8.16
074      syn boolean Modifier.isRuntimeInvisible() = false;
075      eq Annotation.isRuntimeInvisible() {
076        Annotation a = decl().annotation(lookupType("java.lang.annotation", "Retention"));
077        if(a == null) return true; // default bahavior if not annotated
078        ElementConstantValue value = (ElementConstantValue)a.getElementValuePair(0).getElementValue();
079        Variable v = value.getExpr().varDecl();
080        return v != null &&  v.name().equals("CLASS");
081      }
082    
083      // 4.8.17
084      public void MethodDecl.addRuntimeVisibleParameterAnnotationsAttribute(Collection c) {
085        boolean foundVisibleAnnotations = false;
086        Collection annotations = new ArrayList(getNumParameter());
087        for(int i = 0; i < getNumParameter(); i++) {
088          Collection a = getParameter(i).getModifiers().runtimeVisibleAnnotations();
089          if(!a.isEmpty()) foundVisibleAnnotations = true;
090          annotations.add(a);
091        }
092        if(foundVisibleAnnotations)
093          c.add(new ParameterAnnotationsAttribute(hostType().constantPool(), annotations, "RuntimeVisibleParameterAnnotations"));
094      }
095    
096      public Collection Modifiers.runtimeVisibleAnnotations() {
097        Collection annotations = new ArrayList();
098        for(int i = 0; i < getNumModifier(); i++)
099          if(getModifier(i).isRuntimeVisible())
100            annotations.add(getModifier(i));
101        return annotations;
102      }
103    
104      // 4.8.18
105      public void MethodDecl.addRuntimeInvisibleParameterAnnotationsAttribute(Collection c) {
106        boolean foundInvisibleAnnotations = false;
107        Collection annotations = new ArrayList(getNumParameter());
108        for(int i = 0; i < getNumParameter(); i++) {
109          Collection a = getParameter(i).getModifiers().runtimeInvisibleAnnotations();
110          if(!a.isEmpty()) foundInvisibleAnnotations = true;
111          annotations.add(a);
112        }
113        if(foundInvisibleAnnotations)
114          c.add(new ParameterAnnotationsAttribute(hostType().constantPool(), annotations, "RuntimeInvisibleParameterAnnotations"));
115      }
116    
117      public Collection Modifiers.runtimeInvisibleAnnotations() {
118        Collection annotations = new ArrayList();
119        for(int i = 0; i < getNumModifier(); i++)
120          if(getModifier(i).isRuntimeInvisible())
121            annotations.add(getModifier(i));
122        return annotations;
123      }
124    
125      class ParameterAnnotationsAttribute extends Attribute {
126        public ParameterAnnotationsAttribute(ConstantPool cp, Collection annotations, String name) {
127          super(cp, name);
128          u1(annotations.size());
129          for(Iterator iter = annotations.iterator(); iter.hasNext(); ) {
130            Collection c = (Collection)iter.next();
131            for(Iterator inner = c.iterator(); inner.hasNext(); ) {
132              Annotation a = (Annotation)inner.next();
133              a.appendAsAttributeTo(this);
134            }
135          }
136        }
137      }
138    
139      // Add ACC_ANNOTATION flag to generated class file
140      public static final int Modifiers.ACC_ANNOTATION = 0x2000;
141      eq AnnotationDecl.flags() = super.flags() | Modifiers.ACC_ANNOTATION;
142    
143      eq AnnotationMethodDecl.attributes() {
144        Collection c = super.attributes();
145        // 4.8.19
146        if(hasDefaultValue()) {
147          Attribute attribute = new Attribute(hostType().constantPool(), "AnnotationDefault");
148          getDefaultValue().appendAsAttributeTo(attribute);
149          c.add(attribute);
150        }
151        return c;
152      }
153    
154      // 4.8.15
155      public void Annotation.appendAsAttributeTo(Attribute buf) {
156        ConstantPool cp = hostType().constantPool();
157        String typeDescriptor = decl().typeDescriptor();
158        int type_index = cp.addUtf8(typeDescriptor);
159        buf.u2(type_index);
160        buf.u2(getNumElementValuePair());
161        for(int i = 0; i < getNumElementValuePair(); i++) {
162          int name_index = cp.addUtf8(getElementValuePair(i).getName());
163          buf.u2(name_index);
164          getElementValuePair(i).getElementValue().appendAsAttributeTo(buf);
165        }
166      }
167    
168      /**
169       * Add an annotation parameter constant to the constant pool.
170       * @see AST.TypeDecl#addConstant(ConstantPool, Constant) TypeDecl.addConstant(ConstantPool, Constant)
171       */
172      public int TypeDecl.addAnnotConstant(ConstantPool p, Constant c)     { 
173        if(isString())
174          return p.addUtf8(c.stringValue());
175        throw new Error("Not supported"); 
176      }
177      public int BooleanType.addAnnotConstant(ConstantPool p, Constant c)  {
178        return addConstant(p, c);
179      } 
180      public int IntegralType.addAnnotConstant(ConstantPool p, Constant c) {
181        return addConstant(p, c);
182      }
183      public int LongType.addAnnotConstant(ConstantPool p, Constant c) {
184        return addConstant(p, c);
185      }
186      public int FloatType.addAnnotConstant(ConstantPool p, Constant c) {
187        return addConstant(p, c);
188      }
189      public int DoubleType.addAnnotConstant(ConstantPool p, Constant c) {
190        return addConstant(p, c);
191      }
192    
193      // 4.8.15.1
194      public void ElementValue.appendAsAttributeTo(Attribute buf) {
195        throw new Error(getClass().getName() + " does not support appendAsAttributeTo(Attribute buf)");
196      }
197      public void ElementConstantValue.appendAsAttributeTo(Attribute buf) {
198        if(getExpr().isConstant() && !getExpr().type().isEnumDecl()) {
199          char tag = getExpr().type().isString() ? 's' : getExpr().type().typeDescriptor().charAt(0);
200          int const_value_index = getExpr().type().addAnnotConstant(hostType().constantPool(), getExpr().constant());
201          buf.u1(tag);
202          buf.u2(const_value_index);
203        }
204        else if(getExpr().isClassAccess()) {
205          int const_class_index = hostType().constantPool().addUtf8(getExpr().type().typeDescriptor());
206          buf.u1('c');
207          buf.u2(const_class_index);
208        }
209        else {
210          Variable v = getExpr().varDecl();
211          if(v == null) throw new Error("Expected Enumeration constant");
212    
213          int type_name_index = hostType().constantPool().addUtf8(v.type().typeDescriptor());
214          int const_name_index = hostType().constantPool().addUtf8(v.name());
215          buf.u1('e');
216          buf.u2(type_name_index);
217          buf.u2(const_name_index);
218        }
219      }
220      public void ElementAnnotationValue.appendAsAttributeTo(Attribute buf) {
221        buf.u1('@');
222        getAnnotation().appendAsAttributeTo(buf);
223      }
224      public void ElementArrayValue.appendAsAttributeTo(Attribute buf) {
225        buf.u1('[');
226        buf.u2(getNumElementValue());
227        for(int i = 0; i < getNumElementValue(); i++)
228          getElementValue(i).appendAsAttributeTo(buf);
229      }
230    
231      inh TypeDecl ElementValue.hostType();
232    }