All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.api.java.source.CompilationInfo Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.api.java.source;

import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.DocTrees;
import com.sun.source.util.JavacTask;
import com.sun.source.util.TreePath;
import com.sun.source.util.Trees;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.model.JavacElements;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.swing.text.Document;
import javax.tools.Diagnostic;

import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.CheckReturnValue;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.annotations.common.NullUnknown;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.modules.java.preprocessorbridge.spi.WrapperFactory;
import org.netbeans.modules.java.source.CompilationInfoAccessor;
import org.netbeans.modules.java.source.ElementUtils;
import org.netbeans.modules.java.source.parsing.CompilationInfoImpl;
import org.netbeans.modules.java.source.parsing.DocPositionRegion;
import org.netbeans.modules.java.source.parsing.FileObjects;
import org.netbeans.modules.java.source.parsing.JavacParser;
import org.netbeans.modules.java.source.parsing.JavacParserResult;
import org.netbeans.modules.parsing.api.Snapshot;
import org.netbeans.modules.parsing.spi.Parser;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Pair;
import org.openide.util.Parameters;

/** Assorted information about the JavaSource.
 *
 * @author Petr Hrebejk, Tomas Zezula
 */
public class CompilationInfo {
    
    private static final boolean VERIFY_CONFINEMENT = Boolean.getBoolean(CompilationInfo.class.getName()+".vetifyConfinement"); //NOI18N
    
    //INV: never null
    final CompilationInfoImpl impl;
    //Expert: set to true when the runUserActionTask(,true), runModificationTask(,true)
    //ended or when reschedulable task leaved run method to verify confinement
    private boolean invalid;
    //@GuarderBy(this)
    private Trees trees;
    //@GuarderBy(this)
    private ElementUtilities elementUtilities;
    //@GuarderBy(this)
    private TreeUtilities treeUtilities;
    //@GuarderBy(this)
    private TypeUtilities typeUtilities;
    //@NotThreadSafe
    private JavaSource javaSource;
    
    
    CompilationInfo (final CompilationInfoImpl impl)  {
        assert impl != null;
        this.impl = impl;
    }

    /**
     * Returns an instance of the {@link CompilationInfo} for
     * given {@link org.netbeans.modules.parsing.spi.Parser.Result} if it is a result
     * of a java parser.
     * @param result for which the {@link CompilationInfo} should be
     * returned.
     * @return a {@link CompilationInfo} or null when the given result
     * is not a result of java parsing.
     * @since 0.42
     */
    public static @NullUnknown CompilationInfo get (@NonNull final Parser.Result result) {
        Parameters.notNull("result", result);   //NOI18N
        CompilationInfo info = null;
        if (result instanceof JavacParserResult) {
            final JavacParserResult javacResult = (JavacParserResult)result;            
            info = javacResult.get(CompilationInfo.class);            
        }
        return info;
    }
             
    // API of the class --------------------------------------------------------
    
    /**
     * Returns the current phase of the {@link JavaSource}.
     * @return {@link JavaSource.Phase} the state which was reached by the {@link JavaSource}.
     */
    public @NonNull JavaSource.Phase getPhase() {
        checkConfinement();
        return this.impl.getPhase();
    }
    
    /**
     * Returns tree which was reparsed by an incremental reparse.
     * When the source file wasn't parsed yet or the parse was a full parse
     * this method returns null.
     * 

* Currently the leaf tree is a MethodTree but this may change in the future. * Client of this method is responsible to check the corresponding TreeKind * to find out if it may perform on the changed subtree or it needs to * reprocess the whole tree. *

* @return {@link TreePath} or null * @since 0.31 */ public @CheckForNull @CheckReturnValue TreePath getChangedTree () { checkConfinement(); if (JavaSource.Phase.PARSED.compareTo (impl.getPhase())>0) { return null; } final Pair changedTree = impl.getChangedTree(); if (changedTree == null) { return null; } final CompilationUnitTree cu = impl.getCompilationUnit(); if (cu == null) { return null; } return TreePath.getPath(cu, changedTree.second()); } /** * Returns the javac tree representing the source file. * @return {@link CompilationUnitTree} the compilation unit containing the top level classes contained in the, * java source file. * @throws java.lang.IllegalStateException when the phase is less than {@link JavaSource.Phase#PARSED} */ public CompilationUnitTree getCompilationUnit() { checkConfinement(); return this.impl.getCompilationUnit(); } /** * Returns the content of the file represented by the {@link JavaSource}. * @return String the java source */ public @NonNull String getText() { checkConfinement(); return this.impl.getText(); } /** * Returns the snapshot used by java parser * @return the snapshot * @since 0.42 */ public @NonNull Snapshot getSnapshot () { checkConfinement(); return this.impl.getSnapshot(); } /** * Returns the {@link TokenHierarchy} for the file represented by the {@link JavaSource}. * @return lexer TokenHierarchy */ public @NonNull TokenHierarchy getTokenHierarchy() { checkConfinement(); return this.impl.getTokenHierarchy(); } /** * Returns the errors in the file represented by the {@link JavaSource}. * @return an list of {@link Diagnostic} */ public @NonNull List getDiagnostics() { checkConfinement(); return this.impl.getDiagnostics(); } /** * Returns all top level elements defined in file for which the {@link CompilationInfo} * was created. The {@link CompilationInfo} has to be in phase {@link JavaSource.Phase#ELEMENTS_RESOLVED}. * @return list of top level elements, it may return null when this {@link CompilationInfo} is not * in phase {@link JavaSource.Phase#ELEMENTS_RESOLVED} or higher. * @throws IllegalStateException is thrown when the {@link JavaSource} was created with no files * @since 0.14 */ public @NullUnknown List getTopLevelElements () throws IllegalStateException { checkConfinement(); if (this.impl.getFileObject() == null) { throw new IllegalStateException (); } final List result = new ArrayList(); if (this.impl.isClassFile()) { final JavacElements elements = (JavacElements) getElements(); assert elements != null; assert this.impl.getRoot() != null; final String name = FileObjects.convertFolder2Package(FileObjects.stripExtension(FileUtil.getRelativePath(this.impl.getRoot(), this.impl.getFileObject()))); final TypeElement e = Optional.ofNullable( SourceVersion.RELEASE_9.compareTo(getSourceVersion()) <= 0 ? SourceUtils.getModuleName(impl.getRoot().toURL(), true) : null) .map(elements::getModuleElement) .map((module) -> ElementUtils.getTypeElementByBinaryName(this, module, name)) .orElseGet(() -> ElementUtils.getTypeElementByBinaryName(this, name)); if (e != null) { result.add (e); } } else { CompilationUnitTree cu = getCompilationUnit(); if (cu == null) { return null; } else { final Trees ts = getTrees(); assert ts != null; List typeDecls = cu.getTypeDecls(); TreePath cuPath = new TreePath(cu); for( Tree t : typeDecls ) { TreePath p = new TreePath(cuPath,t); Element e = ts.getElement(p); if ( e != null && ( e.getKind().isClass() || e.getKind().isInterface() ) ) { result.add((TypeElement)e); } } } } return Collections.unmodifiableList(result); } /** * Return the {@link Trees} service of the javac represented by this {@link CompilationInfo}. * @return javac Trees service */ public synchronized @NonNull Trees getTrees() { checkConfinement(); if (trees == null) { //use a working init order: com.sun.tools.javac.main.JavaCompiler.instance(impl.getJavacTask().getContext()); trees = JavacTrees.instance(impl.getJavacTask().getContext()); Snapshot snapshot = impl.getSnapshot(); Document doc = snapshot != null ? snapshot.getSource().getDocument(false) : null; WrapperFactory factory = doc != null ? (WrapperFactory)doc.getProperty(WrapperFactory.class) : null; if (factory != null) { trees = factory.wrapTrees(trees); } } return trees; } /** * Return the {@link DocTrees} service of the javac represented by this {@link CompilationInfo}. * @return javac DocTrees service * @since 0.124 */ public @NonNull DocTrees getDocTrees() { final Trees ts = getTrees(); return ts instanceof DocTrees ? (DocTrees) ts : JavacTrees.instance(impl.getJavacTask().getContext()); } /** * Return the {@link Types} service of the javac represented by this {@link CompilationInfo}. * @return javac Types service */ public @NonNull Types getTypes() { checkConfinement(); //use a working init order: com.sun.tools.javac.main.JavaCompiler.instance(impl.getJavacTask().getContext()); return impl.getJavacTask().getTypes(); } /** * Return the {@link Elements} service of the javac represented by this {@link CompilationInfo}. * @return javac Elements service */ public @NonNull Elements getElements() { checkConfinement(); //use a working init order: com.sun.tools.javac.main.JavaCompiler.instance(impl.getJavacTask().getContext()); return impl.getJavacTask().getElements(); } /** * Returns {@link JavaSource} for which this {@link CompilationInfo} was created. * @return JavaSource or null * @deprecated Works only when the CompilationInfo was created by JavaSource using * the compatibility bridge, when the CompilationInfo was created by the parsing api * it returns null. Use {@link CompilationInfo#getSnapshot()} instead. */ @Deprecated public @NullUnknown JavaSource getJavaSource() { checkConfinement(); return javaSource; } void setJavaSource (final JavaSource javaSource) { this.javaSource = javaSource; } /** * Returns {@link ClasspathInfo} for which this {@link CompilationInfo} was created. * @return ClasspathInfo */ public @NonNull ClasspathInfo getClasspathInfo() { checkConfinement(); return this.impl.getClasspathInfo(); } /** * Returns the {@link FileObject} represented by this {@link CompilationInfo}. * @return FileObject */ public @NullUnknown FileObject getFileObject() { checkConfinement(); return impl.getFileObject(); } /**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 (e.g. 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 * @deprecated as of 0.42, this is superseded by Parsing API. */ @Deprecated public PositionConverter getPositionConverter() { checkConfinement(); if (this.impl.getFileObject() == null) { throw new IllegalStateException (); } return new PositionConverter(impl.getSnapshot()); } /** * Returns {@link Document} of this {@link CompilationInfoImpl} * @return Document or null when the DataObject doesn't * exist or has no EditorCookie. * @throws java.io.IOException */ public @CheckForNull Document getDocument() throws IOException { //XXX cleanup: IOException is no longer required? Used by PositionEstimator, DiffFacility checkConfinement(); return this.impl.getDocument(); } /** * Returns {@link TreeUtilities}. * @return TreeUtilities */ public synchronized @NonNull TreeUtilities getTreeUtilities() { checkConfinement(); if (treeUtilities == null) { treeUtilities = new TreeUtilities(this); } return treeUtilities; } /** * Returns {@link ElementUtilities}. * @return ElementUtilities */ public synchronized @NonNull ElementUtilities getElementUtilities() { checkConfinement(); if (elementUtilities == null) { elementUtilities = new ElementUtilities(this); } return elementUtilities; } /**Get the TypeUtilities. * @return an instance of TypeUtilities */ public synchronized @NonNull TypeUtilities getTypeUtilities() { checkConfinement(); if (typeUtilities == null) { typeUtilities = new TypeUtilities(this); } return typeUtilities; } /** * Returns the {@link SourceVersion} used by the javac represented by this {@link CompilationInfo}. * @return SourceVersion * @since 0.47 */ public @NonNull SourceVersion getSourceVersion() { checkConfinement(); return Source.toSourceVersion(Source.instance(impl.getJavacTask().getContext())); } /**Retrieve a value cached under the given key using the * {@link #putCachedValue(java.lang.Object, java.lang.Object, org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy)} method. * * @param key for which the cached value should be retrieved * @return value originally passed to {@link #putCachedValue(java.lang.Object, java.lang.Object, org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy)}, or null if none * @since 0.90 */ public @CheckForNull Object getCachedValue(@NonNull Object key) { Parameters.notNull("key", key); return impl.getCachedValue(key); } /**Put a value into a cache under the given key. The {@code clearPolicy} parameter specifies the latest time the * references to the key and value should be cleared. The infrastructure is free to clear the references at any earlier time. * The clients should not depend on this cache for correctness, only to improve performance. * * @param key a unique key under which the value should be stored * @param value the value to store - any value previously set under the same key will be erased from the cache * @param clearPolicy the latest time when the mapping should be cleared from the cache * @since 0.90 */ public void putCachedValue(@NonNull Object key, @NullAllowed Object value, @NonNull CacheClearPolicy clearPolicy) { Parameters.notNull("key", key); Parameters.notNull("clearPolicy", clearPolicy); impl.putCachedValue(key, value, clearPolicy); } /** * Marks this {@link CompilationInfo} as invalid, may be used to * verify confinement. */ final void invalidate () { this.invalid = true; this.impl.taskFinished(); doInvalidate(); } protected void doInvalidate () { final JavacParser parser = this.impl.getParser(); if (parser != null) { parser.resultFinished (true); } } /** * Checks concurrency confinement. * When {@link VERIFY_CONFINEMENT} is enabled & thread accesses the CompilationInfo * outside guarded run() method the {@link IllegalStateException} is thrown * @throws java.lang.IllegalStateException */ final void checkConfinement () throws IllegalStateException { if (VERIFY_CONFINEMENT && this.invalid) { throw new IllegalStateException (String.format("Access to the shared %s outside a guarded run method.", this.getClass().getSimpleName())); } } /**Constants to specify when a valued cached by {@link #putCachedValue(java.lang.Object, java.lang.Object, org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy)} * should be evicted from the cache. * * @since 0.90 */ public enum CacheClearPolicy { /** The cached value will be cleared at the end of the current parsing.api's task. */ ON_TASK_END, /** The cached value will be cleared on any change in the source document. */ ON_CHANGE, /** The cached value will be cleared when a method/field/class is added, removed or its signature changes. */ ON_SIGNATURE_CHANGE; } static { CompilationInfoAccessor.setInstance(new CompilationInfoAccessor() { @Override public JavacTask getJavacTask(CompilationInfo info) { return info.impl.getJavacTask(); } @Override public CompilationInfoImpl getCompilationInfoImpl(CompilationInfo info) { return info.impl; } }); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy