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 GenericMethods {
011      public void ParMethodAccess.typeCheck() {
012        super.typeCheck();
013        if(!decl().hostType().isUnknown()) {
014          if(!(decl() instanceof ParMethodDecl))
015            error("can not have type parameters on a non generic method");
016          else {
017            ParMethodDecl m = (ParMethodDecl)decl();
018            if(!(m instanceof RawMethodDecl) && m.numTypeParameter() != getNumTypeArgument())
019              error("generic method " + m.signature() + " requires " + m.numTypeParameter() + " type arguments");
020            else {
021            }
022          }
023        }
024      }
025    
026      
027      // ES: removing this, it has been replaced with a paramaterized syn nta attribute
028      //syn lazy final List GenericMethodDecl.getParMethodDeclList() = new List();
029      //
030      // ES: removing this, it appears not to be used. Maybe needed earlier due to some interface (?)
031      //syn lazy final List GenericConstructorDecl.getParConstructorDeclList() = new List();
032      //
033    
034      syn lazy final MethodDecl GenericMethodDecl.rawMethodDecl() = lookupParMethodDecl(new ArrayList());
035      //syn lazy final ParConstructorDecl GenericConstructorDecl.rawConstructorDecl() = lookupParConstructorDecl(new ArrayList());
036    
037      /* ES: replacing this with
038      syn lazy GenericMethodDecl ParMethodDecl.genericMethodDecl() {
039          if(getParent() != null && getParent().getParent() instanceof GenericMethodDecl)
040                  return (GenericMethodDecl)getParent().getParent();
041          return null;
042      }
043      with:
044      */
045      syn lazy GenericMethodDecl ParMethodDecl.genericMethodDecl() {
046          return getGenericMethodDecl();
047      }
048      
049      syn lazy GenericConstructorDecl ParConstructorDecl.genericConstructorDecl() {
050          if(getParent() != null && getParent().getParent() instanceof GenericConstructorDecl)
051                  return (GenericConstructorDecl)getParent().getParent();
052          return null;
053      }
054    
055    /* ES: replacing this:
056      syn lazy MethodDecl GenericMethodDecl.lookupParMethodDecl(java.util.List typeArguments) {
057        l: for(int i = 0; i < getNumParMethodDecl(); i++) {
058          ParMethodDecl decl = getParMethodDecl(i);
059          if(decl instanceof RawMethodDecl) {
060            if(typeArguments.isEmpty())
061              return decl;
062          }
063          else if(decl.getNumTypeArgument() == typeArguments.size()) {
064            for(int j = 0; j < decl.getNumTypeArgument(); j++)
065              if(decl.getTypeArgument(j).type() != typeArguments.get(j))
066                continue l;
067            return decl;
068          }
069        }
070        return newParMethodDecl(typeArguments);
071      }
072      with:
073    */
074      syn nta MethodDecl GenericMethodDecl.lookupParMethodDecl(java.util.List typeArguments) {
075        return newParMethodDecl(typeArguments);
076      }
077    
078    
079    /* ES: replacing this:
080      public ParMethodDecl GenericMethodDecl.newParMethodDecl(java.util.List typeArguments) {
081        ParMethodDecl methodDecl = typeArguments.isEmpty() ? new RawMethodDecl() : new ParMethodDecl();
082        addParMethodDecl(methodDecl);
083        List list = new List();
084        if(typeArguments.isEmpty()) {
085          GenericMethodDecl original = original();
086          for(int i = 0; i < original.getNumTypeParameter(); i++)
087            list.add(original.getTypeParameter(i).erasure().createBoundAccess());
088        }
089        else {
090          for(Iterator iter = typeArguments.iterator(); iter.hasNext(); )
091            list.add(((TypeDecl)iter.next()).createBoundAccess());
092        }
093        methodDecl.setTypeArgumentList(list);
094        methodDecl.setModifiers((Modifiers)getModifiers().fullCopy());
095        methodDecl.setTypeAccess(getTypeAccess().type().substituteReturnType(methodDecl));
096        methodDecl.setID(getID());
097        methodDecl.setParameterList(getParameterList().substitute(methodDecl));
098        methodDecl.setExceptionList(getExceptionList().substitute(methodDecl));
099        return getParMethodDecl(getNumParMethodDecl()-1);
100      }
101      with:
102    */
103      public ParMethodDecl GenericMethodDecl.newParMethodDecl(java.util.List typeArguments) {
104        ParMethodDecl methodDecl = typeArguments.isEmpty() ? new RawMethodDecl() : new ParMethodDecl();
105        // adding a link to GenericMethodDecl to be used during substitution 
106        // instead of the not yet existing parent link
107        methodDecl.setGenericMethodDecl(this); 
108        List list = new List();
109        if(typeArguments.isEmpty()) {
110          GenericMethodDecl original = original();
111          for(int i = 0; i < original.getNumTypeParameter(); i++)
112            list.add(original.getTypeParameter(i).erasure().createBoundAccess());
113        }
114        else {
115          for(Iterator iter = typeArguments.iterator(); iter.hasNext(); )
116            list.add(((TypeDecl)iter.next()).createBoundAccess());
117        }
118        methodDecl.setTypeArgumentList(list);
119        methodDecl.setModifiers((Modifiers)getModifiers().fullCopy());
120        methodDecl.setTypeAccess(getTypeAccess().type().substituteReturnType(methodDecl));
121        methodDecl.setID(getID());
122        methodDecl.setParameterList(getParameterList().substitute(methodDecl));
123        methodDecl.setExceptionList(getExceptionList().substitute(methodDecl));
124        return methodDecl;
125      }
126    
127    
128    }
129    
130    aspect TypeCheck {
131      // Disable error checking in instantiated generic methods
132      public void ParMethodDecl.collectErrors() {
133      }
134      // Allow covariant return types
135      refine TypeHierarchyCheck eq MethodDecl.mayOverrideReturn(MethodDecl m) {
136        return type().instanceOf(m.type());
137      }
138    }
139    
140    aspect GenericMethodsNameAnalysis {
141    
142      eq ParMethodAccess.getTypeArgument().nameType() = NameType.TYPE_NAME;
143      eq ParMethodAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name);
144      eq GenericMethodDecl.getTypeParameter().nameType() = NameType.TYPE_NAME;
145      
146      inh SimpleSet GenericMethodDecl.lookupType(String name);
147      syn SimpleSet GenericMethodDecl.localLookupType(String name) {
148        for(int i = 0; i < getNumTypeParameter(); i++) {
149          if(original().getTypeParameter(i).name().equals(name))
150            return SimpleSet.emptySet.add(original().getTypeParameter(i));
151        }
152        return SimpleSet.emptySet;
153      }
154      eq GenericMethodDecl.getChild().lookupType(String name) = localLookupType(name).isEmpty() ? lookupType(name) : localLookupType(name);
155    
156      eq ParConstructorAccess.getTypeArgument().nameType() = NameType.TYPE_NAME;
157      eq ParConstructorAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name);
158      eq ParSuperConstructorAccess.getTypeArgument().nameType() = NameType.TYPE_NAME;
159      eq ParSuperConstructorAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name);
160      eq GenericConstructorDecl.getTypeParameter().nameType() = NameType.TYPE_NAME;
161    
162      inh SimpleSet GenericConstructorDecl.lookupType(String name);
163      syn SimpleSet GenericConstructorDecl.localLookupType(String name) {
164        for(int i = 0; i < getNumTypeParameter(); i++) {
165          if(original().getTypeParameter(i).name().equals(name))
166            return SimpleSet.emptySet.add(original().getTypeParameter(i));
167        }
168        return SimpleSet.emptySet;
169      }
170      eq GenericConstructorDecl.getChild().lookupType(String name) = localLookupType(name).isEmpty() ? lookupType(name) : localLookupType(name);
171    
172      eq ParClassInstanceExpr.getTypeArgument().nameType() = NameType.TYPE_NAME;
173      eq ParClassInstanceExpr.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name);
174    
175    }
176    
177    aspect GenericMethodsPrettyPrint {
178    
179      public void ParMethodAccess.toString(StringBuffer s) {
180        s.append("<");
181        for(int i = 0; i < getNumTypeArgument(); i++) {
182          if(i != 0) s.append(", ");
183          getTypeArgument(i).toString(s);
184        }
185        s.append(">");
186        super.toString(s);
187      }
188      public void ParConstructorAccess.toString(StringBuffer s) {
189        s.append("<");
190        for(int i = 0; i < getNumTypeArgument(); i++) {
191          if(i != 0) s.append(", ");
192          getTypeArgument(i).toString(s);
193        }
194        s.append(">");
195        super.toString(s);
196      }
197      public void ParSuperConstructorAccess.toString(StringBuffer s) {
198        s.append("<");
199        for(int i = 0; i < getNumTypeArgument(); i++) {
200          if(i != 0) s.append(", ");
201          getTypeArgument(i).toString(s);
202        }
203        s.append(">");
204        super.toString(s);
205      }
206      public void ParClassInstanceExpr.toString(StringBuffer s) {
207        s.append("<");
208        for(int i = 0; i < getNumTypeArgument(); i++) {
209          if(i != 0) s.append(", ");
210          getTypeArgument(i).toString(s);
211        }
212        s.append(">");
213        super.toString(s);
214      }
215    
216      private void GenericMethodDecl.ppTypeParameters(StringBuffer s) {
217        s.append(" <");
218        for(int i = 0; i < getNumTypeParameter(); i++) {
219          if(i != 0) s.append(", ");
220          original().getTypeParameter(i).toString(s);
221        }
222        s.append("> ");
223      }
224    
225      public void GenericMethodDecl.toString(StringBuffer s) {
226        s.append(indent());
227        getModifiers().toString(s);
228        
229        ppTypeParameters(s);
230        
231        getTypeAccess().toString(s);
232        s.append(" " + getID());
233        s.append("(");
234        if(getNumParameter() > 0) {
235          getParameter(0).toString(s);
236          for(int i = 1; i < getNumParameter(); i++) {
237            s.append(", ");
238            getParameter(i).toString(s);
239          }
240        }
241        s.append(")");
242        if(getNumException() > 0) {
243          s.append(" throws ");
244          getException(0).toString(s);
245          for(int i = 1; i < getNumException(); i++) {
246            s.append(", ");
247            getException(i).toString(s);
248          }
249        }
250        if(hasBlock()) {
251          s.append(" ");
252          getBlock().toString(s);
253        }
254        else {
255          s.append(";\n");
256        }
257      }
258      public void GenericConstructorDecl.toString(StringBuffer s) {
259        s.append(indent());
260        getModifiers().toString(s);
261    
262        s.append(" <");
263        for(int i = 0; i < getNumTypeParameter(); i++) {
264          if(i != 0) s.append(", ");
265          original().getTypeParameter(i).toString(s);
266        }
267        s.append("> ");
268    
269        s.append(getID() + "(");
270        if(getNumParameter() > 0) {
271          getParameter(0).toString(s);
272          for(int i = 1; i < getNumParameter(); i++) {
273            s.append(", ");
274            getParameter(i).toString(s);
275          }
276        }
277        s.append(")");
278        if(getNumException() > 0) {
279          s.append(" throws ");
280          getException(0).toString(s);
281          for(int i = 1; i < getNumException(); i++) {
282            s.append(", ");
283            getException(i).toString(s);
284          }
285        }
286    
287        s.append(" {");
288        if(hasConstructorInvocation()) {
289          s.append(indent());
290          getConstructorInvocation().toString(s);
291        }
292        for(int i = 0; i < getBlock().getNumStmt(); i++) {
293          s.append(indent());
294          getBlock().getStmt(i).toString(s);
295        }
296        s.append(indent());
297        s.append("}");
298      }
299    
300    }