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 }