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 &sect;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    }