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    import java.util.*;
011    import java.util.ArrayList;
012    
013    aspect LookupMethod {
014      inh MethodDecl MethodDecl.unknownMethod();
015      inh MethodDecl MethodAccess.unknownMethod();
016      
017      syn Expr Access.unqualifiedScope() = isQualified() ? nestedScope() : this;
018      inh Expr Access.nestedScope();
019      eq AbstractDot.getRight().nestedScope() = isQualified() ? nestedScope() : this;
020      eq AbstractDot.getLeft().nestedScope() = isQualified() ? nestedScope() : this;
021      eq Program.getChild().nestedScope() { throw new UnsupportedOperationException(); }
022    
023      inh Collection Expr.lookupMethod(String name);
024      inh Collection Stmt.lookupMethod(String name);
025      inh Collection BodyDecl.lookupMethod(String name);
026      inh lazy Collection TypeDecl.lookupMethod(String name);
027      
028      eq MethodAccess.getArg().lookupMethod(String name) = unqualifiedScope().lookupMethod(name);
029      eq ConstructorAccess.getArg().lookupMethod(String name) = unqualifiedScope().lookupMethod(name);
030      eq ArrayAccess.getExpr().lookupMethod(String name) = unqualifiedScope().lookupMethod(name);
031      eq ArrayTypeWithSizeAccess.getExpr().lookupMethod(String name) = unqualifiedScope().lookupMethod(name);
032    
033      eq Program.getChild().lookupMethod(String name) = Collections.EMPTY_LIST;
034      eq TypeDecl.getBodyDecl(int i).lookupMethod(String name) = unqualifiedLookupMethod(name);
035    
036      syn lazy Collection TypeDecl.unqualifiedLookupMethod(String name) {
037        Collection c = memberMethods(name);
038        if(!c.isEmpty()) return c;
039        if(isInnerType())
040          return lookupMethod(name);
041        return removeInstanceMethods(lookupMethod(name));
042      }
043    
044      // in explicit constructor invocation
045      eq ConstructorDecl.getConstructorInvocation().lookupMethod(String name) {
046        Collection c = new ArrayList();
047        for(Iterator iter = lookupMethod(name).iterator(); iter.hasNext(); ) {
048          MethodDecl m = (MethodDecl)iter.next();
049          if(!hostType().memberMethods(name).contains(m) || m.isStatic())
050            c.add(m);
051        }
052        return c;
053      }
054      public static Collection ASTNode.removeInstanceMethods(Collection c) {
055        c = new LinkedList(c);
056        for(Iterator iter = c.iterator(); iter.hasNext(); ) {
057          MethodDecl m = (MethodDecl)iter.next();
058          if(!m.isStatic())
059            iter.remove();
060        }
061        return c;
062      }
063    
064      eq AbstractDot.getRight().lookupMethod(String name) = getLeft().type().memberMethods(name);
065    
066      syn MethodDecl MethodAccess.singleCandidateDecl() {
067        MethodDecl result = null;
068        for(Iterator iter = lookupMethod(name()).iterator(); iter.hasNext(); ) {
069          MethodDecl m = (MethodDecl)iter.next();
070          if(result == null)
071            result = m;
072          else if(m.getNumParameter() == getNumArg() && result.getNumParameter() != getNumArg())
073            result = m;
074        }
075        return result;
076      }
077    
078      protected SimpleSet MethodAccess.maxSpecific(Collection candidates) {
079        SimpleSet maxSpecific = SimpleSet.emptySet;
080        for(Iterator iter = candidates.iterator(); iter.hasNext(); ) {
081          MethodDecl decl = (MethodDecl)iter.next();
082          if(applicable(decl) && accessible(decl)) {
083            if(maxSpecific.isEmpty())
084              maxSpecific = maxSpecific.add(decl);
085            else {
086              if(decl.moreSpecificThan((MethodDecl)maxSpecific.iterator().next()))
087                maxSpecific = SimpleSet.emptySet.add(decl);
088              else if(!((MethodDecl)maxSpecific.iterator().next()).moreSpecificThan(decl))
089                maxSpecific = maxSpecific.add(decl);
090            }
091          }
092        }
093        return maxSpecific;
094      }
095    
096      syn lazy SimpleSet MethodAccess.decls() {
097        SimpleSet maxSpecific = maxSpecific(lookupMethod(name()));
098        if(isQualified() ? qualifier().staticContextQualifier() : inStaticContext())
099          maxSpecific = removeInstanceMethods(maxSpecific);
100        return maxSpecific;
101      }
102    
103      syn lazy MethodDecl MethodAccess.decl() {
104        SimpleSet decls = decls();
105        if(decls.size() == 1)
106          return (MethodDecl)decls.iterator().next();
107    
108        // 8.4.6.4 - only return the first method in case of multply inherited abstract methods
109        boolean allAbstract = true;
110        for(Iterator iter = decls.iterator(); iter.hasNext() && allAbstract; ) {
111          MethodDecl m = (MethodDecl)iter.next();
112          if(!m.isAbstract() && !m.hostType().isObject())
113            allAbstract = false;
114        }
115        if(decls.size() > 1 && allAbstract)
116          return (MethodDecl)decls.iterator().next();
117        return unknownMethod();
118      }
119      private static SimpleSet MethodAccess.removeInstanceMethods(SimpleSet c) {
120        SimpleSet set = SimpleSet.emptySet;
121        for(Iterator iter = c.iterator(); iter.hasNext(); ) {
122          MethodDecl m = (MethodDecl)iter.next();
123          if(m.isStatic())
124            set = set.add(m);
125        }
126        return set;
127      }
128    }
129    
130    aspect MethodDecl {
131      syn String MethodDecl.name() = getID();
132    
133      // 8.4.2
134      syn lazy String MethodDecl.signature() {
135        StringBuffer s = new StringBuffer();
136        s.append(name() + "(");
137        for(int i = 0; i < getNumParameter(); i++) {
138          if(i != 0) s.append(", ");
139          s.append(getParameter(i).type().typeName());
140        }
141        s.append(")");
142        return s.toString();
143      }
144    
145      // 8.4.2 Method Signature
146      syn boolean MethodDecl.sameSignature(MethodDecl m) = signature().equals(m.signature());
147      
148      syn lazy boolean MethodDecl.moreSpecificThan(MethodDecl m) {
149        if(getNumParameter() == 0)
150          return false;
151        for(int i = 0; i < getNumParameter(); i++) {
152          if(!getParameter(i).type().instanceOf(m.getParameter(i).type()))
153            return false;
154        }
155        return true;
156      }
157      
158      public boolean MethodAccess.applicable(MethodDecl decl) {
159        if(getNumArg() != decl.getNumParameter())
160          return false;
161        if(!name().equals(decl.name()))
162          return false;
163        for(int i = 0; i < getNumArg(); i++) {
164          if(!getArg(i).type().instanceOf(decl.getParameter(i).type()))
165            return false;
166        }
167        return true;
168      }
169      
170      syn boolean MethodAccess.accessible(MethodDecl m) {
171        if(!isQualified())
172          return true;
173        if(!m.accessibleFrom(hostType()))
174          return false;
175        // the method is not accessible if the type is not accessible
176        if(!qualifier().type().accessibleFrom(hostType()))
177          return false;
178        // 6.6.2.1 -  include qualifier type for protected access
179        if(m.isProtected() && !m.hostPackage().equals(hostPackage())
180            && !m.isStatic() && !qualifier().isSuperAccess()) {
181          return hostType().mayAccess(this, m);
182        }
183        return true;
184      }
185    
186      /**
187       * @return true if the method access may access the method
188       */
189      public boolean TypeDecl.mayAccess(MethodAccess access, MethodDecl method) {
190        if (instanceOf(method.hostType())
191            && access.qualifier().type().instanceOf(this))
192            return true;
193    
194        if (isNestedType())
195          return enclosingType().mayAccess(access, method);
196        else
197          return false;
198      }
199      
200      syn lazy boolean MethodDecl.overrides(MethodDecl m) =
201        !isStatic() && !m.isPrivate() && m.accessibleFrom(hostType()) && 
202         hostType().instanceOf(m.hostType()) && m.signature().equals(signature());
203         
204      syn lazy boolean MethodDecl.hides(MethodDecl m) =
205        isStatic() && !m.isPrivate() && m.accessibleFrom(hostType()) && 
206         hostType().instanceOf(m.hostType()) && m.signature().equals(signature());
207    }
208    
209    aspect MemberMethods {
210      syn Collection TypeDecl.memberMethods(String name) {
211        Collection c = (Collection)methodsNameMap().get(name);
212        if(c != null) return c;
213        return Collections.EMPTY_LIST;
214      }
215      // name -> Collection
216      syn lazy HashMap TypeDecl.methodsNameMap() {
217        HashMap map = new HashMap();
218        for(Iterator iter = methodsIterator(); iter.hasNext(); ) {
219          MethodDecl m = (MethodDecl)iter.next();
220          ArrayList list = (ArrayList)map.get(m.name());
221          if(list == null) {
222            list = new ArrayList(4);
223            map.put(m.name(), list);
224          }
225          list.add(m);
226        }
227        return map;
228      }
229    
230    
231      public Iterator TypeDecl.localMethodsIterator() {
232        return new Iterator() {
233          private Iterator outer = localMethodsSignatureMap().values().iterator();
234          private Iterator inner = null;
235          public boolean hasNext() {
236            if((inner == null || !inner.hasNext()) && outer.hasNext())
237              inner = ((SimpleSet)outer.next()).iterator();
238            return inner == null ? false : inner.hasNext();
239          }
240          public Object next() {
241            return inner.next();
242          }
243          public void remove() { throw new UnsupportedOperationException(); }
244        };
245        //return localMethodsSignatureMap().values().iterator();
246      }
247      syn SimpleSet TypeDecl.localMethodsSignature(String signature) {
248        SimpleSet set = (SimpleSet)localMethodsSignatureMap().get(signature);
249        if(set != null) return set;
250        return SimpleSet.emptySet;
251      }
252      // signature -> method declaration
253      syn lazy HashMap TypeDecl.localMethodsSignatureMap() {
254        HashMap map = new HashMap(getNumBodyDecl());
255        for(int i = 0; i < getNumBodyDecl(); i++) {
256          if(getBodyDecl(i) instanceof MethodDecl) {
257            MethodDecl decl = (MethodDecl)getBodyDecl(i);
258            map.put(decl.signature(), decl);
259          }
260        }
261        return map;
262      }
263    
264      // iterator over all methods in implemented interfaces
265      public Iterator ClassDecl.interfacesMethodsIterator() {
266        return new Iterator() {
267          private Iterator outer = interfacesMethodsSignatureMap().values().iterator();
268          private Iterator inner = null;
269          public boolean hasNext() {
270            if((inner == null || !inner.hasNext()) && outer.hasNext())
271              inner = ((SimpleSet)outer.next()).iterator();
272            return inner == null ? false : inner.hasNext();
273          }
274          public Object next() {
275            return inner.next();
276          }
277          public void remove() { throw new UnsupportedOperationException(); }
278        };
279      }
280      syn SimpleSet ClassDecl.interfacesMethodsSignature(String signature) {
281        SimpleSet set = (SimpleSet)interfacesMethodsSignatureMap().get(signature);
282        if(set != null) return set;
283        return SimpleSet.emptySet;
284      }
285      // signature -> set of method declarations
286      syn lazy HashMap ClassDecl.interfacesMethodsSignatureMap() {
287        HashMap map = new HashMap();
288        for(Iterator iter = interfacesIterator(); iter.hasNext(); ) {
289          TypeDecl typeDecl = (InterfaceDecl)iter.next();
290          for(Iterator i2 = typeDecl.methodsIterator(); i2.hasNext(); ) {
291            MethodDecl m = (MethodDecl)i2.next();
292            putSimpleSetElement(map, m.signature(), m);
293          }
294        }
295        return map;
296      }
297    
298      // iterate over all member methods in this type
299      public Iterator TypeDecl.methodsIterator() {
300        return new Iterator() {
301          private Iterator outer = methodsSignatureMap().values().iterator();
302          private Iterator inner = null;
303          public boolean hasNext() {
304            if((inner == null || !inner.hasNext()) && outer.hasNext())
305              inner = ((SimpleSet)outer.next()).iterator();
306            return inner != null ? inner.hasNext() : false;
307          }
308          public Object next() {
309            return inner.next();
310          }
311          public void remove() { throw new UnsupportedOperationException(); }
312        };
313      }
314    
315      syn SimpleSet TypeDecl.methodsSignature(String signature) {
316        SimpleSet set = (SimpleSet)methodsSignatureMap().get(signature);
317        if(set != null) return set;
318        return SimpleSet.emptySet;
319      }
320      // signature -> SimpleSet
321      syn lazy HashMap TypeDecl.methodsSignatureMap() = localMethodsSignatureMap();
322      eq ClassDecl.methodsSignatureMap() {
323        HashMap map = new HashMap(localMethodsSignatureMap());
324        if(hasSuperclass()) {
325          for(Iterator iter = superclass().methodsIterator(); iter.hasNext(); ) {
326            MethodDecl m = (MethodDecl)iter.next();
327            if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature()))
328              putSimpleSetElement(map, m.signature(), m);
329          }
330        }
331        for(Iterator outerIter = interfacesIterator(); outerIter.hasNext(); ) {
332          TypeDecl typeDecl = (TypeDecl)outerIter.next();
333          for(Iterator iter = typeDecl.methodsIterator(); iter.hasNext(); ) {
334            MethodDecl m = (MethodDecl)iter.next();
335            if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature()))
336              if(allMethodsAbstract((SimpleSet)map.get(m.signature())))
337                putSimpleSetElement(map, m.signature(), m);
338          }
339        }
340        return map;
341      }
342      eq InterfaceDecl.methodsSignatureMap() {
343        HashMap map = new HashMap(localMethodsSignatureMap());
344        for(Iterator outerIter = superinterfacesIterator(); outerIter.hasNext(); ) {
345          TypeDecl typeDecl = (TypeDecl)outerIter.next();
346          for(Iterator iter = typeDecl.methodsIterator(); iter.hasNext(); ) {
347            MethodDecl m = (MethodDecl)iter.next();
348            if(!m.isPrivate() && m.accessibleFrom(this) && !localMethodsSignatureMap().containsKey(m.signature()))
349              putSimpleSetElement(map, m.signature(), m);
350          }
351        }
352        for(Iterator iter = typeObject().methodsIterator(); iter.hasNext(); ) {
353          MethodDecl m = (MethodDecl)iter.next();
354          if(m.isPublic() && !map.containsKey(m.signature()))
355            putSimpleSetElement(map, m.signature(), m);
356        }
357        return map;
358      }
359      protected static void ASTNode.putSimpleSetElement(HashMap map, Object key, Object value) {
360        SimpleSet set = (SimpleSet)map.get(key);
361        if(set == null) set = SimpleSet.emptySet;
362        map.put(key, set.add(value));
363      }
364      protected boolean TypeDecl.allMethodsAbstract(SimpleSet set) {
365        if(set == null) return true;
366        for(Iterator iter = set.iterator(); iter.hasNext(); ) {
367          MethodDecl m = (MethodDecl)iter.next();
368          if(!m.isAbstract())
369            return false;
370        }
371        return true;
372      }
373    }
374    
375    aspect AncestorMethods {
376      // methods with the same signature declared in ancestors
377      // this is used when checking correct overriding, hiding, and implementation of abstract methods
378      syn lazy SimpleSet TypeDecl.ancestorMethods(String signature) = SimpleSet.emptySet;
379    
380      eq ClassDecl.ancestorMethods(String signature) {
381        SimpleSet set = SimpleSet.emptySet;
382        if(hasSuperclass()) {
383          for(Iterator iter = superclass().localMethodsSignature(signature).iterator(); iter.hasNext(); ) {
384            MethodDecl m = (MethodDecl)iter.next();
385            if(!m.isPrivate())
386              set = set.add(m);
387          }
388        }
389        if(set.size() != 1 || ((MethodDecl)set.iterator().next()).isAbstract()) { 
390          for(Iterator iter = interfacesMethodsSignature(signature).iterator(); iter.hasNext(); ) {
391            MethodDecl m = (MethodDecl)iter.next();
392            set = set.add(m);
393          }
394        }
395        if(!hasSuperclass()) return set;
396        if(set.size() == 1) {
397          MethodDecl m = (MethodDecl)set.iterator().next();
398          if(!m.isAbstract()) {
399            boolean done = true;
400            for(Iterator iter = superclass().ancestorMethods(signature).iterator(); iter.hasNext(); ) {
401              MethodDecl n = (MethodDecl)iter.next();
402              if(n.isPrivate() || !n.accessibleFrom(m.hostType()))
403                done = false;
404            }
405            if(done) return set;
406          }
407        }
408        for(Iterator iter = superclass().ancestorMethods(signature).iterator(); iter.hasNext(); ) {
409          MethodDecl m = (MethodDecl)iter.next();
410          set = set.add(m);
411        }
412        return set;
413      }
414      eq InterfaceDecl.ancestorMethods(String signature) {
415        SimpleSet set = SimpleSet.emptySet;
416        for(Iterator outerIter = superinterfacesIterator(); outerIter.hasNext(); ) {
417          TypeDecl typeDecl = (TypeDecl)outerIter.next();
418          for(Iterator iter = typeDecl.methodsSignature(signature).iterator(); iter.hasNext(); ) {
419            MethodDecl m = (MethodDecl)iter.next();
420            set = set.add(m);
421          }
422        }
423        if(!superinterfacesIterator().hasNext()) {
424          for(Iterator iter = typeObject().methodsSignature(signature).iterator(); iter.hasNext(); ) {
425            MethodDecl m = (MethodDecl)iter.next();
426            if(m.isPublic())
427              set = set.add(m);
428          }
429        }
430        return set;
431      }
432    }