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 GenericsCodegen {
032       refine InnerClasses eq ClassDecl.superEnclosing() {
033         return superclass().erasure().enclosing();
034       }
035    
036       eq TypeVariable.typeDescriptor() = erasure().typeDescriptor();
037       eq ParClassDecl.typeDescriptor() = erasure().typeDescriptor();
038       eq ParInterfaceDecl.typeDescriptor() = erasure().typeDescriptor();
039    
040       eq GenericClassDeclSubstituted.typeDescriptor() = original().typeDescriptor();
041       eq GenericInterfaceDeclSubstituted.typeDescriptor() = original().typeDescriptor();
042       eq ClassDeclSubstituted.typeDescriptor() = original().typeDescriptor();
043       eq InterfaceDeclSubstituted.typeDescriptor() = original().typeDescriptor();
044    
045       eq GenericClassDeclSubstituted.constantPoolName() = original().constantPoolName();
046       eq GenericInterfaceDeclSubstituted.constantPoolName() = original().constantPoolName();
047       eq ClassDeclSubstituted.constantPoolName() = original().constantPoolName();
048       eq InterfaceDeclSubstituted.constantPoolName() = original().constantPoolName();
049    
050       eq ClassDeclSubstituted.uniqueIndex() = original().uniqueIndex();
051       eq GenericClassDeclSubstituted.uniqueIndex() = original().uniqueIndex();
052       eq InterfaceDeclSubstituted.uniqueIndex() = original().uniqueIndex();
053       eq GenericInterfaceDeclSubstituted.uniqueIndex() = original().uniqueIndex();
054       eq ParTypeDecl.uniqueIndex() = genericDecl().uniqueIndex();
055    
056       eq TypeVariable.arrayTypeDescriptor() = erasure().arrayTypeDescriptor();
057       eq ParClassDecl.arrayTypeDescriptor() = erasure().arrayTypeDescriptor();
058       eq ParInterfaceDecl.arrayTypeDescriptor() = erasure().arrayTypeDescriptor();
059       //eq WildcardType.typeDescriptor() = erasure().typeDescriptor();
060    
061       eq GenericClassDeclSubstituted.arrayTypeDescriptor() = original().arrayTypeDescriptor();
062       eq GenericInterfaceDeclSubstituted.arrayTypeDescriptor() = original().arrayTypeDescriptor();
063       eq ClassDeclSubstituted.arrayTypeDescriptor() = original().arrayTypeDescriptor();
064       eq InterfaceDeclSubstituted.arrayTypeDescriptor() = original().arrayTypeDescriptor();
065    
066       public ConstructorDecl ConstructorDeclSubstituted.createAccessor() {
067         return sourceConstructorDecl().createAccessor();
068       }
069    
070       protected TypeDecl ConstructorDeclSubstituted.createAnonymousJavaTypeDecl() {
071         return sourceConstructorDecl().createAnonymousJavaTypeDecl();
072       }
073    
074      refine CodeGeneration public void VarAccess.emitStore(CodeGeneration gen) {
075        Variable v = decl();
076        if (v instanceof FieldDeclaration) {
077          FieldDeclaration f = (FieldDeclaration) v;
078          f = f.erasedField();
079          if (requiresAccessor()) {
080            f.createAccessorWrite(fieldQualifierType()).emitInvokeMethod(gen, fieldQualifierType());
081          } else {
082            f.emitStoreField(gen, fieldQualifierType());
083          }
084        } else {
085          refined(gen);
086        }
087      }
088      refine CreateBCode public void VarAccess.createAssignLoadDest(CodeGeneration gen) {
089        Variable v = decl();
090        if (v instanceof FieldDeclaration) {
091          createLoadQualifier(gen);
092          if (v.isInstanceVariable()) {
093            gen.emitDup();
094          }
095          FieldDeclaration f = (FieldDeclaration) v;
096          f = f.erasedField();
097          if (requiresAccessor()) {
098            f.createAccessor(fieldQualifierType()).emitInvokeMethod(gen, fieldQualifierType());
099          } else {
100            f.emitLoadField(gen, fieldQualifierType());
101          }
102        } else {
103          refined(gen);
104        }
105      }
106    
107      refine CreateBCode public void VarAccess.createBCode(CodeGeneration gen) {
108        Variable v = decl();
109        if (v instanceof FieldDeclaration) {
110          FieldDeclaration f = (FieldDeclaration) v;
111          f = f.erasedField();
112          createLoadQualifier(gen);
113          if (f.isConstant() && (f.type().isPrimitive() || f.type().isString())) {
114            if (!f.isStatic()) {
115              fieldQualifierType().emitPop(gen);
116            }
117            f.constant().createBCode(gen);
118          } else if (requiresAccessor()) {
119            f.createAccessor(fieldQualifierType()).emitInvokeMethod(gen, fieldQualifierType());
120          } else {
121            f.emitLoadField(gen, fieldQualifierType());
122          }
123          if (f.type() != decl().type()) {
124            gen.emitCheckCast(decl().type());
125          }
126        } else {
127          refined(gen);
128        }
129      }
130    
131      refine CreateBCode public void MethodAccess.createBCode(CodeGeneration gen) {
132        MethodDecl decl = decl().erasedMethod();
133        createLoadQualifier(gen);
134    
135        if (program().options().hasOption("-debug")) {
136          if (decl.type().isUnknown()) {
137            System.err.println("Could not bind " + this);
138            for (int i = 0; i < getNumArg(); ++i) {
139              System.err.println("Argument " + getArg(i)
140                  + " is of type " + getArg(i).type().typeName());
141              if (getArg(i).varDecl() != null) {
142                System.err.println(getArg(i).varDecl() + " in "
143                    + getArg(i).varDecl().hostType().typeName());
144              }
145            }
146            if (isQualified()) {
147              System.err.println("Qualifier " + qualifier()
148                  + " is of type " + qualifier().type().typeName());
149            }
150            throw new Error("Could not bind " + this);
151          }
152          if (decl.getNumParameter() != getNumArg()) {
153            System.out.println(this
154                + " does not have the same number of arguments as " + decl);
155          }
156        }
157    
158        for (int i = 0; i < getNumArg(); ++i) {
159          getArg(i).createBCode(gen);
160          // The cast or boxing/unboxing operation must know the bound rather than the erased type.
161          getArg(i).type().emitCastTo(gen, decl().getParameter(i).type()); // MethodInvocationConversion
162        }
163    
164        if (!decl.isStatic() && isQualified() && prevExpr().isSuperAccess()) {
165          if (!hostType().instanceOf(prevExpr().type())) {
166            /* Should this be decl instead? possible copy/paste error? */
167            decl().createSuperAccessor(superAccessorTarget()).emitInvokeMethod(gen, superAccessorTarget());
168          } else {
169            decl.emitInvokeSpecialMethod(gen, methodQualifierType());
170          }
171        } else {
172          decl.emitInvokeMethod(gen, methodQualifierType());
173        }
174    
175        if (decl.type() != decl().type()) {
176          gen.emitCheckCast(decl().type());
177        }
178      }
179    
180      refine InnerClasses protected TypeDecl MethodAccess.methodQualifierType() {
181        TypeDecl typeDecl = refined();
182        if (typeDecl == null) {
183          return null;
184        }
185        typeDecl = typeDecl.erasure();
186        MethodDecl m = decl().sourceMethodDecl();
187        Collection methods = typeDecl.memberMethods(m.name());
188        if (!methods.contains(decl()) && !methods.contains(m)) {
189          return m.hostType();
190        }
191        return typeDecl.erasure();
192      }
193    
194      refine InnerClasses protected TypeDecl VarAccess.fieldQualifierType() {
195        TypeDecl typeDecl = refined();
196        return typeDecl == null ? null : typeDecl.erasure();
197      }
198    
199      public void ConstructorDeclSubstituted.emitInvokeConstructor(CodeGeneration gen) {
200        erasedConstructor().emitInvokeConstructor(gen);
201      }
202    
203      public void ParConstructorDecl.emitInvokeConstructor(CodeGeneration gen) {
204        genericConstructorDecl().emitInvokeConstructor(gen);
205      }
206    
207      syn ConstructorDecl ConstructorDecl.erasedConstructor() = this;
208      eq ConstructorDeclSubstituted.erasedConstructor() = getOriginal().erasedConstructor();
209    
210    
211      eq TypeVariable.constantPoolName() = erasure().constantPoolName();
212      eq ParClassDecl.constantPoolName() = genericDecl().constantPoolName();
213      eq ParInterfaceDecl.constantPoolName() = genericDecl().constantPoolName();
214    
215      public void BridgeMethodDecl.transformation() { }
216      public void MethodDeclSubstituted.transformation() { }
217      public void ParMethodDecl.transformation() { }
218    
219      public static final int Modifiers.ACC_BRIDGE = 0x0040;
220    
221      eq BridgeMethodDecl.flags() {
222        int res = super.flags();
223        res |= Modifiers.ACC_BRIDGE;
224        res |= Modifiers.ACC_SYNTHETIC;
225        return res;
226      }
227    
228      syn SimpleSet TypeDecl.bridgeCandidates(String signature) = SimpleSet.emptySet;
229      eq InterfaceDecl.bridgeCandidates(String signature) = ancestorMethods(signature);
230      eq ClassDecl.bridgeCandidates(String signature) {
231        SimpleSet set = ancestorMethods(signature);
232        for (Iterator iter = interfacesMethodsSignature(signature).iterator(); iter.hasNext(); ) {
233          set = set.add(iter.next());
234        }
235        return set;
236      }
237    
238      public void MethodDecl.transformation() {
239        super.transformation();
240        HashSet processed = new HashSet();
241        for (Iterator iter = hostType().bridgeCandidates(signature()).iterator(); iter.hasNext(); ) {
242          MethodDecl m = (MethodDecl) iter.next();
243          if (this.overrides(m)) {
244            MethodDecl erased = m.erasedMethod();
245            if (!erased.signature().equals(signature()) || erased.type().erasure() != type().erasure()) {
246              StringBuilder keyBuffer = new StringBuilder();
247              for (int i = 0; i < getNumParameter(); i++) {
248                keyBuffer.append(erased.getParameter(i).type().erasure().fullName());
249              }
250              keyBuffer.append(erased.type().erasure().fullName());
251              String key = keyBuffer.toString();
252              if (!processed.contains(key)) {
253                processed.add(key);
254    
255                List args = new List();
256                List parameters = new List();
257                for (int i = 0; i < getNumParameter(); i++) {
258                  args.add(new CastExpr(getParameter(i).type().erasure().createBoundAccess(), new VarAccess("p" + i)));
259                  parameters.add(new ParameterDeclaration(erased.getParameter(i).type().erasure(), "p" + i));
260                }
261                Stmt stmt;
262                if (type().isVoid()) {
263                  stmt = new ExprStmt(
264                      createBoundAccess(
265                        args
266                        )
267                      );
268                } else {
269                  stmt = new ReturnStmt(
270                      createBoundAccess(
271                        args
272                        )
273                      );
274                }
275                List modifiersList = new List();
276                if (isPublic()) {
277                  modifiersList.add(new Modifier("public"));
278                } else if (isProtected()) {
279                  modifiersList.add(new Modifier("protected"));
280                } else if (isPrivate()) {
281                  modifiersList.add(new Modifier("private"));
282                }
283                MethodDecl bridge = new BridgeMethodDecl(
284                    new Modifiers(modifiersList),
285                    erased.type().erasure().createBoundAccess(),
286                    erased.name(),
287                    parameters,
288                    (List) getExceptionList().treeCopyNoTransform(),
289                    new Opt(
290                      new Block(
291                        new List().add(stmt)
292                        )
293                      )
294                    );
295                hostType().addBodyDecl(bridge);
296              }
297            }
298          }
299        }
300      }
301    
302      public void ParTypeDecl.transformation() {
303      }
304    
305      refine Transformations public void TypeAccess.transformation() {
306        super.transformation();
307        if (type().elementType().isNestedType() && hostType() != null) {
308          hostType().addUsedNestedType(type().elementType().erasure().sourceTypeDecl());
309        }
310      }
311    
312      // add Signature Attribute
313      refine AnnotationsCodegen eq TypeDecl.attributes() {
314        Collection c = refined();
315        if (needsSignatureAttribute()) {
316          c.add(new SignatureAttribute(constantPool(), classSignature()));
317        }
318        return c;
319      }
320    
321      refine AnnotationsCodegen eq MethodDecl.attributes() {
322        Collection c = refined();
323        if (needsSignatureAttribute()) {
324          c.add(new SignatureAttribute(hostType().constantPool(), methodTypeSignature()));
325        }
326        return c;
327      }
328    
329      refine AnnotationsCodegen eq FieldDeclaration.attributes() {
330        Collection c = refined();
331        if (needsSignatureAttribute()) {
332          c.add(new SignatureAttribute(hostType().constantPool(), type().fieldTypeSignature()));
333        }
334        return c;
335      }
336    
337      class SignatureAttribute extends Attribute {
338        public SignatureAttribute(ConstantPool cp, String signature) {
339          super(cp, "Signature");
340          u2(cp.addUtf8(signature));
341        }
342      }
343    
344      // Determine which classes, interfaces, methods, and fields need a signature attribute
345      syn lazy boolean TypeDecl.needsSignatureAttribute() = false;
346      eq GenericClassDecl.needsSignatureAttribute() = true;
347      eq GenericInterfaceDecl.needsSignatureAttribute() = true;
348      eq ParClassDecl.needsSignatureAttribute() = true;
349      eq ParInterfaceDecl.needsSignatureAttribute() = true;
350      eq AbstractWildcardType.needsSignatureAttribute() = true;
351      eq TypeVariable.needsSignatureAttribute() = true;
352      eq ArrayDecl.needsSignatureAttribute() = elementType().needsSignatureAttribute();
353      eq ClassDecl.needsSignatureAttribute() {
354        if (hasSuperclass() && superclass().needsSignatureAttribute()) {
355          return true;
356        }
357        for (Iterator<TypeDecl> iter = interfacesIterator(); iter.hasNext(); ) {
358          if (iter.next().needsSignatureAttribute()) {
359            return true;
360          }
361        }
362        return false;
363      }
364    
365      eq InterfaceDecl.needsSignatureAttribute() {
366        for (Iterator<TypeDecl> iter = interfacesIterator(); iter.hasNext(); ) {
367          if (iter.next().needsSignatureAttribute()) {
368            return true;
369          }
370        }
371        return false;
372      }
373    
374      syn boolean BodyDecl.needsSignatureAttribute() = false;
375      syn boolean MethodDecl.needsSignatureAttribute() {
376        if (type().needsSignatureAttribute()) {
377          return true;
378        }
379        for (int i = 0; i < getNumParameter(); i++) {
380          if (getParameter(i).type().needsSignatureAttribute()) {
381            return true;
382          }
383        }
384        return false;
385      }
386    
387      eq GenericMethodDecl.needsSignatureAttribute() = true;
388      syn boolean ConstructorDecl.needsSignatureAttribute() {
389        for (int i = 0; i < getNumParameter(); i++) {
390          if (getParameter(i).type().needsSignatureAttribute()) {
391            return true;
392          }
393        }
394        return false;
395      }
396      eq GenericConstructorDecl.needsSignatureAttribute() = true;
397    
398      eq FieldDeclaration.needsSignatureAttribute() = type().needsSignatureAttribute();
399    
400      // compute the signature string used for the signature attribute
401      syn lazy String TypeDecl.classSignature() = "";
402      eq ClassDecl.classSignature() {
403        StringBuilder buf = new StringBuilder();
404        // SuperclassSignature
405        if (hasSuperclass()) {
406          buf.append(superclass().classTypeSignature());
407        }
408        // SuperinterfaceSignature*
409        for (Iterator<TypeDecl> iter = interfacesIterator(); iter.hasNext(); ) {
410          buf.append(iter.next().classTypeSignature());
411        }
412        return buf.toString();
413      }
414      eq InterfaceDecl.classSignature() {
415        StringBuilder buf = new StringBuilder();
416        // SuperclassSignature
417        buf.append(typeObject().classTypeSignature());
418        // SuperinterfaceSignature*
419        for (Iterator<TypeDecl> iter = interfacesIterator(); iter.hasNext(); ) {
420          buf.append(iter.next().classTypeSignature());
421        }
422        return buf.toString();
423      }
424      eq GenericClassDecl.classSignature() {
425        StringBuilder buf = new StringBuilder();
426        // FormalTypeParameters
427        buf.append("<");
428        for (int i = 0; i < getNumTypeParameter(); i++) {
429          buf.append(getTypeParameter(i).formalTypeParameter());
430        }
431        buf.append(">");
432        buf.append(super.classSignature());
433        return buf.toString();
434      }
435      eq GenericInterfaceDecl.classSignature() {
436        StringBuilder buf = new StringBuilder();
437        // FormalTypeParameters
438        buf.append("<");
439        for (int i = 0; i < getNumTypeParameter(); i++) {
440          buf.append(getTypeParameter(i).formalTypeParameter());
441        }
442        buf.append(">");
443        buf.append(super.classSignature());
444        return buf.toString();
445      }
446    
447      // FormalTypeParameter
448      syn String TypeVariable.formalTypeParameter() {
449        StringBuilder buf = new StringBuilder();
450        // Identifier
451        buf.append(name());
452        buf.append(":");
453        if (getNumTypeBound() > 0) {
454          // ClassBound InterfaceBound*
455          if (getTypeBound(0).type().isClassDecl()) {
456            buf.append(getTypeBound(0).type().fieldTypeSignature());
457          } else {
458            buf.append(":" + getTypeBound(0).type().fieldTypeSignature());
459          }
460          for (int i = 1; i < getNumTypeBound(); i++) {
461            buf.append(":" + getTypeBound(i).type().fieldTypeSignature());
462          }
463        }
464        return buf.toString();
465      }
466    
467      syn lazy String TypeDecl.fieldTypeSignature() = classTypeSignature();
468      eq ArrayDecl.fieldTypeSignature() = "[" + componentType().fieldTypeSignature();
469      eq TypeVariable.fieldTypeSignature() = classTypeSignature();
470      eq WildcardType.fieldTypeSignature() = "*";
471      eq WildcardExtendsType.fieldTypeSignature() = "+" + extendsType().fieldTypeSignature();
472      eq WildcardSuperType.fieldTypeSignature() = "-" + superType().fieldTypeSignature();
473      eq PrimitiveType.fieldTypeSignature() = classTypeSignature();
474      eq VoidType.fieldTypeSignature() = classTypeSignature();
475    
476      syn lazy String TypeDecl.classTypeSignature() = "L" + classTypeSignatureContents() + ";";
477      eq ArrayDecl.classTypeSignature() = "[" + componentType().classTypeSignature();
478      eq TypeVariable.classTypeSignature() = "T" + name() + ";";
479      eq PrimitiveType.classTypeSignature() = typeDescriptor();
480      eq VoidType.classTypeSignature() = typeDescriptor();
481    
482      syn String TypeDecl.classTypeSignatureContents() {
483        StringBuilder buf = new StringBuilder();
484        if (isTopLevelType()) {
485          if (!packageName().equals("")) {
486            buf.append(packageName().replace('.', '/') + "/");
487          }
488        } else {
489          buf.append(enclosingType().classTypeSignatureContents() + ".");
490        }
491        buf.append(name());
492        buf.append(typeArgumentsOpt());
493        return buf.toString();
494      }
495      syn String TypeDecl.typeArgumentsOpt() = "";
496      eq ParTypeDecl.typeArgumentsOpt() {
497        StringBuilder buf = new StringBuilder();
498        buf.append("<");
499        for (int i = 0; i < getNumArgument(); i++) {
500          buf.append(getArgument(i).type().fieldTypeSignature());
501        }
502        buf.append(">");
503        return buf.toString();
504      }
505      eq RawClassDecl.typeArgumentsOpt() = "";
506      eq RawInterfaceDecl.typeArgumentsOpt() = "";
507    
508      syn String MethodDecl.methodTypeSignature() {
509        StringBuilder buf = new StringBuilder();
510        buf.append("(");
511        for (int i = 0; i < getNumParameter(); i++) {
512          buf.append(getParameter(i).type().classTypeSignature());
513        }
514        buf.append(")");
515        buf.append(type().classTypeSignature());
516        for (int i = 0; i < getNumException(); i++) {
517          buf.append("^" + getException(i).type().classTypeSignature());
518        }
519        return buf.toString();
520      }
521      eq GenericMethodDecl.methodTypeSignature() {
522        StringBuilder buf = new StringBuilder();
523        buf.append("<");
524        for (int i = 0; i < getNumTypeParameter(); i++) {
525          TypeVariable param = getTypeParameter(i);
526          buf.append(param.getID() + ":" + param.classBound() + param.interfaceBounds());
527        }
528        buf.append(">");
529        buf.append(super.methodTypeSignature());
530        return buf.toString();
531      }
532      syn lazy String TypeVariable.classBound() {
533        if (getNumTypeBound() > 0) {
534          return getTypeBound(0).type().fieldTypeSignature();
535        }
536        return "";
537      }
538      syn lazy String TypeVariable.interfaceBounds() {
539        StringBuilder buf = new StringBuilder();
540        for (int i = 1; i < getNumTypeBound(); ++i) {
541          buf.append(":");
542          buf.append(getTypeBound(i).type().fieldTypeSignature());
543        }
544        return buf.toString();
545      }
546    }