001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    aspect VariableArityParameters {
032      // 8.4.1
033    
034      /* The last formal parameter in a list is special; it may be a variable arity
035      parameter, indicated by an elipsis following the type.*/
036      public void VariableArityParameterDeclaration.nameCheck() {
037        super.nameCheck();
038        if (!variableArityValid()) {
039          error("only the last formal paramater may be of variable arity");
040        }
041      }
042    
043      eq ConstructorDecl.getParameter(int i).variableArityValid() = i == getNumParameter() - 1;
044      eq MethodDecl.getParameter(int i).variableArityValid() = i == getNumParameter() - 1;
045      eq BasicCatch.getParameter().variableArityValid() = false;
046      eq Program.getChild().variableArityValid() = false;
047    
048      inh boolean VariableArityParameterDeclaration.variableArityValid();
049    
050      /* If the last formal parameter is a variable arity parameter of type T, it is
051      considered to define a formal parameter of type T[].*/
052      eq VariableArityParameterDeclaration.type() = super.type().arrayType();
053    
054      /* The method is then a variable arity method. Otherwise, it is a fixed arity method.*/
055      syn boolean MethodDecl.isVariableArity() = getNumParameter() == 0 ? false : getParameter(getNumParameter()-1).isVariableArity();
056      syn boolean ConstructorDecl.isVariableArity() = getNumParameter() == 0 ? false : getParameter(getNumParameter()-1).isVariableArity();
057      syn boolean ParameterDeclaration.isVariableArity() = false;
058      eq VariableArityParameterDeclaration.isVariableArity() = true;
059    
060      syn ParameterDeclaration MethodDecl.lastParameter() = getParameter(getNumParameter() - 1);
061      syn boolean MethodAccess.invokesVariableArityAsArray() {
062        if (!decl().isVariableArity()) {
063          return false;
064        }
065        if (arity() != decl().arity()) {
066          return false;
067        }
068        return getArg(getNumArg()-1).type().methodInvocationConversionTo(decl().lastParameter().type());
069      }
070      syn boolean ConstructorAccess.invokesVariableArityAsArray() {
071        if (!decl().isVariableArity()) {
072          return false;
073        }
074        if (arity() != decl().arity()) {
075          return false;
076        }
077        return getArg(getNumArg()-1).type().methodInvocationConversionTo(decl().lastParameter().type());
078      }
079      syn boolean ClassInstanceExpr.invokesVariableArityAsArray() {
080        if (!decl().isVariableArity()) {
081          return false;
082        }
083        if (arity() != decl().arity()) {
084          return false;
085        }
086        return getArg(getNumArg()-1).type().methodInvocationConversionTo(decl().lastParameter().type());
087      }
088    
089    
090      syn ParameterDeclaration ConstructorDecl.lastParameter() = getParameter(getNumParameter() - 1);
091    
092      // 15.12.2
093    
094    /*
095    A method is applicable if it is either applicable by subtyping (�15.12.2.2),
096    applicable by method invocation conversion (�15.12.2.3), or it is an applicable
097    variable arity method (�15.12.2.4).
098    
099    The process of determining applicability begins by determining the potentially
100    applicable methods (�15.12.2.1). The remainder of the process is split into
101    three phases.
102    
103    The first phase (�15.12.2.2) performs overload resolution without permitting
104    boxing or unboxing conversion, or the use of variable arity method invocation.
105    If no applicable method is found during this phase then processing continues to
106    the second phase.
107    
108    The second phase (�15.12.2.3) performs overload resolution while allowing
109    boxing and unboxing, but still precludes the use of variable arity method
110    invocation. If no applicable method is found during this phase then processing
111    continues to the third phase.
112    
113    The third phase (�15.12.2.4) allows overloading to be combined with variable
114    arity methods, boxing and unboxing.
115    
116    Deciding whether a method is applicable will, in the case of generic methods
117    (�8.4.4), require that actual type arguments be determined. Actual type
118    arguments may be passed explicitly or implicitly. If they are passed
119    implicitly, they must be inferred (�15.12.2.7) from the types of the argument
120    expressions.
121    
122    If several applicable methods have been identified during one of the three
123    phases of applicability testing, then the most specific one is chosen, as
124    specified in section �15.12.2.5. See the following subsections for details.
125    */
126    
127      refine AnonymousClasses
128      protected List AnonymousDecl.constructorParameterList(ConstructorDecl decl) {
129        List parameterList = new List();
130        for (int i = 0; i < decl.getNumParameter(); i++) {
131          ParameterDeclaration param = decl.getParameter(i);
132          if (param instanceof VariableArityParameterDeclaration) {
133            parameterList.add(
134                new VariableArityParameterDeclaration(
135                  new Modifiers(new List()),
136                  ((ArrayDecl) param.type()).componentType().createBoundAccess(),
137                  param.name()
138                  ));
139          } else {
140            parameterList.add(
141                new ParameterDeclaration(
142                  param.type().createBoundAccess(),
143                  param.name()
144                  ));
145          }
146        }
147    
148        return parameterList;
149      }
150    
151    }