001 /* Copyright (c) 2011, Jesper Öqvist <jesper.oqvist@cs.lth.se> 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 MultiCatch { 032 033 /** 034 * Inherit the lookupVariable attribute. 035 */ 036 inh SimpleSet CatchParameterDeclaration.lookupVariable(String name); 037 038 CatchParameterDeclaration implements Variable; 039 syn boolean CatchParameterDeclaration.isParameter() = true; 040 041 // 4.5.3 042 syn boolean CatchParameterDeclaration.isClassVariable() = false; 043 syn boolean CatchParameterDeclaration.isInstanceVariable() = false; 044 inh boolean CatchParameterDeclaration.isMethodParameter(); 045 inh boolean CatchParameterDeclaration.isConstructorParameter(); 046 inh boolean CatchParameterDeclaration.isExceptionHandlerParameter(); 047 syn boolean CatchParameterDeclaration.isLocalVariable() = false; 048 049 eq MultiCatch.getParameter().isMethodParameter() = false; 050 eq MultiCatch.getParameter().isConstructorParameter() = false; 051 eq MultiCatch.getParameter().isExceptionHandlerParameter() = true; 052 053 /** 054 * The catch parameter of a multi-catch clause is implicitly final. 055 */ 056 syn boolean CatchParameterDeclaration.isFinal() = true; 057 syn boolean CatchParameterDeclaration.isVolatile() = getModifiers().isVolatile(); 058 syn boolean CatchParameterDeclaration.isBlank() = false; 059 syn boolean CatchParameterDeclaration.isStatic() = false; 060 061 syn String CatchParameterDeclaration.name() = getID(); 062 063 syn boolean CatchParameterDeclaration.hasInit() = false; 064 syn Expr CatchParameterDeclaration.getInit() { 065 throw new UnsupportedOperationException(); 066 } 067 syn Constant CatchParameterDeclaration.constant() { 068 throw new UnsupportedOperationException(); 069 } 070 071 inh TypeDecl CatchParameterDeclaration.hostType(); 072 syn boolean CatchParameterDeclaration.isSynthetic() = getModifiers().isSynthetic(); 073 074 /** 075 * @see "Generics.jrag" 076 */ 077 eq CatchParameterDeclaration.sourceVariableDecl() = this; 078 079 // Name lookup 080 081 // CatchParameterDeclaration is a SimpleSet 082 CatchParameterDeclaration implements SimpleSet; 083 syn int CatchParameterDeclaration.size() = 1; 084 syn boolean CatchParameterDeclaration.isEmpty() = false; 085 public SimpleSet CatchParameterDeclaration.add(Object o) { 086 return new SimpleSetImpl().add(this).add(o); 087 } 088 syn boolean CatchParameterDeclaration.contains(Object o) = this == o; 089 public boolean CatchParameterDeclaration.isSingleton() { return true; } 090 public boolean CatchParameterDeclaration.isSingleton(Object o) { return contains(o); } 091 092 CatchParameterDeclaration implements Iterator; 093 private CatchParameterDeclaration CatchParameterDeclaration.iterElem; 094 public Iterator CatchParameterDeclaration.iterator() { iterElem = this; return this; } 095 public boolean CatchParameterDeclaration.hasNext() { return iterElem != null; } 096 public Object CatchParameterDeclaration.next() { Object o = iterElem; iterElem = null; return o; } 097 public void CatchParameterDeclaration.remove() { throw new UnsupportedOperationException(); } 098 099 /** 100 * Variable lookup in catch parameter scope. 101 */ 102 eq MultiCatch.getParameter().lookupVariable(String name) = parameterDeclaration(name); 103 104 /** 105 * Variable lookup in catch parameter scope. 106 */ 107 eq MultiCatch.parameterDeclaration(String name) = 108 getParameter().name().equals(name) ? getParameter() : SimpleSet.emptySet; 109 110 /** 111 * Syntactic classification 112 */ 113 eq CatchParameterDeclaration.getTypeAccess(int i).nameType() = NameType.TYPE_NAME; 114 115 eq MultiCatch.handles(TypeDecl exceptionType) { 116 CatchParameterDeclaration param = getParameter(); 117 for (int i = 0; i < param.getNumTypeAccess(); ++i) { 118 TypeDecl type = param.getTypeAccess(i).type(); 119 if (!type.isUnknown() && exceptionType.instanceOf(type)) { 120 return true; 121 } 122 } 123 return false; 124 } 125 126 /** 127 * Type checking. 128 * The types given in a disjunction type may not be 129 * subtypes of each other. 130 */ 131 public void CatchParameterDeclaration.typeCheck() { 132 boolean pass = true; 133 for (int i = 0; i < getNumTypeAccess(); ++i) { 134 for (int j = 0; j < getNumTypeAccess(); ++j) { 135 if (i == j) { 136 continue; 137 } 138 TypeDecl t1 = getTypeAccess(i).type(); 139 TypeDecl t2 = getTypeAccess(j).type(); 140 if (t2.instanceOf(t1)) { 141 errorf("%s is a subclass of %s, which is not allowed in multi-catch type alternatives", 142 t2.fullName(), t1.fullName()); 143 pass = false; 144 } 145 } 146 } 147 } 148 149 /** 150 * Reachability checking for multi-catch. 151 */ 152 eq MultiCatch.getBlock().reachable() { 153 boolean anyReachable = false; 154 CatchParameterDeclaration param = getParameter(); 155 for (int i = 0; i < param.getNumTypeAccess(); ++i) { 156 TypeDecl type = param.getTypeAccess(i).type(); 157 if (!reachableCatchClause(type)) { 158 errorf("The exception type %s can not be caught by this multi-catch clause", 159 type.fullName()); 160 } else { 161 anyReachable = true; 162 } 163 } 164 return anyReachable; 165 } 166 167 inh LUBType CatchParameterDeclaration.lookupLUBType(Collection bounds); 168 169 /** 170 * A catch parameter declared with a disjunction type has the 171 * effective type lub(t1, t2, ...) 172 * 173 * @see "JLSv3 §15.12.2.7" 174 */ 175 syn TypeDecl CatchParameterDeclaration.type() { 176 ArrayList<TypeDecl> list = new ArrayList<TypeDecl>(); 177 for (int i = 0; i < getNumTypeAccess(); i++) 178 list.add(getTypeAccess(i).type()); 179 return lookupLUBType(list).lub(); 180 } 181 182 inh VariableScope CatchParameterDeclaration.outerScope(); 183 inh BodyDecl CatchParameterDeclaration.enclosingBodyDecl(); 184 185 /** 186 * Duplicate declaration checking for catch parameters. 187 */ 188 public void CatchParameterDeclaration.nameCheck() { 189 SimpleSet decls = outerScope().lookupVariable(name()); 190 for (Iterator iter = decls.iterator(); iter.hasNext(); ) { 191 Variable var = (Variable) iter.next(); 192 if (var instanceof VariableDeclaration) { 193 VariableDeclaration decl = (VariableDeclaration) var; 194 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 195 errorf("duplicate declaration of catch parameter %s", name()); 196 } 197 } else if (var instanceof ParameterDeclaration) { 198 ParameterDeclaration decl = (ParameterDeclaration) var; 199 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 200 errorf("duplicate declaration of catch parameter %s", name()); 201 } 202 } else if (var instanceof CatchParameterDeclaration) { 203 CatchParameterDeclaration decl = (CatchParameterDeclaration) var; 204 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 205 errorf("duplicate declaration of catch parameter %s", name()); 206 } 207 } 208 } 209 210 // 8.4.1 211 if (!lookupVariable(name()).contains(this)) { 212 errorf("duplicate declaration of catch parameter %s", name()); 213 } 214 } 215 216 refine NameCheck 217 public void ParameterDeclaration.nameCheck() { 218 SimpleSet decls = outerScope().lookupVariable(name()); 219 for (Iterator iter = decls.iterator(); iter.hasNext(); ) { 220 Variable var = (Variable) iter.next(); 221 if (var instanceof VariableDeclaration) { 222 VariableDeclaration decl = (VariableDeclaration) var; 223 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 224 errorf("duplicate declaration of parameter %s", name()); 225 } 226 } else if (var instanceof ParameterDeclaration) { 227 ParameterDeclaration decl = (ParameterDeclaration) var; 228 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 229 errorf("duplicate declaration of parameter %s", name()); 230 } 231 } else if (var instanceof CatchParameterDeclaration) { 232 CatchParameterDeclaration decl = (CatchParameterDeclaration) var; 233 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 234 errorf("duplicate declaration of parameter %s", name()); 235 } 236 } 237 } 238 239 // 8.4.1 240 if (!lookupVariable(name()).contains(this)) { 241 errorf("duplicate declaration of parameter %s", name()); 242 } 243 } 244 245 refine NameCheck 246 public void VariableDeclaration.nameCheck() { 247 SimpleSet decls = outerScope().lookupVariable(name()); 248 for (Iterator iter = decls.iterator(); iter.hasNext(); ) { 249 Variable var = (Variable) iter.next(); 250 if (var instanceof VariableDeclaration) { 251 VariableDeclaration decl = (VariableDeclaration) var; 252 if (decl != this && decl.enclosingBodyDecl() == enclosingBodyDecl()) { 253 errorf("duplicate declaration of local variable %s", name()); 254 } 255 } 256 // 8.4.1 257 else if (var instanceof ParameterDeclaration) { 258 ParameterDeclaration decl = (ParameterDeclaration) var; 259 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 260 errorf("duplicate declaration of local variable %s", name()); 261 } 262 } else if (var instanceof CatchParameterDeclaration) { 263 CatchParameterDeclaration decl = (CatchParameterDeclaration) var; 264 if (decl.enclosingBodyDecl() == enclosingBodyDecl()) { 265 errorf("duplicate declaration of local variable %s", name()); 266 } 267 } 268 } 269 if (getParent().getParent() instanceof Block) { 270 Block block = (Block) getParent().getParent(); 271 for (int i = 0; i < block.getNumStmt(); i++) { 272 if (block.getStmt(i) instanceof Variable) { 273 Variable v = (Variable) block.getStmt(i); 274 if (v.name().equals(name()) && v != this) { 275 errorf("duplicate declaration of local variable %s", name()); 276 } 277 } 278 } 279 } 280 } 281 }