1 11 package org.eclipse.jdt.internal.debug.eval.ast.engine; 12 13 14 import java.util.Map ; 15 import java.util.StringTokenizer ; 16 import java.util.regex.Matcher ; 17 import java.util.regex.Pattern ; 18 19 import org.eclipse.core.runtime.CoreException; 20 import org.eclipse.core.runtime.IProgressMonitor; 21 import org.eclipse.core.runtime.IStatus; 22 import org.eclipse.core.runtime.Status; 23 import org.eclipse.debug.core.DebugEvent; 24 import org.eclipse.debug.core.DebugException; 25 import org.eclipse.debug.core.DebugPlugin; 26 import org.eclipse.debug.core.IDebugEventFilter; 27 import org.eclipse.debug.core.model.ITerminate; 28 import org.eclipse.jdt.core.IJavaProject; 29 import org.eclipse.jdt.core.JavaCore; 30 import org.eclipse.jdt.core.Signature; 31 import org.eclipse.jdt.core.compiler.IProblem; 32 import org.eclipse.jdt.core.dom.AST; 33 import org.eclipse.jdt.core.dom.ASTParser; 34 import org.eclipse.jdt.core.dom.CompilationUnit; 35 import org.eclipse.jdt.debug.core.IEvaluationRunnable; 36 import org.eclipse.jdt.debug.core.IJavaArray; 37 import org.eclipse.jdt.debug.core.IJavaArrayType; 38 import org.eclipse.jdt.debug.core.IJavaDebugTarget; 39 import org.eclipse.jdt.debug.core.IJavaInterfaceType; 40 import org.eclipse.jdt.debug.core.IJavaObject; 41 import org.eclipse.jdt.debug.core.IJavaReferenceType; 42 import org.eclipse.jdt.debug.core.IJavaStackFrame; 43 import org.eclipse.jdt.debug.core.IJavaThread; 44 import org.eclipse.jdt.debug.core.IJavaType; 45 import org.eclipse.jdt.debug.core.IJavaValue; 46 import org.eclipse.jdt.debug.core.IJavaVariable; 47 import org.eclipse.jdt.debug.core.JDIDebugModel; 48 import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; 49 import org.eclipse.jdt.debug.eval.ICompiledExpression; 50 import org.eclipse.jdt.debug.eval.IEvaluationListener; 51 import org.eclipse.jdt.debug.eval.IEvaluationResult; 52 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; 53 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget; 54 import org.eclipse.jdt.internal.debug.core.model.JDIThread; 55 import org.eclipse.jdt.internal.debug.core.model.JDIValue; 56 import org.eclipse.jdt.internal.debug.eval.EvaluationResult; 57 import org.eclipse.jdt.internal.debug.eval.ast.instructions.InstructionSequence; 58 59 import com.sun.jdi.InvocationException; 60 import com.sun.jdi.ObjectReference; 61 62 public class ASTEvaluationEngine implements IAstEvaluationEngine { 63 64 private IJavaProject fProject; 65 66 private IJavaDebugTarget fDebugTarget; 67 68 71 private static Pattern fgThisPattern = Pattern.compile("(.*[^a-zA-Z0-9]+|^)(this)([^a-zA-Z0-9]+|$).*"); 73 77 class EventFilter implements IDebugEventFilter { 78 79 82 public DebugEvent[] filterDebugEvents(DebugEvent[] events) { 83 if (events.length == 1) { 84 DebugEvent event = events[0]; 85 if (event.getSource() instanceof IJavaVariable && event.getKind() == DebugEvent.CHANGE) { 86 if (((IJavaVariable)event.getSource()).getDebugTarget().equals(getDebugTarget())) { 87 return null; 88 } 89 } 90 } 91 return events; 92 } 93 94 } 95 96 public ASTEvaluationEngine(IJavaProject project, IJavaDebugTarget debugTarget) { 97 setJavaProject(project); 98 setDebugTarget(debugTarget); 99 } 100 101 public void setJavaProject(IJavaProject project) { 102 fProject = project; 103 } 104 105 public void setDebugTarget(IJavaDebugTarget debugTarget) { 106 fDebugTarget = debugTarget; 107 } 108 109 112 public void evaluate(String snippet, IJavaStackFrame frame, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { 113 checkInterface(frame); 114 ICompiledExpression expression= getCompiledExpression(snippet, frame); 115 evaluateExpression(expression, frame, listener, evaluationDetail, hitBreakpoints); 116 } 117 118 121 public void evaluate(String snippet, IJavaObject thisContext, IJavaThread thread, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { 122 ICompiledExpression expression= getCompiledExpression(snippet, thisContext); 123 evaluateExpression(expression, thisContext, thread, listener, evaluationDetail, hitBreakpoints); 124 } 125 126 133 private void checkInterface(IJavaStackFrame frame) throws DebugException { 134 if (frame.getReferenceType() instanceof IJavaInterfaceType) { 135 IStatus status = new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED, 136 EvaluationEngineMessages.ASTEvaluationEngine_0, null); 137 throw new DebugException(status); 138 } 139 } 140 141 144 public void evaluateExpression(ICompiledExpression expression, IJavaStackFrame frame, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { 145 RuntimeContext context = new RuntimeContext(getJavaProject(), frame); 146 doEvaluation(expression, context, (IJavaThread)frame.getThread(), listener, evaluationDetail, hitBreakpoints); 147 } 148 149 152 public void evaluateExpression(ICompiledExpression expression, IJavaObject thisContext, IJavaThread thread, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { 153 IRuntimeContext context = null; 154 if (thisContext instanceof IJavaArray) { 155 context = new ArrayRuntimeContext((IJavaArray) thisContext, thread, getJavaProject()); 156 } else { 157 context = new JavaObjectRuntimeContext(thisContext, getJavaProject(), thread); 158 } 159 doEvaluation(expression, context, thread, listener, evaluationDetail, hitBreakpoints); 160 } 161 162 165 private void doEvaluation(ICompiledExpression expression, IRuntimeContext context, IJavaThread thread, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException { 166 if (expression instanceof InstructionSequence) { 167 if (thread.isSuspended() && ((JDIThread)thread).isInvokingMethod() || thread.isPerformingEvaluation() && evaluationDetail == DebugEvent.EVALUATION) { 169 EvaluationResult result= new EvaluationResult(this, expression.getSnippet(), thread); 170 result.addError(EvaluationEngineMessages.ASTEvaluationEngine_Cannot_perform_nested_evaluations); 171 listener.evaluationComplete(result); 172 return; 173 } 174 thread.queueRunnable(new EvalRunnable((InstructionSequence)expression, thread, context, listener, evaluationDetail, hitBreakpoints)); 175 } else { 176 throw new DebugException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.OK, EvaluationEngineMessages.ASTEvaluationEngine_AST_evaluation_engine_cannot_evaluate_expression, null)); 177 } 178 } 179 180 183 public ICompiledExpression getCompiledExpression(String snippet, IJavaStackFrame frame) { 184 IJavaProject javaProject = getJavaProject(); 185 RuntimeContext context = new RuntimeContext(javaProject, frame); 186 187 EvaluationSourceGenerator mapper = null; 188 CompilationUnit unit = null; 189 try { 190 IJavaVariable[] localsVar = context.getLocals(); 191 int numLocalsVar= localsVar.length; 192 IJavaVariable[] locals= new IJavaVariable[numLocalsVar]; 195 int numLocals= 0; 196 for (int i = 0; i < numLocalsVar; i++) { 197 if (!isLocalType(localsVar[i].getSignature())) { 198 locals[numLocals++]= localsVar[i]; 199 } 200 } 201 String [] localTypesNames= new String [numLocals]; 204 String [] localVariables= new String [numLocals]; 205 for (int i = 0; i < numLocals; i++) { 206 localVariables[i] = locals[i].getName(); 207 localTypesNames[i] = Signature.toString(locals[i].getGenericSignature()).replace('/', '.'); 208 } 209 mapper = new EvaluationSourceGenerator(localTypesNames, localVariables, snippet); 210 IJavaReferenceType receivingType = frame.getReferenceType(); 214 215 222 unit = parseCompilationUnit(mapper.getSource(receivingType, javaProject, frame.isStatic()).toCharArray(), mapper.getCompilationUnitName(), javaProject); 223 } catch (CoreException e) { 224 InstructionSequence expression= new InstructionSequence(snippet); 225 expression.addError(e.getStatus().getMessage()); 226 return expression; 227 } 228 229 return createExpressionFromAST(snippet, mapper, unit); 230 } 231 232 private CompilationUnit parseCompilationUnit(char[] source, String unitName, IJavaProject project) { 233 ASTParser parser = ASTParser.newParser(AST.JLS3); 234 String compilerCompliance= project.getOption(JavaCore.COMPILER_COMPLIANCE, true); 235 parser.setSource(source); 236 parser.setUnitName(unitName); 237 parser.setProject(project); 238 parser.setResolveBindings(true); 239 Map options=JavaCore.getDefaultOptions(); 240 options.put(JavaCore.COMPILER_COMPLIANCE, compilerCompliance); 241 options.put(JavaCore.COMPILER_SOURCE, project.getOption(JavaCore.COMPILER_SOURCE, true)); 242 parser.setCompilerOptions(options); 243 return (CompilationUnit) parser.createAST(null); 244 } 245 246 private boolean isLocalType(String typeName) { 249 StringTokenizer strTok= new StringTokenizer (typeName,"$"); strTok.nextToken(); 251 while (strTok.hasMoreTokens()) { 252 char char0= strTok.nextToken().charAt(0); 253 if ('0' <= char0 && char0 <= '9') { 254 return true; 255 } 256 } 257 return false; 258 } 259 261 265 private ICompiledExpression getCompiledExpression(String snippet, IJavaArrayType arrayType) { 266 EvaluationSourceGenerator mapper = null; 267 CompilationUnit unit = null; 268 try { 269 IJavaProject javaProject = getJavaProject(); 270 String newSnippet = replaceThisReferences(snippet); 272 273 int dimension = 1; 274 IJavaType componentType = arrayType.getComponentType(); 275 while (componentType instanceof IJavaArrayType) { 276 componentType = ((IJavaArrayType)componentType).getComponentType(); 277 dimension++; 278 } 279 280 String recTypeName = "java.lang.Object"; String typeName = arrayType.getName(); 285 if (componentType instanceof IJavaReferenceType) { 286 StringBuffer buf = new StringBuffer (); 287 buf.append("java.lang.Object"); for (int i = 0; i < dimension; i++) { 289 buf.append("[]"); } 291 typeName = buf.toString(); 292 } 293 294 295 String [] localTypesNames= new String []{typeName}; 296 String [] localVariables= new String []{ArrayRuntimeContext.ARRAY_THIS_VARIABLE}; 297 mapper = new EvaluationSourceGenerator(localTypesNames, localVariables, newSnippet); 298 299 300 int index = typeName.indexOf('$'); 301 if (index >= 0) { 303 recTypeName = typeName.substring(0, index); 304 } 305 IJavaType[] javaTypes = getDebugTarget().getJavaTypes(recTypeName); 306 if (javaTypes.length > 0) { 307 IJavaReferenceType recType = (IJavaReferenceType) javaTypes[0]; 308 unit = parseCompilationUnit(mapper.getSource(recType, getJavaProject(), false).toCharArray(), mapper.getCompilationUnitName(), javaProject); 309 } else { 310 IStatus status = new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, 311 EvaluationEngineMessages.ASTEvaluationEngine_1, null); 312 throw new CoreException(status); 313 } 314 } catch (CoreException e) { 315 InstructionSequence expression= new InstructionSequence(snippet); 316 expression.addError(e.getStatus().getMessage()); 317 return expression; 318 } 319 320 return createExpressionFromAST(snippet, mapper, unit); 321 } 322 323 326 public ICompiledExpression getCompiledExpression(String snippet, IJavaObject thisContext) { 327 try { 328 if (thisContext instanceof IJavaArray) { 329 return getCompiledExpression(snippet, (IJavaArrayType)thisContext.getJavaType()); 330 } 331 return getCompiledExpression(snippet, (IJavaReferenceType)thisContext.getJavaType()); 332 } catch (DebugException e) { 333 InstructionSequence expression= new InstructionSequence(snippet); 334 expression.addError(e.getStatus().getMessage()); 335 return expression; 336 } 337 338 } 339 340 343 public ICompiledExpression getCompiledExpression(String snippet, IJavaReferenceType type) { 344 if (type instanceof IJavaArrayType) { 345 return getCompiledExpression(snippet, (IJavaArrayType)type); 346 } 347 IJavaProject javaProject = getJavaProject(); 348 349 EvaluationSourceGenerator mapper = null; 350 CompilationUnit unit = null; 351 352 mapper = new EvaluationSourceGenerator(new String [0], new String [0], snippet); 353 354 try { 355 unit = parseCompilationUnit(mapper.getSource(type, javaProject, false).toCharArray(), mapper.getCompilationUnitName(), javaProject); 356 } catch (CoreException e) { 357 InstructionSequence expression= new InstructionSequence(snippet); 358 expression.addError(e.getStatus().getMessage()); 359 return expression; 360 } 361 return createExpressionFromAST(snippet, mapper, unit); 362 } 363 364 371 private ICompiledExpression createExpressionFromAST(String snippet, EvaluationSourceGenerator mapper, CompilationUnit unit) { 372 IProblem[] problems= unit.getProblems(); 373 if (problems.length != 0) { 374 boolean snippetError= false; 375 boolean runMethodError= false; 376 InstructionSequence errorSequence= new InstructionSequence(snippet); 377 int codeSnippetStart= mapper.getSnippetStart(); 378 int codeSnippetEnd= codeSnippetStart + mapper.getSnippet().length(); 379 int runMethodStart= mapper.getRunMethodStart(); 380 int runMethodEnd= runMethodStart + mapper.getRunMethodLength(); 381 for (int i = 0; i < problems.length; i++) { 382 IProblem problem= problems[i]; 383 int errorOffset= problem.getSourceStart(); 384 int problemId= problem.getID(); 385 if (problemId == IProblem.IsClassPathCorrect) { 386 errorSequence.addError(problem.getMessage()); 387 snippetError = true; 388 } 389 if (problemId == IProblem.VoidMethodReturnsValue 390 || problemId == IProblem.NotVisibleMethod 391 || problemId == IProblem.NotVisibleConstructor 392 || problemId == IProblem.NotVisibleField 393 || problemId == IProblem.NotVisibleType) { 394 continue; 395 } 396 if (problem.isError()) { 397 if (codeSnippetStart <= errorOffset && errorOffset <= codeSnippetEnd) { 398 errorSequence.addError(problem.getMessage()); 399 snippetError = true; 400 } else if (runMethodStart <= errorOffset && errorOffset <= runMethodEnd) { 401 runMethodError = true; 402 } 403 } 404 } 405 if (snippetError || runMethodError) { 406 if (runMethodError) { 407 errorSequence.addError(EvaluationEngineMessages.ASTEvaluationEngine_Evaluations_must_contain_either_an_expression_or_a_block_of_well_formed_statements_1); 408 } 409 return errorSequence; 410 } 411 } 412 413 ASTInstructionCompiler visitor = new ASTInstructionCompiler(mapper.getSnippetStart(), snippet); 414 unit.accept(visitor); 415 416 return visitor.getInstructions(); 417 } 418 419 422 public IJavaProject getJavaProject() { 423 return fProject; 424 } 425 426 429 public IJavaDebugTarget getDebugTarget() { 430 return fDebugTarget; 431 } 432 433 436 public void dispose() { 437 } 438 439 class EvalRunnable implements Runnable { 440 441 private InstructionSequence fExpression; 442 443 private IJavaThread fThread; 444 445 private int fEvaluationDetail; 446 447 private boolean fHitBreakpoints; 448 449 private IRuntimeContext fContext; 450 451 private IEvaluationListener fListener; 452 453 public EvalRunnable(InstructionSequence expression, IJavaThread thread, IRuntimeContext context, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) { 454 fExpression= expression; 455 fThread= thread; 456 fContext= context; 457 fListener= listener; 458 fEvaluationDetail= evaluationDetail; 459 fHitBreakpoints= hitBreakpoints; 460 } 461 462 public void run() { 463 EvaluationResult result = new EvaluationResult(ASTEvaluationEngine.this, fExpression.getSnippet(), fThread); 464 if (fExpression.hasErrors()) { 465 String [] errors = fExpression.getErrorMessages(); 466 for (int i = 0, numErrors = errors.length; i < numErrors; i++) { 467 result.addError(errors[i]); 468 } 469 evaluationFinished(result); 470 return; 471 } 472 final Interpreter interpreter = new Interpreter(fExpression, fContext); 473 474 class EvaluationRunnable implements IEvaluationRunnable, ITerminate { 475 476 CoreException fException; 477 478 public void run(IJavaThread jt, IProgressMonitor pm) { 479 EventFilter filter = new EventFilter(); 480 try { 481 DebugPlugin.getDefault().addDebugEventFilter(filter); 482 interpreter.execute(); 483 } catch (CoreException exception) { 484 fException = exception; 485 if (fEvaluationDetail == DebugEvent.EVALUATION && exception.getStatus().getException() instanceof InvocationException) { 486 InvocationException invocationException = (InvocationException)exception.getStatus().getException(); 488 ObjectReference exObject = invocationException.exception(); 489 IJavaObject modelObject = (IJavaObject)JDIValue.createValue((JDIDebugTarget)getDebugTarget(), exObject); 490 try { 491 modelObject.sendMessage("printStackTrace", "()V", null, jt, false); } catch (DebugException e) { 493 } 495 } 496 } finally { 497 DebugPlugin.getDefault().removeDebugEventFilter(filter); 498 } 499 } 500 public void terminate() { 501 interpreter.stop(); 502 } 503 public boolean canTerminate() { 504 return true; 505 } 506 public boolean isTerminated() { 507 return false; 508 } 509 510 public CoreException getException() { 511 return fException; 512 } 513 } 514 515 EvaluationRunnable er = new EvaluationRunnable(); 516 CoreException exception = null; 517 try { 518 fThread.runEvaluation(er, null, fEvaluationDetail, fHitBreakpoints); 519 } catch (DebugException e) { 520 exception = e; 521 } 522 523 IJavaValue value = interpreter.getResult(); 524 525 if (exception == null) { 526 exception = er.getException(); 527 } 528 529 if (exception != null) { 530 if (exception instanceof DebugException) { 531 result.setException((DebugException)exception); 532 } else { 533 result.setException(new DebugException(exception.getStatus())); 534 } 535 } else { 536 if (value != null) { 537 result.setValue(value); 538 } else { 539 result.addError(EvaluationEngineMessages.ASTEvaluationEngine_An_unknown_error_occurred_during_evaluation); 540 } 541 } 542 543 544 evaluationFinished(result); 545 } 546 private void evaluationFinished(IEvaluationResult result) { 547 if(JDIDebugPlugin.getDefault() != null) { 549 fListener.evaluationComplete(result); 550 } 551 } 552 553 } 554 555 561 public static String replaceThisReferences(String snippet) { 562 StringBuffer updatedSnippet = new StringBuffer (); 564 Matcher matcher = fgThisPattern.matcher(snippet); 565 int start = 0; 566 while (matcher.find()) { 567 int end = matcher.start(2); 568 updatedSnippet.append(snippet.substring(start, end)); 569 updatedSnippet.append(ArrayRuntimeContext.ARRAY_THIS_VARIABLE); 570 start = end + 4; 571 } 572 if (start < snippet.length()) { 573 updatedSnippet.append(snippet.substring(start, snippet.length())); 574 } 575 return updatedSnippet.toString(); 576 } 577 } 578 | Popular Tags |