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 InnerClasses {
032      // no attribute since needed in phases when the AST has been modified
033      public boolean TypeDecl.hasField(String name) {
034        if (!memberFields(name).isEmpty()) {
035          return true;
036        }
037        for (int i = 0; i < getNumBodyDecl(); i++) {
038          if (getBodyDecl(i) instanceof FieldDeclaration) {
039            FieldDeclaration decl = (FieldDeclaration) getBodyDecl(i);
040            if (decl.name().equals(name)) {
041              return true;
042            }
043          }
044        }
045        return false;
046      }
047    
048      private TypeDecl VarAccess.fieldQualifierType() {
049        if (hasPrevExpr()) {
050          return prevExpr().type();
051        }
052        TypeDecl typeDecl = hostType();
053        while (typeDecl != null && !typeDecl.hasField(name())) {
054          typeDecl = typeDecl.enclosingType();
055        }
056        if (typeDecl != null) {
057          return typeDecl;
058        }
059        return decl().hostType();
060      }
061    
062      public boolean TypeDecl.hasMethod(String id) {
063        if (!memberMethods(id).isEmpty()) {
064          return true;
065        }
066        for (int i = 0; i < getNumBodyDecl(); i++) {
067          if (getBodyDecl(i) instanceof MethodDecl) {
068            MethodDecl decl = (MethodDecl) getBodyDecl(i);
069            if (decl.name().equals(id)) {
070              return true;
071            }
072          }
073        }
074        return false;
075      }
076    
077      private TypeDecl MethodAccess.methodQualifierType() {
078        if (hasPrevExpr()) {
079          return prevExpr().type();
080        }
081        TypeDecl typeDecl = hostType();
082        while (typeDecl != null && !typeDecl.hasMethod(name())) {
083          typeDecl = typeDecl.enclosingType();
084        }
085        if (typeDecl != null) {
086          return typeDecl;
087        }
088        return decl().hostType();
089      }
090    
091    
092      // Helpers for arrays
093      inh TypeDecl ArrayInit.expectedType();
094    
095      eq Program.getChild().expectedType() = null;
096    
097      eq ArrayCreationExpr.getArrayInit().expectedType() = type().componentType();
098      eq FieldDeclaration.getInit().expectedType() = type().componentType();
099      eq VariableDeclaration.getInit().expectedType() = type().componentType();
100      eq VariableDecl.getInit().expectedType() = null;
101      eq ArrayInit.getInit().expectedType() = expectedType().componentType();
102    
103      syn lazy int ArrayCreationExpr.numArrays() {
104        int i = type().dimension();
105        Access a = getTypeAccess();
106        while (a instanceof ArrayTypeAccess && !(a instanceof ArrayTypeWithSizeAccess)) {
107          i--;
108          a = ((ArrayTypeAccess) a).getAccess();
109        }
110        return i;
111      }
112    
113      syn TypeDecl TypeDecl.stringPromotion() = this;
114      eq ReferenceType.stringPromotion() = typeObject();
115      eq NullType.stringPromotion() = typeObject();
116      eq ByteType.stringPromotion() = typeInt();
117      eq ShortType.stringPromotion() = typeInt();
118    
119      syn boolean ASTNode.isStringAdd() = false;
120      eq AddExpr.isStringAdd() = type().isString() && !isConstant();
121    
122      syn boolean AddExpr.firstStringAddPart() = type().isString() && !getLeftOperand().isStringAdd();
123      syn boolean AddExpr.lastStringAddPart() = !getParent().isStringAdd();
124    
125      syn MethodDecl TypeDecl.methodWithArgs(String name, TypeDecl[] args) {
126        for (Iterator iter = memberMethods(name).iterator(); iter.hasNext(); ) {
127          MethodDecl m = (MethodDecl) iter.next();
128          if (m.getNumParameter() == args.length) {
129            for (int i = 0; i < args.length; i++) {
130              if (m.getParameter(i).type() == args[i]) {
131                return m;
132              }
133            }
134          }
135        }
136        return null;
137      }
138    
139      protected TypeDecl Access.superConstructorQualifier(TypeDecl targetEnclosingType) {
140        TypeDecl enclosing = hostType();
141        while (!enclosing.instanceOf(targetEnclosingType)) {
142          enclosing = enclosing.enclosingType();
143        }
144        return enclosing;
145      }
146    
147      public TypeDecl MethodAccess.superAccessorTarget() {
148        TypeDecl targetDecl = prevExpr().type();
149        TypeDecl enclosing = hostType();
150        do {
151          enclosing = enclosing.enclosingType();
152        } while (!enclosing.instanceOf(targetDecl));
153        return enclosing;
154      }
155    
156      // The set of TypeDecls that has this TypeDecl as their directly enclosing TypeDecl.
157      // I.e., NestedTypes, InnerTypes, AnonymousClasses, LocalClasses.
158      public Collection<TypeDecl> TypeDecl.nestedTypes =
159          new RobustLinkedList<TypeDecl>();
160    
161      public void TypeDecl.addNestedType(TypeDecl typeDecl) {
162        if (typeDecl != this) {
163          nestedTypes.add(typeDecl);
164        }
165      }
166    
167      // The set of nested TypeDecls that are accessed in this TypeDecl
168      public Collection<TypeDecl> TypeDecl.usedNestedTypes =
169          new RobustLinkedList<TypeDecl>();
170    
171      public void TypeDecl.addUsedNestedType(TypeDecl typeDecl) {
172        usedNestedTypes.add(typeDecl);
173      }
174    
175      // collect the set of variables used in the enclosing class(es)
176      syn lazy Collection TypeDecl.enclosingVariables() {
177        HashSet set = new HashSet();
178        for (TypeDecl e = this; e != null; e = e.enclosingType()) {
179          if (e.isLocalClass() || e.isAnonymous()) {
180            collectEnclosingVariables(set, e.enclosingType());
181          }
182        }
183        if (isClassDecl()) {
184          ClassDecl classDecl = (ClassDecl) this;
185          if (classDecl.isNestedType() && classDecl.hasSuperclass()) {
186            set.addAll(classDecl.superclass().enclosingVariables());
187          }
188        }
189        return set;
190      }
191    
192      public void ASTNode.collectEnclosingVariables(HashSet set, TypeDecl typeDecl) {
193        for (int i = 0; i < getNumChild(); i++) {
194          getChild(i).collectEnclosingVariables(set, typeDecl);
195        }
196      }
197      public void VarAccess.collectEnclosingVariables(HashSet set, TypeDecl typeDecl) {
198        Variable v = decl();
199        if (!v.isInstanceVariable() && !v.isClassVariable() && v.hostType() == typeDecl) {
200          set.add(v);
201        }
202        super.collectEnclosingVariables(set, typeDecl);
203      }
204    
205    
206      public int TypeDecl.accessorCounter = 0;
207    
208      private HashMap TypeDecl.accessorMap = null;
209      public ASTNode TypeDecl.getAccessor(ASTNode source, String name) {
210        ArrayList key = new ArrayList(2);
211        key.add(source);
212        key.add(name);
213        if (accessorMap == null || !accessorMap.containsKey(key)) {
214          return null;
215        }
216        return (ASTNode) accessorMap.get(key);
217      }
218    
219      public void TypeDecl.addAccessor(ASTNode source, String name, ASTNode accessor) {
220        ArrayList key = new ArrayList(2);
221        key.add(source);
222        key.add(name);
223        if (accessorMap == null) {
224          accessorMap = new HashMap();
225        }
226        accessorMap.put(key, accessor);
227      }
228    
229      public ASTNode TypeDecl.getAccessorSource(ASTNode accessor) {
230        Iterator i = accessorMap.entrySet().iterator();
231        while (i.hasNext()) {
232          Map.Entry entry = (Map.Entry) i.next();
233          if (entry.getValue() == accessor) {
234            return (ASTNode) ((ArrayList) entry.getKey()).get(0);
235          }
236        }
237        return null;
238      }
239    
240      public MethodDecl MethodDecl.createAccessor(TypeDecl methodQualifier) {
241        MethodDecl m = (MethodDecl) methodQualifier.getAccessor(this, "method");
242        if (m != null) {
243          return m;
244        }
245    
246        int accessorIndex = methodQualifier.accessorCounter++;
247    
248        List parameterList = new List();
249        for (int i = 0; i < getNumParameter(); i++) {
250          parameterList.add(new ParameterDeclaration(
251                // We don't need to create a qualified access to the type here
252                // since there can be no ambiguity concerning unqualified
253                // type names in an inner/enclosing class
254                // Jesper 2012-05-04
255                // FALSE! We need to create a qualified access in case the
256                // method we are generating an access for is not declared
257                // in the methodQualifier type
258                getParameter(i).type().createQualifiedAccess(),
259                getParameter(i).name()));
260        }
261        List exceptionList = new List();
262        for (int i = 0; i < getNumException(); i++) {
263          exceptionList.add((Access) getException(i).treeCopyNoTransform());
264        }
265    
266        // add synthetic flag to modifiers
267        Modifiers modifiers = new Modifiers(new List());
268        if (getModifiers().isStatic()) {
269          modifiers.addModifier(new Modifier("static"));
270        }
271        modifiers.addModifier(new Modifier("synthetic"));
272        modifiers.addModifier(new Modifier("public"));
273        // build accessor declaration
274        m = new MethodDecl(
275          modifiers,
276          getTypeAccess().type().createQualifiedAccess(),
277          name() + "$access$" + accessorIndex,
278          parameterList,
279          exceptionList,
280          new Opt(
281            new Block(
282              new List().add(
283                createAccessorStmt()
284              )
285            )
286          )
287        );
288        m = methodQualifier.addMemberMethod(m);
289        methodQualifier.addAccessor(this, "method", m);
290        return m;
291      }
292    
293      private Stmt MethodDecl.createAccessorStmt() {
294        List argumentList = new List();
295        for (int i = 0; i < getNumParameter(); i++) {
296          argumentList.add(new VarAccess(getParameter(i).name()));
297        }
298        Access access = new BoundMethodAccess(name(), argumentList, this);
299        if (!isStatic()) {
300          access = new ThisAccess("this").qualifiesAccess(access);
301        }
302        return isVoid() ? (Stmt) new ExprStmt(access) : new ReturnStmt(new Opt(access));
303      }
304    
305      public MethodDecl MethodDecl.createSuperAccessor(TypeDecl methodQualifier) {
306        MethodDecl m = (MethodDecl) methodQualifier.getAccessor(this, "method_super");
307        if (m != null) {
308          return m;
309        }
310    
311        int accessorIndex = methodQualifier.accessorCounter++;
312        List parameters = new List();
313        List args = new List();
314        for (int i = 0; i < getNumParameter(); i++) {
315          parameters.add(new ParameterDeclaration(getParameter(i).type(), getParameter(i).name()));
316          args.add(new VarAccess(getParameter(i).name()));
317        }
318        Stmt stmt;
319        if (type().isVoid()) {
320          stmt = new ExprStmt(new SuperAccess("super").qualifiesAccess(new MethodAccess(name(), args)));
321        } else {
322          stmt = new ReturnStmt(new Opt(new SuperAccess("super").qualifiesAccess(new MethodAccess(name(), args))));
323        }
324        m = new MethodDecl(
325          new Modifiers(new List().add(new Modifier("synthetic"))),
326          type().createQualifiedAccess(),
327          name() + "$access$" + accessorIndex,
328          parameters,
329          new List(),
330          new Opt(
331            new Block(
332              new List().add(stmt)
333            )
334          )
335        );
336        m = methodQualifier.addMemberMethod(m);
337        methodQualifier.addAccessor(this, "method_super", m);
338        return m;
339      }
340    
341      public MethodDecl FieldDeclaration.createAccessor(TypeDecl fieldQualifier) {
342        MethodDecl m = (MethodDecl) fieldQualifier.getAccessor(this, "field_read");
343        if (m != null) {
344          return m;
345        }
346    
347        int accessorIndex = fieldQualifier.accessorCounter++;
348        Modifiers modifiers = new Modifiers(new List());
349        modifiers.addModifier(new Modifier("static"));
350        modifiers.addModifier(new Modifier("synthetic"));
351        modifiers.addModifier(new Modifier("public"));
352    
353        List parameters = new List();
354        if (!isStatic()) {
355          parameters.add(new ParameterDeclaration(fieldQualifier.createQualifiedAccess(), "that"));
356        }
357    
358        m = new MethodDecl(
359          modifiers,
360          type().createQualifiedAccess(),
361          "get$" + name() + "$access$" + accessorIndex,
362          parameters,
363          new List(),
364          new Opt(
365            new Block(
366              new List().add(
367                new ReturnStmt(createAccess())
368              )
369            )
370          )
371        );
372        m = fieldQualifier.addMemberMethod(m);
373        fieldQualifier.addAccessor(this, "field_read", m);
374        return m;
375      }
376    
377      public MethodDecl FieldDeclaration.createAccessorWrite(TypeDecl fieldQualifier) {
378        MethodDecl m = (MethodDecl) fieldQualifier.getAccessor(this, "field_write");
379        if (m != null) {
380          return m;
381        }
382    
383        int accessorIndex = fieldQualifier.accessorCounter++;
384        Modifiers modifiers = new Modifiers(new List());
385        modifiers.addModifier(new Modifier("static"));
386        modifiers.addModifier(new Modifier("synthetic"));
387        modifiers.addModifier(new Modifier("public"));
388    
389        List parameters = new List();
390        if (!isStatic()) {
391          parameters.add(new ParameterDeclaration(fieldQualifier.createQualifiedAccess(), "that"));
392        }
393        parameters.add(new ParameterDeclaration(type().createQualifiedAccess(), "value"));
394    
395        m = new MethodDecl(
396          modifiers,
397          type().createQualifiedAccess(),
398          "set$" + name() + "$access$" + accessorIndex,
399          parameters,
400          new List(),
401          new Opt(
402            new Block(
403              new List().add(
404                new ExprStmt(
405                  new AssignSimpleExpr(
406                    createAccess(),
407                    new VarAccess("value")
408                  )
409                )
410              ).add(
411                new ReturnStmt(
412                  new Opt(
413                    new VarAccess("value")
414                  )
415                )
416              )
417            )
418          )
419        );
420        m = fieldQualifier.addMemberMethod(m);
421        fieldQualifier.addAccessor(this, "field_write", m);
422        return m;
423      }
424    
425      private Access FieldDeclaration.createAccess() {
426        Access fieldAccess = new BoundFieldAccess(this);
427        return isStatic() ? fieldAccess : new VarAccess("that").qualifiesAccess(fieldAccess);
428      }
429    
430      syn boolean VarAccess.requiresAccessor() {
431        Variable v = decl();
432        if (!(v instanceof FieldDeclaration)) {
433          return false;
434        }
435        FieldDeclaration f = (FieldDeclaration) v;
436        if (f.isPrivate() && !hostType().hasField(v.name())) {
437          return true;
438        }
439        if (f.isProtected() && !f.hostPackage().equals(hostPackage()) && !hostType().hasField(v.name())) {
440          return true;
441        }
442        return false;
443      }
444    
445      syn boolean MethodAccess.requiresAccessor() {
446        MethodDecl m = decl();
447        if (m.isPrivate() && m.hostType() != hostType()) {
448          return true;
449        }
450        if (m.isProtected() && !m.hostPackage().equals(hostPackage()) && !hostType().hasMethod(m.name())) {
451          return true;
452        }
453        return false;
454      }
455    
456      syn boolean TypeDecl.isAnonymousInNonStaticContext() {
457        return isAnonymous() &&
458               !((ClassInstanceExpr) getParent().getParent()).unqualifiedScope().inStaticContext()
459               && (!inExplicitConstructorInvocation() || enclosingBodyDecl().hostType().isInnerType());
460      }
461    
462      syn lazy boolean TypeDecl.needsEnclosing() {
463        if (isAnonymous()) {
464          return isAnonymousInNonStaticContext();
465        } else if (isLocalClass()) {
466          return !inStaticContext();
467        } else if (isInnerType()) {
468          return true;
469        }
470        return false;
471      }
472    
473      syn lazy boolean TypeDecl.needsSuperEnclosing() {
474        if (!isAnonymous()) {
475          return false;
476        }
477        TypeDecl superClass = ((ClassDecl) this).superclass();
478        if (superClass.isLocalClass()) {
479          return !superClass.inStaticContext();
480        } else if (superClass.isInnerType()) {
481          return true;
482        } if (needsEnclosing() && enclosing() == superEnclosing()) {
483          return false;
484        }
485        return false;
486      }
487    
488      syn TypeDecl TypeDecl.enclosing() {
489        if (!needsEnclosing()) {
490          return null;
491        }
492        TypeDecl typeDecl = enclosingType();
493        if (isAnonymous() && inExplicitConstructorInvocation()) {
494          typeDecl = typeDecl.enclosingType();
495        }
496        return typeDecl;
497      }
498    
499      syn TypeDecl TypeDecl.superEnclosing() = null;
500      eq ClassDecl.superEnclosing() = superclass().enclosing();
501    
502      syn boolean ConstructorDecl.needsEnclosing() = hostType().needsEnclosing();
503      syn boolean ConstructorDecl.needsSuperEnclosing() = hostType().needsSuperEnclosing();
504    
505      syn TypeDecl ConstructorDecl.enclosing() = hostType().enclosing();
506      syn TypeDecl ConstructorDecl.superEnclosing() = hostType().superEnclosing();
507    
508      // add val$name as fields to the class
509      private boolean TypeDecl.addEnclosingVariables = true;
510      public void TypeDecl.addEnclosingVariables() {
511        if (!addEnclosingVariables) {
512          return;
513        }
514        addEnclosingVariables = false;
515        for (Iterator iter = enclosingVariables().iterator(); iter.hasNext(); ) {
516          Variable v = (Variable) iter.next();
517          Modifiers m = new Modifiers();
518          m.addModifier(new Modifier("public"));
519          m.addModifier(new Modifier("synthetic"));
520          m.addModifier(new Modifier("final"));
521          addMemberField(new FieldDeclaration(m, v.type().createQualifiedAccess(), "val$" + v.name(), new Opt()));
522        }
523      }
524    
525      // add val$name as parameters to the constructor
526      protected boolean ConstructorDecl.addEnclosingVariables = true;
527      public void ConstructorDecl.addEnclosingVariables() {
528        if (!addEnclosingVariables) {
529          return;
530        }
531        addEnclosingVariables = false;
532        hostType().addEnclosingVariables();
533        for (Iterator iter = hostType().enclosingVariables().iterator(); iter.hasNext(); ) {
534          Variable v = (Variable) iter.next();
535          getParameterList().add(new ParameterDeclaration(v.type(), "val$" + v.name()));
536        }
537      }
538    
539      // add val$name as arguments to the constructor
540      protected boolean ConstructorAccess.addEnclosingVariables = true;
541      public void ConstructorAccess.addEnclosingVariables() {
542        if (!addEnclosingVariables) {
543          return;
544        }
545        addEnclosingVariables = false;
546        decl().addEnclosingVariables();
547        for (Iterator iter = decl().hostType().enclosingVariables().iterator(); iter.hasNext(); ) {
548          Variable v = (Variable) iter.next();
549          getArgList().add(new VarAccess("val$" + v.name()));
550        }
551      }
552    
553      // add val$name as arguments to the constructor
554      protected boolean ClassInstanceExpr.addEnclosingVariables = true;
555      public void ClassInstanceExpr.addEnclosingVariables() {
556        if (!addEnclosingVariables) {
557          return;
558        }
559        addEnclosingVariables = false;
560        decl().addEnclosingVariables();
561        for (Iterator iter = decl().hostType().enclosingVariables().iterator(); iter.hasNext(); ) {
562          Variable v = (Variable) iter.next();
563          getArgList().add(new VarAccess(v.name()));
564        }
565      }
566    
567      public ConstructorDecl ConstructorDecl.createAccessor() {
568        ConstructorDecl c = (ConstructorDecl) hostType().getAccessor(this, "constructor");
569        if (c != null) {
570          return c;
571        }
572    
573        // make sure enclosing varibles are added as parameters prior to building accessor
574        addEnclosingVariables();
575    
576        Modifiers modifiers = new Modifiers(new List());
577        modifiers.addModifier(new Modifier("synthetic"));
578        modifiers.addModifier(new Modifier("public"));
579    
580        List parameters = createAccessorParameters();
581    
582        List exceptionList = new List();
583        for (int i = 0; i < getNumException(); i++) {
584          exceptionList.add(getException(i).type().createQualifiedAccess());
585        }
586    
587        // add all parameters as arguments except for the dummy parameter
588        List args = new List();
589        for (int i = 0; i < parameters.getNumChildNoTransform() - 1; i++) {
590          args.add(new VarAccess(((ParameterDeclaration) parameters.getChildNoTransform(i)).name()));
591        }
592        ConstructorAccess access = new ConstructorAccess("this", args);
593        access.addEnclosingVariables = false;
594    
595        c = new ConstructorDecl(
596          modifiers,
597          name(),
598          parameters,
599          exceptionList,
600          new Opt(
601            new ExprStmt(
602              access
603            )
604          ),
605          new Block()
606        );
607        c = hostType().addConstructor(c);
608        c.addEnclosingVariables = false;
609        hostType().addAccessor(this, "constructor", c);
610        return c;
611      }
612    
613      protected List ConstructorDecl.createAccessorParameters() {
614        List parameters = new List();
615        for (int i=0; i<getNumParameter(); i++) {
616          parameters.add(new ParameterDeclaration(getParameter(i).type(), getParameter(i).name()));
617        }
618        parameters.add(new ParameterDeclaration(createAnonymousJavaTypeDecl().createBoundAccess(), ("p" + getNumParameter())));
619        return parameters;
620      }
621    
622      protected TypeDecl ConstructorDecl.createAnonymousJavaTypeDecl() {
623        ClassDecl classDecl =
624            new ClassDecl(
625                new Modifiers(new List().add(new Modifier("synthetic"))),
626                "" + hostType().nextAnonymousIndex(),
627                new Opt(),
628                new List(),
629                new List()
630                );
631        classDecl = hostType().addMemberClass(classDecl);
632        hostType().addNestedType(classDecl);
633        return classDecl;
634      }
635    
636    }