001 /* 002 * $Id: JSRVariableScopeCodeVisitor.java,v 1.24 2005/11/13 16:42:11 blackdrag Exp $ 003 * 004 * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 005 * 006 * Redistribution and use of this software and associated documentation 007 * ("Software"), with or without modification, are permitted provided that the 008 * following conditions are met: 1. Redistributions of source code must retain 009 * copyright statements and notices. Redistributions must also contain a copy 010 * of this document. 2. Redistributions in binary form must reproduce the above 011 * copyright notice, this list of conditions and the following disclaimer in 012 * the documentation and/or other materials provided with the distribution. 3. 013 * The name "groovy" must not be used to endorse or promote products derived 014 * from this Software without prior written permission of The Codehaus. For 015 * written permission, please contact info@codehaus.org. 4. Products derived 016 * from this Software may not be called "groovy" nor may "groovy" appear in 017 * their names without prior written permission of The Codehaus. "groovy" is a 018 * registered trademark of The Codehaus. 5. Due credit should be given to The 019 * Codehaus - http://groovy.codehaus.org/ 020 * 021 * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY 022 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 023 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 024 * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR 025 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 026 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 027 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 028 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 029 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 030 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 031 * DAMAGE. 032 * 033 */ 034 035 package org.codehaus.groovy.classgen; 036 037 import java.lang.reflect.Modifier; 038 import java.lang.reflect.Field; 039 import java.lang.reflect.Method; 040 import java.util.HashMap; 041 import java.util.HashSet; 042 import java.util.Iterator; 043 import java.util.Set; 044 import java.util.List; 045 import org.codehaus.groovy.ast.ASTNode; 046 import org.codehaus.groovy.ast.ClassHelper; 047 import org.codehaus.groovy.ast.ClassNode; 048 import org.codehaus.groovy.ast.CodeVisitorSupport; 049 import org.codehaus.groovy.ast.CompileUnit; 050 import org.codehaus.groovy.ast.ConstructorNode; 051 import org.codehaus.groovy.ast.FieldNode; 052 import org.codehaus.groovy.ast.GroovyClassVisitor; 053 import org.codehaus.groovy.ast.MethodNode; 054 import org.codehaus.groovy.ast.Parameter; 055 import org.codehaus.groovy.ast.PropertyNode; 056 import org.codehaus.groovy.ast.expr.ClosureExpression; 057 import org.codehaus.groovy.ast.expr.DeclarationExpression; 058 import org.codehaus.groovy.ast.expr.Expression; 059 import org.codehaus.groovy.ast.expr.FieldExpression; 060 import org.codehaus.groovy.ast.expr.PropertyExpression; 061 import org.codehaus.groovy.ast.expr.VariableExpression; 062 import org.codehaus.groovy.ast.stmt.BlockStatement; 063 import org.codehaus.groovy.ast.stmt.CatchStatement; 064 import org.codehaus.groovy.ast.stmt.DoWhileStatement; 065 import org.codehaus.groovy.ast.stmt.ForStatement; 066 import org.codehaus.groovy.ast.stmt.Statement; 067 import org.codehaus.groovy.ast.stmt.WhileStatement; 068 import org.codehaus.groovy.control.SourceUnit; 069 import org.codehaus.groovy.control.messages.SyntaxErrorMessage; 070 import org.codehaus.groovy.syntax.SyntaxException; 071 072 import org.codehaus.groovy.ast.Variable; 073 074 public class JSRVariableScopeCodeVisitor extends CodeVisitorSupport implements GroovyClassVisitor { 075 076 private static class Var implements Variable{ 077 //TODO: support final and native 078 String name; 079 ClassNode type=null; 080 boolean isInStaticContext=false; 081 boolean isDynamicTyped; 082 083 public Var(String name,VarScope scope) { 084 // a Variable without type and other modifiers 085 // make it dynamic type, non final and non static 086 this.name=name; 087 setType(ClassHelper.DYNAMIC_TYPE); 088 isInStaticContext = scope.isInStaticContext; 089 } 090 091 public Var(String pName, MethodNode f) { 092 name = pName; 093 setType(f.getReturnType()); 094 isInStaticContext=f.isStatic(); 095 } 096 097 public Var(String pName, Method m) { 098 name = pName; 099 type = ClassHelper.make(m.getReturnType()); 100 isInStaticContext=Modifier.isStatic(m.getModifiers()); 101 } 102 103 public Var(Field f) { 104 name = f.getName(); 105 type = ClassHelper.make(f.getType()); 106 isInStaticContext=Modifier.isStatic(f.getModifiers()); 107 } 108 109 public Var(Variable v) { 110 name=v.getName(); 111 type=v.getType(); 112 isInStaticContext=v.isInStaticContext(); 113 isDynamicTyped=v.isDynamicTyped(); 114 } 115 116 public void setType(ClassNode cn) { 117 type = cn; 118 isDynamicTyped |= cn==ClassHelper.DYNAMIC_TYPE; 119 } 120 121 public ClassNode getType() { 122 return type; 123 } 124 125 public String getName() { 126 return name; 127 } 128 129 public Expression getInitialExpression() { 130 return null; 131 } 132 133 public boolean hasInitialExpression() { 134 return false; 135 } 136 137 public boolean isInStaticContext() { 138 return isInStaticContext; 139 } 140 141 public boolean isDynamicTyped() { 142 return isDynamicTyped; 143 } 144 } 145 146 private static class VarScope { 147 boolean isClass=true; 148 boolean isInStaticContext = false; 149 150 VarScope parent; 151 HashMap declares = new HashMap(); 152 HashMap visibles = new HashMap(); 153 154 public VarScope(boolean isClass, VarScope parent, boolean staticContext) { 155 this.isClass=isClass; 156 this.parent = parent; 157 isInStaticContext = staticContext; 158 } 159 160 public VarScope(VarScope parent, boolean staticContext) { 161 this(false,parent,staticContext); 162 } 163 164 public VarScope(VarScope parent) { 165 this(false,parent,parent!=null?parent.isInStaticContext:false); 166 } 167 } 168 169 private static class JRoseCheck extends CodeVisitorSupport{ 170 boolean closureStarted=false; 171 boolean itUsed=false; 172 173 public void visitClosureExpression(ClosureExpression expression) { 174 // don't visit subclosures if already in a closure 175 if (closureStarted) return; 176 closureStarted=true; 177 Parameter[] param = expression.getParameters(); 178 for (int i=0; i<param.length; i++) { 179 itUsed = (param[i].getName().equals("it")) && closureStarted || itUsed; 180 } 181 super.visitClosureExpression(expression); 182 } 183 184 public void visitVariableExpression(VariableExpression expression) { 185 itUsed = (expression.getName().equals("it")) && closureStarted || itUsed; 186 } 187 188 } 189 190 private VarScope currentScope = null; 191 private CompileUnit unit; 192 private SourceUnit source; 193 private boolean scriptMode=false; 194 private ClassNode currentClass=null; 195 196 private boolean jroseRule=false; 197 198 public JSRVariableScopeCodeVisitor(VarScope scope, SourceUnit source) { 199 //System.out.println("scope check enabled"); 200 if ("true".equals(System.getProperty("groovy.jsr.check.rule.jrose"))) { 201 jroseRule=true; 202 //System.out.println("jrose check enabled"); 203 } 204 currentScope = scope; 205 this.source = source; 206 if (source.getAST() == null) return; 207 this.unit = source.getAST().getUnit(); 208 } 209 210 public void visitBlockStatement(BlockStatement block) { 211 VarScope scope = currentScope; 212 currentScope = new VarScope(currentScope); 213 super.visitBlockStatement(block); 214 currentScope = scope; 215 } 216 217 public void visitForLoop(ForStatement forLoop) { 218 VarScope scope = currentScope; 219 // TODO: always define a variable here? What about type? 220 currentScope = new VarScope(currentScope); 221 declare(new Var(forLoop.getVariable(),currentScope), forLoop); 222 super.visitForLoop(forLoop); 223 currentScope = scope; 224 } 225 226 public void visitWhileLoop(WhileStatement loop) { 227 //TODO: check while loop variables 228 VarScope scope = currentScope; 229 currentScope = new VarScope(currentScope); 230 super.visitWhileLoop(loop); 231 currentScope = scope; 232 } 233 234 public void visitDoWhileLoop(DoWhileStatement loop) { 235 //TODO: still existant? 236 VarScope scope = currentScope; 237 currentScope = new VarScope(currentScope); 238 super.visitDoWhileLoop(loop); 239 currentScope = scope; 240 } 241 242 public void visitDeclarationExpression(DeclarationExpression expression) { 243 // visit right side first to avoid the usage of a 244 // variable before its declaration 245 expression.getRightExpression().visit(this); 246 // no need to visit left side, just get the variable name 247 VariableExpression vex = expression.getVariableExpression(); 248 vex.setInStaticContext(currentScope.isInStaticContext); 249 if (!jroseRule && "it".equals(vex.getName())) { 250 // we are not in jrose mode, so don't allow variables 251 // of the name 'it' 252 addError("'it' is a keyword in this mode.",vex); 253 } else { 254 declare(vex); 255 } 256 } 257 258 private void addError(String msg, ASTNode expr) { 259 int line = expr.getLineNumber(); 260 int col = expr.getColumnNumber(); 261 source.getErrorCollector().addErrorAndContinue( 262 new SyntaxErrorMessage(new SyntaxException(msg + '\n', line, col), source) 263 ); 264 } 265 266 private void declare(VariableExpression expr) { 267 declare(expr,expr); 268 } 269 270 private void declare(Variable var, ASTNode expr) { 271 String scopeType = "scope"; 272 String variableType = "variable"; 273 274 if (expr.getClass()==FieldNode.class){ 275 scopeType = "class"; 276 variableType = "field"; 277 } else if (expr.getClass()==PropertyNode.class){ 278 scopeType = "class"; 279 variableType = "property"; 280 } 281 282 StringBuffer msg = new StringBuffer(); 283 msg.append("The current ").append(scopeType); 284 msg.append(" does already contain a ").append(variableType); 285 msg.append(" of the name ").append(var.getName()); 286 287 if (currentScope.declares.get(var.getName())!=null) { 288 addError(msg.toString(),expr); 289 return; 290 } 291 292 //TODO: this case is not visited I think 293 if (currentScope.isClass) { 294 currentScope.declares.put(var.getName(),var); 295 } 296 297 for (VarScope scope = currentScope.parent; scope!=null; scope = scope.parent) { 298 HashMap declares = scope.declares; 299 if (scope.isClass) break; 300 if (declares.get(var.getName())!=null) { 301 // variable already declared 302 addError(msg.toString(), expr); 303 break; 304 } 305 } 306 // declare the variable even if there was an error to allow more checks 307 currentScope.declares.put(var.getName(),var); 308 } 309 310 public void visitVariableExpression(VariableExpression expression) { 311 String name = expression.getName(); 312 Variable v = checkVariableNameForDeclaration(name,expression); 313 if (v==null) return; 314 checkVariableContextAccess(v,expression); 315 } 316 317 public void visitFieldExpression(FieldExpression expression) { 318 String name = expression.getFieldName(); 319 //TODO: change that to get the correct scope 320 Variable v = checkVariableNameForDeclaration(name,expression); 321 checkVariableContextAccess(v,expression); 322 } 323 324 private void checkAbstractDeclaration(MethodNode methodNode) { 325 if (!Modifier.isAbstract(methodNode.getModifiers())) return; 326 if (Modifier.isAbstract(currentClass.getModifiers())) return; 327 addError("Can't have an abstract method in a non abstract class." + 328 " The class '" + currentClass.getName() + "' must be declared abstract or the method '" + 329 methodNode.getName() + "' must not be abstract.",methodNode); 330 } 331 332 private boolean hasEqualParameterTypes(Parameter[] first, Parameter[] second) { 333 if (first.length!=second.length) return false; 334 for (int i=0; i<first.length; i++) { 335 String ft = first[i].getType().getName(); 336 String st = second[i].getType().getName(); 337 if (ft.equals(st)) continue; 338 return false; 339 } 340 return true; 341 } 342 343 private void checkImplementsAndExtends(ClassNode node) { 344 ClassNode cn = node.getSuperClass(); 345 if (cn.isInterface()) addError("you are not allowed to extend the Interface "+cn.getName()+", use implements instead", node); 346 ClassNode[] interfaces = node.getInterfaces(); 347 for (int i = 0; i < interfaces.length; i++) { 348 cn = interfaces[i]; 349 if (!cn.isInterface()) addError ("you are not allowed to implement the Class "+cn.getName()+", use extends instead", node); 350 } 351 } 352 353 private void checkClassForOverwritingFinal(ClassNode cn) { 354 ClassNode superCN = cn.getSuperClass(); 355 if (superCN==null) return; 356 if (!Modifier.isFinal(superCN.getModifiers())) return; 357 StringBuffer msg = new StringBuffer(); 358 msg.append("you are not allowed to overwrite the final class "); 359 msg.append(superCN.getName()); 360 msg.append("."); 361 addError(msg.toString(),cn); 362 363 } 364 365 private void checkMethodsForOverwritingFinal(ClassNode cn) { 366 List l = cn.getMethods(); 367 for (Iterator cnIter = l.iterator(); cnIter.hasNext();) { 368 MethodNode method =(MethodNode) cnIter.next(); 369 Parameter[] parameters = method.getParameters(); 370 for (ClassNode superCN = cn.getSuperClass(); superCN!=null; superCN=superCN.getSuperClass()){ 371 List methods = superCN.getMethods(method.getName()); 372 for (Iterator iter = methods.iterator(); iter.hasNext();) { 373 MethodNode m = (MethodNode) iter.next(); 374 Parameter[] np = m.getParameters(); 375 if (!hasEqualParameterTypes(parameters,np)) continue; 376 if (!Modifier.isFinal(m.getModifiers())) return; 377 378 StringBuffer msg = new StringBuffer(); 379 msg.append("you are not allowed to overwrite the final method ").append(method.getName()); 380 msg.append("("); 381 boolean semi = false; 382 for (int i=0; i<parameters.length;i++) { 383 if (semi) { 384 msg.append(","); 385 } else { 386 semi = true; 387 } 388 msg.append(parameters[i].getType()); 389 } 390 msg.append(")"); 391 msg.append(" from class ").append(superCN.getName()); 392 msg.append("."); 393 addError(msg.toString(),method); 394 return; 395 } 396 } 397 } 398 } 399 400 private void checkVariableContextAccess(Variable v, Expression expr) { 401 if (v.isInStaticContext() || !currentScope.isInStaticContext) return; 402 403 String msg = v.getName()+ 404 " is declared in a dynamic context, but you tried to"+ 405 " access it from a static context."; 406 addError(msg,expr); 407 408 // decalre a static variable to be able to continue the check 409 Var v2 = new Var(v); 410 v2.isInStaticContext = true; 411 currentScope.declares.put(v2.name,v2); 412 } 413 414 private Variable checkVariableNameForDeclaration(VariableExpression expression) { 415 if (expression == VariableExpression.THIS_EXPRESSION) return null; 416 String name = expression.getName(); 417 return checkVariableNameForDeclaration(name,expression); 418 } 419 420 private Variable checkVariableNameForDeclaration(String name, Expression expression) { 421 Variable var = new Var(name,currentScope); 422 423 // TODO: this line is not working 424 // if (expression==VariableExpression.SUPER_EXPRESSION) return; 425 if ("super".equals(var.getName()) || "this".equals(var.getName())) return null; 426 427 VarScope scope = currentScope; 428 while (scope != null) { 429 if (scope.declares.get(var.getName())!=null) { 430 var = (Variable) scope.declares.get(var.getName()); 431 break; 432 } 433 if (scope.visibles.get(var.getName())!=null) { 434 var = (Variable) scope.visibles.get(var.getName()); 435 break; 436 } 437 // scope.getReferencedVariables().add(name); 438 scope = scope.parent; 439 } 440 441 VarScope end = scope; 442 443 if (scope == null) { 444 //TODO add a check to be on the lhs! 445 ClassNode vn = unit.getClass(var.getName()); 446 // vn==null means there is no class of that name 447 // note: we need to do this check because it's possible in groovy to access 448 // Classes without the .class known from Java. Example: def type = String; 449 if (vn==null) { 450 declare(var,expression); 451 // don't create an error when inside a script body 452 if (!scriptMode) addError("The variable " + var.getName() + 453 " is undefined in the current scope", expression); 454 } 455 } else { 456 scope = currentScope; 457 while (scope != end) { 458 scope.visibles.put(var.getName(),var); 459 scope = scope.parent; 460 } 461 } 462 463 return var; 464 } 465 466 public void visitClosureExpression(ClosureExpression expression) { 467 VarScope scope = currentScope; 468 currentScope = new VarScope(false,currentScope,scope.isInStaticContext); 469 470 // TODO: set scope 471 // expression.setVarScope(currentScope); 472 473 if (expression.isParameterSpecified()) { 474 Parameter[] parameters = expression.getParameters(); 475 for (int i = 0; i < parameters.length; i++) { 476 parameters[i].setInStaticContext(currentScope.isInStaticContext); 477 declare(parameters[i],expression); 478 } 479 } else { 480 Var var = new Var("it",scope); 481 // TODO: when to add "it" and when not? 482 // John's rule is to add it only to the closures using 'it' 483 // and only to the closure itself, not to subclosures 484 if (jroseRule) { 485 JRoseCheck check = new JRoseCheck(); 486 expression.visit(check); 487 if (check.itUsed) declare(var,expression); 488 } else { 489 currentScope.declares.put("it",var); 490 } 491 } 492 493 // currentScope = new VarScope(currentScope); 494 super.visitClosureExpression(expression); 495 currentScope = scope; 496 } 497 498 public void visitClass(ClassNode node) { 499 checkImplementsAndExtends(node); 500 checkClassForOverwritingFinal(node); 501 checkMethodsForOverwritingFinal(node); 502 VarScope scope = currentScope; 503 currentScope = new VarScope(true,currentScope,false); 504 boolean scriptModeBackup = scriptMode; 505 scriptMode = node.isScript(); 506 ClassNode classBackup = currentClass; 507 currentClass = node; 508 509 HashMap declares = currentScope.declares; 510 // first pass, add all possible variable names (properies and fields) 511 // TODO: handle interfaces 512 // TODO: handle static imports 513 addVarNames(node); 514 addVarNames(node.getOuterClass(), currentScope.visibles, true); 515 addVarNames(node.getSuperClass(), currentScope.visibles, true); 516 // second pass, check contents 517 node.visitContents(this); 518 519 currentClass = classBackup; 520 currentScope = scope; 521 scriptMode = scriptModeBackup; 522 } 523 524 private void addVarNames(ClassNode cn) { 525 //TODO: change test for currentScope.declares 526 //TODO: handle indexed properties 527 if (cn == null) return; 528 List l = cn.getFields(); 529 Set fields = new HashSet(); 530 for (Iterator iter = l.iterator(); iter.hasNext();) { 531 FieldNode f = (FieldNode) iter.next(); 532 if (fields.contains(f)) { 533 declare(f,f); 534 } else { 535 fields.add(f); 536 currentScope.declares.put(f.getName(),f); 537 } 538 } 539 540 //TODO: ignore double delcaration of methods for the moment 541 l = cn.getMethods(); 542 Set setter = new HashSet(); 543 Set getter = new HashSet(); 544 for (Iterator iter = l.iterator(); iter.hasNext();) { 545 MethodNode f =(MethodNode) iter.next(); 546 String methodName = f.getName(); 547 String pName = getPropertyName(methodName); 548 if (pName == null) continue; 549 Var var = new Var(pName,f); 550 currentScope.declares.put(var.name,var); 551 } 552 553 l = cn.getProperties(); 554 Set props = new HashSet(); 555 for (Iterator iter = l.iterator(); iter.hasNext();) { 556 PropertyNode f = (PropertyNode) iter.next(); 557 if (props.contains(f)) { 558 declare(f,f); 559 } else { 560 props.add(f); 561 currentScope.declares.put(f.getName(),f); 562 } 563 } 564 } 565 566 private void addVarNames(ClassNode cn, HashMap refs, boolean visitParent){ 567 // note this method is only called for parent classes 568 569 if (cn == null) return; 570 List l = cn.getFields(); 571 for (Iterator iter = l.iterator(); iter.hasNext();) { 572 FieldNode f = (FieldNode) iter.next(); 573 if (visitParent && Modifier.isPrivate(f.getModifiers())) 574 continue; 575 refs.put(f.getName(),f); 576 } 577 l = cn.getMethods(); 578 for (Iterator iter = l.iterator(); iter.hasNext();) { 579 MethodNode f = (MethodNode) iter.next(); 580 if (visitParent && Modifier.isPrivate(f.getModifiers())) 581 continue; 582 String name = getPropertyName(f.getName()); 583 if (name == null) continue; 584 refs.put(name, new Var(name,f)); 585 } 586 587 l = cn.getProperties(); 588 for (Iterator iter = l.iterator(); iter.hasNext();) { 589 PropertyNode f = (PropertyNode) iter.next(); 590 if (visitParent && Modifier.isPrivate(f.getModifiers())) 591 continue; 592 refs.put(f.getName(),f); 593 } 594 595 if (!visitParent) return; 596 597 addVarNames(cn.getSuperClass(), refs, visitParent); 598 MethodNode enclosingMethod = cn.getEnclosingMethod(); 599 600 if (enclosingMethod == null) return; 601 602 Parameter[] params = enclosingMethod.getParameters(); 603 for (int i = 0; i < params.length; i++) { 604 refs.put(params[i].getName(),params[i]); 605 } 606 607 if (visitParent) 608 addVarNames(enclosingMethod.getDeclaringClass(), refs, visitParent); 609 610 addVarNames(cn.getOuterClass(), refs, visitParent); 611 } 612 613 /*private void addVarNames(ClassNode superclassType, HashMap refs, boolean visitParent) 614 throws ClassNotFoundException 615 { 616 617 if (superclassType == null) return; 618 String superclassName = superclassType.getName(); 619 620 ClassNode cn = unit.getClass(superclassName); 621 if (cn != null) { 622 addVarNames(cn, refs, visitParent); 623 return; 624 } 625 626 Class c = superclassType.getTypeClass(); 627 if (c==null) c = unit.getClassLoader().loadClass(superclassName); 628 Field[] fields = c.getFields(); 629 for (int i = 0; i < fields.length; i++) { 630 Field f = fields[i]; 631 if (visitParent && Modifier.isPrivate(f.getModifiers())) 632 continue; 633 refs.put(f.getName(),new Var(f)); 634 } 635 636 Method[] methods = c.getMethods(); 637 for (int i = 0; i < methods.length; i++) { 638 Method m = methods[i]; 639 if (visitParent && Modifier.isPrivate(m.getModifiers())) 640 continue; 641 String name = getPropertyName(m.getName()); 642 if (name == null) continue; 643 refs.put(name,new Var(name,m)); 644 } 645 646 if (!visitParent) return; 647 648 addVarNames(c.getSuperclass(), refs, visitParent); 649 650 // it's not possible to know the variable names used for an enclosing 651 // method 652 653 // addVarNames(c.getEnclosingClass(),refs,visitParent); 654 }*/ 655 656 private String getPropertyName(String name) { 657 if (!(name.startsWith("set") || name.startsWith("get"))) return null; 658 String pname = name.substring(3); 659 if (pname.length() == 0) return null; 660 String s = pname.substring(0, 1).toLowerCase(); 661 String rest = pname.substring(1); 662 return s + rest; 663 } 664 665 public void visitConstructor(ConstructorNode node) { 666 VarScope scope = currentScope; 667 currentScope = new VarScope(currentScope); 668 669 // TODO: set scope 670 // node.setVarScope(currentScope); 671 672 HashMap declares = currentScope.declares; 673 Parameter[] parameters = node.getParameters(); 674 for (int i = 0; i < parameters.length; i++) { 675 // a constructor is never static 676 declare(parameters[i],node); 677 } 678 currentScope = new VarScope(currentScope); 679 Statement code = node.getCode(); 680 if (code != null) code.visit(this); 681 currentScope = scope; 682 } 683 684 public void visitMethod(MethodNode node) { 685 checkAbstractDeclaration(node); 686 687 VarScope scope = currentScope; 688 currentScope = new VarScope(currentScope,node.isStatic()); 689 690 // TODO: set scope 691 // node.setVarScope(currentScope); 692 693 HashMap declares = currentScope.declares; 694 Parameter[] parameters = node.getParameters(); 695 for (int i = 0; i < parameters.length; i++) { 696 declares.put(parameters[i].getName(),parameters[i]); 697 } 698 699 currentScope = new VarScope(currentScope); 700 Statement code = node.getCode(); 701 if (code!=null) code.visit(this); 702 currentScope = scope; 703 } 704 705 public void visitField(FieldNode node) { 706 Expression init = node.getInitialExpression(); 707 if (init != null) init.visit(this); 708 } 709 710 public void visitProperty(PropertyNode node) { 711 Statement statement = node.getGetterBlock(); 712 if (statement != null) statement.visit(this); 713 714 statement = node.getSetterBlock(); 715 if (statement != null) statement.visit(this); 716 717 Expression init = node.getInitialExpression(); 718 if (init != null) init.visit(this); 719 } 720 721 public void visitPropertyExpression(PropertyExpression expression) {} 722 723 public void visitCatchStatement(CatchStatement statement) { 724 VarScope scope = currentScope; 725 currentScope = new VarScope(currentScope); 726 declare(new Var(statement.getVariable(),currentScope), statement); 727 super.visitCatchStatement(statement); 728 currentScope = scope; 729 } 730 731 }