001 /* Copyright (c) 2014, Erik Hogeman <Erik.Hogemn@gmail.com> 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 * * Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * * Redistributions in binary form must reproduce the above copyright 010 * notice, this list of conditions and the following disclaimer in the 011 * documentation and/or other materials provided with the distribution. 012 * * Neither the name of the Lund University nor the names of its 013 * contributors may be used to endorse or promote products derived from 014 * this software without specific prior written permission. 015 * 016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 019 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 020 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 021 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 022 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 023 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 024 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026 * POSSIBILITY OF SUCH DAMAGE. 027 */ 028 aspect FunctionDescriptor { 029 class FunctionDescriptor { 030 ArrayList<TypeDecl> throwsList = null; 031 MethodDecl method = null; 032 InterfaceDecl fromInterface = null; 033 034 public FunctionDescriptor(InterfaceDecl fromInterface) { 035 this.fromInterface = fromInterface; 036 } 037 038 public boolean isGeneric() { 039 if (method == null) { 040 return false; 041 } else { 042 return method.isGeneric(); 043 } 044 } 045 046 public InterfaceDecl fromInterface() { 047 return this.fromInterface; 048 } 049 050 public String toString() { 051 StringBuilder str = new StringBuilder(); 052 if (method != null) { 053 if (method.isGeneric()) { 054 GenericMethodDecl genericMethod = method.genericDecl(); 055 str.append("<" + genericMethod.getTypeParameter(0).prettyPrint()); 056 for (int i = 1; i < genericMethod.getNumTypeParameter(); i++) { 057 str.append(", " + genericMethod.getTypeParameter(i).prettyPrint()); 058 } 059 str.append("> "); 060 } 061 str.append("("); 062 if (method.getNumParameter() > 0) { 063 str.append(method.getParameter(0).type().typeName()); 064 for (int i = 1; i < method.getNumParameter(); i++) { 065 str.append(", " + method.getParameter(i).type().typeName()); 066 } 067 } 068 str.append(")->"); 069 str.append(method.type().typeName()); 070 071 str.append(" throws "); 072 if (throwsList.size() > 0) { 073 str.append(throwsList.get(0).typeName()); 074 for (int i = 1; i < throwsList.size(); i++) { 075 str.append(", " + throwsList.get(i).typeName()); 076 } 077 } 078 } 079 080 return str.toString(); 081 } 082 } 083 084 syn lazy boolean InterfaceDecl.hasFunctionDescriptor() { 085 return functionDescriptor() != null; 086 } 087 088 syn lazy FunctionDescriptor ParInterfaceDecl.functionDescriptor() { 089 if (getNumArgument() != ((GenericInterfaceDecl)original()).getNumTypeParameter()) { 090 return null; 091 } else { 092 return super.functionDescriptor(); 093 } 094 } 095 096 // 9.8 097 syn lazy FunctionDescriptor InterfaceDecl.functionDescriptor() { 098 LinkedList<MethodDecl> methods = collectAbstractMethods(); 099 100 if (methods.size() == 0) { 101 return null; 102 } else if (methods.size() == 1) { 103 MethodDecl m = methods.getFirst(); 104 FunctionDescriptor f = new FunctionDescriptor(this); 105 f.method = m; 106 ArrayList<TypeDecl> throwsList = new ArrayList<TypeDecl>(); 107 for (Access exception : m.getExceptionList()) { 108 throwsList.add(exception.type()); 109 } 110 f.throwsList = throwsList; 111 return f; 112 } else { 113 FunctionDescriptor f = null; 114 MethodDecl foundMethod = null; 115 116 for (MethodDecl current : methods) { 117 foundMethod = current; 118 for (MethodDecl inner : methods) { 119 if (!current.subsignatureTo(inner) || !current.returnTypeSubstitutableFor(inner)) { 120 foundMethod = null; 121 } 122 } 123 if (foundMethod != null) { 124 break; 125 } 126 } 127 128 ArrayList<Access> descriptorThrows = new ArrayList<Access>(); 129 if (foundMethod != null) { 130 // Now the throws-list needs to be computed as stated in 9.8 131 for (MethodDecl current : methods) { 132 for (Access exception : current.getExceptionList()) { 133 boolean alreadyInserted = false; 134 for (Access found : descriptorThrows) { 135 if (found.sameType(exception)) { 136 alreadyInserted = true; 137 break; 138 } 139 } 140 if (alreadyInserted) { 141 continue; 142 } 143 144 boolean foundIncompatibleClause = false; 145 // Has to be the subtype to at least one exception in each clause 146 if (foundMethod.isGeneric()) { 147 for (MethodDecl inner : methods) { 148 if (!inner.subtypeThrowsClause(exception)) { 149 foundIncompatibleClause = true; 150 break; 151 } 152 } 153 } else { 154 for (MethodDecl inner : methods) { 155 if (!inner.subtypeThrowsClauseErased(exception)) { 156 foundIncompatibleClause = true; 157 break; 158 } 159 } 160 } 161 162 if (!foundIncompatibleClause) { 163 // Was subtype to one exception in every clause 164 descriptorThrows.add(exception); 165 } 166 } 167 } 168 169 /* Found a suitable method and finished building throws-list, 170 now the descriptor just needs to be put together */ 171 f = new FunctionDescriptor(this); 172 f.method = foundMethod; 173 if (descriptorThrows.size() == 0) { 174 f.throwsList = new ArrayList<TypeDecl>(); 175 } else { 176 ArrayList<TypeDecl> throwsList = new ArrayList<TypeDecl>(); 177 178 /* All type variables must be replaced with foundMethods 179 type variables if the descriptor is generic */ 180 if (foundMethod.isGeneric()) { 181 GenericMethodDecl foundGeneric = foundMethod.genericDecl(); 182 for (Access exception : descriptorThrows) { 183 if (exception.type() instanceof TypeVariable) { 184 TypeVariable foundVar = (TypeVariable) exception.type(); 185 TypeVariable original = foundGeneric.getTypeParameter(foundVar.typeVarPosition()); 186 throwsList.add(original); 187 } else { 188 throwsList.add(exception.type()); 189 } 190 } 191 } else { 192 // All throwed types must be erased if the descriptor is not generic. 193 for (Access exception : descriptorThrows) { 194 throwsList.add(exception.type().erasure()); 195 } 196 } 197 f.throwsList = throwsList; 198 } 199 } 200 return f; 201 } 202 } 203 204 /** 205 * Checks that the argument exception is a subtype to all exceptions 206 * in the methods throws-clause. This takes the position of the type 207 * parameters into account. 208 */ 209 public boolean MethodDecl.subtypeThrowsClause(Access exception) { 210 boolean foundCompatible = false; 211 for (Access throwsException : getExceptionList()) { 212 if (exception.type().strictSubtype(throwsException.type())) { 213 foundCompatible = true; 214 break; 215 } 216 } 217 return foundCompatible; 218 } 219 220 /** 221 * Checks that the argument exception is a subtype to all exceptions 222 * in the methods throws-clause. Performs erasure on all types before 223 * comparing them. 224 */ 225 public boolean MethodDecl.subtypeThrowsClauseErased(Access exception) { 226 boolean foundCompatible = false; 227 for (Access throwsException : getExceptionList()) { 228 if (exception.type().erasure().strictSubtype(throwsException.type().erasure())) { 229 foundCompatible = true; 230 break; 231 } 232 } 233 return foundCompatible; 234 } 235 236 }