1 19 20 package org.netbeans.modules.debugger.jpda.expr; 21 22 import com.sun.jdi.*; 23 24 import java.util.*; 25 import java.util.logging.Level ; 26 import java.util.logging.Logger ; 27 28 import org.netbeans.api.debugger.jpda.InvalidExpressionException; 29 import org.netbeans.api.debugger.jpda.JPDAClassType; 30 import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl; 31 import org.openide.util.NbBundle; 32 33 34 43 public class Evaluator implements JavaParserVisitor { 44 45 private static final boolean verbose = 46 System.getProperty ("netbeans.debugger.noInvokeMethods") != null; 47 48 private static final Logger loggerMethod = Logger.getLogger("org.netbeans.modules.debugger.jpda.invokeMethod"); private static final Logger loggerValue = Logger.getLogger("org.netbeans.modules.debugger.jpda.getValue"); 51 private Expression expression; 52 private EvaluationContext evaluationContext; 53 54 private VirtualMachine vm; 55 private StackFrame frame; 56 private ThreadReference frameThread; 57 private int frameIndex; 58 59 private SimpleNode currentNode; 60 private String currentPackage; 61 private Operators operators; 62 63 Evaluator(Expression expression, EvaluationContext context) { 64 this.expression = expression; 65 this.evaluationContext = context; 66 } 67 68 77 public Value evaluate() throws EvaluationException, IncompatibleThreadStateException 78 { 79 frame = evaluationContext.getFrame(); 80 vm = evaluationContext.getFrame().virtualMachine(); 81 frameThread = frame.thread(); 82 frameIndex = indexOf(frameThread.frames(), frame); 83 if (frameIndex == -1) { 84 throw new IncompatibleThreadStateException("Thread does not contain current frame"); 85 } 86 currentPackage = evaluationContext.getFrame().location().declaringType().name(); 87 int idx = currentPackage.lastIndexOf('.'); 88 currentPackage = (idx > 0) ? currentPackage.substring(0, idx + 1) : ""; 89 operators = new Operators(vm); 90 SimpleNode rootNode = expression.getRoot(); 91 return (Value) rootNode.jjtAccept(this, null); 92 } 93 94 private int indexOf(List frames, StackFrame frame) { 95 int n = frames.size(); 96 Location loc = frame.location(); 97 for (int i = 0; i < n; i++) { 98 if (loc.equals(((StackFrame)frames.get(i)).location())) return i; 99 } 100 return -1; 101 } 102 103 public Object visit(SimpleNode node, Object data) throws EvaluationException { 104 currentNode = node; 105 switch (node.jjtGetID()) 106 { 107 case JavaParserTreeConstants.JJTRESULTTYPE: 108 return visitResultType(node, data); 109 110 case JavaParserTreeConstants.JJTARRAYINITIALIZER: 111 return visitArrayInitializer(node, data); 112 113 case JavaParserTreeConstants.JJTARRAYDIMSANDINITS: 114 return visitArrayDimsAndInits(node, data); 115 116 case JavaParserTreeConstants.JJTALLOCATIONEXPRESSION: 117 return visitAllocationExpression(node, data); 118 119 case JavaParserTreeConstants.JJTARGUMENTLIST: 120 return visitArgumentList(node, data); 121 122 case JavaParserTreeConstants.JJTARGUMENTS: 123 return visitArguments(node, data); 124 125 case JavaParserTreeConstants.JJTCASTEXPRESSION: 126 return visitCastExpression(node, data); 127 128 case JavaParserTreeConstants.JJTPOSTFIXEXPRESSION: 129 return visitPostfixExpression(node, data); 130 131 case JavaParserTreeConstants.JJTPREDECREMENTEXPRESSION: 132 case JavaParserTreeConstants.JJTPREINCREMENTEXPRESSION: 133 return visitPrefixExpression(node, data); 134 135 case JavaParserTreeConstants.JJTUNARYEXPRESSION: 136 case JavaParserTreeConstants.JJTUNARYEXPRESSIONNOTPLUSMINUS: 137 return visitUnaryExpression(node, data); 138 139 case JavaParserTreeConstants.JJTCLASSORINTERFACETYPE: 140 return visitClassOrInterfaceType(node, data); 141 142 case JavaParserTreeConstants.JJTIDENTIFIER: 143 return visitIdentifier(node, data); 144 145 case JavaParserTreeConstants.JJTPRIMITIVETYPE: 146 return visitPrimitiveType(node, data); 147 148 case JavaParserTreeConstants.JJTREFERENCETYPE: 149 return visitReferenceType(node, data); 150 151 case JavaParserTreeConstants.JJTNAME: 152 return visitName(node, data); 153 154 case JavaParserTreeConstants.JJTEXPRESSION: 155 return visitExpression(node, data); 156 157 case JavaParserTreeConstants.JJTPRIMARYEXPRESSION: 158 return visitPrimaryExpression(node, data); 159 160 case JavaParserTreeConstants.JJTPRIMARYPREFIX: 161 return visitPrimaryPrefix(node, data); 162 163 case JavaParserTreeConstants.JJTPRIMARYSUFFIX: 164 return visitPrimarySuffix(node, data); 165 166 case JavaParserTreeConstants.JJTCONDITIONALEXPRESSION: 167 return visitConditionalExpression(node, data); 168 169 case JavaParserTreeConstants.JJTCONDITIONALOREXPRESSION: 170 case JavaParserTreeConstants.JJTCONDITIONALANDEXPRESSION: 171 return visitConditionalOrAndExpression(node, data); 172 173 case JavaParserTreeConstants.JJTSHIFTEXPRESSION: 174 case JavaParserTreeConstants.JJTRELATIONALEXPRESSION: 175 case JavaParserTreeConstants.JJTEQUALITYEXPRESSION: 176 case JavaParserTreeConstants.JJTINCLUSIVEOREXPRESSION: 177 case JavaParserTreeConstants.JJTANDEXPRESSION: 178 case JavaParserTreeConstants.JJTEXCLUSIVEOREXPRESSION: 179 case JavaParserTreeConstants.JJTADDITIVEEXPRESSION: 180 case JavaParserTreeConstants.JJTMULTIPLICATIVEEXPRESSION: 181 return visitBinaryExpression(node, data); 182 183 case JavaParserTreeConstants.JJTINSTANCEOFEXPRESSION: 184 return visitInstanceOfExpression(node, data); 185 186 case JavaParserTreeConstants.JJTLITERAL: 187 return visitLiteral(node, data); 188 189 case JavaParserTreeConstants.JJTBOOLEANLITERAL: 190 return visitBooleanLiteral(node, data); 191 192 case JavaParserTreeConstants.JJTNULLLITERAL: 193 return null; 194 } 195 return Assert.error(node, "unknownNonterminal"); 196 } 197 198 private ObjectReference primitiveClass(String name) throws IncompatibleThreadStateException { 199 ReferenceType primType = resolveType("java.lang." + name.substring(0, 1).toUpperCase() + name.substring(1)); 200 try { 201 if (loggerValue.isLoggable(Level.FINE)) { 202 loggerValue.fine("STARTED : "+primType+".getValue("+primType.fieldByName("TYPE")+")"); 203 } 204 return (ObjectReference) primType.getValue(primType.fieldByName("TYPE")); 205 } finally { 206 if (loggerValue.isLoggable(Level.FINE)) { 207 loggerValue.fine("FINISHED: "+primType+".getValue("+primType.fieldByName("TYPE")+")"); 208 } 209 } 210 } 211 212 private Object visitResultType(SimpleNode node, Object data) { 213 try { 214 if (node.getAttribute("void") != null) { 215 return primitiveClass("void"); 216 } 217 Type type = (Type) node.jjtGetChild(0).jjtAccept(this, data); 218 if (type instanceof ReferenceType) return type; 219 220 return primitiveClass(type.name()); 221 } catch (IncompatibleThreadStateException e) { 222 return Assert.error(node, "internalErrorResolvingType", "void"); 223 } 224 } 225 226 private Object visitArrayInitializer(SimpleNode node, Object data) { 227 Object [] values = new Object [node.jjtGetNumChildren()]; 228 for (int i = 0; i < values.length; i++) { 229 values[i] = node.jjtGetChild(i).jjtAccept(this, data); 230 if (!(values[i] instanceof Value) && !(values[i] instanceof Object [])) { 231 Assert.error(node, "invalidArrayInitializer", values[i]); 232 } 233 } 234 return values; 235 } 236 237 private Object visitArrayDimsAndInits(SimpleNode node, Object data) { 238 239 Type arrayType = (Type) data; 240 int dimensions = ((Integer ) node.getAttribute("dimensions")).intValue(); 241 ArrayReference arrayRef = null; 242 243 try { 244 if (node.getAttribute("initializers") != null) { 245 Object [] initValues = (Object []) node.jjtGetChild(0).jjtAccept(this, data); 246 return createArray(arrayType, dimensions, initValues); 247 } else { 248 int sizeCount = node.jjtGetNumChildren(); 249 int [] sizes = new int[sizeCount]; 250 for (int i = 0; i < sizeCount; i++) { 251 Object sizeObj = node.jjtGetChild(i).jjtAccept(this, data); 252 Assert.assertAssignable(sizeObj, PrimitiveValue.class, node, "arraySizeBadType", sizeObj); 253 Assert.assertNotAssignable(sizeObj, BooleanValue.class, node, "arraySizeBadType", sizeObj); 254 Assert.assertNotAssignable(sizeObj, FloatValue.class, node, "arraySizeBadType", sizeObj); 255 Assert.assertNotAssignable(sizeObj, DoubleValue.class, node, "arraySizeBadType", sizeObj); 256 sizes[i] = ((PrimitiveValue) sizeObj).intValue(); 257 } 258 return createArray(arrayType, dimensions, sizes, 0); 259 } 260 } catch (IncompatibleThreadStateException e) { 261 Assert.error(node, "arrayCreateError", e); 262 } catch (ClassNotLoadedException e) { 263 Assert.error(node, "arrayCreateError", e); 264 } catch (InvalidTypeException e) { 265 Assert.error(node, "arrayCreateError", e); 266 } catch (UnsupportedOperationException uoex) { 267 return Assert.error(node, "calleeException", uoex); 268 } 269 270 return arrayRef; 271 } 272 273 private String brackets = "[[[[[[[[[[[[[[[[[[["; 274 private String brackets(int length) { 275 if (brackets.length() < length) { 276 char [] bracketsArray = new char[length]; 277 Arrays.fill(bracketsArray, '['); 278 brackets = new String (bracketsArray); 279 } 280 return brackets.substring(0, length); 281 } 282 283 private ArrayReference createArray(Type baseType, int dimensions, int [] sizes, int index) throws IncompatibleThreadStateException, 284 ClassNotLoadedException, InvalidTypeException { 285 286 ArrayType arrayType = (ArrayType) resolveType(brackets(dimensions) + baseType.signature()); 287 ArrayReference arrayRef = arrayType.newInstance(sizes[index]); 288 if (sizes.length > index + 1) { 289 for (int i = 0; i < sizes[index]; i++) { 290 arrayRef.setValue(i, createArray(baseType, dimensions - 1, sizes, index + 1)); 291 } 292 } 293 return arrayRef; 294 } 295 296 private ArrayReference createArray(Type baseType, int dimensions, Object [] values) throws IncompatibleThreadStateException, 297 ClassNotLoadedException, InvalidTypeException { 298 299 ArrayType arrayType = (ArrayType) resolveType(brackets(dimensions) + baseType.signature()); 300 ArrayReference arrayRef = arrayType.newInstance(values.length); 301 for (int i = 0; i < values.length; i++) { 302 if (values[i] instanceof Object []) { 303 arrayRef.setValue(i, createArray(baseType, dimensions - 1, (Object []) values[i])); 304 } else { 305 arrayRef.setValue(i, (Value) values[i]); 306 } 307 } 308 return arrayRef; 309 } 310 311 private Object visitAllocationExpression(SimpleNode node, Object data) { 312 313 Type arrayType = (Type) node.jjtGetChild(0).jjtAccept(this, data); 314 315 if (((SimpleNode) node.jjtGetChild(1)).jjtGetID() == JavaParserTreeConstants.JJTARGUMENTS) { 317 if (arrayType instanceof ClassType) { 318 Identifier fvmc = new Identifier(false, (ReferenceType) arrayType, "<init>"); 319 return node.jjtGetChild(1).jjtAccept(this, fvmc); 320 } 321 Assert.assertNotAssignable(arrayType, InterfaceType.class, node, "instantiateInterface", arrayType.name()); 322 } 323 324 return node.jjtGetChild(1).jjtAccept(this, arrayType); 326 } 327 328 private Object visitPrimitiveType(SimpleNode node, Object data) { 329 Token token = (Token) node.getAttribute("token"); 331 switch (token.kind) { 332 case JavaParserConstants.BOOLEAN: 333 return vm.mirrorOf(true).type(); 334 case JavaParserConstants.CHAR: 335 return vm.mirrorOf('a').type(); 336 case JavaParserConstants.BYTE: 337 return vm.mirrorOf((byte)0).type(); 338 case JavaParserConstants.SHORT: 339 return vm.mirrorOf((short)0).type(); 340 case JavaParserConstants.INT: 341 return vm.mirrorOf(0).type(); 342 case JavaParserConstants.LONG: 343 return vm.mirrorOf(0L).type(); 344 case JavaParserConstants.FLOAT: 345 return vm.mirrorOf(1.0f).type(); 346 case JavaParserConstants.DOUBLE: 347 return vm.mirrorOf(1.0).type(); 348 default: 349 throw new RuntimeException ("Unknown primitive type: " + token.image); 350 } 351 } 352 353 private Object visitCastExpression(SimpleNode node, Object data) { 354 Object value = node.jjtGetChild(1).jjtAccept(this, data); 355 if (value == null) return null; 356 Type castType = (Type) node.jjtGetChild(0).jjtAccept(this, data); 357 358 if (value instanceof PrimitiveValue) { 359 PrimitiveValue primValue = (PrimitiveValue) value; 360 if (primValue instanceof BooleanValue) { 361 Assert.assertAssignable(castType, BooleanType.class, node, "castToBooleanRequired", primValue, castType); 362 return primValue; 363 } 364 Assert.assertNotAssignable(castType, BooleanType.class, node, "castFromBooleanRequired", primValue, castType); 365 if (castType instanceof ByteType) { 366 return vm.mirrorOf(primValue.byteValue()); 367 } else if (castType instanceof CharType) { 368 return vm.mirrorOf(primValue.charValue()); 369 } else if (castType instanceof DoubleType) { 370 return vm.mirrorOf(primValue.doubleValue()); 371 } else if (castType instanceof FloatType) { 372 return vm.mirrorOf(primValue.floatValue()); 373 } else if (castType instanceof IntegerType) { 374 return vm.mirrorOf(primValue.intValue()); 375 } else if (castType instanceof LongType) { 376 return vm.mirrorOf(primValue.longValue()); 377 } else { 378 return vm.mirrorOf(primValue.shortValue()); 379 } 380 } 381 382 ObjectReference valueType = (ObjectReference) value; 384 if (!instanceOf(valueType.type(), castType)) { 385 Assert.error(node, "castError", valueType.type(), castType); 386 } 387 return value; 388 } 389 390 399 private Object visitPostfixExpression(SimpleNode node, Object data) { 400 Object value = node.jjtGetChild(0).jjtAccept(this, data); 401 Assert.assertAssignable(value, PrimitiveValue.class, node, "badOperandForPostfixOperator", value); 402 Assert.assertNotAssignable(value, BooleanValue.class, node, "badOperandForPostfixOperator", value); 403 404 Token operator = (Token) node.getAttribute("operator"); 405 try { 406 return operators.evaluate(operator, (PrimitiveValue) value); 407 } catch (IllegalArgumentException e) { 408 return Assert.error(node, "postfixOperatorEvaluationError", operator, e); 409 } 410 } 411 412 421 private Object visitPrefixExpression(SimpleNode node, Object data) { 422 Object value = node.jjtGetChild(0).jjtAccept(this, data); 423 Assert.assertAssignable(value, PrimitiveValue.class, node, "badOperandForPrefixOperator", value); 424 Assert.assertNotAssignable(value, BooleanValue.class, node, "badOperandForPrefixOperator", value); 425 426 Token operator = (Token) node.getAttribute("operator"); 427 try { 428 return operators.evaluate(operator, (PrimitiveValue) value); 429 } catch (IllegalArgumentException e) { 430 return Assert.error(node, "prefixOperatorEvaluationError", operator, e); 431 } 432 } 433 434 private Object visitUnaryExpression(SimpleNode node, Object data) { 435 436 Object value = node.jjtGetChild(0).jjtAccept(this, data); 437 Assert.assertAssignable(value, PrimitiveValue.class, node, "badOperandForUnaryOperator", value); 444 447 448 Token operator = (Token) node.getAttribute("operator"); 449 try { 450 return operators.evaluate(operator, (PrimitiveValue) value); 451 } catch (IllegalArgumentException e) { 452 return Assert.error(node, "unaryOperatorEvaluationError", operator, e); 453 } 454 } 455 456 private Object visitIdentifier(SimpleNode node, Object data) { 457 return ((Token) node.getAttribute("token")).image; 458 } 459 460 private Object visitClassOrInterfaceType(SimpleNode node, Object data) { 461 462 StringBuffer fullName = new StringBuffer (); 463 464 int n = node.jjtGetNumChildren(); 465 for (int i = 0; i < n; i++) { 466 String namePart = (String ) node.jjtGetChild(i).jjtAccept(this, data); 467 fullName.append('.'); 468 fullName.append(namePart); 469 470 if (i < n-1) { 471 SimpleNode nextNode = (SimpleNode) node.jjtGetChild(i + 1); 472 if (nextNode.jjtGetID() == JavaParserTreeConstants.JJTTYPEARGUMENTS) { 473 i++; 474 } 475 } 476 } 477 478 String name = fullName.substring(1); 479 try { 480 return resolveType(name); 481 } catch (IncompatibleThreadStateException e) { 482 return Assert.error(node, "internalErrorResolvingType", name); 483 } 484 } 485 486 493 private ReferenceType resolveType(String name) throws IncompatibleThreadStateException { 494 ReferenceType type; 495 496 if (name.charAt(0) == '[') { 497 if ((type = getClass(name)) != null) return type; 498 Assert.error(currentNode, "unknownType", name); 499 } 500 501 String innerName = frame.location().declaringType().name() + "$" + name; 502 if ((type = getClass(innerName)) != null) return type; 503 504 int idx = name.lastIndexOf('.'); 505 if (idx == -1) { 506 if ((type = getClass(currentPackage + name)) != null) return type; 507 } else { 508 if ((type = getClass(name)) != null) return type; 509 } 510 511 if (idx != -1) { 512 innerName = name.substring(0, idx) + "$" + name.substring(idx + 1); 513 if (innerName.indexOf('.') == -1) innerName = currentPackage + innerName; 514 if ((type = getClass(innerName)) != null) return type; 515 } 516 517 List imports = evaluationContext.getImports(); 518 for (Iterator i = imports.iterator(); i.hasNext();) { 519 String importStatement = (String ) i.next(); 520 int ix = importStatement.lastIndexOf('.'); 521 String qualifier = importStatement.substring(ix + 1); 522 if (!qualifier.equals("*") && !qualifier.equals(name)) continue; 523 String fullName = importStatement.substring(0, ix + 1) + name; 524 type = getClass(fullName); 525 if (type != null) return type; 526 } 527 528 Assert.error(currentNode, "unknownType", name); 529 return null; 530 } 531 532 private ReferenceType getClass(String typeName) throws IncompatibleThreadStateException { 533 534 List classes = vm.classesByName(typeName); 535 if (classes.size() != 0) { 536 return (ReferenceType) classes.get(0); 537 } 538 539 return null; 572 } 573 574 private Object visitReferenceType(SimpleNode node, Object data) { 575 Type baseType = (Type) node.jjtGetChild(0).jjtAccept(this, data); 576 int dimensions = ((Integer ) node.getAttribute("arrayCount")).intValue(); 577 if (dimensions > 0) { 578 try { 579 return resolveType(brackets(dimensions) + baseType.signature().replace('/', '.')); 580 } catch (IncompatibleThreadStateException e) { 581 Assert.error(node, "internalError"); 582 } 583 } 584 return baseType; 585 } 586 587 private Object visitInstanceOfExpression(SimpleNode node, Object data) { 588 589 Object leftOper = node.jjtGetChild(0).jjtAccept(this, data); 590 if (leftOper == null) return vm.mirrorOf(false); 591 Assert.assertAssignable(leftOper, ObjectReference.class, node, "instanceOfLeftOperandNotAReference", leftOper); 592 593 ReferenceType left = ((ObjectReference) leftOper).referenceType(); ReferenceType right = (ReferenceType) node.jjtGetChild(1).jjtAccept(this, data); 596 return vm.mirrorOf(instanceOf(left, right)); 597 } 598 599 private boolean instanceOf(Type left, Type right) { 600 if (left == null) return false; 601 if (left.equals(right)) return true; 602 603 if (right instanceof ArrayType) { 604 if (!(left instanceof ArrayType)) { 605 return false; 606 } else { 607 ArrayType leftArray = (ArrayType) left; 608 ArrayType rightArray = (ArrayType) right; 609 Type leftType; 610 Type rightType; 611 try { 612 leftType = leftArray.componentType(); 613 rightType = rightArray.componentType(); 614 } catch (ClassNotLoadedException e) { 615 return false; 617 } 618 return instanceOf(leftType, rightType); 619 } 620 } 621 622 if (left instanceof ClassType) { 623 ClassType classLeft = (ClassType) left; 624 if (right instanceof InterfaceType) { 625 List ifaces = classLeft.allInterfaces(); 626 for (Iterator i = ifaces.iterator(); i.hasNext();) { 627 InterfaceType type = (InterfaceType) i.next(); 628 if (type.equals(right)) return true; 629 } 630 return false; 631 } else { for (;;) { 633 classLeft = classLeft.superclass(); 634 if (classLeft == null) return false; 635 if (classLeft.equals(right)) return true; 636 } 637 } 638 } 639 640 return false; 641 } 642 643 644 private Object visitConditionalOrAndExpression(SimpleNode node, Object data) { 645 646 Token operator = (Token) node.getAttribute("operator"); 647 648 int n = node.jjtGetNumChildren(); 649 for (int i = 0; i < n; i++) { 650 Object value = node.jjtGetChild(i).jjtAccept(this, data); 651 Assert.assertAssignable(value, BooleanValue.class, node, "conditionalOrAndBooleanOperandRequired", value); 652 boolean val = ((BooleanValue) value).booleanValue(); 653 if (operator.kind == JavaParserConstants.SC_OR && val || operator.kind == JavaParserConstants.SC_AND && !val) { 654 return value; 655 } 656 } 657 return vm.mirrorOf(operator.kind == JavaParserConstants.SC_AND); 658 } 659 660 private Object visitConditionalExpression(SimpleNode node, Object data) { 661 662 Object condition = node.jjtGetChild(0).jjtAccept(this, data); 663 Assert.assertAssignable(condition, BooleanValue.class, node, "conditionalQuestionMarkBooleanOperandRequired", condition); 664 665 boolean val = ((BooleanValue) condition).booleanValue(); 666 667 if (val) { 668 return node.jjtGetChild(1).jjtAccept(this, data); 669 } else { 670 return node.jjtGetChild(2).jjtAccept(this, data); 671 } 672 } 673 674 private Object visitBooleanLiteral(SimpleNode node, Object data) { 675 Token token = (Token) node.getAttribute("token"); 676 return vm.mirrorOf(token.kind == JavaParserConstants.TRUE); 677 } 678 679 private Object visitName(SimpleNode node, Object data) { 680 Object [] tokens = node.getAttributes("token"); 681 StringBuffer name = new StringBuffer (); 682 for (int i = 0; i < tokens.length; i++) { 683 name.append('.'); 684 name.append(tokens[i]); 685 } 686 return name.substring(1); 687 } 688 689 private Object visitPrimaryPrefix(SimpleNode node, Object data) { 690 691 if (node.jjtGetNumChildren() == 0) { 692 ObjectReference thisObject = frame.thisObject(); 693 if (thisObject == null) { 694 Assert.error(node, "thisObjectUnavailable"); 695 } 696 697 if (node.getAttribute("this") != null) return thisObject; 699 String qualifier = (String ) node.getAttribute("qualifier"); 701 String identifier = (String ) node.getAttribute("identifier"); 702 703 return new Identifier((ObjectReference) thisObject, identifier, qualifier); 704 } 705 706 SimpleNode first = (SimpleNode) node.jjtGetChild(0); 707 switch (first.jjtGetID()) { 708 709 case JavaParserTreeConstants.JJTLITERAL: 710 return visit(first, data); 711 712 case JavaParserTreeConstants.JJTEXPRESSION: 713 return visit(first, data); 714 715 case JavaParserTreeConstants.JJTNAME: 716 { 717 String identifier = (String ) visit(first, data); 718 if (identifier.indexOf('.') == -1) { 719 return new Identifier(true, frame.thisObject(), frame.location().declaringType(), identifier); 720 } 721 722 int idx = identifier.indexOf('.'); 724 String name = identifier.substring(0, idx); 725 726 ObjectReference member = null; 727 try { 728 Value variable = evaluateVariable(new Identifier(true, frame.thisObject(), frame.location().declaringType(), name)); 729 Assert.assertAssignable(variable, ObjectReference.class, node, "objectReferenceRequiredOnDereference", variable); 730 member = (ObjectReference) variable; 731 } catch (EvaluationException e) { 732 } 734 735 ReferenceType type = null; 736 if (member == null) { 737 for (;;) { 739 try { 740 type = resolveType(name); 741 break; 742 } catch (EvaluationException e) { 743 } catch (IncompatibleThreadStateException e) { 745 Assert.error(node, "internalError"); 746 } 747 idx = identifier.indexOf('.', idx + 1); 748 if (idx == -1) break; 749 name = identifier.substring(0, idx); 750 } 751 if (type == null) Assert.error(node, "unknownType", identifier); 752 } 753 754 for (;;) { 756 int idx2 = identifier.indexOf('.', idx + 1); 757 int idx22 = idx2; 758 if (idx2 == -1) { 759 idx2 = identifier.length(); 760 } 761 Identifier ident; 762 if (member != null) { 763 ident = new Identifier(false, member, identifier.substring(idx + 1, idx2)); 764 } else { 765 ident = new Identifier(false, type, identifier.substring(idx + 1, idx2)); 766 } 767 if (idx22 == -1) return ident; 768 Value variable = evaluateVariable(ident); 769 Assert.assertAssignable(variable, ObjectReference.class, node, "objectReferenceRequiredOnDereference", variable); 770 member = (ObjectReference) variable; 771 idx = idx2; 772 } 773 } 774 case JavaParserTreeConstants.JJTRESULTTYPE: 775 Object type = first.jjtAccept(this, data); 776 if (type instanceof ReferenceType) { 777 return ((ReferenceType)type).classObject(); 778 } else { 779 return type; 780 } 781 782 default: 783 return first.jjtAccept(this, data); 784 } 785 } 786 787 private Object visitArgumentList(SimpleNode node, Object data) { 788 int n = node.jjtGetNumChildren(); 789 Value [] argValues = new Value[n]; 790 for (int i = 0; i < n ; i++) { 791 Object val = node.jjtGetChild(i).jjtAccept(this, data); 792 if (val != null) Assert.assertAssignable(val, Value.class, node, "badArgument", val); 793 argValues[i] = (Value) val; 794 } 795 return argValues; 796 } 797 798 private class MethodCall { 799 ReferenceType typeContext; 800 ObjectReference instanceContext; 801 Method method; 802 List<Value> args; 803 804 public MethodCall(ReferenceType typeContext, ObjectReference instanceContext, Method method, List<Value> args) { 805 this.typeContext = typeContext; 806 this.instanceContext = instanceContext; 807 this.method = method; 808 this.args = args; 809 } 810 } 811 812 private Object visitArguments(SimpleNode node, Object data) { 813 Assert.assertAssignable(data, Identifier.class, node, "argumentsBadSyntax", data); 814 Identifier ctx = (Identifier) data; 815 816 Value [] args; 817 if (node.jjtGetNumChildren() > 0) { 818 args = (Value[]) node.jjtGetChild(0).jjtAccept(this, null); 819 } else { 820 args = new Value[0]; 821 } 822 823 MethodCall method; 824 try { 825 method = getConcreteMethod(ctx, args); 826 } catch (UnsupportedOperationException uoex) { 827 return Assert.error(node, "calleeException", uoex, ctx); 828 } 829 830 if (method.instanceContext != null) { 831 try { 832 if (verbose) 833 throw new UnsupportedOperationException (NbBundle.getMessage ( 834 Evaluator.class, 835 "CTL_UnsupportedOperationException" 836 )); 837 if (!evaluationContext.canInvokeMethods()) { 838 return Assert.error(node, "calleeException", new UnsupportedOperationException (), ctx); 839 } 840 evaluationContext.methodToBeInvoked(); 841 if (loggerMethod.isLoggable(Level.FINE)) { 842 loggerMethod.fine("STARTED : "+method.instanceContext+"."+method.method+" ("+method.args+") in thread "+frameThread); 843 } 844 return method.instanceContext.invokeMethod(frameThread, method.method, method.args, 845 ObjectReference.INVOKE_SINGLE_THREADED | ObjectReference.INVOKE_NONVIRTUAL); 846 } catch (InvalidTypeException e) { 847 Assert.error(node, "callException", e, ctx); 848 } catch (ClassNotLoadedException e) { 849 Assert.error(node, "callException", e, ctx); 851 } catch (IncompatibleThreadStateException e) { 852 Assert.error(node, "callException", e, ctx); 853 } catch (InvocationException e) { 854 Assert.error(node, "calleeException", e, ctx); 855 } catch (UnsupportedOperationException e) { 856 evaluationContext.setCanInvokeMethods(false); 857 Assert.error(node, "calleeException", e, ctx); 858 } 859 finally { 860 if (loggerMethod.isLoggable(Level.FINE)) { 861 loggerMethod.fine("FINISHED: "+method.instanceContext+"."+method.method+" ("+method.args+") in thread "+frameThread); 862 } 863 try { 864 frame = frameThread.frame(frameIndex); 865 } catch (IncompatibleThreadStateException e) { 866 Assert.error(node, "callException", e, ctx); 867 } 868 } 869 } 870 871 if (method.typeContext instanceof ClassType) { 872 ClassType classContext = (ClassType) method.typeContext; 873 try { 874 if (method.method.isConstructor()) { 875 if (verbose) 876 throw new UnsupportedOperationException (NbBundle.getMessage ( 877 Evaluator.class, 878 "CTL_UnsupportedOperationException" 879 )); 880 try { 881 return classContext.newInstance(frameThread, method.method, method.args, ClassType.INVOKE_SINGLE_THREADED); 882 } catch (UnsupportedOperationException uoex) { 883 return Assert.error(node, "calleeException", uoex, ctx); 884 } 885 } else { 886 if (verbose) 887 throw new UnsupportedOperationException (NbBundle.getMessage ( 888 Evaluator.class, 889 "CTL_UnsupportedOperationException" 890 )); 891 if (!evaluationContext.canInvokeMethods()) { 892 return Assert.error(node, "calleeException", new UnsupportedOperationException (), ctx); 893 } 894 evaluationContext.methodToBeInvoked(); 895 return classContext.invokeMethod(frameThread, method.method, method.args, ClassType.INVOKE_SINGLE_THREADED); 896 } 897 } catch (InvalidTypeException e) { 898 Assert.error(node, "callException", e, ctx); 899 } catch (ClassNotLoadedException e) { 900 Assert.error(node, "callException", e, ctx); 902 } catch (IncompatibleThreadStateException e) { 903 Assert.error(node, "callException", e, ctx); 904 } catch (InvocationException e) { 905 Assert.error(node, "calleeException", e, ctx); 906 } catch (IllegalArgumentException e) { 907 Assert.error(node, "callException", e, ctx); 908 } catch (UnsupportedOperationException e) { 909 evaluationContext.setCanInvokeMethods(false); 910 Assert.error(node, "calleeException", e, ctx); 911 } 912 finally { 913 try { 914 frame = frameThread.frame(frameIndex); 915 } catch (IncompatibleThreadStateException e) { 916 Assert.error(node, "callException", e, ctx); 917 } 918 } 919 } 920 921 return Assert.error(node, "noSuchMethod", ctx); 922 } 923 924 private boolean isAccessible(TypeComponent member) { 925 if (member.isPublic()) return true; 926 927 ReferenceType callerType = frame.location().declaringType(); 928 ReferenceType calleeType = member.declaringType(); 929 930 if (member.isPrivate()) { 931 if (callerType.equals(calleeType)) return true; 932 if (isNested(calleeType, callerType) || isNested(callerType, calleeType)) return true; 933 return false; 934 } 935 936 String callerName = callerType.name(); 937 String calleeName = calleeType.name(); 938 int idx1 = callerName.lastIndexOf('.'); 939 int idx2 = calleeName.lastIndexOf('.'); 940 941 if (idx1 * idx2 < 0) return false; 942 if (idx1 + idx2 == -2) return true; 943 944 if (callerName.substring(0, idx1).equals(calleeName.substring(0, idx2))) return true; 945 if (member.isProtected()) { 946 return instanceOf(callerType, calleeType); 947 } 948 949 return false; 950 } 951 952 private boolean isNested(ReferenceType outter, ReferenceType inner) { 953 List nestedTypes = outter.nestedTypes(); 954 for (Iterator i = nestedTypes.iterator(); i.hasNext();) { 955 ReferenceType type = (ReferenceType) i.next(); 956 if (type.equals(inner) || isNested(type, inner)) return true; 957 } 958 return false; 959 } 960 961 private MethodCall getConcreteMethod(Identifier ctx, Value [] args) { 962 ReferenceType type = ctx.typeContext; 963 ObjectReference object = ctx.instanceContext; 964 965 if (ctx.superQualifier != null) { 966 if (!(ctx.typeContext instanceof ClassType)) Assert.error(currentNode, "superUsedOnNonClass", ctx); 967 if (ctx.superQualifier.length() > 0) { 968 object = getEnclosingObject(ctx.instanceContext, ctx.superQualifier); 969 Assert.assertNotNull(object, currentNode, "notEnclosingType", ctx); 970 } 971 ClassType cls = (ClassType) object.referenceType(); 972 type = cls.superclass(); 973 } 974 975 if (ctx.typeContext == null) { 976 Assert.error(currentNode, "methodCallOnNull", ctx.identifier); 977 } 978 979 List<Method> methods = getMethodsByName(type, ctx.identifier); 980 981 ReferenceType origType = type; 983 ObjectReference origObject = object; 984 985 while (methods.size() == 0) { 986 Field outerRef = type.fieldByName("this$0"); 987 if (outerRef == null) { 988 type = origType; 990 object = origObject; 991 break; } 993 if (loggerValue.isLoggable(Level.FINE)) { 994 loggerValue.fine("STARTED : "+object+".getValue("+outerRef+")"); 995 } 996 object = (ObjectReference) object.getValue(outerRef); 997 if (loggerValue.isLoggable(Level.FINE)) { 998 loggerValue.fine("FINISHED: getValue("+outerRef+") = "+object); 999 } 1000 type = object.referenceType(); 1001 methods = getMethodsByName(type, ctx.identifier); 1002 1003 } 1004 1005 if (ctx.localContext && methods.size() == 0) { 1007 for (Iterator i = staticImportsIterator(ctx.identifier); i.hasNext(); ) { 1008 String typeName = (String ) i.next(); 1009 try { 1010 ReferenceType importedType = resolveType(typeName); 1011 methods = getMethodsByName(importedType, ctx.identifier); 1012 if (methods.size() > 0) { 1013 type = importedType; 1014 object = null; 1015 break; 1016 } 1017 } catch (Exception e) { 1018 continue; 1020 } 1021 } 1022 } 1023 1024 List<MethodCall> possibleMethods = new ArrayList<MethodCall>(); 1025 1026 for (Iterator<Method> i = methods.iterator(); i.hasNext();) { 1027 Method method = i.next(); 1028 if (!isAccessible(method)) continue; 1029 1030 List argTypes = null; 1031 try { 1032 argTypes = method.argumentTypes(); 1033 } catch (ClassNotLoadedException e) { 1034 continue; 1036 } 1037 1038 if (args.length == 0 && "<init>".equals(ctx.identifier) && argTypes.size() == 1) { 1040 if (frame.thisObject() != null && argTypes.get(0).equals(frame.location().declaringType())) { 1041 args = new Value[] { frame.thisObject() } ; 1042 } 1043 } 1044 1045 List<Value> newArgs = prepareArguments(args, argTypes); 1046 if (newArgs == null) continue; 1047 possibleMethods.add(new MethodCall(type, object, method, newArgs)); 1048 } 1049 Assert.assertNonEmpty(possibleMethods, currentNode, "noSuchMethod", ctx); 1050 MethodCall call = mostSpecific(possibleMethods, args); 1051 call = findConcrete(call); 1052 Assert.assertNotNull(call, currentNode, "ambigousMethod", ctx); 1053 return call; 1054 } 1055 1056 private static List<Method> getMethodsByName(ReferenceType type, String name) { 1057 if (type instanceof ArrayType) { type = type.classObject().referenceType(); 1059 if ("toString".equals(name)) { type = ((ClassType) type).superclass(); 1062 } 1063 } 1064 List<Method> methods = type.methodsByName(name); 1065 return methods; 1066 } 1067 1068 private MethodCall mostSpecific(List<MethodCall> possibleMethods, Value [] args) { 1069 if (possibleMethods.size() == 0) return null; 1070 if (possibleMethods.size() == 1) return possibleMethods.get(0); 1071 1072 MethodCall mostSpecific = null; 1073 int conversions = Integer.MAX_VALUE; 1074 for (Iterator<MethodCall> i = possibleMethods.iterator(); i.hasNext();) { 1075 MethodCall methodCall = i.next(); 1076 List methodArguments = null; 1077 try { 1078 methodArguments = methodCall.method.argumentTypes(); 1079 } catch (ClassNotLoadedException e) { 1080 continue; 1081 } 1082 int cc = conversionsCount(methodArguments, args); 1083 if (cc == 0) return methodCall; 1084 if (cc == conversions) { 1085 return null; 1086 } 1087 if (cc < conversions) { 1088 conversions = cc; 1089 mostSpecific = methodCall; 1090 } 1091 } 1092 return mostSpecific; 1093 } 1094 1095 private int conversionsCount(List argumentTypes, Value[] args) { 1096 int idx = 0; 1097 int cc = 0; 1098 for (Iterator i = argumentTypes.iterator(); i.hasNext(); idx++) { 1099 Type argType = (Type) i.next(); 1100 if (args[idx] == null) continue; 1101 if (representSameType(argType, args[idx].type())) continue; 1102 cc ++; 1103 } 1104 return cc; 1105 } 1106 1107 private boolean representSameType(Type t1, Type t2) { 1108 String t1s = t1.signature(); 1109 String t2s = t2.signature(); 1110 1111 if (t1s.equals(t2s)) return true; 1112 if (t1s.length() == 1 && t2s.length() == 1 || 1113 t1s.length() > 1 && t2s.length() > 1) return false; 1114 1115 String primitiveType = t1s.length() == 1 ? t1s : t2s; 1116 String classType = t1s.length() > 1 ? t1s : t2s; 1117 1118 return wrapperSignature(primitiveType.charAt(0)).equals(classType); 1119 } 1120 1121 private MethodCall findConcrete(MethodCall call) { 1122 if (call.method.isAbstract()) { 1123 ReferenceType type = call.instanceContext.referenceType(); 1124 if (type instanceof ClassType) { 1125 Method m = ((ClassType) type).concreteMethodByName(call.method.name(), call.method.signature()); 1126 if (m != null) { 1127 call.method = m; 1128 call.typeContext = type; 1129 } 1130 } 1131 } 1132 return call; 1133 } 1134 1135 private List<Value> prepareArguments(Value [] args, List argTypes) { 1136 1137 boolean ellipsis; 1138 try { 1139 ellipsis = argTypes.size() > 0 && 1140 argTypes.get(argTypes.size() - 1) instanceof ArrayType && 1141 (args.length == 0 || 1142 args[args.length - 1] == null || 1143 isConvertible(((ArrayType) argTypes.get(argTypes.size() - 1)).componentType(), 1144 args[args.length - 1])); 1145 } catch (ClassNotLoadedException e) { 1146 return null; 1148 } 1149 if (ellipsis) { 1150 if (args.length < argTypes.size() - 1) return null; 1151 } else { 1152 if (args.length != argTypes.size()) return null; 1153 } 1154 1155 List<Value> newArgs = new ArrayList<Value>(); 1156 int idx = 0; 1157 for (Iterator i = argTypes.iterator(); i.hasNext(); idx++) { 1158 Type type = (Type) i.next(); 1159 if (ellipsis && !i.hasNext()) continue; 1160 if (!isConvertible(type, args[idx])) return null; 1161 newArgs.add(boxUnboxIfNeeded(args[idx], type)); 1162 } 1163 1164 if (ellipsis) { 1165 ArrayType elipsisType = (ArrayType) argTypes.get(argTypes.size() - 1); 1167 if (args.length == argTypes.size() - 1) { 1168 } else { 1170 Type componentType = null; 1171 try { 1172 componentType = elipsisType.componentType(); 1173 } catch (ClassNotLoadedException e) { 1174 return null; 1176 } 1177 if (args.length == argTypes.size()) { 1178 if (args[args.length -1] != null && !elipsisType.equals(args[args.length -1].type())) { 1179 if (!isConvertible(componentType, args[args.length -1])) return null; 1180 } 1181 newArgs.add(boxUnboxIfNeeded(args[args.length -1], componentType)); 1182 } else if (args.length > argTypes.size()) { 1183 for (int i = argTypes.size() - 1; i < args.length; i++) { 1184 if (!isConvertible(componentType, args[i])) return null; 1185 newArgs.add(boxUnboxIfNeeded(args[i], componentType)); 1186 } 1187 } 1188 } 1189 } 1190 1191 return newArgs; 1192 } 1193 1194 private Value boxUnboxIfNeeded(Value value, Type type) { 1195 if (value instanceof ObjectReference && type instanceof PrimitiveType) { 1196 return unbox((ObjectReference) value, type); 1197 } else if (value instanceof PrimitiveValue && type instanceof ClassType) { 1198 return box((PrimitiveValue) value, (ClassType) type); 1199 } else { 1200 return value; 1201 } 1202 } 1203 1204 1212 private ObjectReference box(PrimitiveValue primitiveValue, ClassType type) { 1213 try { 1214 if (type instanceof Object ) { 1215 type = wrapperType((PrimitiveType) primitiveValue.type()); 1216 } 1217 return newInstance(type, new Value[] { primitiveValue }); 1218 } catch (Exception e) { 1219 throw new RuntimeException ("Unexpected exception while invoking boxing method", e); 1221 } 1222 } 1223 1224 private ClassType wrapperType(PrimitiveType type) throws IncompatibleThreadStateException { 1225 char sig = type.signature().charAt(0); 1226 return (ClassType) resolveType(wrapperClassname(sig)); 1227 } 1228 1229 private String wrapperSignature(char primitiveSignature) { 1230 switch (primitiveSignature) { 1231 case 'Z': 1232 return "Ljava/lang/Boolean;"; 1233 case 'B': 1234 return "Ljava/lang/Byte;"; 1235 case 'C': 1236 return "Ljava/lang/Character;"; 1237 case 'S': 1238 return "Ljava/lang/Short;"; 1239 case 'I': 1240 return "Ljava/lang/Integer;"; 1241 case 'J': 1242 return "Ljava/lang/Long;"; 1243 case 'F': 1244 return "Ljava/lang/Float;"; 1245 case 'D': 1246 return "Ljava/lang/Double;"; 1247 } 1248 throw new RuntimeException (); } 1250 1251 private String wrapperClassname(char primitiveSignature) { 1252 switch (primitiveSignature) { 1253 case 'Z': 1254 return "java.lang.Boolean"; 1255 case 'B': 1256 return "java.lang.Byte"; 1257 case 'C': 1258 return "java.lang.Character"; 1259 case 'S': 1260 return "java.lang.Short"; 1261 case 'I': 1262 return "java.lang.Integer"; 1263 case 'J': 1264 return "java.lang.Long"; 1265 case 'F': 1266 return "java.lang.Float"; 1267 case 'D': 1268 return "java.lang.Double"; 1269 } 1270 throw new RuntimeException (); } 1272 1273 private ObjectReference newInstance(ClassType type, Value [] constructorArgs) throws 1274 InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException { 1275 1276 MethodCall method = getConcreteMethod(new Identifier(type, "<init>"), constructorArgs); 1277 try { 1278 return type.newInstance(frameThread, method.method, method.args, ObjectReference.INVOKE_SINGLE_THREADED); 1279 } finally { 1280 frame = frameThread.frame(frameIndex); 1281 } 1282 } 1283 1284 private PrimitiveValue unbox(ObjectReference val, Type type) { 1285 1286 if (type instanceof BooleanType) return invokeUnboxingMethod(val, "booleanValue"); 1287 if (type instanceof ByteType) return invokeUnboxingMethod(val, "byteValue"); 1288 if (type instanceof CharType) return invokeUnboxingMethod(val, "charValue"); 1289 if (type instanceof ShortType) return invokeUnboxingMethod(val, "shortValue"); 1290 if (type instanceof IntegerType) return invokeUnboxingMethod(val, "intValue"); 1291 if (type instanceof LongType) return invokeUnboxingMethod(val, "longValue"); 1292 if (type instanceof FloatType) return invokeUnboxingMethod(val, "floatValue"); 1293 if (type instanceof DoubleType) return invokeUnboxingMethod(val, "doubleValue"); 1294 throw new RuntimeException ("Invalid type while unboxing: " + type.signature()); } 1296 1297 private PrimitiveValue invokeUnboxingMethod(ObjectReference reference, String methodName) { 1298 Method toCall = (Method) reference.referenceType().methodsByName(methodName).get(0); 1299 try { 1300 if (verbose) 1301 throw new UnsupportedOperationException (NbBundle.getMessage ( 1302 Evaluator.class, 1303 "CTL_UnsupportedOperationException" 1304 )); 1305 if (!evaluationContext.canInvokeMethods()) { 1306 throw new UnsupportedOperationException (); 1307 } 1308 evaluationContext.methodToBeInvoked(); 1309 if (loggerMethod.isLoggable(Level.FINE)) { 1310 loggerMethod.fine("STARTED : "+reference+"."+toCall+" () in thread "+frameThread); 1311 } 1312 return (PrimitiveValue) reference.invokeMethod(frameThread, toCall, new ArrayList<Value>(0), ObjectReference.INVOKE_SINGLE_THREADED); 1313 } catch (UnsupportedOperationException uoex) { 1314 evaluationContext.setCanInvokeMethods(false); 1315 throw new RuntimeException ("Unexpected exception while invoking unboxing method", uoex); 1317 } catch (Exception e) { 1318 throw new RuntimeException ("Unexpected exception while invoking unboxing method", e); 1320 } finally { 1321 if (loggerMethod.isLoggable(Level.FINE)) { 1322 loggerMethod.fine("FINISHED: "+reference+"."+toCall+" () in thread "+frameThread); 1323 } 1324 try { 1325 frame = frameThread.frame(frameIndex); 1326 } catch (IncompatibleThreadStateException e) { 1327 throw new RuntimeException ("Unexpected exception while invoking unboxing method", e); 1328 } 1329 } 1330 } 1331 1332 private static final String [] typeSignaturesSorted = { 1333 "Ljava/lang/Byte;", "B", 1334 "Ljava/lang/Character;", "C", 1335 "Ljava/lang/Short;", "S", 1336 "Ljava/lang/Integer;", "I", 1337 "Ljava/lang/Long;", "J", 1338 "Ljava/lang/Float;", "F", 1339 "Ljava/lang/Double;", "D" 1340 }; 1341 1342 1354 private boolean isConvertible(Type wideType, Value value) { 1355 1356 if (value == null) return wideType instanceof ReferenceType; 1357 1358 String narrow = value.type().signature(); 1359 String wide = wideType.signature(); 1360 if (wide.equals(narrow)) return true; 1361 1362 if (wide.length() == 1) { 1363 if (wide.equals("Z")) return narrow.equals("Ljava/lang/Boolean;"); 1364 for (int i = 0; i < typeSignaturesSorted.length; i++) { 1365 if (narrow.equals(typeSignaturesSorted[i])) return true; 1366 if (wide.equals(typeSignaturesSorted[i])) return false; 1367 } 1368 return false; 1369 } 1370 1371 if (wide.equals("Ljava/lang/Object;")) return true; 1372 1373 if (narrow.length() == 1) { 1374 if (narrow.equals("Z")) return wide.equals("Ljava/lang/Boolean;"); 1375 for (int i = 0; i < typeSignaturesSorted.length; i++) { 1376 if (narrow.equals(typeSignaturesSorted[i])) { 1377 for (int j = i - 1; j < typeSignaturesSorted.length; j++) { 1378 if (wide.equals(typeSignaturesSorted[j])) return true; 1379 } 1380 return false; 1381 } 1382 } 1383 } 1384 1385 return instanceOf(value.type(), wideType); 1386 } 1387 1388 private Object visitPrimarySuffix(SimpleNode node, Object data) { 1389 Token token = (Token) node.getAttribute("token"); 1390 if (token == null) { 1391 return node.jjtGetChild(0).jjtAccept(this, data); 1393 } 1394 switch (token.kind) { 1395 case JavaParserConstants.IDENTIFIER: 1396 data = resolveVariable(data); Assert.assertAssignable(data, ObjectReference.class, node, "identifierNotAReference", data); 1398 return new Identifier(false, (ObjectReference)data, token.image); 1399 1400 case JavaParserConstants.LBRACKET: 1401 { 1402 data = resolveVariable(data); 1403 Assert.assertAssignable(data, ArrayReference.class, node, "notarray", data, token); 1404 Object index = node.jjtGetChild(0).jjtAccept(this, data); 1405 Assert.assertAssignable(index, PrimitiveValue.class, node, "arrayIndexNAN", data, index); 1406 Assert.assertNotAssignable(index, BooleanValue.class, node, "arrayIndexNAN", data, index); 1407 int idx = ((PrimitiveValue) index).intValue(); 1408 ArrayReference array = (ArrayReference) data; 1409 Assert.assertLess(idx, array.length(), node, "arrayIndexOutOfBounds", array, new Integer (idx)); 1410 return array.getValue(idx); 1411 } 1412 1413 case JavaParserConstants.THIS: 1414 case JavaParserConstants.SUPER: 1415 { 1416 Identifier ctx = (Identifier) data; 1417 if (!vm.canGetSyntheticAttribute()) Assert.error(node, "unknownType", ctx.identifier); 1418 1419 ObjectReference enclosingObject = getEnclosingObject(frame.thisObject(), ctx.identifier); 1420 Assert.assertNotNull(enclosingObject, node, "unknownType", ctx.identifier); 1421 return enclosingObject; 1422 } 1423 } 1424 return Assert.error(node, "internalError"); 1425 } 1426 1427 private ObjectReference getEnclosingObject(ObjectReference obj, String typeQualifier) { 1428 boolean done; 1429 do { 1430 done = true; 1431 List fields = obj.referenceType().allFields(); 1432 for (Iterator j = fields.iterator(); j.hasNext();) { 1433 Field field = (Field) j.next(); 1434 if (field.isSynthetic() && field.name().startsWith("this$")) { 1435 if (loggerValue.isLoggable(Level.FINE)) { 1436 loggerValue.fine("STARTED : "+obj+".getValue("+field+")"); 1437 } 1438 obj = (ObjectReference) obj.getValue(field); 1439 if (loggerValue.isLoggable(Level.FINE)) { 1440 loggerValue.fine("FINISHED: getValue("+field+") = "+obj); 1441 } 1442 ClassType type = (ClassType) obj.referenceType(); 1443 if (type.name().endsWith(typeQualifier)) { 1444 return obj; 1445 } 1446 done = false; 1447 break; 1448 } 1449 } 1450 } while (!done); 1451 return null; 1452 } 1453 1454 private Value evaluateVariable(Identifier ctx) { 1455 1456 if (ctx.localContext) { 1458 try { 1459 LocalVariable var = frame.visibleVariableByName(ctx.identifier); 1460 if (var != null) return frame.getValue(var); 1461 } catch (AbsentInformationException e) { 1462 } 1463 } 1464 1465 if (ctx.instanceContext != null) { 1467 Field field = ctx.typeContext.fieldByName(ctx.identifier); 1468 if (field != null) { 1469 try { 1470 if (loggerValue.isLoggable(Level.FINE)) { 1471 loggerValue.fine("STARTED : "+ctx.instanceContext+".getValue("+field+")"); 1472 } 1473 return ctx.instanceContext.getValue(field); 1474 } finally { 1475 if (loggerValue.isLoggable(Level.FINE)) { 1476 loggerValue.fine("FINISHED : "+ctx.instanceContext+".getValue("+field+")"); 1477 } 1478 } 1479 } 1480 if (ctx.instanceContext instanceof ArrayReference) { 1481 if (ctx.identifier.equals("length")) { 1482 return vm.mirrorOf(((ArrayReference) ctx.instanceContext).length()); 1483 } 1484 } 1485 } 1486 1487 Field field = ctx.typeContext.fieldByName(ctx.identifier); 1489 try { 1490 if (field != null) { 1491 try { 1492 if (loggerValue.isLoggable(Level.FINE)) { 1493 loggerValue.fine("STARTED : "+ctx.typeContext+".getValue("+field+")"); 1494 } 1495 return ctx.typeContext.getValue(field); 1496 } finally { 1497 if (loggerValue.isLoggable(Level.FINE)) { 1498 loggerValue.fine("FINISHED : "+ctx.typeContext+".getValue("+field+")"); 1499 } 1500 } 1501 } 1502 } catch (IllegalArgumentException e) { 1503 Assert.error(currentNode, "accessInstanceVariableFromStaticContext", ctx); 1504 } 1505 1506 if (ctx.instanceContext != null) { 1508 field = ctx.typeContext.fieldByName("val$" + ctx.identifier); 1509 if (field != null) { 1510 try { 1511 if (loggerValue.isLoggable(Level.FINE)) { 1512 loggerValue.fine("STARTED : "+ctx.instanceContext+".getValue("+field+")"); 1513 } 1514 return ctx.instanceContext.getValue(field); 1515 } finally { 1516 if (loggerValue.isLoggable(Level.FINE)) { 1517 loggerValue.fine("FINISHED: "+ctx.instanceContext+".getValue("+field+")"); 1518 } 1519 } 1520 } 1521 } 1522 1523 if (ctx.instanceContext != null) { 1525 Field helpField = ctx.typeContext.fieldByName("this$0"); 1526 if (helpField != null) { 1527 if (loggerValue.isLoggable(Level.FINE)) { 1528 loggerValue.fine("STARTED : "+ctx.instanceContext+".getValue("+helpField+")"); 1529 } 1530 ObjectReference or = (ObjectReference)ctx.instanceContext.getValue(helpField); 1531 if (loggerValue.isLoggable(Level.FINE)) { 1532 loggerValue.fine("FINISHED: "+ctx.instanceContext+".getValue("+helpField+") = "+or); 1533 } 1534 if (or != null) { 1535 field = or.referenceType().fieldByName(ctx.identifier); 1536 if (field != null) { 1537 try { 1538 if (loggerValue.isLoggable(Level.FINE)) { 1539 loggerValue.fine("STARTED : "+or+".getValue("+field+")"); 1540 } 1541 return or.getValue(field); 1542 } finally { 1543 if (loggerValue.isLoggable(Level.FINE)) { 1544 loggerValue.fine("FINISHED: "+or+".getValue("+field+")"); 1545 } 1546 } 1547 } 1548 } 1549 } 1550 } 1551 1552 for (Iterator i = staticImportsIterator(ctx.identifier); i.hasNext(); ) { 1554 String typeName = (String ) i.next(); 1555 try { 1556 ReferenceType type = resolveType(typeName); 1557 field = type.fieldByName(ctx.identifier); 1558 if (field != null) { 1559 try { 1560 if (loggerValue.isLoggable(Level.FINE)) { 1561 loggerValue.fine("STARTED : "+type+".getValue("+field+")"); 1562 } 1563 return type.getValue(field); 1564 } finally { 1565 if (loggerValue.isLoggable(Level.FINE)) { 1566 loggerValue.fine("FINISHED: "+type+".getValue("+field+")"); 1567 } 1568 } 1569 } 1570 } catch (Exception e) { 1571 } 1573 } 1574 1575 if (expression.classReplaced().equals(ctx.identifier)) { 1577 ReferenceType refType = frame.location().declaringType(); 1578 JPDAClassType classType = evaluationContext.getDebugger().getClassType(refType); 1579 return ((JDIObjectVariable) classType.classObject()).getJDIValue(); 1580 } 1581 1582 if (expression.returnReplaced().equals(ctx.identifier)) { 1584 ThreadReference tr = frame.thread(); 1585 JPDAThreadImpl thread = (JPDAThreadImpl) evaluationContext.getDebugger().getThread(tr); 1586 JDIObjectVariable returnVar = (JDIObjectVariable) thread.getReturnVariable(); 1587 if (returnVar != null) { 1588 return returnVar.getJDIValue(); 1589 } else { 1590 return null; 1591 } 1592 } 1593 1594 return (Value) Assert.error(currentNode, "unknownVariable", ctx); 1595 } 1596 1597 private Iterator<String > staticImportsIterator(String identifier) { 1598 return iterator(evaluationContext.getStaticImports(), identifier); 1599 } 1600 1601 private Iterator<String > iterator(List<String > imports, String identifier) { 1602 List<String > filteredList = new ArrayList<String >(); 1603 for (Iterator<String > i = imports.iterator(); i.hasNext();) { 1604 String statement = i.next(); 1605 int idx = statement.lastIndexOf('.'); 1606 String qualifier = statement.substring(idx + 1); 1607 if (qualifier.equals("*") || qualifier.equals(identifier)) { 1608 filteredList.add(statement.substring(0, idx)); 1609 } 1610 } 1611 return filteredList.iterator(); 1612 } 1613 1614 private Value resolveVariable(Object data) { 1615 if (data == null || data instanceof Value) return (Value) data; 1616 1617 Identifier name = (Identifier) data; 1618 return evaluateVariable(name); 1619 } 1620 1621 private Object visitPrimaryExpression(SimpleNode node, Object data) { 1622 1623 int n = node.jjtGetNumChildren(); 1624 1625 Object value = node.jjtGetChild(0).jjtAccept(this, data); 1626 for (int i = 1; i < n; i++) { 1627 value = node.jjtGetChild(i).jjtAccept(this, value); 1628 } 1629 1630 if (value instanceof Identifier) { 1631 Identifier ctx = (Identifier) value; 1632 return evaluateVariable(ctx); 1633 } 1634 1635 return value; 1636 } 1637 1638 private Object visitExpression(SimpleNode node, Object data) { 1639 int n = node.jjtGetNumChildren(); 1640 if (n == 1) { 1641 return node.jjtGetChild(0).jjtAccept(this, data); 1643 } else { 1644 return node.jjtGetChild(2).jjtAccept(this, data); 1646 } 1647 } 1648 1649 private Object visitLiteral(SimpleNode node, Object data) { 1650 Token token = (Token) node.getAttribute("token"); 1651 if (token == null) return node.jjtGetChild(0).jjtAccept(this, data); 1652 1653 1654 try { 1655 switch (token.kind) { 1656 1657 case JavaParser.INTEGER_LITERAL: 1658 String name = token.image.toLowerCase(); 1660 boolean isLong = name.endsWith("l"); 1661 long value; 1662 1663 if (isLong) { 1664 name = name.substring(0, name.length() -1); 1665 } 1666 1667 if (name.startsWith("0x")) { 1668 value = Long.parseLong(name.substring(2), 16); 1669 } 1670 else if (name.length() > 1 && name.charAt(0) == '0') { 1671 value = Long.parseLong(name.substring(1), 8); 1672 } 1673 else { 1674 value = Long.parseLong(name); 1675 } 1676 1677 if (isLong) { 1678 return vm.mirrorOf(value); 1679 } 1680 else { 1681 if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) { 1682 Assert.error(node, "integerLiteralTooBig", name); 1683 } 1684 else { 1685 return vm.mirrorOf((int) value); 1686 } 1687 } 1688 1689 case JavaParser.FLOATING_POINT_LITERAL: 1690 char spec = token.image.charAt(token.image.length() - 1); 1691 if (spec == 'f' || spec == 'F') { 1692 return vm.mirrorOf(Float.parseFloat(token.image)); 1693 } else { 1694 return vm.mirrorOf(Double.parseDouble(token.image)); 1695 } 1696 1697 case JavaParser.STRING_LITERAL: 1698 return vm.mirrorOf(resolveString(token.image.substring(1, token.image.length() - 1))); 1699 1700 case JavaParser.CHARACTER_LITERAL: 1701 return vm.mirrorOf(resolveString(token.image.substring(1, token.image.length() - 1)).charAt(0)); 1702 1703 default: 1704 return Assert.error(node, "unknownLiteralType", token.image); 1705 } 1706 } catch (NumberFormatException e) { 1707 return Assert.error(node, "badFormatOfIntegerLiteral", token.image); 1708 } 1709 } 1710 1711 private String resolveString(String input) { 1712 String result = ""; 1713 int index = 0; 1714 while (index < input.length()) { 1715 if (input.charAt(index) != '\\') 1716 result = result + input.charAt (index); 1717 else { index++; 1719 char c; 1720 switch (input.charAt(index)) { 1721 case 'b': c = '\b'; break; 1722 case 't': c = '\t'; break; 1723 case 'n': c = '\n'; break; 1724 case 'f': c = '\f'; break; 1725 case 'r': c = '\r'; break; 1726 case '\"': c = '\"'; break; 1727 case '\'': c = '\''; break; 1728 case '\\': c = '\\'; break; 1729 1730 default: 1731 c = 0; 1733 while ((index < input.length ()) && 1734 (input.charAt (index) >= '0') && (input.charAt (index) <= '7') && 1735 (c*8 + input.charAt (index) - '0' < 256)) { 1736 c = (char) (c*8 + (input.charAt (index) - '0')); 1737 index++; 1738 } index--; 1740 } result = result + c; 1742 } index++; 1744 } return result; 1746 } 1747 1748 private Object visitBinaryExpression(SimpleNode node, Object data) { 1749 Object [] operators = node.getAttributes("operator"); 1750 int n = node.jjtGetNumChildren(); 1751 1752 Value value = (Value) node.jjtGetChild(0).jjtAccept(this, data); 1753 for (int i = 1; i < n; i++) { 1754 Value next = (Value) node.jjtGetChild(i).jjtAccept(this, data); 1755 try { 1756 value = this.operators.evaluate(value, (Token) operators[i-1], next); 1757 } catch (IllegalArgumentException e) { 1758 return Assert.error(node, "evaluateError", value, ((Token) operators[i-1]).image, next); 1759 } 1760 } 1761 return value; 1762 } 1763 1764 public static Value invokeVirtual ( 1765 ObjectReference objectReference, 1766 Method method, 1767 ThreadReference evaluationThread, 1768 List<Value> args 1769 ) throws InvalidExpressionException { 1770 1771 if (verbose) 1772 throw new UnsupportedOperationException (NbBundle.getMessage ( 1773 Evaluator.class, 1774 "CTL_UnsupportedOperationException" 1775 )); 1776 try { 1777 if (loggerMethod.isLoggable(Level.FINE)) { 1778 loggerMethod.fine("STARTED : "+objectReference+"."+method+" ("+args+") in thread "+evaluationThread); 1779 } 1780 Value value = 1781 objectReference.invokeMethod(evaluationThread, method, 1782 args, 1783 ObjectReference.INVOKE_SINGLE_THREADED); 1784 if (loggerMethod.isLoggable(Level.FINE)) { 1785 loggerMethod.fine(" return = "+value); 1786 } 1787 return value; 1788 } catch (InvalidTypeException itex) { 1789 throw new InvalidExpressionException (itex); 1790 } catch (ClassNotLoadedException cnlex) { 1791 throw new InvalidExpressionException (cnlex); 1792 } catch (IncompatibleThreadStateException itsex) { 1793 InvalidExpressionException ieex = new InvalidExpressionException (itsex); 1794 ieex.initCause(itsex); 1795 throw ieex; 1796 } catch (InvocationException iex) { 1797 InvalidExpressionException ieex = new InvalidExpressionException (iex); 1798 ieex.initCause(iex); 1799 throw ieex; 1800 } catch (UnsupportedOperationException uoex) { 1801 InvalidExpressionException ieex = new InvalidExpressionException (uoex); 1802 ieex.initCause(uoex); 1803 throw ieex; 1804 } catch (ObjectCollectedException ocex) { 1805 throw new InvalidExpressionException(NbBundle.getMessage( 1806 Evaluator.class, "CTL_EvalError_collected")); 1807 } finally { 1808 if (loggerMethod.isLoggable(Level.FINE)) { 1809 loggerMethod.fine("FINISHED: "+objectReference+"."+method+" ("+args+") in thread "+evaluationThread); 1810 } 1811 } 1812 } 1813} 1814 | Popular Tags |