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 Java2Rewrites {
032      int TypeDecl.uniqueIndexCounter = 1;
033      syn lazy int TypeDecl.uniqueIndex() = topLevelType().uniqueIndexCounter++;
034    
035    
036      syn lazy String TypeDecl.jvmName() {
037        throw new Error("Jvm name only supported for reference types and not " + getClass().getName());
038      }
039      eq ReferenceType.jvmName() {
040        if (!isNestedType()) {
041          return fullName();
042        } else if (isAnonymous() || isLocalClass()) {
043          return enclosingType().jvmName() + "$" + uniqueIndex() + name();
044        } else {
045          return enclosingType().jvmName() + "$" + name();
046        }
047      }
048      eq ArrayDecl.jvmName() {
049        StringBuffer dim = new StringBuffer();
050        for (int i = 0; i < dimension(); i++) {
051          dim.append("[");
052        }
053        if (elementType().isReferenceType()) {
054          return dim.toString() + "L" + elementType().jvmName() + ";";
055        } else {
056          return dim.toString() + elementType().jvmName();
057        }
058      }
059      eq ByteType.jvmName() = "B";
060      eq CharType.jvmName() = "C";
061      eq ShortType.jvmName() = "S";
062      eq IntType.jvmName() = "I";
063      eq LongType.jvmName() = "J";
064      eq FloatType.jvmName() = "F";
065      eq DoubleType.jvmName() = "D";
066      eq BooleanType.jvmName() = "Z";
067    
068      syn String TypeDecl.primitiveClassName() {
069        throw new Error("primitiveClassName not supported for " + name() + " of type " + getClass().getName());
070      }
071      eq ByteType.primitiveClassName() = "Byte";
072      eq CharType.primitiveClassName() = "Character";
073      eq ShortType.primitiveClassName() = "Short";
074      eq IntType.primitiveClassName() = "Integer";
075      eq LongType.primitiveClassName() = "Long";
076      eq FloatType.primitiveClassName() = "Float";
077      eq DoubleType.primitiveClassName() = "Double";
078      eq BooleanType.primitiveClassName() = "Boolean";
079      eq VoidType.primitiveClassName() = "Void";
080    
081      syn String TypeDecl.referenceClassFieldName() {
082        throw new Error("referenceClassFieldName not supported for " + name() + " of type " + getClass().getName());
083      }
084      eq ReferenceType.referenceClassFieldName() = "class$" + jvmName().replace('[', '$').replace('.', '$').replace(';', ' ').trim();
085      eq ArrayDecl.referenceClassFieldName() = "array" + jvmName().replace('[', '$').replace('.', '$').replace(';', ' ').trim();
086    
087    
088      // lazily build a static field for assertionsDisabled
089      private FieldDeclaration TypeDecl.createAssertionsDisabled = null;
090      public FieldDeclaration TypeDecl.createAssertionsDisabled() {
091        if (createAssertionsDisabled != null) {
092          return createAssertionsDisabled;
093        }
094        // static final boolean $assertionsDisabled = !TypeName.class.desiredAssertionStatus();
095        createAssertionsDisabled = new FieldDeclaration(
096          new Modifiers(new List().add(new Modifier("public")).add(new Modifier("static")).add(new Modifier("final"))),
097          new PrimitiveTypeAccess("boolean"),
098          "$assertionsDisabled",
099          new Opt(
100              new LogNotExpr(
101                topLevelType().createQualifiedAccess().qualifiesAccess(
102                  new ClassAccess().qualifiesAccess(
103                    new MethodAccess(
104                      "desiredAssertionStatus",
105                      new List()
106                    )
107                  )
108                )
109              )
110          )
111        );
112        getBodyDeclList().insertChild(createAssertionsDisabled, 0);
113        // TODO remove this!
114        // explicit read to trigger possible rewrites
115        createAssertionsDisabled = (FieldDeclaration) getBodyDeclList().getChild(0);
116        // transform the generated initalization, e.g., the ClassAccess construct
117        createAssertionsDisabled.transformation();
118        return createAssertionsDisabled;
119      }
120    
121      public FieldDeclaration InterfaceDecl.createStaticClassField(String name) {
122        return methodHolder().createStaticClassField(name);
123      }
124      public MethodDecl InterfaceDecl.createStaticClassMethod() {
125        return methodHolder().createStaticClassMethod();
126      }
127      // create anonymous class to delegate to
128      private TypeDecl InterfaceDecl.methodHolder = null;
129      public TypeDecl InterfaceDecl.methodHolder() {
130        if (methodHolder != null) {
131          return methodHolder;
132        }
133        String name = "$" + nextAnonymousIndex();
134        ClassDecl c = addMemberClass(new ClassDecl(
135          new Modifiers(new List()),
136          name,
137          new Opt(),
138          new List(),
139          new List()
140        ));
141        methodHolder = c;
142        return c;
143      }
144    
145      // lazily build a static field for each typename used in a .class expression
146      private HashMap TypeDecl.createStaticClassField = null;
147      public FieldDeclaration TypeDecl.createStaticClassField(String name) {
148        if (createStaticClassField == null) {
149          createStaticClassField = new HashMap();
150        }
151        if (createStaticClassField.containsKey(name)) {
152          return (FieldDeclaration) createStaticClassField.get(name);
153        }
154        // static synthetic Class class$java$lang$String;
155        FieldDeclaration f = new FieldDeclaration(
156          new Modifiers(new List().add(new Modifier("public")).add(new Modifier("static"))),
157          lookupType("java.lang", "Class").createQualifiedAccess(),
158          name,
159          new Opt()
160        ) {
161          public boolean isConstant() {
162            return true;
163          }
164        };
165        createStaticClassField.put(name, f);
166        return addMemberField(f);
167      }
168    
169      // lazily build a static class$ method in this type declaration
170      private MethodDecl TypeDecl.createStaticClassMethod = null;
171      public MethodDecl TypeDecl.createStaticClassMethod() {
172        if (createStaticClassMethod != null) {
173          return createStaticClassMethod;
174        }
175        // static synthetic Class class$(String name) {
176        //   try {
177        //     return java.lang.Class.forName(name);
178        //   } catch(java.lang.ClassNotFoundException e) {
179        //     throw new java.lang.NoClassDefFoundError(e.getMessage());
180        //   }
181        // }
182        createStaticClassMethod = new MethodDecl(
183          new Modifiers(new List().add(new Modifier("public")).add(new Modifier("static"))),
184          lookupType("java.lang", "Class").createQualifiedAccess(),
185          "class$",
186          new List().add(
187            new ParameterDeclaration(
188              new Modifiers(new List()),
189              lookupType("java.lang", "String").createQualifiedAccess(),
190              "name"
191            )
192          ),
193          new List(),
194          new Opt(
195            new Block(
196              new List().add(
197                new TryStmt(
198                  new Block(
199                    new List().add(
200                      new ReturnStmt(
201                        new Opt(
202                          lookupType("java.lang", "Class").createQualifiedAccess().qualifiesAccess(
203                            new MethodAccess(
204                              "forName",
205                              new List().add(
206                                new VarAccess("name")
207                              )
208                            )
209                          )
210                        )
211                      )
212                    )
213                  ),
214                  new List().add(
215                    new BasicCatch(
216                      new ParameterDeclaration(
217                        new Modifiers(new List()),
218                        lookupType("java.lang", "ClassNotFoundException").createQualifiedAccess(),
219                        "e"
220                      ),
221                      new Block(
222                        new List().add(
223                          new ThrowStmt(
224                            new ClassInstanceExpr(
225                              lookupType("java.lang", "NoClassDefFoundError").createQualifiedAccess(),
226                              new List().add(
227                                new VarAccess("e").qualifiesAccess(
228                                  new MethodAccess(
229                                    "getMessage",
230                                    new List()
231                                  )
232                                )
233                              ),
234                              new Opt()
235                            )
236                          )
237                        )
238                      )
239                    )
240                  ),
241                  new Opt()
242                )
243              )
244            )
245          )
246        ) {
247          public boolean isConstant() {
248            return true;
249          }
250        };
251        return addMemberMethod(createStaticClassMethod);
252      }
253    
254    }