001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.api.java.source;
043:
044: import com.sun.source.tree.CompilationUnitTree;
045: import com.sun.source.tree.MethodTree;
046: import com.sun.source.tree.Tree;
047: import com.sun.source.util.TreePath;
048: import com.sun.source.util.Trees;
049: import com.sun.tools.javac.model.JavacElements;
050: import java.io.IOException;
051: import java.util.ArrayList;
052: import java.util.Collections;
053: import java.util.List;
054: import javax.lang.model.element.Element;
055: import javax.lang.model.element.TypeElement;
056: import javax.lang.model.util.Elements;
057: import javax.lang.model.util.Types;
058: import javax.swing.text.Document;
059: import javax.tools.Diagnostic;
060: import org.netbeans.api.lexer.TokenHierarchy;
061: import org.netbeans.modules.java.source.parsing.FileObjects;
062: import org.netbeans.modules.java.source.usages.Pair;
063: import org.openide.filesystems.FileObject;
064: import org.openide.filesystems.FileUtil;
065:
066: /** Asorted information about the JavaSource.
067: *
068: * @author Petr Hrebejk, Tomas Zezula
069: */
070: public class CompilationInfo {
071:
072: private static final boolean VERIFY_CONFINEMENT = Boolean
073: .getBoolean(CompilationInfo.class.getName()
074: + ".vetifyConfinement"); //NOI18N
075:
076: //INV: never null
077: final CompilationInfoImpl impl;
078: //Expert: set to true when the runUserActionTask(,true), runModificationTask(,true)
079: //ended or when reschedulable task leaved run method to verify confinement
080: private boolean invalid;
081: //@GuarderBy(this)
082: private ElementUtilities elementUtilities;
083: //@GuarderBy(this)
084: private TreeUtilities treeUtilities;
085: //@GuarderBy(this)
086: private TypeUtilities typeUtilities;
087:
088: CompilationInfo(final CompilationInfoImpl impl) {
089: assert impl != null;
090: this .impl = impl;
091: }
092:
093: // API of the class --------------------------------------------------------
094:
095: /**
096: * Returns the current phase of the {@link JavaSource}.
097: * @return {@link JavaSource.Phase} the state which was reached by the {@link JavaSource}.
098: */
099: public JavaSource.Phase getPhase() {
100: checkConfinement();
101: return this .impl.getPhase();
102: }
103:
104: /**
105: * Returns tree which was reparsed by an incremental reparse.
106: * When the source file wasn't parsed yet or the parse was a full parse
107: * this method returns null.
108: * <p class="nonnormative">
109: * Currently the leaf tree is a MethodTree but this may change in the future.
110: * Client of this method is responsible to check the corresponding TreeKind
111: * to find out if it may perform on the changed subtree or it needs to
112: * reprocess the whole tree.
113: * </p>
114: * @return {@link TreePath} or null
115: * @since 0.31
116: */
117: public TreePath getChangedTree() {
118: checkConfinement();
119: if (JavaSource.Phase.PARSED.compareTo(impl.getPhase()) > 0) {
120: return null;
121: }
122: final Pair<JavaSource.DocPositionRegion, MethodTree> changedTree = impl
123: .getChangedTree();
124: if (changedTree == null) {
125: return null;
126: }
127: final CompilationUnitTree cu = impl.getCompilationUnit();
128: if (cu == null) {
129: return null;
130: }
131: return TreePath.getPath(cu, changedTree.second);
132: }
133:
134: /**
135: * Returns the javac tree representing the source file.
136: * @return {@link CompilationUnitTree} the compilation unit cantaining the top level classes contained in the,
137: * java source file.
138: * @throws java.lang.IllegalStateException when the phase is less than {@link JavaSource.Phase#PARSED}
139: */
140: public CompilationUnitTree getCompilationUnit() {
141: checkConfinement();
142: return this .impl.getCompilationUnit();
143: }
144:
145: /**
146: * Returns the content of the file represented by the {@link JavaSource}.
147: * @return String the java source
148: */
149: public String getText() {
150: checkConfinement();
151: return this .impl.getText();
152: }
153:
154: /**
155: * Returns the {@link TokenHierarchy} for the file represented by the {@link JavaSource}.
156: * @return lexer TokenHierarchy
157: */
158: public TokenHierarchy<?> getTokenHierarchy() {
159: checkConfinement();
160: return this .impl.getTokenHierarchy();
161: }
162:
163: /**
164: * Returns the errors in the file represented by the {@link JavaSource}.
165: * @return an list of {@link Diagnostic}
166: */
167: public List<Diagnostic> getDiagnostics() {
168: checkConfinement();
169: return this .impl.getDiagnostics();
170: }
171:
172: /**
173: * Returns all top level elements defined in file for which the {@link CompilationInfo}
174: * was created. The {@link CompilationInfo} has to be in phase {@link JavaSource#Phase#ELEMENTS_RESOLVED}.
175: * @return list of top level elements, it may return null when this {@link CompilationInfo} is not
176: * in phase {@link JavaSource#Phase#ELEMENTS_RESOLVED} or higher.
177: * @throws IllegalStateException is thrown when the {@link JavaSource} was created with no files
178: * @since 0.14
179: */
180: public List<? extends TypeElement> getTopLevelElements()
181: throws IllegalStateException {
182: checkConfinement();
183: if (this .impl.getPositionConverter() == null) {
184: throw new IllegalStateException();
185: }
186: final List<TypeElement> result = new ArrayList<TypeElement>();
187: final JavaSource javaSource = this .impl.getJavaSource();
188: if (javaSource.isClassFile()) {
189: Elements elements = getElements();
190: assert elements != null;
191: assert javaSource.rootFo != null;
192: String name = FileObjects.convertFolder2Package(FileObjects
193: .stripExtension(FileUtil.getRelativePath(
194: javaSource.rootFo, getFileObject())));
195: TypeElement e = ((JavacElements) elements)
196: .getTypeElementByBinaryName(name);
197: if (e != null) {
198: result.add(e);
199: }
200: } else {
201: CompilationUnitTree cu = getCompilationUnit();
202: if (cu == null) {
203: return null;
204: } else {
205: final Trees trees = getTrees();
206: assert trees != null;
207: List<? extends Tree> typeDecls = cu.getTypeDecls();
208: TreePath cuPath = new TreePath(cu);
209: for (Tree t : typeDecls) {
210: TreePath p = new TreePath(cuPath, t);
211: Element e = trees.getElement(p);
212: if (e != null
213: && (e.getKind().isClass() || e.getKind()
214: .isInterface())) {
215: result.add((TypeElement) e);
216: }
217: }
218: }
219: }
220: return Collections.unmodifiableList(result);
221: }
222:
223: /**
224: * Return the {@link Trees} service of the javac represented by this {@link CompilationInfo}.
225: * @return javac Trees service
226: */
227: public Trees getTrees() {
228: checkConfinement();
229: return Trees.instance(impl.getJavacTask());
230: }
231:
232: /**
233: * Return the {@link Types} service of the javac represented by this {@link CompilationInfo}.
234: * @return javac Types service
235: */
236: public Types getTypes() {
237: checkConfinement();
238: return impl.getJavacTask().getTypes();
239: }
240:
241: /**
242: * Return the {@link Elements} service of the javac represented by this {@link CompilationInfo}.
243: * @return javac Elements service
244: */
245: public Elements getElements() {
246: checkConfinement();
247: return impl.getJavacTask().getElements();
248: }
249:
250: /**
251: * Returns {@link JavaSource} for which this {@link CompilationInfo} was created.
252: * @return JavaSource
253: */
254: public JavaSource getJavaSource() {
255: checkConfinement();
256: return this .impl.getJavaSource();
257: }
258:
259: /**
260: * Returns {@link ClasspathInfo} for which this {@link CompilationInfo} was created.
261: * @return ClasspathInfo
262: */
263: public ClasspathInfo getClasspathInfo() {
264: checkConfinement();
265: return this .impl.getClasspathInfo();
266: }
267:
268: /**
269: * Returns the {@link FileObject} represented by this {@link CompilationInfo}.
270: * @return FileObject
271: */
272: public FileObject getFileObject() {
273: checkConfinement();
274: return impl.getFileObject();
275: }
276:
277: /**Return {@link PositionConverter} binding virtual Java source and the real source.
278: * Please note that this method is needed only for clients that need to work
279: * in non-Java files (eg. JSP files) or in dialogs, like code completion.
280: * Most clients do not need to use {@link PositionConverter}.
281: *
282: * @return PositionConverter binding the virtual Java source and the real source.
283: * @since 0.21
284: */
285: public PositionConverter getPositionConverter() {
286: checkConfinement();
287: return this .impl.getPositionConverter();
288: }
289:
290: /**
291: * Returns {@link Document} of this {@link CompilationInfoImpl}
292: * @return Document or null when the {@link DataObject} doesn't
293: * exist or has no {@link EditorCookie}.
294: * @throws java.io.IOException
295: */
296: public Document getDocument() throws IOException { //XXX cleanup: IOException is no longer required? Used by PositionEstimator, DiffFacility
297: checkConfinement();
298: return this .impl.getDocument();
299: }
300:
301: /**
302: * Returns {@link TreeUtilities}.
303: * @return TreeUtilities
304: */
305: public synchronized TreeUtilities getTreeUtilities() {
306: checkConfinement();
307: if (treeUtilities == null) {
308: treeUtilities = new TreeUtilities(this );
309: }
310: return treeUtilities;
311: }
312:
313: /**
314: * Returns {@link ElementUtilities}.
315: * @return ElementUtilities
316: */
317: public synchronized ElementUtilities getElementUtilities() {
318: checkConfinement();
319: if (elementUtilities == null) {
320: elementUtilities = new ElementUtilities(this );
321:
322: }
323: return elementUtilities;
324: }
325:
326: /**Get the TypeUtilities.
327: * @return an instance of TypeUtilities
328: */
329: public synchronized TypeUtilities getTypeUtilities() {
330: checkConfinement();
331: if (typeUtilities == null) {
332: typeUtilities = new TypeUtilities(this );
333: }
334: return typeUtilities;
335: }
336:
337: /**
338: * Marks this {@link CompilationInfo} as invalid, may be used to
339: * verify confinement.
340: */
341: final void invalidate() {
342: this .invalid = true;
343: }
344:
345: /**
346: * Checks concurrency confinement.
347: * When {@link VERIFY_CONFINEMENT} is enabled & thread accesses the CompilationInfo
348: * outside guarded run() method the {@link IllegalStateException} is thrown
349: * @throws java.lang.IllegalStateException
350: */
351: final void checkConfinement() throws IllegalStateException {
352: if (VERIFY_CONFINEMENT && this .invalid) {
353: throw new IllegalStateException(
354: String
355: .format(
356: "Access to the shared %s outside a guarded run method.",
357: this.getClass().getSimpleName()));
358: }
359: }
360: }
|