001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * 2014, Jesper Öqvist <jesper.oqvist@cs.lth.se> 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions are met: 007 * 008 * 1. Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * 2. Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * 3. Neither the name of the copyright holder nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 023 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 029 * POSSIBILITY OF SUCH DAMAGE. 030 */ 031 032 aspect GenericMethods { 033 public void ParMethodAccess.typeCheck() { 034 super.typeCheck(); 035 if (!decl().hostType().isUnknown()) { 036 // JLS 15.12.2.1 specifically permits type arguments on non-generic method access 037 if (decl() instanceof ParMethodDecl) { 038 ParMethodDecl m = (ParMethodDecl) decl(); 039 if (!(m instanceof RawMethodDecl) && m.numTypeParameter() != getNumTypeArgument()) { 040 errorf("generic method %s requires %s type arguments", 041 m.signature(), m.numTypeParameter()); 042 } else { 043 } 044 } 045 } 046 } 047 048 syn lazy final MethodDecl GenericMethodDecl.rawMethodDecl() = 049 lookupParMethodDecl(Collections.<TypeDecl>emptyList()); 050 051 syn lazy GenericMethodDecl ParMethodDecl.genericMethodDecl() = getGenericMethodDecl(); 052 053 syn lazy GenericConstructorDecl ParConstructorDecl.genericConstructorDecl() = 054 getGenericConstructorDecl(); 055 056 syn nta MethodDecl GenericMethodDecl.lookupParMethodDecl(Collection<TypeDecl> typeArguments) = 057 newParMethodDecl(typeArguments); 058 059 public ParMethodDecl GenericMethodDecl.newParMethodDecl(Collection<TypeDecl> typeArguments) { 060 ParMethodDecl methodDecl = typeArguments.isEmpty() ? new RawMethodDecl() : new ParMethodDecl(); 061 062 // Adding a link to GenericMethodDecl to be used during substitution 063 // instead of the not yet existing parent link. 064 methodDecl.setGenericMethodDecl(this); 065 066 List<Access> list = new List<Access>(); 067 if (typeArguments.isEmpty()) { 068 GenericMethodDecl original = original(); 069 for (int i = 0; i < original.getNumTypeParameter(); i++) { 070 list.add(original.getTypeParameter(i).erasure().createBoundAccess()); 071 } 072 } else { 073 for (TypeDecl arg : typeArguments) { 074 list.add(arg.createBoundAccess()); 075 } 076 } 077 methodDecl.setTypeArgumentList(list); 078 methodDecl.setModifiers((Modifiers) getModifiers().treeCopyNoTransform()); 079 methodDecl.setTypeAccess(getTypeAccess().type().substituteReturnType(methodDecl)); 080 methodDecl.setID(getID()); 081 methodDecl.setParameterList(getParameterList().substitute(methodDecl)); 082 methodDecl.setExceptionList(getExceptionList().substitute(methodDecl)); 083 return methodDecl; 084 } 085 086 syn nta ParConstructorDecl GenericConstructorDecl.lookupParConstructorDecl(Collection<TypeDecl> typeArguments) = 087 newParConstructorDecl(typeArguments); 088 089 public ParConstructorDecl GenericConstructorDecl.newParConstructorDecl(Collection<TypeDecl> typeArguments) { 090 ParConstructorDecl constructorDecl = typeArguments.isEmpty() 091 ? new RawConstructorDecl() 092 : new ParConstructorDecl(); 093 094 // Adding a link to GenericConstructorDecl to be used during substitution 095 // instead of the not yet existing parent link. 096 constructorDecl.setGenericConstructorDecl(this); 097 098 List<Access> list = new List<Access>(); 099 if (typeArguments.isEmpty()) { 100 GenericConstructorDecl original = original(); 101 for (int i = 0; i < original.getNumTypeParameter(); i++) { 102 list.add(original.getTypeParameter(i).erasure().createBoundAccess()); 103 } 104 } else { 105 for (TypeDecl arg : typeArguments) { 106 list.add(arg.createBoundAccess()); 107 } 108 } 109 constructorDecl.setTypeArgumentList(list); 110 constructorDecl.setModifiers((Modifiers) getModifiers().treeCopyNoTransform()); 111 constructorDecl.setID(getID()); 112 constructorDecl.setParameterList(getParameterList().substitute(constructorDecl)); 113 constructorDecl.setExceptionList(getExceptionList().substitute(constructorDecl)); 114 return constructorDecl; 115 } 116 117 } 118 119 aspect TypeCheck { 120 // Disable error checking in instantiated generic methods 121 public void ParMethodDecl.collectErrors() { 122 } 123 124 /** 125 * Allows covariant return types. 126 * <a href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.5">JLSv7 8.4.5</a> 127 * @param other 128 * @return {@code true} if this method is return-type-substitutable for the 129 * other declaration 130 */ 131 refine TypeHierarchyCheck eq MethodDecl.mayOverride(MethodDecl m) { 132 TypeDecl typeA = type(); 133 TypeDecl typeB = m.type(); 134 if (typeA == typeB) { 135 return true; 136 } 137 if (typeA.isPrimitive() && typeB.isPrimitive()) { 138 return false; 139 } 140 return typeA.subtype(typeB); 141 } 142 143 /** 144 * @param other 145 * @return {@code true} if the signature of this method is same as the 146 * the signature of the argument method, taking generics into consideration. 147 */ 148 refine LookupMethod eq MethodDecl.sameSignature(MethodDecl other) { 149 if (!refined(other)) { 150 return false; 151 } 152 for (int i = 0; i < getNumParameter(); ++i) { 153 TypeDecl p1 = getParameter(i).type(); 154 TypeDecl p2 = other.getParameter(i).type(); 155 // JLSv7 $8.4.8.1 exception: if one parameter type is raw, then don't check type bounds 156 if (p1 != p2 && !p1.isRawType() && !p2.isRawType()) { 157 return false; 158 } 159 } 160 return true; 161 } 162 163 refine TypeHierarchyCheck protected void TypeDecl.checkAbstractMethodDecls(MethodDecl m1, MethodDecl m2) { 164 165 if (!m1.sameSignature(m2)) { 166 errorf("method declarations %s and %s in interface %s are incompatible", 167 m1.fullSignature(), m2.fullSignature(), fullName()); 168 } else { 169 refined(m1, m2); 170 } 171 } 172 } 173 174 aspect GenericMethodsNameAnalysis { 175 176 eq ParMethodAccess.getTypeArgument().nameType() = NameType.TYPE_NAME; 177 eq ParMethodAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name); 178 eq GenericMethodDecl.getTypeParameter().nameType() = NameType.TYPE_NAME; 179 180 inh SimpleSet GenericMethodDecl.lookupType(String name); 181 syn SimpleSet GenericMethodDecl.localLookupType(String name) { 182 for (int i = 0; i < getNumTypeParameter(); i++) { 183 if (original().getTypeParameter(i).name().equals(name)) { 184 return SimpleSet.emptySet.add(original().getTypeParameter(i)); 185 } 186 } 187 return SimpleSet.emptySet; 188 } 189 eq GenericMethodDecl.getChild().lookupType(String name) = localLookupType(name).isEmpty() ? lookupType(name) : localLookupType(name); 190 191 eq ParConstructorAccess.getTypeArgument().nameType() = NameType.TYPE_NAME; 192 eq ParConstructorAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name); 193 eq ParSuperConstructorAccess.getTypeArgument().nameType() = NameType.TYPE_NAME; 194 eq ParSuperConstructorAccess.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name); 195 eq GenericConstructorDecl.getTypeParameter().nameType() = NameType.TYPE_NAME; 196 197 inh SimpleSet GenericConstructorDecl.lookupType(String name); 198 syn SimpleSet GenericConstructorDecl.localLookupType(String name) { 199 for (int i = 0; i < getNumTypeParameter(); i++) { 200 if (original().getTypeParameter(i).name().equals(name)) { 201 return SimpleSet.emptySet.add(original().getTypeParameter(i)); 202 } 203 } 204 return SimpleSet.emptySet; 205 } 206 eq GenericConstructorDecl.getChild().lookupType(String name) = localLookupType(name).isEmpty() ? lookupType(name) : localLookupType(name); 207 208 eq ParClassInstanceExpr.getTypeArgument().nameType() = NameType.TYPE_NAME; 209 eq ParClassInstanceExpr.getTypeArgument().lookupType(String name) = unqualifiedScope().lookupType(name); 210 211 } 212 213 aspect GenericMethodsPrettyPrint { 214 215 public void ParMethodAccess.prettyPrint(PrettyPrinter out) { 216 out.print("<"); 217 for (int i = 0; i < getNumTypeArgument(); i++) { 218 if (i != 0) { 219 out.print(", "); 220 } 221 out.print(getTypeArgument(i)); 222 } 223 out.print(">"); 224 super.prettyPrint(out); 225 } 226 227 public void ParConstructorAccess.prettyPrint(PrettyPrinter out) { 228 out.print("<"); 229 for (int i = 0; i < getNumTypeArgument(); i++) { 230 if (i != 0) { 231 out.print(", "); 232 } 233 out.print(getTypeArgument(i)); 234 } 235 out.print(">"); 236 super.prettyPrint(out); 237 } 238 239 public void ParSuperConstructorAccess.prettyPrint(PrettyPrinter out) { 240 out.print("<"); 241 for (int i = 0; i < getNumTypeArgument(); i++) { 242 if (i != 0) { 243 out.print(", "); 244 } 245 out.print(getTypeArgument(i)); 246 } 247 out.print(">"); 248 super.prettyPrint(out); 249 } 250 251 public void ParClassInstanceExpr.prettyPrint(PrettyPrinter out) { 252 out.print("<"); 253 for (int i = 0; i < getNumTypeArgument(); i++) { 254 if (i != 0) { 255 out.print(", "); 256 } 257 out.print(getTypeArgument(i)); 258 } 259 out.print(">"); 260 super.prettyPrint(out); 261 } 262 263 }