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 MethodSignature15 {
011      refine LookupMethod protected SimpleSet MethodAccess.maxSpecific(Collection candidates) {
012        SimpleSet potentiallyApplicable = potentiallyApplicable(candidates);
013        // first phase
014        SimpleSet maxSpecific = applicableBySubtyping(potentiallyApplicable);
015        // second phase
016        maxSpecific = applicableByMethodInvocationConversion(potentiallyApplicable,
017            maxSpecific);
018        // third phase
019        maxSpecific = applicableVariableArity(potentiallyApplicable, maxSpecific);
020        return maxSpecific;
021      }
022    
023      protected SimpleSet MethodAccess.potentiallyApplicable(Collection candidates) {
024        SimpleSet potentiallyApplicable = SimpleSet.emptySet;
025        // select potentially applicable methods
026        for(Iterator iter = candidates.iterator(); iter.hasNext(); ) {
027          MethodDecl decl = (MethodDecl)iter.next();
028          if(potentiallyApplicable(decl) && accessible(decl)) {
029            if(decl instanceof GenericMethodDecl) {
030              decl = ((GenericMethodDecl)decl).lookupParMethodDecl(typeArguments(decl));
031            }
032            potentiallyApplicable = potentiallyApplicable.add(decl);
033          }
034        }
035        return potentiallyApplicable;
036      }
037    
038      protected SimpleSet MethodAccess.applicableBySubtyping(SimpleSet potentiallyApplicable) {
039        SimpleSet maxSpecific = SimpleSet.emptySet;
040        for(Iterator iter = potentiallyApplicable.iterator(); iter.hasNext(); ) {
041          MethodDecl decl = (MethodDecl)iter.next();
042          if(applicableBySubtyping(decl))
043            maxSpecific = mostSpecific(maxSpecific, decl);
044        }
045        return maxSpecific;
046      }
047    
048      protected SimpleSet MethodAccess.applicableByMethodInvocationConversion(SimpleSet potentiallyApplicable, SimpleSet maxSpecific) {
049        if(maxSpecific.isEmpty()) {
050          for(Iterator iter = potentiallyApplicable.iterator(); iter.hasNext(); ) {
051            MethodDecl decl = (MethodDecl)iter.next();
052            if(applicableByMethodInvocationConversion(decl))
053              maxSpecific = mostSpecific(maxSpecific, decl);
054          }
055        }
056        return maxSpecific;
057      }
058    
059      protected SimpleSet MethodAccess.applicableVariableArity(SimpleSet potentiallyApplicable, SimpleSet maxSpecific) {
060        if(maxSpecific.isEmpty()) {
061          for(Iterator iter = potentiallyApplicable.iterator(); iter.hasNext(); ) {
062            MethodDecl decl = (MethodDecl)iter.next();
063            if(decl.isVariableArity() && applicableVariableArity(decl))
064              maxSpecific = mostSpecific(maxSpecific, decl);
065          }
066        }
067        return maxSpecific;
068      }
069    
070      refine ConstructScope eq ClassInstanceExpr.decls() {
071        TypeDecl typeDecl = hasTypeDecl() ? getTypeDecl() : getAccess().type();
072        return chooseConstructor(typeDecl.constructors(), getArgList());
073      }
074      refine ConstructScope eq ConstructorAccess.decls() {
075        return chooseConstructor(lookupConstructor(), getArgList());
076      }
077      refine ConstructScope eq SuperConstructorAccess.decls() {
078        Collection c = hasPrevExpr() && !prevExpr().isTypeAccess() ?
079          hostType().lookupSuperConstructor() : lookupSuperConstructor();
080        return chooseConstructor(c, getArgList());
081      }
082    
083      refine AnonymousClasses eq ClassInstanceExpr.getTypeDecl().constructorDecl() {
084        Collection c = getAccess().type().constructors();
085        SimpleSet maxSpecific = chooseConstructor(c, getArgList());
086        if(maxSpecific.size() == 1)
087          return (ConstructorDecl)maxSpecific.iterator().next();
088        return unknownConstructor();
089      }
090    
091      protected SimpleSet Expr.chooseConstructor(Collection constructors, List argList) {
092        SimpleSet potentiallyApplicable = SimpleSet.emptySet;
093        // select potentially applicable constructors
094        for(Iterator iter = constructors.iterator(); iter.hasNext(); ) {
095          ConstructorDecl decl = (ConstructorDecl)iter.next();
096          if(decl.potentiallyApplicable(argList) && decl.accessibleFrom(hostType()))
097            potentiallyApplicable = potentiallyApplicable.add(decl);
098        }
099        // first phase
100        SimpleSet maxSpecific = SimpleSet.emptySet;
101        for(Iterator iter = potentiallyApplicable.iterator(); iter.hasNext(); ) {
102          ConstructorDecl decl = (ConstructorDecl)iter.next();
103          if(decl.applicableBySubtyping(argList))
104            maxSpecific = mostSpecific(maxSpecific, decl);
105        }
106    
107        // second phase
108        if(maxSpecific.isEmpty()) {
109          for(Iterator iter = potentiallyApplicable.iterator(); iter.hasNext(); ) {
110            ConstructorDecl decl = (ConstructorDecl)iter.next();
111            if(decl.applicableByMethodInvocationConversion(argList))
112              maxSpecific = mostSpecific(maxSpecific, decl);
113          }
114        }
115    
116        // third phase
117        if(maxSpecific.isEmpty()) {
118          for(Iterator iter = potentiallyApplicable.iterator(); iter.hasNext(); ) {
119            ConstructorDecl decl = (ConstructorDecl)iter.next();
120            if(decl.isVariableArity() && decl.applicableVariableArity(argList))
121              maxSpecific = mostSpecific(maxSpecific, decl);
122          }
123        }
124        return maxSpecific;
125      }
126    
127    
128      protected static SimpleSet Expr.mostSpecific(SimpleSet maxSpecific, ConstructorDecl decl) {
129        if(maxSpecific.isEmpty())
130          maxSpecific = maxSpecific.add(decl);
131        else {
132          if(decl.moreSpecificThan((ConstructorDecl)maxSpecific.iterator().next()))
133            maxSpecific = SimpleSet.emptySet.add(decl);
134          else if(!((ConstructorDecl)maxSpecific.iterator().next()).moreSpecificThan(decl))
135            maxSpecific = maxSpecific.add(decl);
136        }
137        return maxSpecific;
138      }
139    
140      private static SimpleSet MethodAccess.mostSpecific(SimpleSet maxSpecific, MethodDecl decl) {
141        if(maxSpecific.isEmpty())
142          maxSpecific = maxSpecific.add(decl);
143        else {
144          if(decl.moreSpecificThan((MethodDecl)maxSpecific.iterator().next()))
145            maxSpecific = SimpleSet.emptySet.add(decl);
146          else if(!((MethodDecl)maxSpecific.iterator().next()).moreSpecificThan(decl))
147            maxSpecific = maxSpecific.add(decl);
148        }
149        return maxSpecific;
150      }
151    
152      eq ParMethodDecl.moreSpecificThan(MethodDecl m) =
153        genericMethodDecl().moreSpecificThan(m instanceof ParMethodDecl ? ((ParMethodDecl)m).genericMethodDecl() : m );
154    
155      refine MethodDecl eq MethodDecl.moreSpecificThan(MethodDecl m) {
156        if(!isVariableArity() && !m.isVariableArity())
157          return refined(m);
158        int num = Math.max(getNumParameter(), m.getNumParameter());
159        for(int i = 0; i < num; i++) {
160          TypeDecl t1 = i < getNumParameter() - 1 ? getParameter(i).type() : getParameter(getNumParameter()-1).type().componentType();
161          TypeDecl t2 = i < m.getNumParameter() - 1 ? m.getParameter(i).type() : m.getParameter(m.getNumParameter()-1).type().componentType();
162          if(!t1.instanceOf(t2))
163            return false;
164        }
165        return true;
166      }
167    
168      refine ConstructorDecl eq ConstructorDecl.moreSpecificThan(ConstructorDecl m) {
169        if(!isVariableArity() && !m.isVariableArity())
170          return refined(m);
171        int num = Math.max(getNumParameter(), m.getNumParameter());
172        for(int i = 0; i < num; i++) {
173          TypeDecl t1 = i < getNumParameter() - 1 ? getParameter(i).type() : getParameter(getNumParameter()-1).type().componentType();
174          TypeDecl t2 = i < m.getNumParameter() - 1 ? m.getParameter(i).type() : m.getParameter(m.getNumParameter()-1).type().componentType();
175          if(!t1.instanceOf(t2))
176            return false;
177        }
178        return true;
179      }
180    
181      syn boolean MethodAccess.applicableBySubtyping(MethodDecl m) {
182        if(m.getNumParameter() != getNumArg())
183          return false;
184        for(int i = 0; i < m.getNumParameter(); i++)
185          if(!getArg(i).type().instanceOf(m.getParameter(i).type()))
186            return false;
187        return true;
188      }
189    
190      syn boolean ConstructorDecl.applicableBySubtyping(List argList) {
191        if(getNumParameter() != argList.getNumChild())
192          return false;
193        for(int i = 0; i < getNumParameter(); i++) {
194          TypeDecl arg = ((Expr)argList.getChild(i)).type();
195          if(!arg.instanceOf(getParameter(i).type()))
196            return false;
197        }
198        return true;
199      }
200    
201      syn boolean MethodAccess.applicableByMethodInvocationConversion(MethodDecl m) {
202        if(m.getNumParameter() != getNumArg())
203          return false;
204        for(int i = 0; i < m.getNumParameter(); i++)
205          if(!getArg(i).type().methodInvocationConversionTo(m.getParameter(i).type()))
206            return false;
207        return true;
208      }
209    
210      syn boolean ConstructorDecl.applicableByMethodInvocationConversion(List argList) {
211        if(getNumParameter() != argList.getNumChild())
212          return false;
213        for(int i = 0; i < getNumParameter(); i++) {
214          TypeDecl arg = ((Expr)argList.getChild(i)).type();
215          if(!arg.methodInvocationConversionTo(getParameter(i).type()))
216            return false;
217        }
218        return true;
219      }
220    
221      syn boolean MethodAccess.applicableVariableArity(MethodDecl m) {
222        for(int i = 0; i < m.getNumParameter() - 1; i++)
223          if(!getArg(i).type().methodInvocationConversionTo(m.getParameter(i).type()))
224            return false;
225        for(int i = m.getNumParameter() - 1; i < getNumArg(); i++)
226          if(!getArg(i).type().methodInvocationConversionTo(m.lastParameter().type().componentType()))
227            return false;
228        return true;
229      }
230    
231      syn boolean ConstructorDecl.applicableVariableArity(List argList) {
232        for(int i = 0; i < getNumParameter() - 1; i++) {
233          TypeDecl arg = ((Expr)argList.getChild(i)).type();
234          if(!arg.methodInvocationConversionTo(getParameter(i).type()))
235            return false;
236        }
237        for(int i = getNumParameter() - 1; i < argList.getNumChild(); i++) {
238          TypeDecl arg = ((Expr)argList.getChild(i)).type();
239          if(!arg.methodInvocationConversionTo(lastParameter().type().componentType()))
240            return false;
241        }
242        return true;
243      }
244    
245      // 15.12.2.1
246    
247      /* A member method is potentially applicable to a method invocation if and only if
248         all of the following are true:
249        * The name of the member is identical to the name of the method in the method
250          invocation.
251        * The member is accessible (�6.6) to the class or interface in which the
252          method invocation appears.
253        * The arity of the member is lesser or equal to the arity of the method
254          invocation.
255        * If the member is a variable arity method with arity n, the arity of the
256          method invocation is greater or equal to n-1.
257        * If the member is a fixed arity method with arity n, the arity of the method
258          invocation is equal to n.
259        * If the method invocation includes explicit type parameters, and the member
260          is a generic method, then the number of actual type parameters is equal to
261          the number of formal type parameters.*/
262      syn boolean MethodAccess.potentiallyApplicable(MethodDecl m) {
263        if(!m.name().equals(name()))
264          return false;
265        if(!m.accessibleFrom(hostType()))
266          return false;
267        if(m.isVariableArity() && !(arity() >= m.arity()-1))
268          return false;
269        if(!m.isVariableArity() && !(m.arity() == arity()))
270          return false;
271        if(m instanceof GenericMethodDecl) {
272          GenericMethodDecl gm = (GenericMethodDecl)m;
273          ArrayList list = typeArguments(m);
274          if(list.size() != 0) {
275            if(gm.getNumTypeParameter() != list.size())
276              return false;
277            for(int i = 0; i < gm.getNumTypeParameter(); i++)
278              if(!((TypeDecl)list.get(i)).subtype(gm.original().getTypeParameter(i)))
279                return false;
280          }
281        }
282        return true;
283      }
284      syn int MethodDecl.arity() = getNumParameter();
285      syn int MethodAccess.arity() = getNumArg();
286    
287      syn lazy ArrayList MethodAccess.typeArguments(MethodDecl m) {
288        ArrayList typeArguments = new ArrayList();
289        if(m instanceof GenericMethodDecl) {
290          GenericMethodDecl g = (GenericMethodDecl)m;
291          Collection arguments = computeConstraints(g);
292          if(arguments.isEmpty())
293            return typeArguments;
294          int i = 0;
295          for(Iterator iter = arguments.iterator(); iter.hasNext(); i++) {
296            TypeDecl typeDecl = (TypeDecl)iter.next();
297            if(typeDecl == null) {
298              TypeVariable v = g.original().getTypeParameter(i);
299              if(v.getNumTypeBound() == 0)
300                typeDecl = typeObject();
301              else if(v.getNumTypeBound() == 1)
302                typeDecl = v.getTypeBound(0).type();
303              else
304                typeDecl = v.lubType();
305            }
306            typeArguments.add(typeDecl);
307          }
308        }
309        return typeArguments;
310      }
311      eq ParMethodAccess.typeArguments(MethodDecl m) {
312        ArrayList typeArguments = new ArrayList();
313        for(int i = 0; i < getNumTypeArgument(); i++)
314          typeArguments.add(getTypeArgument(i).type());
315        return typeArguments;
316      }
317    
318      syn boolean ConstructorDecl.potentiallyApplicable(List argList) {
319        if(isVariableArity() && !(argList.getNumChild() >= arity()-1))
320          return false;
321        if(!isVariableArity() && !(arity() == argList.getNumChild()))
322          return false;
323        return true;
324      }
325      syn int ConstructorDecl.arity() = getNumParameter();
326      syn int ConstructorAccess.arity() = getNumArg();
327      syn int ClassInstanceExpr.arity() = getNumArg();
328    
329      // 15.12.3
330      // refine old type checking to be valid when using variable arity parameters
331      refine TypeCheck public void MethodAccess.typeCheck() {
332        if(isQualified() && decl().isAbstract() && qualifier().isSuperAccess())
333          error("may not access abstract methods in superclass");
334        if(!decl().isVariableArity() || invokesVariableArityAsArray()) {
335          for(int i = 0; i < decl().getNumParameter(); i++) {
336            TypeDecl exprType = getArg(i).type();
337            TypeDecl parmType = decl().getParameter(i).type();
338            if(!exprType.methodInvocationConversionTo(parmType) && !exprType.isUnknown() && !parmType.isUnknown()) {
339              error("#The type " + exprType.typeName() + " of expr " +
340                getArg(i) + " is not compatible with the method parameter " +
341                decl().getParameter(i));
342            }
343          }
344        }
345      }
346    
347      refine MethodDecl eq MethodDecl.signature() {
348        StringBuffer s = new StringBuffer();
349        s.append(name() + "(");
350        for(int i = 0; i < getNumParameter(); i++) {
351          if(i != 0) s.append(", ");
352          s.append(getParameter(i).type().erasure().typeName());
353        }
354        s.append(")");
355        return s.toString();
356    
357      }
358    
359      refine MemberMethods eq ClassDecl.methodsSignatureMap() {
360        HashMap map = new HashMap(localMethodsSignatureMap());
361        if(hasSuperclass()) {
362          for(Iterator iter = superclass().methodsIterator(); iter.hasNext(); ) {
363            MethodDecl m = (MethodDecl)iter.next();
364            if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature())) {
365              if(!(m instanceof MethodDeclSubstituted) || !localMethodsSignatureMap().containsKey(m.sourceMethodDecl().signature()))
366                putSimpleSetElement(map, m.signature(), m);
367            }
368          }
369        }
370        for(Iterator outerIter = interfacesIterator(); outerIter.hasNext(); ) {
371          TypeDecl typeDecl = (TypeDecl)outerIter.next();
372          for(Iterator iter = typeDecl.methodsIterator(); iter.hasNext(); ) {
373            MethodDecl m = (MethodDecl)iter.next();
374            if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature())) {
375              if(!(m instanceof MethodDeclSubstituted) || !localMethodsSignatureMap().containsKey(m.sourceMethodDecl().signature())) {
376                if(allMethodsAbstract((SimpleSet)map.get(m.signature())) &&
377                  (!(m instanceof MethodDeclSubstituted) ||
378                   allMethodsAbstract((SimpleSet)map.get(m.sourceMethodDecl().signature()))              )
379                )
380                  putSimpleSetElement(map, m.signature(), m);
381              }
382            }
383          }
384        }
385        return map;
386      }
387      refine MemberMethods eq InterfaceDecl.methodsSignatureMap() {
388        HashMap map = new HashMap(localMethodsSignatureMap());
389        for(Iterator outerIter = superinterfacesIterator(); outerIter.hasNext(); ) {
390          TypeDecl typeDecl = (TypeDecl)outerIter.next();
391          for(Iterator iter = typeDecl.methodsIterator(); iter.hasNext(); ) {
392            MethodDecl m = (MethodDecl)iter.next();
393            if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature()))
394              if(!(m instanceof MethodDeclSubstituted) || !localMethodsSignatureMap().containsKey(m.sourceMethodDecl().signature()))
395                putSimpleSetElement(map, m.signature(), m);
396          }
397        }
398        for(Iterator iter = typeObject().methodsIterator(); iter.hasNext(); ) {
399          MethodDecl m = (MethodDecl)iter.next();
400          if(m.isPublic() && !map.containsKey(m.signature()))
401            putSimpleSetElement(map, m.signature(), m);
402        }
403        return map;
404      }
405    
406      eq ParTypeDecl.unimplementedMethods() {
407        HashSet set = new HashSet();
408        HashSet result = new HashSet();
409        for(Iterator iter = genericDecl().unimplementedMethods().iterator(); iter.hasNext(); ) {
410          MethodDecl m = (MethodDecl)iter.next();
411          set.add(m.sourceMethodDecl());
412        }
413        for(Iterator iter = super.unimplementedMethods().iterator(); iter.hasNext(); ) {
414          MethodDecl m = (MethodDecl)iter.next();
415          if(set.contains(m.sourceMethodDecl()))
416            result.add(m);
417        }
418        return result;
419      }
420    
421    }