CompilationInfoImpl.java :  » IDE-Netbeans » java » org » netbeans » api » java » source » Java Open Source

Java Open Source » IDE Netbeans » java 
java » org » netbeans » api » java » source » CompilationInfoImpl.java
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 * 
 * Contributor(s):
 * 
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
 */

package org.netbeans.api.java.source;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.api.JavacTaskImpl;
import com.sun.tools.javac.util.JCDiagnostic;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.Document;
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.modules.java.source.parsing.SourceFileObject;
import org.netbeans.modules.java.source.usages.Pair;
import org.openide.cookies.EditorCookie;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.util.Exceptions;

/**
 *
 * @author Tomas Zezula
 */
final class CompilationInfoImpl {
    
    private JavaSource.Phase phase = JavaSource.Phase.MODIFIED;
    private CompilationUnitTree compilationUnit;    
    
    private JavacTaskImpl javacTask;
    private final PositionConverter binding;
    Pair<JavaSource.DocPositionRegion,MethodTree> changedMethod;
    final JavaFileObject jfo;    
    final JavaSource javaSource;        
    boolean needsRestart;
    JavaSource.Phase parserCrashed = JavaSource.Phase.UP_TO_DATE;      //When javac throws an error, the moveToPhase sets this to the last safe phase        
        
    
    CompilationInfoImpl (final JavaSource javaSource, final PositionConverter binding, final JavacTaskImpl javacTask) throws IOException {
        assert javaSource != null;        
        this.javaSource = javaSource;
        this.binding = binding;
        this.jfo = this.binding != null ? javaSource.jfoProvider.createJavaFileObject(binding.getFileObject(), this.javaSource.rootFo, this.binding.getFilter()) : null;
        this.javacTask = javacTask;
    }
    
    
    /**
     * Returns the current phase of the {@link JavaSource}.
     * @return {@link JavaSource.Phase} the state which was reached by the {@link JavaSource}.
     */
    JavaSource.Phase getPhase() {
        return this.phase;
    }
    
    Pair<JavaSource.DocPositionRegion,MethodTree> getChangedTree () {
        return this.changedMethod;
    }
    
    /**
     * Returns the javac tree representing the source file.
     * @return {@link CompilationUnitTree} the compilation unit cantaining the top level classes contained in the,
     * java source file. 
     * @throws java.lang.IllegalStateException  when the phase is less than {@link JavaSource.Phase#PARSED}
     */
    CompilationUnitTree getCompilationUnit() {
        if (this.jfo == null) {
            throw new IllegalStateException ();
        }
        if (this.phase.compareTo (JavaSource.Phase.PARSED) < 0)
            throw new IllegalStateException("Cannot call getCompilationInfo() if current phase < JavaSource.Phase.PARSED. You must call toPhase(Phase.PARSED) first.");//NOI18N
        return this.compilationUnit;
    }
    
    /**
     * Returns the content of the file represented by the {@link JavaSource}.
     * @return String the java source
     */
    String getText() {
        if (this.jfo == null) {
            throw new IllegalStateException ();
        }
        try {
            return this.jfo.getCharContent(false).toString();
        } catch (IOException ioe) {
            //Should never happen
            Exceptions.printStackTrace(ioe);
            return null;
        }
    }
    
    /**
     * Returns the {@link TokenHierarchy} for the file represented by the {@link JavaSource}.
     * @return lexer TokenHierarchy
     */
    TokenHierarchy<?> getTokenHierarchy() {
        if (this.jfo == null) {
            throw new IllegalStateException ();
        }
        try {
            return ((SourceFileObject) this.jfo).getTokenHierarchy();
        } catch (IOException ioe) {
            //Should never happen
            Exceptions.printStackTrace(ioe);
            return null;
        }
    }
    
    /**
     * Returns the errors in the file represented by the {@link JavaSource}.
     * @return an list of {@link Diagnostic} 
     */
    List<Diagnostic> getDiagnostics() {
        if (this.jfo == null) {
            throw new IllegalStateException ();
        }
        Collection<Diagnostic> errors = ((DiagnosticListenerImpl) javacTask.getContext().get(DiagnosticListener.class)).errors.values();
        List<Diagnostic> partialReparseErrors = ((DiagnosticListenerImpl) javacTask.getContext().get(DiagnosticListener.class)).partialReparseErrors;
        List<Diagnostic> affectedErrors = ((DiagnosticListenerImpl) javacTask.getContext().get(DiagnosticListener.class)).affectedErrors;        
        List<Diagnostic> localErrors = new ArrayList<Diagnostic>(errors.size() + 
                (partialReparseErrors == null ? 0 : partialReparseErrors.size()) + 
                (affectedErrors == null ? 0 : affectedErrors.size()));
        localErrors.addAll(errors);
        if (partialReparseErrors != null) {
            localErrors.addAll (partialReparseErrors);
        }
        if (affectedErrors != null) {
            localErrors.addAll (affectedErrors);
        }
        return localErrors;
    }
    
                   
                
    /**
     * Returns {@link JavaSource} for which this {@link CompilationInfoImpl} was created.
     * @return JavaSource
     */
    JavaSource getJavaSource() {
        return javaSource;
    }
    
    /**
     * Returns {@link ClasspathInfo} for which this {@link CompilationInfoImpl} was created.
     * @return ClasspathInfo
     */
    ClasspathInfo getClasspathInfo() {
  return javaSource.getClasspathInfo();
    }
    
    
    /**
     * Returns the {@link FileObject} represented by this {@link CompilationInfo}.
     * @return FileObject
     */
    FileObject getFileObject () {
        return this.binding != null ? this.binding.getFileObject() : null;
    }
    
    /**
     * Returns {@link Document} of this {@link CompilationInfoImpl}
     * @return Document or null when the {@link DataObject} doesn't
     * exist or has no {@link EditorCookie}.
     * @throws java.io.IOException
     */
    public Document getDocument() {
        final PositionConverter binding = this.getPositionConverter();
        FileObject fo;
        if (binding == null || (fo=binding.getFileObject()) == null) {
            return null;
        }
        if (!fo.isValid()) {
            return null;
        }
        try {
            DataObject od = DataObject.find(fo);            
            EditorCookie ec = od.getCookie(EditorCookie.class);
            if (ec != null) {
                return  ec.getDocument();
            } else {
                return null;
            }
        } catch (DataObjectNotFoundException e) {
            //may happen when the underlying FileObject has just been deleted
            //should be safe to ignore
            Logger.getLogger(CompilationInfo.class.getName()).log(Level.FINE, null, e);
            return null;
        }
    }
        
    
    /**Return {@link PositionConverter} binding virtual Java source and the real source.
     * Please note that this method is needed only for clients that need to work
     * in non-Java files (eg. JSP files) or in dialogs, like code completion.
     * Most clients do not need to use {@link PositionConverter}.
     * 
     * @return PositionConverter binding the virtual Java source and the real source.
     * @since 0.21
     */
    PositionConverter getPositionConverter() {
        return binding;
    }        
                
    /**
     * Moves the state to required phase. If given state was already reached 
     * the state is not changed. The method will throw exception if a state is 
     * illegal required. Acceptable parameters for thid method are <BR>
     * <LI>{@link org.netbeans.api.java.source.JavaSource.Phase.PARSED}
     * <LI>{@link org.netbeans.api.java.source.JavaSource.Phase.ELEMENTS_RESOLVED}
     * <LI>{@link org.netbeans.api.java.source.JavaSource.Phase.RESOLVED}
     * <LI>{@link org.netbeans.api.java.source.JavaSource.Phase.UP_TO_DATE}   
     * @param phase The required phase
     * @return the reached state
     * @throws IllegalArgumentException in case that given state can not be 
     *         reached using this method
     * @throws IOException when the file cannot be red
     */    
    JavaSource.Phase toPhase(JavaSource.Phase phase ) throws IOException {
        if (phase == JavaSource.Phase.MODIFIED) {
            throw new IllegalArgumentException( "Invalid phase: " + phase );    //NOI18N
        }
        if (jfo == null) {
            JavaSource.Phase currentPhase = getPhase();
            if (currentPhase.compareTo(phase)<0) {
                setPhase(phase);
                currentPhase = phase;
            }
            return currentPhase;
        }
        else {
            JavaSource.Phase currentPhase = JavaSource.moveToPhase(phase, this, false);
            return currentPhase.compareTo (phase) < 0 ? currentPhase : phase;
        }
    }
    
    /**
     * Sets the current {@link JavaSource.Phase}
     * @param phase
     */
    void setPhase(final JavaSource.Phase phase) {
        assert phase != null;
        this.phase = phase;
    }
    
    /**
     * Sets changed method
     * @param changedMethod
     */
    void setChangedMethod (final Pair<JavaSource.DocPositionRegion,MethodTree> changedMethod) {
        this.changedMethod = changedMethod;
    }
    
    /**
     * Sets the {@link CompilationUnitTree}
     * @param compilationUnit
     */
    void setCompilationUnit(final CompilationUnitTree compilationUnit) {
        assert compilationUnit != null;
        this.compilationUnit = compilationUnit;
    }        
    
    /**
     * Returns {@link JavacTaskImpl}, when it doesn't exist
     * it's created.
     * @return JavacTaskImpl
     */
    synchronized JavacTaskImpl getJavacTask() {  
        if (javacTask == null) {
            javacTask = javaSource.createJavacTask(new DiagnosticListenerImpl(this.jfo), null);
        }
  return javacTask;
    }
    
    
    // Innerclasses ------------------------------------------------------------    
    static class DiagnosticListenerImpl implements DiagnosticListener {
        
        private final TreeMap<Integer,Diagnostic> errors;
        private final JavaFileObject jfo;
        private volatile List<Diagnostic> partialReparseErrors;
        private volatile List<Diagnostic> affectedErrors;
        private volatile int currentDelta;
        
        public DiagnosticListenerImpl(final JavaFileObject jfo) {
            this.jfo = jfo;
            this.errors = new TreeMap<Integer,Diagnostic>();
        }
        
        public void report(Diagnostic message) {            
            if (this.jfo != null && this.jfo == message.getSource()) {
                if (partialReparseErrors != null) {
                    partialReparseErrors.add(message);
                }
                else {
                    errors.put((int)message.getPosition(),message);
                }
            }
        }
        
        final boolean hasPartialReparseErrors () {
            return this.partialReparseErrors != null && !this.partialReparseErrors.isEmpty();
        }
        
        final void startPartialReparse (int from, int to) {
            if (partialReparseErrors == null) {
                partialReparseErrors = new ArrayList<Diagnostic>();
                this.errors.subMap(from, to).clear();       //Remove errors in changed method durring the partial reparse                
                Map<Integer,Diagnostic> tail = this.errors.tailMap(to);
                this.affectedErrors = new ArrayList<Diagnostic>(tail.size());
                for (Iterator<Map.Entry<Integer,Diagnostic>> it = tail.entrySet().iterator(); it.hasNext();) {
                    Map.Entry<Integer,Diagnostic> e = it.next();
                    it.remove();
                    this.affectedErrors.add(new D ((JCDiagnostic)e.getValue()));
                }
            }
            else {
                this.partialReparseErrors.clear();
            }
        }
        
        final void endPartialReparse (final int delta) {
            this.currentDelta+=delta;
        }        
        
        private final class D implements Diagnostic {
            
            private final JCDiagnostic delegate;
            
            public D (final JCDiagnostic delegate) {
                assert delegate != null;
                this.delegate = delegate;
            }

            public Kind getKind() {
                return this.delegate.getKind();
            }

            public Object getSource() {
                return this.delegate.getSource();
            }

            public long getPosition() {
                long ret = this.delegate.getPosition();
                if (delegate.hasFixedPositions()) {
                    ret+=currentDelta;
                }
                return ret;
            }

            public long getStartPosition() {
                long ret = this.delegate.getStartPosition();
                if (delegate.hasFixedPositions()) {
                    ret+=currentDelta;
                }
                return ret;
            }

            public long getEndPosition() {
                long ret = this.delegate.getEndPosition();
                if (delegate.hasFixedPositions()) {
                    ret+=currentDelta;
                }
                return ret;
            }

            public long getLineNumber() {
                return -1;
            }

            public long getColumnNumber() {
                return -1;
            }

            public String getCode() {
                return this.delegate.getCode();
            }

            public String getMessage(Locale locale) {
                return this.delegate.getMessage(locale);
            }
            
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.