/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html * * 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 com.google.dart.engine.context; import com.google.dart.engine.ast.CompilationUnit; import com.google.dart.engine.constant.DeclaredVariables; import com.google.dart.engine.element.CompilationUnitElement; import com.google.dart.engine.element.Element; import com.google.dart.engine.element.ElementLocation; import com.google.dart.engine.element.HtmlElement; import com.google.dart.engine.element.LibraryElement; import com.google.dart.engine.error.AnalysisError; import com.google.dart.engine.html.ast.HtmlUnit; import com.google.dart.engine.internal.context.TimestampedData; import com.google.dart.engine.internal.element.angular.AngularApplication; import com.google.dart.engine.source.Source; import com.google.dart.engine.source.Source.ContentReceiver; import com.google.dart.engine.source.SourceContainer; import com.google.dart.engine.source.SourceFactory; import com.google.dart.engine.source.SourceKind; import com.google.dart.engine.utilities.source.LineInfo; import com.google.dart.engine.utilities.translation.DartOmit; import java.util.List; /** * The interface {@code AnalysisContext} defines the behavior of objects that represent a context in * which a single analysis can be performed and incrementally maintained. The context includes such * information as the version of the SDK being analyzed against as well as the package-root used to * resolve 'package:' URI's. (Both of which are known indirectly through the {@link SourceFactory * source factory}.) * <p> * An analysis context also represents the state of the analysis, which includes knowing which * sources have been included in the analysis (either directly or indirectly) and the results of the * analysis. Sources must be added and removed from the context using the method * {@link #applyChanges(ChangeSet)}, which is also used to notify the context when sources have been * modified and, consequently, previously known results might have been invalidated. * <p> * There are two ways to access the results of the analysis. The most common is to use one of the * 'get' methods to access the results. The 'get' methods have the advantage that they will always * return quickly, but have the disadvantage that if the results are not currently available they * will return either nothing or in some cases an incomplete result. The second way to access * results is by using one of the 'compute' methods. The 'compute' methods will always attempt to * compute the requested results but might block the caller for a significant period of time. * <p> * When results have been invalidated, have never been computed (as is the case for newly added * sources), or have been removed from the cache, they are <b>not</b> automatically recreated. They * will only be recreated if one of the 'compute' methods is invoked. * <p> * However, this is not always acceptable. Some clients need to keep the analysis results * up-to-date. For such clients there is a mechanism that allows them to incrementally perform * needed analysis and get notified of the consequent changes to the analysis results. This * mechanism is realized by the method {@link #performAnalysisTask()}. * <p> * Analysis engine allows for having more than one context. This can be used, for example, to * perform one analysis based on the state of files on disk and a separate analysis based on the * state of those files in open editors. It can also be used to perform an analysis based on a * proposed future state, such as the state after a refactoring. */ public interface AnalysisContext { /** * Add the given listener to the list of objects that are to be notified when various analysis * results are produced in this context. * * @param listener the listener to be added */ public void addListener(AnalysisListener listener); /** * Apply the given delta to change the level of analysis that will be performed for the sources * known to this context. * * @param delta a description of the level of analysis that should be performed for some sources */ public void applyAnalysisDelta(AnalysisDelta delta); /** * Apply the changes specified by the given change set to this context. Any analysis results that * have been invalidated by these changes will be removed. * * @param changeSet a description of the changes that are to be applied */ public void applyChanges(ChangeSet changeSet); /** * Return the documentation comment for the given element as it appears in the original source * (complete with the beginning and ending delimiters) for block documentation comments, or lines * starting with {@code "///"} and separated with {@code "\n"} characters for end-of-line * documentation comments, or {@code null} if the element does not have a documentation comment * associated with it. This can be a long-running operation if the information needed to access * the comment is not cached. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param element the element whose documentation comment is to be returned * @return the element's documentation comment * @throws AnalysisException if the documentation comment could not be determined because the * analysis could not be performed */ public String computeDocumentationComment(Element element) throws AnalysisException; /** * Return an array containing all of the errors associated with the given source. If the errors * are not already known then the source will be analyzed in order to determine the errors * associated with it. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the source whose errors are to be returned * @return all of the errors associated with the given source * @throws AnalysisException if the errors could not be determined because the analysis could not * be performed * @see #getErrors(Source) */ public AnalysisError[] computeErrors(Source source) throws AnalysisException; /** * Return the element model corresponding to the HTML file defined by the given source. If the * element model does not yet exist it will be created. The process of creating an element model * for an HTML file can be long-running, depending on the size of the file and the number of * libraries that are defined in it (via script tags) that also need to have a model built for * them. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the source defining the HTML file whose element model is to be returned * @return the element model corresponding to the HTML file defined by the given source * @throws AnalysisException if the element model could not be determined because the analysis * could not be performed * @see #getHtmlElement(Source) */ public HtmlElement computeHtmlElement(Source source) throws AnalysisException; /** * Return the kind of the given source, computing it's kind if it is not already known. Return * {@link SourceKind#UNKNOWN} if the source is not contained in this context. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the source whose kind is to be returned * @return the kind of the given source * @see #getKindOf(Source) */ public SourceKind computeKindOf(Source source); /** * Return the element model corresponding to the library defined by the given source. If the * element model does not yet exist it will be created. The process of creating an element model * for a library can long-running, depending on the size of the library and the number of * libraries that are imported into it that also need to have a model built for them. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the source defining the library whose element model is to be returned * @return the element model corresponding to the library defined by the given source * @throws AnalysisException if the element model could not be determined because the analysis * could not be performed * @see #getLibraryElement(Source) */ public LibraryElement computeLibraryElement(Source source) throws AnalysisException; /** * Return the line information for the given source, or {@code null} if the source is not of a * recognized kind (neither a Dart nor HTML file). If the line information was not previously * known it will be created. The line information is used to map offsets from the beginning of the * source to line and column pairs. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the source whose line information is to be returned * @return the line information for the given source * @throws AnalysisException if the line information could not be determined because the analysis * could not be performed * @see #getLineInfo(Source) */ public LineInfo computeLineInfo(Source source) throws AnalysisException; /** * Notifies the context that the client is going to stop using this context. */ public void dispose(); /** * Return {@code true} if the given source exists. * <p> * This method should be used rather than the method {@link Source#exists()} because contexts can * have local overrides of the content of a source that the source is not aware of and a source * with local content is considered to exist even if there is no file on disk. * * @param source the source whose modification stamp is to be returned * @return {@code true} if the source exists */ public boolean exists(Source source); /** * Create a new context in which analysis can be performed. Any sources in the specified container * will be removed from this context and added to the newly created context. * * @param container the container containing sources that should be removed from this context and * added to the returned context * @return the analysis context that was created */ public AnalysisContext extractContext(SourceContainer container); /** * Return the set of analysis options controlling the behavior of this context. Clients should not * modify the returned set of options. The options should only be set by invoking the method * {@link #setAnalysisOptions(AnalysisOptions)}. * * @return the set of analysis options controlling the behavior of this context */ public AnalysisOptions getAnalysisOptions(); /** * Return the Angular application that contains the HTML file defined by the given source, or * {@code null} if the source does not represent an HTML file, the Angular application containing * the file has not yet been resolved, or the analysis of the HTML file failed for some reason. * * @param htmlSource the source defining the HTML file * @return the Angular application that contains the HTML file defined by the given source */ public AngularApplication getAngularApplicationWithHtml(Source htmlSource); /** * Return the element model corresponding to the compilation unit defined by the given source in * the library defined by the given source, or {@code null} if the element model does not * currently exist or if the library cannot be analyzed for some reason. * * @param unitSource the source of the compilation unit * @param librarySource the source of the defining compilation unit of the library containing the * compilation unit * @return the element model corresponding to the compilation unit defined by the given source */ public CompilationUnitElement getCompilationUnitElement(Source unitSource, Source librarySource); /** * Get the contents and timestamp of the given source. * <p> * This method should be used rather than the method {@link Source#getContents()} because contexts * can have local overrides of the content of a source that the source is not aware of. * * @param source the source whose content is to be returned * @return the contents and timestamp of the source * @throws Exception if the contents of the source could not be accessed */ public TimestampedData<CharSequence> getContents(Source source) throws Exception; /** * Get the contents of the given source and pass it to the given content receiver. * <p> * This method should be used rather than the method * {@link Source#getContentsToReceiver(ContentReceiver)} because contexts can have local overrides * of the content of a source that the source is not aware of. * * @param source the source whose content is to be returned * @param receiver the content receiver to which the content of the source will be passed * @throws Exception if the contents of the source could not be accessed */ @Deprecated @DartOmit public void getContentsToReceiver(Source source, ContentReceiver receiver) throws Exception; /** * Return the set of declared variables used when computing constant values. * * @return the set of declared variables used when computing constant values */ public DeclaredVariables getDeclaredVariables(); /** * Return the element referenced by the given location, or {@code null} if the element is not * immediately available or if there is no element with the given location. The latter condition * can occur, for example, if the location describes an element from a different context or if the * element has been removed from this context as a result of some change since it was originally * obtained. * * @param location the reference describing the element to be returned * @return the element referenced by the given location */ public Element getElement(ElementLocation location); /** * Return an analysis error info containing the array of all of the errors and the line info * associated with the given source. The array of errors will be empty if the source is not known * to this context or if there are no errors in the source. The errors contained in the array can * be incomplete. * * @param source the source whose errors are to be returned * @return all of the errors associated with the given source and the line info * @see #computeErrors(Source) */ public AnalysisErrorInfo getErrors(Source source); /** * Return the element model corresponding to the HTML file defined by the given source, or * {@code null} if the source does not represent an HTML file, the element representing the file * has not yet been created, or the analysis of the HTML file failed for some reason. * * @param source the source defining the HTML file whose element model is to be returned * @return the element model corresponding to the HTML file defined by the given source * @see #computeHtmlElement(Source) */ public HtmlElement getHtmlElement(Source source); /** * Return the sources for the HTML files that reference the given compilation unit. If the source * does not represent a Dart source or is not known to this context, the returned array will be * empty. The contents of the array can be incomplete. * * @param source the source referenced by the returned HTML files * @return the sources for the HTML files that reference the given compilation unit */ public Source[] getHtmlFilesReferencing(Source source); /** * Return an array containing all of the sources known to this context that represent HTML files. * The contents of the array can be incomplete. * * @return the sources known to this context that represent HTML files */ public Source[] getHtmlSources(); /** * Return the kind of the given source, or {@code null} if the kind is not known to this context. * * @param source the source whose kind is to be returned * @return the kind of the given source * @see #computeKindOf(Source) */ public SourceKind getKindOf(Source source); /** * Return an array containing all of the sources known to this context that represent the defining * compilation unit of a library that can be run within a browser. The sources that are returned * represent libraries that have a 'main' method and are either referenced by an HTML file or * import, directly or indirectly, a client-only library. The contents of the array can be * incomplete. * * @return the sources known to this context that represent the defining compilation unit of a * library that can be run within a browser */ public Source[] getLaunchableClientLibrarySources(); /** * Return an array containing all of the sources known to this context that represent the defining * compilation unit of a library that can be run outside of a browser. The contents of the array * can be incomplete. * * @return the sources known to this context that represent the defining compilation unit of a * library that can be run outside of a browser */ public Source[] getLaunchableServerLibrarySources(); /** * Return the sources for the defining compilation units of any libraries of which the given * source is a part. The array will normally contain a single library because most Dart sources * are only included in a single library, but it is possible to have a part that is contained in * multiple identically named libraries. If the source represents the defining compilation unit of * a library, then the returned array will contain the given source as its only element. If the * source does not represent a Dart source or is not known to this context, the returned array * will be empty. The contents of the array can be incomplete. * * @param source the source contained in the returned libraries * @return the sources for the libraries containing the given source */ public Source[] getLibrariesContaining(Source source); /** * Return the sources for the defining compilation units of any libraries that depend on the given * library. One library depends on another if it either imports or exports that library. * * @param librarySource the source for the defining compilation unit of the library being depended * on * @return the sources for the libraries that depend on the given library */ public Source[] getLibrariesDependingOn(Source librarySource); /** * Return the sources for the defining compilation units of any libraries that are referenced from * the given HTML file. * * @param htmlSource the source for the HTML file * @return the sources for the libraries that are referenced by the given HTML file */ public Source[] getLibrariesReferencedFromHtml(Source htmlSource); /** * Return the element model corresponding to the library defined by the given source, or * {@code null} if the element model does not currently exist or if the library cannot be analyzed * for some reason. * * @param source the source defining the library whose element model is to be returned * @return the element model corresponding to the library defined by the given source */ public LibraryElement getLibraryElement(Source source); /** * Return an array containing all of the sources known to this context that represent the defining * compilation unit of a library. The contents of the array can be incomplete. * * @return the sources known to this context that represent the defining compilation unit of a * library */ public Source[] getLibrarySources(); /** * Return the line information for the given source, or {@code null} if the line information is * not known. The line information is used to map offsets from the beginning of the source to line * and column pairs. * * @param source the source whose line information is to be returned * @return the line information for the given source * @see #computeLineInfo(Source) */ public LineInfo getLineInfo(Source source); /** * Return the modification stamp for the given source. A modification stamp is a non-negative * integer with the property that if the contents of the source have not been modified since the * last time the modification stamp was accessed then the same value will be returned, but if the * contents of the source have been modified one or more times (even if the net change is zero) * the stamps will be different. * <p> * This method should be used rather than the method {@link Source#getModificationStamp()} because * contexts can have local overrides of the content of a source that the source is not aware of. * * @param source the source whose modification stamp is to be returned * @return the modification stamp for the source */ public long getModificationStamp(Source source); /** * Return an array containing all of the sources known to this context and their resolution state * is not valid or flush. So, these sources are not safe to update during refactoring, because we * may be don't know all the references in them. * * @return the sources known to this context and are not safe for refactoring */ public Source[] getRefactoringUnsafeSources(); /** * Return a fully resolved AST for a single compilation unit within the given library, or * {@code null} if the resolved AST is not already computed. * * @param unitSource the source of the compilation unit * @param library the library containing the compilation unit * @return a fully resolved AST for the compilation unit * @see #resolveCompilationUnit(Source, LibraryElement) */ public CompilationUnit getResolvedCompilationUnit(Source unitSource, LibraryElement library); /** * Return a fully resolved AST for a single compilation unit within the given library, or * {@code null} if the resolved AST is not already computed. * * @param unitSource the source of the compilation unit * @param librarySource the source of the defining compilation unit of the library containing the * compilation unit * @return a fully resolved AST for the compilation unit * @see #resolveCompilationUnit(Source, Source) */ public CompilationUnit getResolvedCompilationUnit(Source unitSource, Source librarySource); /** * Return a fully resolved HTML unit, or {@code null} if the resolved unit is not already * computed. * * @param htmlSource the source of the HTML unit * @return a fully resolved HTML unit * @see #resolveHtmlUnit(Source) */ public HtmlUnit getResolvedHtmlUnit(Source htmlSource); /** * Return the source factory used to create the sources that can be analyzed in this context. * * @return the source factory used to create the sources that can be analyzed in this context */ public SourceFactory getSourceFactory(); /** * Return {@code true} if the given source is known to be the defining compilation unit of a * library that can be run on a client (references 'dart:html', either directly or indirectly). * <p> * <b>Note:</b> In addition to the expected case of returning {@code false} if the source is known * to be a library that cannot be run on a client, this method will also return {@code false} if * the source is not known to be a library or if we do not know whether it can be run on a client. * * @param librarySource the source being tested * @return {@code true} if the given source is known to be a library that can be run on a client */ public boolean isClientLibrary(Source librarySource); /** * Returns {@code true} if this context was disposed using {@link #dispose()}. * * @return {@code true} if this context was disposed */ public boolean isDisposed(); /** * Return {@code true} if the given source is known to be the defining compilation unit of a * library that can be run on the server (does not reference 'dart:html', either directly or * indirectly). * <p> * <b>Note:</b> In addition to the expected case of returning {@code false} if the source is known * to be a library that cannot be run on the server, this method will also return {@code false} if * the source is not known to be a library or if we do not know whether it can be run on the * server. * * @param librarySource the source being tested * @return {@code true} if the given source is known to be a library that can be run on the server */ public boolean isServerLibrary(Source librarySource); /** * Add the sources contained in the specified context to this context's collection of sources. * This method is called when an existing context's pubspec has been removed, and the contained * sources should be reanalyzed as part of this context. * * @param context the context being merged */ public void mergeContext(AnalysisContext context); /** * Parse a single source to produce an AST structure. The resulting AST structure may or may not * be resolved, and may have a slightly different structure depending upon whether it is resolved. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the source to be parsed * @return the AST structure representing the content of the source * @throws AnalysisException if the analysis could not be performed */ public CompilationUnit parseCompilationUnit(Source source) throws AnalysisException; /** * Parse a single HTML source to produce an AST structure. The resulting HTML AST structure may or * may not be resolved, and may have a slightly different structure depending upon whether it is * resolved. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param source the HTML source to be parsed * @return the parse result (not {@code null}) * @throws AnalysisException if the analysis could not be performed */ public HtmlUnit parseHtmlUnit(Source source) throws AnalysisException; /** * Perform the next unit of work required to keep the analysis results up-to-date and return * information about the consequent changes to the analysis results. This method can be long * running. * * @return the results of performing the analysis */ public AnalysisResult performAnalysisTask(); /** * Remove the given listener from the list of objects that are to be notified when various * analysis results are produced in this context. * * @param listener the listener to be removed */ public void removeListener(AnalysisListener listener); /** * Parse and resolve a single source within the given context to produce a fully resolved AST. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param unitSource the source to be parsed and resolved * @param library the library containing the source to be resolved * @return the result of resolving the AST structure representing the content of the source in the * context of the given library * @throws AnalysisException if the analysis could not be performed * @see #getResolvedCompilationUnit(Source, LibraryElement) */ public CompilationUnit resolveCompilationUnit(Source unitSource, LibraryElement library) throws AnalysisException; /** * Parse and resolve a single source within the given context to produce a fully resolved AST. * Return the resolved AST structure, or {@code null} if the source could not be either parsed or * resolved. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param unitSource the source to be parsed and resolved * @param librarySource the source of the defining compilation unit of the library containing the * source to be resolved * @return the result of resolving the AST structure representing the content of the source in the * context of the given library * @throws AnalysisException if the analysis could not be performed * @see #getResolvedCompilationUnit(Source, Source) */ public CompilationUnit resolveCompilationUnit(Source unitSource, Source librarySource) throws AnalysisException; /** * Parse and resolve a single source within the given context to produce a fully resolved AST. * <p> * <b>Note:</b> This method cannot be used in an async environment. * * @param htmlSource the source to be parsed and resolved * @return the result of resolving the AST structure representing the content of the source * @throws AnalysisException if the analysis could not be performed */ public HtmlUnit resolveHtmlUnit(Source htmlSource) throws AnalysisException; /** * Set the set of analysis options controlling the behavior of this context to the given options. * Clients can safely assume that all necessary analysis results have been invalidated. * * @param options the set of analysis options that will control the behavior of this context */ public void setAnalysisOptions(AnalysisOptions options); /** * Set the order in which sources will be analyzed by {@link #performAnalysisTask()} to match the * order of the sources in the given list. If a source that needs to be analyzed is not contained * in the list, then it will be treated as if it were at the end of the list. If the list is empty * (or {@code null}) then no sources will be given priority over other sources. * <p> * Changes made to the list after this method returns will <b>not</b> be reflected in the priority * order. * * @param sources the sources to be given priority over other sources */ public void setAnalysisPriorityOrder(List<Source> sources); /** * Set the contents of the given source to the given contents and mark the source as having * changed. The additional offset and length information is used by the context to determine what * reanalysis is necessary. * * @param source the source whose contents are being overridden * @param contents the text to replace the range in the current contents * @param offset the offset into the current contents * @param oldLength the number of characters in the original contents that were replaced * @param newLength the number of characters in the replacement text */ public void setChangedContents(Source source, String contents, int offset, int oldLength, int newLength); /** * Set the contents of the given source to the given contents and mark the source as having * changed. This has the effect of overriding the default contents of the source. If the contents * are {@code null} the override is removed so that the default contents will be returned. * * @param source the source whose contents are being overridden * @param contents the new contents of the source */ public void setContents(Source source, String contents); /** * Set the source factory used to create the sources that can be analyzed in this context to the * given source factory. Clients can safely assume that all analysis results have been * invalidated. * * @param factory the source factory used to create the sources that can be analyzed in this * context */ public void setSourceFactory(SourceFactory factory); }