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