1 11 12 package org.eclipse.jdt.internal.ui.javaeditor; 13 14 import java.util.List ; 15 16 import org.eclipse.core.runtime.Assert; 17 import org.eclipse.core.runtime.IProgressMonitor; 18 import org.eclipse.core.runtime.ISafeRunnable; 19 import org.eclipse.core.runtime.IStatus; 20 import org.eclipse.core.runtime.OperationCanceledException; 21 import org.eclipse.core.runtime.Platform; 22 import org.eclipse.core.runtime.SafeRunner; 23 import org.eclipse.core.runtime.Status; 24 25 import org.eclipse.ui.IPartListener2; 26 import org.eclipse.ui.IWindowListener; 27 import org.eclipse.ui.IWorkbenchPart; 28 import org.eclipse.ui.IWorkbenchPartReference; 29 import org.eclipse.ui.IWorkbenchWindow; 30 import org.eclipse.ui.PlatformUI; 31 32 import org.eclipse.jdt.core.IClassFile; 33 import org.eclipse.jdt.core.ICompilationUnit; 34 import org.eclipse.jdt.core.IJavaElement; 35 import org.eclipse.jdt.core.ITypeRoot; 36 import org.eclipse.jdt.core.JavaModelException; 37 import org.eclipse.jdt.core.dom.AST; 38 import org.eclipse.jdt.core.dom.ASTNode; 39 import org.eclipse.jdt.core.dom.ASTParser; 40 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 41 import org.eclipse.jdt.core.dom.CompilationUnit; 42 43 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 44 45 import org.eclipse.jdt.ui.JavaUI; 46 47 import org.eclipse.jdt.internal.ui.JavaPlugin; 48 49 50 56 public final class ASTProvider { 57 58 63 public static final class WAIT_FLAG { 64 65 String fName; 66 67 private WAIT_FLAG(String name) { 68 fName= name; 69 } 70 71 74 public String toString() { 75 return fName; 76 } 77 } 78 79 89 public static final WAIT_FLAG WAIT_YES= new WAIT_FLAG("wait yes"); 91 100 public static final WAIT_FLAG WAIT_ACTIVE_ONLY= new WAIT_FLAG("wait active only"); 102 111 public static final WAIT_FLAG WAIT_NO= new WAIT_FLAG("don't wait"); 113 114 118 private static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jdt.ui/debug/ASTProvider")); 120 121 126 private class ActivationListener implements IPartListener2, IWindowListener { 127 128 129 132 public void partActivated(IWorkbenchPartReference ref) { 133 if (isJavaEditor(ref) && !isActiveEditor(ref)) 134 activeJavaEditorChanged(ref.getPart(true)); 135 } 136 137 140 public void partBroughtToTop(IWorkbenchPartReference ref) { 141 if (isJavaEditor(ref) && !isActiveEditor(ref)) 142 activeJavaEditorChanged(ref.getPart(true)); 143 } 144 145 148 public void partClosed(IWorkbenchPartReference ref) { 149 if (isActiveEditor(ref)) { 150 if (DEBUG) 151 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "closed active editor: " + ref.getTitle()); 153 activeJavaEditorChanged(null); 154 } 155 } 156 157 160 public void partDeactivated(IWorkbenchPartReference ref) { 161 } 162 163 166 public void partOpened(IWorkbenchPartReference ref) { 167 if (isJavaEditor(ref) && !isActiveEditor(ref)) 168 activeJavaEditorChanged(ref.getPart(true)); 169 } 170 171 174 public void partHidden(IWorkbenchPartReference ref) { 175 } 176 177 180 public void partVisible(IWorkbenchPartReference ref) { 181 if (isJavaEditor(ref) && !isActiveEditor(ref)) 182 activeJavaEditorChanged(ref.getPart(true)); 183 } 184 185 188 public void partInputChanged(IWorkbenchPartReference ref) { 189 if (isJavaEditor(ref) && isActiveEditor(ref)) 190 activeJavaEditorChanged(ref.getPart(true)); 191 } 192 193 196 public void windowActivated(IWorkbenchWindow window) { 197 IWorkbenchPartReference ref= window.getPartService().getActivePartReference(); 198 if (isJavaEditor(ref) && !isActiveEditor(ref)) 199 activeJavaEditorChanged(ref.getPart(true)); 200 } 201 202 205 public void windowDeactivated(IWorkbenchWindow window) { 206 } 207 208 211 public void windowClosed(IWorkbenchWindow window) { 212 if (fActiveEditor != null && fActiveEditor.getSite() != null && window == fActiveEditor.getSite().getWorkbenchWindow()) { 213 if (DEBUG) 214 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "closed active editor: " + fActiveEditor.getTitle()); 216 activeJavaEditorChanged(null); 217 } 218 window.getPartService().removePartListener(this); 219 } 220 221 224 public void windowOpened(IWorkbenchWindow window) { 225 window.getPartService().addPartListener(this); 226 } 227 228 private boolean isActiveEditor(IWorkbenchPartReference ref) { 229 return ref != null && isActiveEditor(ref.getPart(false)); 230 } 231 232 private boolean isActiveEditor(IWorkbenchPart part) { 233 return part != null && (part == fActiveEditor); 234 } 235 236 private boolean isJavaEditor(IWorkbenchPartReference ref) { 237 if (ref == null) 238 return false; 239 240 String id= ref.getId(); 241 242 return JavaUI.ID_CF_EDITOR.equals(id) || JavaUI.ID_CU_EDITOR.equals(id) || ref.getPart(false) instanceof JavaEditor; 244 } 245 } 246 247 public static final int SHARED_AST_LEVEL= AST.JLS3; 248 public static final boolean SHARED_AST_STATEMENT_RECOVERY= true; 249 public static final boolean SHARED_BINDING_RECOVERY= true; 250 251 private static final String DEBUG_PREFIX= "ASTProvider > "; 253 254 private IJavaElement fReconcilingJavaElement; 255 private IJavaElement fActiveJavaElement; 256 private CompilationUnit fAST; 257 private ActivationListener fActivationListener; 258 private Object fReconcileLock= new Object (); 259 private Object fWaitLock= new Object (); 260 private boolean fIsReconciling; 261 private IWorkbenchPart fActiveEditor; 262 263 264 270 public static ASTProvider getASTProvider() { 271 return JavaPlugin.getDefault().getASTProvider(); 272 } 273 274 277 public ASTProvider() { 278 install(); 279 } 280 281 284 void install() { 285 fActivationListener= new ActivationListener(); 287 PlatformUI.getWorkbench().addWindowListener(fActivationListener); 288 289 IWorkbenchWindow[] windows= PlatformUI.getWorkbench().getWorkbenchWindows(); 291 for (int i= 0, length= windows.length; i < length; i++) 292 windows[i].getPartService().addPartListener(fActivationListener); 293 } 294 295 private void activeJavaEditorChanged(IWorkbenchPart editor) { 296 297 IJavaElement javaElement= null; 298 if (editor instanceof JavaEditor) 299 javaElement= ((JavaEditor)editor).getInputJavaElement(); 300 301 synchronized (this) { 302 fActiveEditor= editor; 303 fActiveJavaElement= javaElement; 304 cache(null, javaElement); 305 } 306 307 if (DEBUG) 308 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "active editor is: " + toString(javaElement)); 310 synchronized (fReconcileLock) { 311 if (fIsReconciling && (fReconcilingJavaElement == null || !fReconcilingJavaElement.equals(javaElement))) { 312 fIsReconciling= false; 313 fReconcilingJavaElement= null; 314 } else if (javaElement == null) { 315 fIsReconciling= false; 316 fReconcilingJavaElement= null; 317 } 318 } 319 } 320 321 328 public boolean isCached(CompilationUnit ast) { 329 return ast != null && fAST == ast; 330 } 331 332 340 public boolean isActive(ICompilationUnit cu) { 341 return cu != null && cu.equals(fActiveJavaElement); 342 } 343 344 350 void aboutToBeReconciled(IJavaElement javaElement) { 351 352 if (javaElement == null) 353 return; 354 355 if (DEBUG) 356 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "about to reconcile: " + toString(javaElement)); 358 synchronized (fReconcileLock) { 359 fIsReconciling= true; 360 fReconcilingJavaElement= javaElement; 361 } 362 cache(null, javaElement); 363 } 364 365 368 private synchronized void disposeAST() { 369 370 if (fAST == null) 371 return; 372 373 if (DEBUG) 374 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "disposing AST: " + toString(fAST) + " for: " + toString(fActiveJavaElement)); 376 fAST= null; 377 378 cache(null, null); 379 } 380 381 387 private String toString(IJavaElement javaElement) { 388 if (javaElement == null) 389 return "null"; else 391 return javaElement.getElementName(); 392 393 } 394 395 401 private String toString(CompilationUnit ast) { 402 if (ast == null) 403 return "null"; 405 List types= ast.types(); 406 if (types != null && types.size() > 0) 407 return ((AbstractTypeDeclaration)types.get(0)).getName().getIdentifier(); 408 else 409 return "AST without any type"; } 411 412 418 private synchronized void cache(CompilationUnit ast, IJavaElement javaElement) { 419 420 if (fActiveJavaElement != null && !fActiveJavaElement.equals(javaElement)) { 421 if (DEBUG && javaElement != null) System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "don't cache AST for inactive: " + toString(javaElement)); return; 424 } 425 426 if (DEBUG && (javaElement != null || ast != null)) System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "caching AST: " + toString(ast) + " for: " + toString(javaElement)); 429 if (fAST != null) 430 disposeAST(); 431 432 fAST= ast; 433 434 synchronized (fWaitLock) { 436 fWaitLock.notifyAll(); 437 } 438 } 439 440 453 public CompilationUnit getAST(IJavaElement je, WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) { 454 if (je == null) 455 return null; 456 457 Assert.isTrue(je.getElementType() == IJavaElement.CLASS_FILE || je.getElementType() == IJavaElement.COMPILATION_UNIT); 458 459 if (progressMonitor != null && progressMonitor.isCanceled()) 460 return null; 461 462 boolean isActiveElement; 463 synchronized (this) { 464 isActiveElement= je.equals(fActiveJavaElement); 465 if (isActiveElement) { 466 if (fAST != null) { 467 if (DEBUG) 468 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning cached AST:" + toString(fAST) + " for: " + je.getElementName()); 470 return fAST; 471 } 472 if (waitFlag == WAIT_NO) { 473 if (DEBUG) 474 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning null (WAIT_NO) for: " + je.getElementName()); 476 return null; 477 478 } 479 } 480 } 481 if (isActiveElement && isReconciling(je)) { 482 try { 483 final IJavaElement activeElement= fReconcilingJavaElement; 484 485 synchronized (fWaitLock) { 487 if (DEBUG) 488 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "waiting for AST for: " + je.getElementName()); 490 fWaitLock.wait(); 491 } 492 493 synchronized (this) { 495 if (activeElement == fActiveJavaElement && fAST != null) { 496 if (DEBUG) 497 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "...got AST for: " + je.getElementName()); 499 return fAST; 500 } 501 } 502 return getAST(je, waitFlag, progressMonitor); 503 } catch (InterruptedException e) { 504 return null; } 506 } else if (waitFlag == WAIT_NO || (waitFlag == WAIT_ACTIVE_ONLY && !(isActiveElement && fAST == null))) 507 return null; 508 509 if (isActiveElement) 510 aboutToBeReconciled(je); 511 512 CompilationUnit ast= null; 513 try { 514 ast= createAST(je, progressMonitor); 515 if (progressMonitor != null && progressMonitor.isCanceled()) { 516 ast= null; 517 if (DEBUG) 518 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "Ignore created AST for: " + je.getElementName() + " - operation has been cancelled"); } 520 } finally { 521 if (isActiveElement) { 522 if (fAST != null) { 523 if (DEBUG) 524 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "Ignore created AST for " + je.getElementName() + " - AST from reconciler is newer"); reconciled(fAST, je, null); 526 } else 527 reconciled(ast, je, null); 528 } 529 } 530 531 return ast; 532 } 533 534 550 public CompilationUnit getAST(IJavaElement je, boolean wait, IProgressMonitor progressMonitor) { 551 if (wait) 552 return getAST(je, WAIT_YES, progressMonitor); 553 else 554 return getAST(je, WAIT_NO, progressMonitor); 555 } 556 557 564 private boolean isReconciling(IJavaElement javaElement) { 565 synchronized (fReconcileLock) { 566 return javaElement != null && javaElement.equals(fReconcilingJavaElement) && fIsReconciling; 567 } 568 } 569 570 577 private CompilationUnit createAST(final IJavaElement je, final IProgressMonitor progressMonitor) { 578 if (!hasSource(je)) 579 return null; 580 581 if (progressMonitor != null && progressMonitor.isCanceled()) 582 return null; 583 584 final ASTParser parser = ASTParser.newParser(SHARED_AST_LEVEL); 585 parser.setResolveBindings(true); 586 parser.setStatementsRecovery(SHARED_AST_STATEMENT_RECOVERY); 587 parser.setBindingsRecovery(SHARED_BINDING_RECOVERY); 588 589 if (progressMonitor != null && progressMonitor.isCanceled()) 590 return null; 591 592 if (je.getElementType() == IJavaElement.COMPILATION_UNIT) 593 parser.setSource((ICompilationUnit)je); 594 else if (je.getElementType() == IJavaElement.CLASS_FILE) 595 parser.setSource((IClassFile)je); 596 597 if (progressMonitor != null && progressMonitor.isCanceled()) 598 return null; 599 600 final CompilationUnit root[]= new CompilationUnit[1]; 601 602 SafeRunner.run(new ISafeRunnable() { 603 public void run() { 604 try { 605 if (progressMonitor != null && progressMonitor.isCanceled()) 606 return; 607 if (DEBUG) 608 System.err.println(getThreadName() + " - " + DEBUG_PREFIX + "creating AST for: " + je.getElementName()); root[0]= (CompilationUnit)parser.createAST(progressMonitor); 610 } catch (OperationCanceledException ex) { 611 return; 612 } 613 } 614 public void handleException(Throwable ex) { 615 IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, "Error in JDT Core during AST creation", ex); JavaPlugin.getDefault().getLog().log(status); 617 } 618 }); 619 620 if (root[0] != null) 622 ASTNodes.setFlagsToAST(root[0], ASTNode.PROTECT); 623 624 return root[0]; 625 } 626 627 634 private boolean hasSource(IJavaElement je) { 635 if (je == null || !je.exists()) 636 return false; 637 638 try { 639 return je instanceof ITypeRoot && ((ITypeRoot)je).getBuffer() != null; 640 } catch (JavaModelException ex) { 641 IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, "Error in JDT Core during AST creation", ex); JavaPlugin.getDefault().getLog().log(status); 643 } 644 return false; 645 } 646 647 650 public void dispose() { 651 652 PlatformUI.getWorkbench().removeWindowListener(fActivationListener); 654 fActivationListener= null; 655 656 disposeAST(); 657 658 synchronized (fWaitLock) { 659 fWaitLock.notifyAll(); 660 } 661 } 662 663 666 void reconciled(CompilationUnit ast, IJavaElement javaElement, IProgressMonitor progressMonitor) { 667 668 if (DEBUG) 669 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "reconciled: " + toString(javaElement) + ", AST: " + toString(ast)); 671 synchronized (fReconcileLock) { 672 673 fIsReconciling= progressMonitor != null && progressMonitor.isCanceled(); 674 if (javaElement == null || !javaElement.equals(fReconcilingJavaElement)) { 675 676 if (DEBUG) 677 System.out.println(getThreadName() + " - " + DEBUG_PREFIX + " ignoring AST of out-dated editor"); 679 synchronized (fWaitLock) { 681 fWaitLock.notifyAll(); 682 } 683 684 return; 685 } 686 687 cache(ast, javaElement); 688 } 689 } 690 691 private String getThreadName() { 692 String name= Thread.currentThread().getName(); 693 if (name != null) 694 return name; 695 else 696 return Thread.currentThread().toString(); 697 } 698 699 } 700 701 | Popular Tags |