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