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 Transformations {
032      // generic traversal of the tree
033      public void ASTNode.transformation() {
034        for (int i = 0; i < getNumChild(); i++) {
035            getChild(i).transformation();
036        }
037      }
038    
039      public void CompilationUnit.transformation() {
040        if (fromSource()) {
041          for (int i = 0; i < getNumTypeDecl(); i++) {
042            getTypeDecl(i).transformation();
043          }
044        }
045      }
046    
047      // remote collection
048      public void TypeDecl.transformation() {
049        addEnclosingVariables();
050        super.transformation();
051        if (isNestedType()) {
052          enclosingType().addNestedType(this);
053        }
054      }
055    
056      public void ClassDecl.transformation() {
057        super.transformation();
058        if (hasImplicitConstructor()) {
059          getImplicitConstructor().transformation();
060        }
061      }
062    
063      // remote collection
064      public void TypeAccess.transformation() {
065        super.transformation();
066        if (type().elementType().isNestedType() && hostType() != null) {
067          hostType().addUsedNestedType(type().elementType());
068        }
069      }
070    
071      // remote collection / demand driven creation of accessor
072      public void MethodAccess.transformation() {
073        MethodDecl m = decl();
074    
075        if (requiresAccessor()) {
076          /* Access to private methods in enclosing types:
077          The original MethodAccess is replaced with an access to an accessor method
078          built by createAccessor(). This method is built lazily and differs from
079          normal MethodDeclarations in the following ways:
080          1) The method in the class file should always be static and the signature
081             is thus changed to include a possible this reference as the first argument.
082          2) The method is always invoked using INVOKESTATIC
083          3) The flags must indicate that the method is static and package private
084          */
085          super.transformation();
086          this.replaceWith(decl().createAccessor(methodQualifierType()).createBoundAccess(getArgList()));
087          return;
088        } else if (!m.isStatic() && isQualified() && prevExpr().isSuperAccess() && !hostType().instanceOf(prevExpr().type())) {
089          decl().createSuperAccessor(superAccessorTarget());
090        }
091        super.transformation();
092      }
093    
094      // remote collection / demand driven creation of accessor
095      public void VarAccess.transformation() {
096        Variable v = decl();
097        if (v instanceof FieldDeclaration) {
098          FieldDeclaration f = (FieldDeclaration) v;
099          if (requiresAccessor()) {
100            TypeDecl typeDecl = fieldQualifierType();
101            if (isSource()) {
102              f.createAccessor(typeDecl);
103            }
104            if (isDest()) {
105              f.createAccessorWrite(typeDecl);
106            }
107          }
108        }
109        super.transformation();
110      }
111    
112    
113      public void ConstructorDecl.transformation() {
114        // this$val as fields and constructor parameters
115        addEnclosingVariables();
116        super.transformation();
117      }
118    
119    
120      // remote collection / demand driven creation of accessor
121      public void ClassInstanceExpr.transformation() {
122        // this$val
123        addEnclosingVariables();
124        // touch accessorIndex go force creation of private constructorAccessor
125        if (decl().isPrivate() && type() != hostType()) {
126          decl().createAccessor();
127        }
128        super.transformation();
129      }
130    
131      // remote collection / demand driven creation of accessor
132      public void ConstructorAccess.transformation() {
133        // this$val
134        addEnclosingVariables();
135        // touch accessorIndex go force creation of private constructorAccessor
136        if (decl().isPrivate() && decl().hostType() != hostType()) {
137          decl().createAccessor();
138        }
139        super.transformation();
140      }
141    
142      // remote collection / demand driven creation of accessor
143      public void SuperConstructorAccess.transformation() {
144        // this$val
145        addEnclosingVariables();
146        // touch accessorIndex to force creation of private constructorAccessor
147        if (decl().isPrivate() && decl().hostType() != hostType()) {
148          decl().createAccessor();
149        }
150        super.transformation();
151      }
152    
153      // remote collection / demand driven creation of accessor
154      public void ClassAccess.transformation() {
155        super.transformation();
156        // touch static class method before any accessors to make it first in method
157        if (isQualified() && qualifier().type().isReferenceType()) {
158          hostType().topLevelType().createStaticClassMethod();
159          FieldDeclaration f = hostType().topLevelType().createStaticClassField(prevExpr().type().referenceClassFieldName());
160        }
161    
162      }
163    
164      public void AssertStmt.transformation() {
165        super.transformation();
166        // add field to hold cached result as a side-effect
167        FieldDeclaration f = hostType().topLevelType().createStaticClassField(hostType().topLevelType().referenceClassFieldName());
168        FieldDeclaration assertionsDisabled = hostType().createAssertionsDisabled();
169        Expr condition = (Expr) getCondition().treeCopyNoTransform();
170        List args = new List();
171        if (hasMessage()) {
172          if (getMessage().type().isString()) {
173            args.add(new CastExpr(new TypeAccess("java.lang", "Object"), (Expr) getMessage().treeCopyNoTransform()));
174          } else {
175            args.add(getMessage().treeCopyNoTransform());
176          }
177        }
178        Stmt stmt = new IfStmt(
179            new LogNotExpr(
180              new ParExpr(
181                new OrLogicalExpr(
182                  new BoundFieldAccess(assertionsDisabled),
183                  condition
184                )
185              )
186            ),
187            new ThrowStmt(
188              new ClassInstanceExpr(
189                lookupType("java.lang", "AssertionError").createQualifiedAccess(),
190                args,
191                new Opt()
192              )
193            ),
194            new Opt()
195          );
196    
197        this.replaceWith(stmt);
198        stmt.transformation();
199      }
200    
201      /** Imperative transformation of the AST
202       * This should be removed.
203       *
204       * Usage: this.replaceWith(replacement)
205       *
206       * @param replacement node to replace this node with
207       * @return the new node
208       * @deprecated
209       */
210      @Deprecated
211      protected void ASTNode.replaceWith(ASTNode replacement) {
212         int replacePos = getParent().getIndexOfChild(this);
213         getParent().setChild(replacement, replacePos);
214      }
215    }