/plugins/plugin-java/che-plugin-java-ext-jdt/org-eclipse-jdt-ui/src/main/java/org/eclipse/jdt/internal/ui/javaeditor/ASTProvider.java
Java | 288 lines | 145 code | 33 blank | 110 comment | 54 complexity | 3b4c7f22412c76c87acc7cd4a577941b MD5 | raw file
- /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * IBM Corporation - initial API and implementation
- *******************************************************************************/
- package org.eclipse.jdt.internal.ui.javaeditor;
- import org.eclipse.che.jdt.dom.ASTNodes;
- import org.eclipse.core.runtime.IProgressMonitor;
- import org.eclipse.core.runtime.ISafeRunnable;
- import org.eclipse.core.runtime.OperationCanceledException;
- import org.eclipse.core.runtime.SafeRunner;
- import org.eclipse.jdt.core.ITypeRoot;
- import org.eclipse.jdt.core.JavaModelException;
- import org.eclipse.jdt.core.dom.AST;
- import org.eclipse.jdt.core.dom.ASTNode;
- import org.eclipse.jdt.core.dom.CheASTParser;
- import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
- import org.eclipse.jdt.core.dom.CompilationUnit;
- import org.eclipse.jdt.ui.SharedASTProvider;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.util.List;
- /**
- * @author Evgen Vidolob
- */
- public class ASTProvider {
- public static final int SHARED_AST_LEVEL = AST.JLS8;
- public static final boolean SHARED_AST_STATEMENT_RECOVERY = true;
- public static final boolean SHARED_BINDING_RECOVERY = true;
- private static final Logger LOG = LoggerFactory.getLogger(ASTProvider.class);
- private static final String DEBUG_PREFIX = "ASTProvider > "; //$NON-NLS-1$
- private Object fReconcileLock= new Object();
- private CompilationUnit fAST;
- /**
- * Tells whether this class is in debug mode.
- * @since 3.0
- */
- private static final boolean DEBUG = false;
- /**
- * Checks whether the given Java element has accessible source.
- *
- * @param je the Java element to test
- * @return <code>true</code> if the element has source
- * @since 3.2
- */
- private static boolean hasSource(ITypeRoot je) {
- if (je == null || !je.exists())
- return false;
- try {
- return je.getBuffer() != null;
- } catch (JavaModelException ex) {
- LOG.error(ex.getMessage(), ex);
- }
- return false;
- }
- /**
- * Returns a string for the given Java element used for debugging.
- *
- * @param javaElement the compilation unit AST
- * @return a string used for debugging
- */
- private String toString(ITypeRoot javaElement) {
- if (javaElement == null)
- return "null"; //$NON-NLS-1$
- else
- return javaElement.getElementName();
- }
- /**
- * Returns a string for the given AST used for debugging.
- *
- * @param ast the compilation unit AST
- * @return a string used for debugging
- */
- private String toString(CompilationUnit ast) {
- if (ast == null)
- return "null"; //$NON-NLS-1$
- List<AbstractTypeDeclaration> types= ast.types();
- if (types != null && types.size() > 0)
- return types.get(0).getName().getIdentifier() + "(" + ast.hashCode() + ")"; //$NON-NLS-1$//$NON-NLS-2$
- else
- return "AST without any type"; //$NON-NLS-1$
- }
- /**
- * Creates a new compilation unit AST.
- *
- * @param input the Java element for which to create the AST
- * @param progressMonitor the progress monitor
- * @return AST
- */
- public static CompilationUnit createAST(final ITypeRoot input, final IProgressMonitor progressMonitor) {
- if (!hasSource(input))
- return null;
- if (progressMonitor != null && progressMonitor.isCanceled())
- return null;
- final CheASTParser parser = CheASTParser.newParser(SHARED_AST_LEVEL);
- parser.setResolveBindings(true);
- parser.setStatementsRecovery(SHARED_AST_STATEMENT_RECOVERY);
- parser.setBindingsRecovery(SHARED_BINDING_RECOVERY);
- parser.setSource(input);
- if (progressMonitor != null && progressMonitor.isCanceled())
- return null;
- final CompilationUnit root[]= new CompilationUnit[1];
- SafeRunner.run(new ISafeRunnable() {
- public void run() {
- try {
- if (progressMonitor != null && progressMonitor.isCanceled())
- return;
- if (DEBUG)
- System.err.println(getThreadName() + " - " + DEBUG_PREFIX + "creating AST for: " +
- input.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
- root[0] = (CompilationUnit)parser.createAST(progressMonitor);
- //mark as unmodifiable
- ASTNodes.setFlagsToAST(root[0], ASTNode.PROTECT);
- } catch (OperationCanceledException ex) {
- return;
- }
- }
- public void handleException(Throwable ex) {
- LOG.error(ex.getMessage(), ex);
- }
- });
- return root[0];
- }
- private static String getThreadName() {
- String name= Thread.currentThread().getName();
- if (name != null)
- return name;
- else
- return Thread.currentThread().toString();
- }
- /**
- * Returns a shared compilation unit AST for the given Java element.
- * <p>
- * Clients are not allowed to modify the AST and must synchronize all access to its nodes.
- * </p>
- *
- * @param input the Java element, must not be <code>null</code>
- * @param waitFlag {@link SharedASTProvider#WAIT_YES}, {@link SharedASTProvider#WAIT_NO} or
- * {@link SharedASTProvider#WAIT_ACTIVE_ONLY}
- * @param progressMonitor the progress monitor or <code>null</code>
- * @return the AST or <code>null</code> if the AST is not available
- */
- public CompilationUnit getAST(final ITypeRoot input, SharedASTProvider.WAIT_FLAG waitFlag, IProgressMonitor progressMonitor) {
- if (input == null || waitFlag == null)
- throw new IllegalArgumentException("input or wait flag are null"); //$NON-NLS-1$
- if (progressMonitor != null && progressMonitor.isCanceled())
- return null;
- boolean isActiveElement;
- synchronized (this) {
- isActiveElement= false; //input.equals(fActiveJavaElement);
- if (isActiveElement) {
- if (fAST != null) {
- if (DEBUG)
- System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning cached AST:" + toString(fAST) + " for: " + input.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- return fAST;
- }
- if (waitFlag == SharedASTProvider.WAIT_NO) {
- if (DEBUG)
- System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "returning null (WAIT_NO) for: " + input.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
- return null;
- }
- }
- }
- final boolean canReturnNull= waitFlag == SharedASTProvider.WAIT_NO || (waitFlag == SharedASTProvider.WAIT_ACTIVE_ONLY && !(isActiveElement && fAST == null));
- boolean isReconciling= false;
- final ITypeRoot activeElement;
- if (isActiveElement) {
- // synchronized (fReconcileLock) {
- // activeElement= fReconcilingJavaElement;
- // isReconciling= isReconciling(input);
- // if (!isReconciling && !canReturnNull)
- // aboutToBeReconciled(input);
- // }
- } else
- activeElement= null;
- if (isReconciling) {
- // Wait for AST
- // synchronized (fWaitLock) {
- // if (isReconciling(input)) {
- // if (DEBUG)
- // System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "waiting for AST for: " + input.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
- // fWaitLock.wait(30000); // XXX: The 30 seconds timeout is an attempt to at least avoid a deadlock. See https://bugs.eclipse.org/366048#c21
- // }
- // }
- // Check whether active element is still valid
- // synchronized (this) {
- // if (activeElement == fActiveJavaElement && fAST != null) {
- // if (DEBUG)
- // System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "...got AST: " + toString(fAST) + " for: " + input.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- //
- // return fAST;
- // }
- // }
- return getAST(input, waitFlag, progressMonitor);
- } /*else if (canReturnNull)
- return null;*/
- CompilationUnit ast= null;
- try {
- ast= createAST(input, progressMonitor);
- if (progressMonitor != null && progressMonitor.isCanceled()) {
- ast= null;
- if (DEBUG)
- System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "Ignore created AST for: " + input.getElementName() + " - operation has been cancelled"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
- } finally {
- if (isActiveElement) {
- if (fAST != null) {
- // in the meantime, reconcile created a new AST. Return that one
- if (DEBUG)
- System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "Ignore created AST for " + input.getElementName() + " - AST from reconciler is newer"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- reconciled(fAST, input, null);
- return fAST;
- } else
- reconciled(ast, input, null);
- }
- }
- return ast;
- }
- /**
- * Update internal structures after reconcile.
- *
- * @param ast the compilation unit AST or <code>null</code> if the working copy was consistent
- * or reconciliation has been cancelled
- * @param javaElement the Java element for which the AST was built
- * @param progressMonitor the progress monitor
- * @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(CompilationUnit,
- * boolean, IProgressMonitor)
- */
- void reconciled(CompilationUnit ast, ITypeRoot javaElement, IProgressMonitor progressMonitor) {
- // if (DEBUG)
- // System.out.println(getThreadName() + " - " + DEBUG_PREFIX + "reconciled: " + toString(javaElement) + ", AST: " + toString(ast)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- //
- // synchronized (fReconcileLock) {
- // fIsReconciling= false;
- // if (javaElement == null || !javaElement.equals(fReconcilingJavaElement)) {
- //
- // if (DEBUG)
- // System.out.println(getThreadName() + " - " + DEBUG_PREFIX + " ignoring AST of out-dated editor"); //$NON-NLS-1$ //$NON-NLS-2$
- //
- // // Signal - threads might wait for wrong element
- // synchronized (fWaitLock) {
- // fWaitLock.notifyAll();
- // }
- //
- // return;
- // }
- // cache(ast, javaElement);
- // }
- }
- }