001    /* This file was generated with JastAdd2 (http://jastadd.org) version 2.1.13-12-g880e696 */
002    package org.extendj.ast;
003    
004    import java.util.HashSet;
005    import java.io.File;
006    import java.util.Set;
007    import java.util.Collections;
008    import java.util.Collection;
009    import java.util.ArrayList;
010    import beaver.*;
011    import java.util.*;
012    import java.io.ByteArrayOutputStream;
013    import java.io.PrintStream;
014    import java.lang.reflect.InvocationTargetException;
015    import java.lang.reflect.Method;
016    import org.jastadd.util.*;
017    import java.util.zip.*;
018    import java.io.*;
019    import org.jastadd.util.PrettyPrintable;
020    import org.jastadd.util.PrettyPrinter;
021    import java.io.FileNotFoundException;
022    import java.io.BufferedInputStream;
023    import java.io.DataInputStream;
024    /**
025     * Type access for a generic class with an empty type parameter list.
026     * @ast node
027     * @declaredat /home/jesper/git/extendj/java7/grammar/Diamond.ast:4
028     * @production DiamondAccess : {@link Access} ::= <span class="component">TypeAccess:{@link Access}</span>;
029    
030     */
031    public class DiamondAccess extends Access implements Cloneable {
032      /**
033       * @aspect Diamond
034       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:94
035       */
036      protected static SimpleSet mostSpecific(SimpleSet maxSpecific, MethodDecl decl) {
037        if (maxSpecific.isEmpty()) {
038          maxSpecific = maxSpecific.add(decl);
039        } else {
040          MethodDecl other = (MethodDecl) maxSpecific.iterator().next();
041          if (decl.moreSpecificThan(other)) {
042            maxSpecific = decl;
043          } else if (!other.moreSpecificThan(decl)) {
044            maxSpecific = maxSpecific.add(decl);
045          }
046        }
047        return maxSpecific;
048      }
049      /**
050       * Choose a constructor for the diamond operator using placeholder
051       * methods.
052       * @aspect Diamond
053       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:112
054       */
055      protected SimpleSet chooseConstructor() {
056        ClassInstanceExpr instanceExpr = getClassInstanceExpr();
057        TypeDecl type = getTypeAccess().type();
058    
059        assert instanceExpr != null;
060        assert type instanceof ParClassDecl;
061    
062        GenericClassDecl genericType = (GenericClassDecl) ((ParClassDecl) type).genericDecl();
063    
064        List<StandInMethodDecl> placeholderMethods = genericType.getStandInMethodList();
065    
066        SimpleSet maxSpecific = SimpleSet.emptySet;
067        Collection<MethodDecl> potentiallyApplicable = potentiallyApplicable(placeholderMethods);
068        for (MethodDecl candidate : potentiallyApplicable) {
069          if (applicableBySubtyping(instanceExpr, candidate)
070              || applicableByMethodInvocationConversion(instanceExpr, candidate)
071              || applicableByVariableArity(instanceExpr, candidate)) {
072            maxSpecific = mostSpecific(maxSpecific, candidate);
073          }
074        }
075        return maxSpecific;
076      }
077      /**
078       * Select potentially applicable method declarations
079       * from a set of candidates.
080       * Type inference is applied to the (potentially) applicable candidates.
081       * @aspect Diamond
082       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:238
083       */
084      protected Collection<MethodDecl> potentiallyApplicable(
085          List<StandInMethodDecl> candidates) {
086        Collection<MethodDecl> potentiallyApplicable = new LinkedList<MethodDecl>();
087        for (GenericMethodDecl candidate : candidates) {
088          if (potentiallyApplicable(candidate)) {
089            MethodDecl decl = candidate.lookupParMethodDecl(
090                inferTypeArguments(
091                    candidate.type(),
092                    candidate.getParameterList(),
093                    getClassInstanceExpr().getArgList(),
094                    candidate.getTypeParameterList()));
095            potentiallyApplicable.add(decl);
096          }
097        }
098        return potentiallyApplicable;
099      }
100      /**
101       * Test if a method is applicable for this diamond access.
102       * @param candidate candidate method
103       * @return false if the candidate method is not applicable.
104       * @aspect Diamond
105       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:260
106       */
107      protected boolean potentiallyApplicable(
108          GenericMethodDecl candidate) {
109        if (candidate.isVariableArity() && !(getClassInstanceExpr().arity() >= candidate.arity()-1)) {
110          return false;
111        }
112        if (!candidate.isVariableArity() && !(getClassInstanceExpr().arity() == candidate.arity())) {
113          return false;
114        }
115    
116        java.util.List<TypeDecl> typeArgs = inferTypeArguments(
117            candidate.type(),
118            candidate.getParameterList(),
119            getClassInstanceExpr().getArgList(),
120            candidate.getTypeParameterList());
121        Parameterization par = new SimpleParameterization(candidate.getTypeParameterList(), typeArgs);
122        if (typeArgs.size() != 0) {
123          if (candidate.getNumTypeParameter() != typeArgs.size()) {
124            return false;
125          }
126          for (int i = 0; i < candidate.getNumTypeParameter(); i++) {
127            if (!typeArgs.get(i).withinBounds(candidate.original().getTypeParameter(i), par)) {
128              return false;
129            }
130          }
131        }
132        return true;
133      }
134      /**
135       * @return true if the method is applicable by subtyping
136       * @aspect Diamond
137       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:291
138       */
139      protected boolean applicableBySubtyping(ClassInstanceExpr expr, MethodDecl method) {
140        if (method.getNumParameter() != expr.getNumArg()) {
141          return false;
142        }
143        for (int i = 0; i < method.getNumParameter(); i++) {
144          if (!expr.getArg(i).type().instanceOf(method.getParameter(i).type())) {
145            return false;
146          }
147        }
148        return true;
149      }
150      /**
151       * @return true if the method is applicable by method invocation conversion
152       * @aspect Diamond
153       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:306
154       */
155      protected boolean applicableByMethodInvocationConversion(
156          ClassInstanceExpr expr, MethodDecl method) {
157        if (method.getNumParameter() != expr.getNumArg()) {
158          return false;
159        }
160        for (int i = 0; i < method.getNumParameter(); i++) {
161          if (!expr.getArg(i).type().methodInvocationConversionTo(
162              method.getParameter(i).type())) {
163            return false;
164          }
165        }
166        return true;
167      }
168      /**
169       * @return true if the method is applicable by variable arity
170       * @aspect Diamond
171       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:323
172       */
173      protected boolean applicableByVariableArity(
174          ClassInstanceExpr expr, MethodDecl method) {
175        for (int i = 0; i < method.getNumParameter() - 1; i++) {
176          if (!expr.getArg(i).type().methodInvocationConversionTo(
177              method.getParameter(i).type())) {
178            return false;
179          }
180        }
181        for (int i = method.getNumParameter() - 1; i < expr.getNumArg(); i++) {
182          if (!expr.getArg(i).type().methodInvocationConversionTo(
183              method.lastParameter().type().componentType())) {
184            return false;
185          }
186        }
187        return true;
188      }
189      /**
190       * Checks if this diamond access is legal.
191       * The diamond access is not legal if it either is part of an inner class
192       * declaration, if it is used to access a non-generic type, or if it is
193       * part of a call to a generic constructor with explicit type arguments.
194       * @aspect Diamond
195       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:435
196       */
197      public void typeCheck() {
198        if (isAnonymousDecl()) {
199          error("the diamond operator can not be used with anonymous classes");
200        }
201        if (isExplicitGenericConstructorAccess()) {
202          error("the diamond operator may not be used with generic "
203              + "constructors with explicit type parameters");
204        }
205        if (getClassInstanceExpr() == null) {
206          error("the diamond operator can only be used in class instance expressions");
207        }
208        if (!(getTypeAccess().type() instanceof ParClassDecl)) {
209          error("the diamond operator can only be used to instantiate generic classes");
210        }
211      }
212      /**
213       * @aspect Java7PrettyPrint
214       * @declaredat /home/jesper/git/extendj/java7/frontend/PrettyPrint.jadd:35
215       */
216      public void prettyPrint(PrettyPrinter out) {
217        out.print(getTypeAccess());
218        out.print("<>");
219      }
220      /**
221       * @declaredat ASTNode:1
222       */
223      public DiamondAccess() {
224        super();
225      }
226      /**
227       * Initializes the child array to the correct size.
228       * Initializes List and Opt nta children.
229       * @apilevel internal
230       * @ast method
231       * @declaredat ASTNode:10
232       */
233      public void init$Children() {
234        children = new ASTNode[1];
235      }
236      /**
237       * @declaredat ASTNode:13
238       */
239      public DiamondAccess(Access p0) {
240        setChild(p0, 0);
241      }
242      /**
243       * @apilevel low-level
244       * @declaredat ASTNode:19
245       */
246      protected int numChildren() {
247        return 1;
248      }
249      /**
250       * @apilevel internal
251       * @declaredat ASTNode:25
252       */
253      public boolean mayHaveRewrite() {
254        return false;
255      }
256      /**
257       * @apilevel internal
258       * @declaredat ASTNode:31
259       */
260      public void flushAttrCache() {
261        super.flushAttrCache();
262        type_reset();
263      }
264      /**
265       * @apilevel internal
266       * @declaredat ASTNode:38
267       */
268      public void flushCollectionCache() {
269        super.flushCollectionCache();
270      }
271      /**
272       * @apilevel internal
273       * @declaredat ASTNode:44
274       */
275      public void flushRewriteCache() {
276        super.flushRewriteCache();
277      }
278      /**
279       * @apilevel internal
280       * @declaredat ASTNode:50
281       */
282      public DiamondAccess clone() throws CloneNotSupportedException {
283        DiamondAccess node = (DiamondAccess) super.clone();
284        return node;
285      }
286      /**
287       * @apilevel internal
288       * @declaredat ASTNode:57
289       */
290      public DiamondAccess copy() {
291        try {
292          DiamondAccess node = (DiamondAccess) clone();
293          node.parent = null;
294          if (children != null) {
295            node.children = (ASTNode[]) children.clone();
296          }
297          return node;
298        } catch (CloneNotSupportedException e) {
299          throw new Error("Error: clone not supported for " + getClass().getName());
300        }
301      }
302      /**
303       * Create a deep copy of the AST subtree at this node.
304       * The copy is dangling, i.e. has no parent.
305       * @return dangling copy of the subtree at this node
306       * @apilevel low-level
307       * @deprecated Please use treeCopy or treeCopyNoTransform instead
308       * @declaredat ASTNode:76
309       */
310      @Deprecated
311      public DiamondAccess fullCopy() {
312        return treeCopyNoTransform();
313      }
314      /**
315       * Create a deep copy of the AST subtree at this node.
316       * The copy is dangling, i.e. has no parent.
317       * @return dangling copy of the subtree at this node
318       * @apilevel low-level
319       * @declaredat ASTNode:86
320       */
321      public DiamondAccess treeCopyNoTransform() {
322        DiamondAccess tree = (DiamondAccess) copy();
323        if (children != null) {
324          for (int i = 0; i < children.length; ++i) {
325            ASTNode child = (ASTNode) children[i];
326            if (child != null) {
327              child = child.treeCopyNoTransform();
328              tree.setChild(child, i);
329            }
330          }
331        }
332        return tree;
333      }
334      /**
335       * Create a deep copy of the AST subtree at this node.
336       * The subtree of this node is traversed to trigger rewrites before copy.
337       * The copy is dangling, i.e. has no parent.
338       * @return dangling copy of the subtree at this node
339       * @apilevel low-level
340       * @declaredat ASTNode:106
341       */
342      public DiamondAccess treeCopy() {
343        doFullTraversal();
344        return treeCopyNoTransform();
345      }
346      /**
347       * @apilevel internal
348       * @declaredat ASTNode:113
349       */
350      protected boolean is$Equal(ASTNode node) {
351        return super.is$Equal(node);    
352      }
353      /**
354       * Replaces the TypeAccess child.
355       * @param node The new node to replace the TypeAccess child.
356       * @apilevel high-level
357       */
358      public void setTypeAccess(Access node) {
359        setChild(node, 0);
360      }
361      /**
362       * Retrieves the TypeAccess child.
363       * @return The current node used as the TypeAccess child.
364       * @apilevel high-level
365       */
366      @ASTNodeAnnotation.Child(name="TypeAccess")
367      public Access getTypeAccess() {
368        return (Access) getChild(0);
369      }
370      /**
371       * Retrieves the TypeAccess child.
372       * <p><em>This method does not invoke AST transformations.</em></p>
373       * @return The current node used as the TypeAccess child.
374       * @apilevel low-level
375       */
376      public Access getTypeAccessNoTransform() {
377        return (Access) getChildNoTransform(0);
378      }
379      /**
380       * @apilevel internal
381       */
382      protected boolean type_computed = false;
383      /**
384       * @apilevel internal
385       */
386      protected TypeDecl type_value;
387      /**
388       * @apilevel internal
389       */
390      private void type_reset() {
391        type_computed = false;
392        type_value = null;
393      }
394      /**
395       * @attribute syn
396       * @aspect TypeAnalysis
397       * @declaredat /home/jesper/git/extendj/java4/frontend/TypeAnalysis.jrag:302
398       */
399      @ASTNodeAnnotation.Attribute
400      public TypeDecl type() {
401        ASTNode$State state = state();
402        if (type_computed) {
403          return type_value;
404        }
405        boolean intermediate = state.INTERMEDIATE_VALUE;
406        state.INTERMEDIATE_VALUE = false;
407        int num = state.boundariesCrossed;
408        boolean isFinal = this.is$Final();
409        type_value = type_compute();
410        if (isFinal && num == state().boundariesCrossed) {
411          type_computed = true;
412        } else {
413        }
414        state.INTERMEDIATE_VALUE |= intermediate;
415    
416        return type_value;
417      }
418      /**
419       * @apilevel internal
420       */
421      private TypeDecl type_compute() {
422          TypeDecl accessType = getTypeAccess().type();
423      
424          if (isAnonymousDecl()) {
425            return accessType;
426          }
427      
428          if (getClassInstanceExpr() == null) {
429            // It is an error if the DiamondAccess does not occurr
430            // within a class instance creation expression, but this
431            // error is handled in typeCheck.
432            return accessType;
433          }
434      
435          if (!(accessType instanceof ParClassDecl)) {
436            // It is an error if the TypeDecl of a DiamondAccess is not
437            // a generic type, but this error is handled in typeCheck.
438            return accessType;
439          }
440      
441          SimpleSet maxSpecific = chooseConstructor();
442      
443          if (maxSpecific.isEmpty()) {
444            return getTypeAccess().type();
445          }
446      
447          MethodDecl constructor = (MethodDecl) maxSpecific.iterator().next();
448          return constructor.type();
449        }
450      /**
451       * @attribute syn
452       * @aspect Diamond
453       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:87
454       */
455      @ASTNodeAnnotation.Attribute
456      public boolean isDiamond() {
457        boolean isDiamond_value = true;
458    
459        return isDiamond_value;
460      }
461      /**
462       * @attribute inh
463       * @aspect Diamond
464       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:90
465       */
466      /**
467       * @attribute inh
468       * @aspect Diamond
469       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:90
470       */
471      @ASTNodeAnnotation.Attribute
472      public ClassInstanceExpr getClassInstanceExpr() {
473        ClassInstanceExpr getClassInstanceExpr_value = getParent().Define_getClassInstanceExpr(this, null);
474    
475        return getClassInstanceExpr_value;
476      }
477      /**
478       * @return true if this access is part of an anonymous class declaration
479       * @attribute inh
480       * @aspect Diamond
481       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:401
482       */
483      /**
484       * @return true if this access is part of an anonymous class declaration
485       * @attribute inh
486       * @aspect Diamond
487       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:401
488       */
489      @ASTNodeAnnotation.Attribute
490      public boolean isAnonymousDecl() {
491        boolean isAnonymousDecl_value = getParent().Define_isAnonymousDecl(this, null);
492    
493        return isAnonymousDecl_value;
494      }
495      /**
496       * @return true if the Access is part of a generic constructor invocation
497       * with explicit type arguments
498       * @attribute inh
499       * @aspect Diamond
500       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:417
501       */
502      /**
503       * @return true if the Access is part of a generic constructor invocation
504       * with explicit type arguments
505       * @attribute inh
506       * @aspect Diamond
507       * @declaredat /home/jesper/git/extendj/java7/frontend/Diamond.jrag:417
508       */
509      @ASTNodeAnnotation.Attribute
510      public boolean isExplicitGenericConstructorAccess() {
511        boolean isExplicitGenericConstructorAccess_value = getParent().Define_isExplicitGenericConstructorAccess(this, null);
512    
513        return isExplicitGenericConstructorAccess_value;
514      }
515      /**
516       * @apilevel internal
517       */
518      public ASTNode rewriteTo() {
519        return super.rewriteTo();
520      }
521    }