blob: 603223ba17174db04cbb36a57fbdabc1472e8456 [file] [log] [blame]
// This code was auto-generated, is not intended to be edited, and is subject to
// significant change. Please see the README file for more information.
library engine;
import 'java_core.dart';
import 'java_engine.dart';
import 'utilities_collection.dart';
import 'utilities_general.dart';
import 'instrumentation.dart';
import 'error.dart';
import 'source.dart';
import 'scanner.dart' show Token, CharBufferScanner, StringScanner;
import 'ast.dart';
import 'parser.dart' show Parser;
import 'sdk.dart' show DartSdk;
import 'element.dart';
import 'resolver.dart';
import 'html.dart' show XmlTagNode, XmlAttributeNode, RecursiveXmlVisitor, HtmlScanner, HtmlScanResult, HtmlParser, HtmlParseResult, HtmlUnit;
/**
* The unique instance of the class `AnalysisEngine` serves as the entry point for the
* functionality provided by the analysis engine.
*
* @coverage dart.engine
*/
class AnalysisEngine {
/**
* The suffix used for Dart source files.
*/
static String SUFFIX_DART = "dart";
/**
* The short suffix used for HTML files.
*/
static String SUFFIX_HTM = "htm";
/**
* The long suffix used for HTML files.
*/
static String SUFFIX_HTML = "html";
/**
* The unique instance of this class.
*/
static final AnalysisEngine instance = new AnalysisEngine();
/**
* Return `true` if the given file name is assumed to contain Dart source code.
*
* @param fileName the name of the file being tested
* @return `true` if the given file name is assumed to contain Dart source code
*/
static bool isDartFileName(String fileName) {
if (fileName == null) {
return false;
}
return javaStringEqualsIgnoreCase(FileNameUtilities.getExtension(fileName), SUFFIX_DART);
}
/**
* Return `true` if the given file name is assumed to contain HTML.
*
* @param fileName the name of the file being tested
* @return `true` if the given file name is assumed to contain HTML
*/
static bool isHtmlFileName(String fileName) {
if (fileName == null) {
return false;
}
String extension = FileNameUtilities.getExtension(fileName);
return javaStringEqualsIgnoreCase(extension, SUFFIX_HTML) || javaStringEqualsIgnoreCase(extension, SUFFIX_HTM);
}
/**
* The logger that should receive information about errors within the analysis engine.
*/
Logger _logger = Logger.NULL;
/**
* Create a new context in which analysis can be performed.
*
* @return the analysis context that was created
*/
AnalysisContext createAnalysisContext() {
if (Instrumentation.isNullLogger) {
return new DelegatingAnalysisContextImpl();
}
return new InstrumentedAnalysisContextImpl.con1(new DelegatingAnalysisContextImpl());
}
/**
* Return the logger that should receive information about errors within the analysis engine.
*
* @return the logger that should receive information about errors within the analysis engine
*/
Logger get logger => _logger;
/**
* Set the logger that should receive information about errors within the analysis engine to the
* given logger.
*
* @param logger the logger that should receive information about errors within the analysis
* engine
*/
void set logger(Logger logger) {
this._logger = logger == null ? Logger.NULL : logger;
}
}
/**
* Container with statistics about the [AnalysisContext].
*/
abstract class AnalysisContentStatistics {
/**
* Return the exceptions that caused some entries to have a state of [CacheState#ERROR].
*
* @return the exceptions that caused some entries to have a state of [CacheState#ERROR]
*/
List<AnalysisException> get exceptions;
/**
* Return the statistics for each kind of cached data.
*
* @return the statistics for each kind of cached data
*/
List<AnalysisContentStatistics_CacheRow> get cacheRows;
}
/**
* Information about single item in the cache.
*/
abstract class AnalysisContentStatistics_CacheRow {
int get errorCount;
int get flushedCount;
int get inProcessCount;
int get invalidCount;
String get name;
int get validCount;
}
/**
* The interface `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 [SourceFactory
].)
*
* 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
* [applyChanges], which is also used to notify the context when sources have been
* modified and, consequently, previously known results might have been invalidated.
*
* 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.
*
* 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.
*
* 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 [performAnalysisTask].
*
* 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.
*/
abstract class AnalysisContext {
/**
* 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
*/
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), or `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.
*
* @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
*/
String computeDocumentationComment(Element element);
/**
* 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.
*
* @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)
*/
List<AnalysisError> computeErrors(Source source);
/**
* 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 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.
*
* @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)
*/
HtmlElement computeHtmlElement(Source source);
/**
* Return the kind of the given source, computing it's kind if it is not already known. Return
* [SourceKind#UNKNOWN] if the source is not contained in this context.
*
* @param source the source whose kind is to be returned
* @return the kind of the given source
* @see #getKindOf(Source)
*/
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.
*
* @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)
*/
LibraryElement computeLibraryElement(Source source);
/**
* Return the line information for the given source, or `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.
*
* @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)
*/
LineInfo computeLineInfo(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
*/
AnalysisContext extractContext(SourceContainer container);
/**
* Return the set of analysis options controlling the behavior of this context.
*
* @return the set of analysis options controlling the behavior of this context
*/
AnalysisOptions get analysisOptions;
/**
* Return the element referenced by the given location, or `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
*/
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)
*/
AnalysisErrorInfo getErrors(Source source);
/**
* Return the element model corresponding to the HTML file defined by the given source, or
* `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)
*/
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
*/
List<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
*/
List<Source> get htmlSources;
/**
* Return the kind of the given source, or `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)
*/
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
*/
List<Source> get launchableClientLibrarySources;
/**
* 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
*/
List<Source> get launchableServerLibrarySources;
/**
* 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
*/
List<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
*/
List<Source> getLibrariesDependingOn(Source librarySource);
/**
* Return the element model corresponding to the library defined by the given source, or
* `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
*/
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
*/
List<Source> get librarySources;
/**
* Return the line information for the given source, or `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)
*/
LineInfo getLineInfo(Source source);
/**
* Return a fully resolved AST for a single compilation unit within the given library, or
* `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)
*/
CompilationUnit getResolvedCompilationUnit(Source unitSource, LibraryElement library);
/**
* Return a fully resolved AST for a single compilation unit within the given library, or
* `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)
*/
CompilationUnit getResolvedCompilationUnit2(Source unitSource, Source librarySource);
/**
* 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
*/
SourceFactory get sourceFactory;
/**
* Return `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).
*
* <b>Note:</b> In addition to the expected case of returning `false` if the source is known
* to be a library that cannot be run on a client, this method will also return `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 `true` if the given source is known to be a library that can be run on a client
*/
bool isClientLibrary(Source librarySource);
/**
* Return `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).
*
* <b>Note:</b> In addition to the expected case of returning `false` if the source is known
* to be a library that cannot be run on the server, this method will also return `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 `true` if the given source is known to be a library that can be run on the server
*/
bool 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
*/
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.
*
* @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
*/
CompilationUnit parseCompilationUnit(Source source);
/**
* 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.
*
* @param source the HTML source to be parsed
* @return the parse result (not `null`)
* @throws AnalysisException if the analysis could not be performed
*/
HtmlUnit parseHtmlUnit(Source source);
/**
* 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. If there were no results the
* returned array will be empty. If there are no more units of work required, then this method
* returns `null`. This method can be long running.
*
* @return an array containing notices of changes to the analysis results
*/
List<ChangeNotice> performAnalysisTask();
/**
* Parse and resolve a single source within the given context to produce a fully resolved AST.
*
* @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)
*/
CompilationUnit resolveCompilationUnit(Source unitSource, LibraryElement library);
/**
* Parse and resolve a single source within the given context to produce a fully resolved AST.
* Return the resolved AST structure, or `null` if the source could not be either parsed or
* resolved.
*
* @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)
*/
CompilationUnit resolveCompilationUnit2(Source unitSource, Source librarySource);
/**
* Parse and resolve a single source within the given context to produce a fully resolved AST.
*
* @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
*/
HtmlUnit resolveHtmlUnit(Source htmlSource);
/**
* 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
*/
void set analysisOptions(AnalysisOptions options);
/**
* Set the order in which sources will be analyzed by [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 `null`) then no sources will be given priority over other sources.
*
* 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
*/
void set analysisPriorityOrder(List<Source> sources);
/**
* 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 `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
*/
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
*/
void set sourceFactory(SourceFactory factory);
/**
* Given a collection of sources with content that has changed, return an [Iterable]
* identifying the sources that need to be resolved.
*
* @param changedSources an array of sources (not `null`, contains no `null`s)
* @return An iterable returning the sources to be resolved
*/
Iterable<Source> sourcesToResolve(List<Source> changedSources);
}
/**
* The interface `AnalysisErrorInfo` contains the analysis errors and line information for the
* errors.
*/
abstract class AnalysisErrorInfo {
/**
* Return the errors that as a result of the analysis, or `null` if there were no errors.
*
* @return the errors as a result of the analysis
*/
List<AnalysisError> get errors;
/**
* Return the line information associated with the errors, or `null` if there were no
* errors.
*
* @return the line information associated with the errors
*/
LineInfo get lineInfo;
}
/**
* Instances of the class `AnalysisException` represent an exception that occurred during the
* analysis of one or more sources.
*
* @coverage dart.engine
*/
class AnalysisException extends JavaException {
/**
* Initialize a newly created exception.
*/
AnalysisException() : super();
/**
* Initialize a newly created exception to have the given message.
*
* @param message the message associated with the exception
*/
AnalysisException.con1(String message) : super(message);
/**
* Initialize a newly created exception to have the given message and cause.
*
* @param message the message associated with the exception
* @param cause the underlying exception that caused this exception
*/
AnalysisException.con2(String message, Exception cause) : super(message, cause);
/**
* Initialize a newly created exception to have the given cause.
*
* @param cause the underlying exception that caused this exception
*/
AnalysisException.con3(Exception cause) : super.withCause(cause);
}
/**
* The interface `AnalysisOptions` defines the behavior of objects that provide access to a
* set of analysis options used to control the behavior of an analysis context.
*/
abstract class AnalysisOptions {
/**
* Return `true` if analysis is to generate dart2js related hint results.
*
* @return `true` if analysis is to generate dart2js related hint results
*/
bool get dart2jsHint;
/**
* Return `true` if analysis is to generate hint results (e.g. type inference based
* information and pub best practices).
*
* @return `true` if analysis is to generate hint results
*/
bool get hint;
/**
* Return `true` if analysis is to use strict mode. In strict mode, error reporting is based
* exclusively on the static type information.
*
* @return `true` if analysis is to use strict mode
*/
bool get strictMode;
}
/**
* The interface `ChangeNotice` defines the behavior of objects that represent a change to the
* analysis results associated with a given source.
*
* @coverage dart.engine
*/
abstract class ChangeNotice implements AnalysisErrorInfo {
/**
* Return the fully resolved AST that changed as a result of the analysis, or `null` if the
* AST was not changed.
*
* @return the fully resolved AST that changed as a result of the analysis
*/
CompilationUnit get compilationUnit;
/**
* Return the source for which the result is being reported.
*
* @return the source for which the result is being reported
*/
Source get source;
}
/**
* Instances of the class `ChangeSet` indicate what sources have been added, changed, or
* removed.
*
* @coverage dart.engine
*/
class ChangeSet {
/**
* A list containing the sources that have been added.
*/
final List<Source> added3 = new List<Source>();
/**
* A list containing the sources that have been changed.
*/
final List<Source> changed3 = new List<Source>();
/**
* A list containing the sources that have been removed.
*/
final List<Source> removed3 = new List<Source>();
/**
* A list containing the source containers specifying additional sources that have been removed.
*/
final List<SourceContainer> removedContainers = new List<SourceContainer>();
/**
* Record that the specified source has been added and that it's content is the default contents
* of the source.
*
* @param source the source that was added
*/
void added(Source source) {
added3.add(source);
}
/**
* Record that the specified source has been changed and that it's content is the default contents
* of the source.
*
* @param source the source that was changed
*/
void changed(Source source) {
changed3.add(source);
}
/**
* Return `true` if this change set does not contain any changes.
*
* @return `true` if this change set does not contain any changes
*/
bool get isEmpty => added3.isEmpty && changed3.isEmpty && removed3.isEmpty && removedContainers.isEmpty;
/**
* Record that the specified source has been removed.
*
* @param source the source that was removed
*/
void removed(Source source) {
if (source != null) {
removed3.add(source);
}
}
/**
* Record that the specified source container has been removed.
*
* @param container the source container that was removed
*/
void removedContainer(SourceContainer container) {
if (container != null) {
removedContainers.add(container);
}
}
String toString() {
JavaStringBuilder builder = new JavaStringBuilder();
bool needsSeparator = appendSources(builder, added3, false, "added");
needsSeparator = appendSources(builder, changed3, needsSeparator, "changed");
appendSources(builder, removed3, needsSeparator, "removed");
int count = removedContainers.length;
if (count > 0) {
if (removed3.isEmpty) {
if (needsSeparator) {
builder.append("; ");
}
builder.append("removed: from ");
builder.append(count);
builder.append(" containers");
} else {
builder.append(", and more from ");
builder.append(count);
builder.append(" containers");
}
}
return builder.toString();
}
/**
* Append the given sources to the given builder, prefixed with the given label and possibly a
* separator.
*
* @param builder the builder to which the sources are to be appended
* @param sources the sources to be appended
* @param needsSeparator `true` if a separator is needed before the label
* @param label the label used to prefix the sources
* @return `true` if future lists of sources will need a separator
*/
bool appendSources(JavaStringBuilder builder, List<Source> sources, bool needsSeparator, String label) {
if (sources.isEmpty) {
return needsSeparator;
}
if (needsSeparator) {
builder.append("; ");
}
builder.append(label);
String prefix = " ";
for (Source source in sources) {
builder.append(prefix);
builder.append(source.fullName);
prefix = ", ";
}
return true;
}
}
/**
* Instances of the class `AnalysisCache` implement an LRU cache of information related to
* analysis.
*/
class AnalysisCache {
/**
* A table mapping the sources known to the context to the information known about the source.
*/
Map<Source, SourceEntry> _sourceMap = new Map<Source, SourceEntry>();
/**
* The maximum number of sources for which AST structures should be kept in the cache.
*/
int _maxCacheSize = 0;
/**
* A list containing the most recently accessed sources with the most recently used at the end of
* the list. When more sources are added than the maximum allowed then the least recently used
* source will be removed and will have it's cached AST structure flushed.
*/
List<Source> _recentlyUsed;
/**
* An array containing sources for which data should not be flushed.
*/
List<Source> _priorityOrder = Source.EMPTY_ARRAY;
/**
* The number of times that the flushing of information from the cache has been disabled without
* being re-enabled.
*/
int _cacheRemovalCount = 0;
/**
* Initialize a newly created cache to maintain at most the given number of AST structures in the
* cache.
*
* @param maxCacheSize the maximum number of sources for which AST structures should be kept in
* the cache
*/
AnalysisCache(int maxCacheSize) {
this._maxCacheSize = maxCacheSize;
_recentlyUsed = new List<Source>();
}
/**
* Record that the given source was just accessed.
*
* @param source the source that was accessed
*/
void accessed(Source source) {
if (_recentlyUsed.remove(source)) {
_recentlyUsed.add(source);
return;
}
if (_cacheRemovalCount == 0 && _recentlyUsed.length >= _maxCacheSize) {
flushAstFromCache();
}
_recentlyUsed.add(source);
}
/**
* Disable flushing information from the cache until [enableCacheRemoval] has been
* called.
*/
void disableCacheRemoval() {
_cacheRemovalCount++;
}
/**
* Re-enable flushing information from the cache.
*/
void enableCacheRemoval() {
if (_cacheRemovalCount > 0) {
_cacheRemovalCount--;
}
if (_cacheRemovalCount == 0) {
while (_recentlyUsed.length > _maxCacheSize) {
flushAstFromCache();
}
}
}
/**
* Return a collection containing all of the map entries mapping sources to cache entries. Clients
* should not modify the returned collection.
*
* @return a collection containing all of the map entries mapping sources to cache entries
*/
Iterable<MapEntry<Source, SourceEntry>> entrySet() => getMapEntrySet(_sourceMap);
/**
* Return the entry associated with the given source.
*
* @param source the source whose entry is to be returned
* @return the entry associated with the given source
*/
SourceEntry get(Source source) => _sourceMap[source];
/**
* Return an array containing sources for which data should not be flushed.
*
* @return an array containing sources for which data should not be flushed
*/
List<Source> get priorityOrder => _priorityOrder;
/**
* Associate the given entry with the given source.
*
* @param source the source with which the entry is to be associated
* @param entry the entry to be associated with the source
*/
void put(Source source, SourceEntry entry) {
_sourceMap[source] = entry;
}
/**
* Remove all information related to the given source from this cache.
*
* @param source the source to be removed
*/
void remove(Source source) {
_sourceMap.remove(source);
}
/**
* Set the sources for which data should not be flushed to the given array.
*
* @param sources the sources for which data should not be flushed
*/
void set priorityOrder(List<Source> sources) {
_priorityOrder = sources;
}
/**
* Flush one AST structure from the cache.
*/
void flushAstFromCache() {
Source removedSource = removeAstToFlush();
SourceEntry sourceEntry = _sourceMap[removedSource];
if (sourceEntry is HtmlEntry) {
HtmlEntryImpl htmlCopy = ((sourceEntry as HtmlEntry)).writableCopy;
htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED);
_sourceMap[removedSource] = htmlCopy;
} else if (sourceEntry is DartEntry) {
DartEntryImpl dartCopy = ((sourceEntry as DartEntry)).writableCopy;
dartCopy.flushAstStructures();
_sourceMap[removedSource] = dartCopy;
}
}
/**
* Return `true` if the given source is in the array of priority sources.
*
* @return `true` if the given source is in the array of priority sources
*/
bool isPrioritySource(Source source) {
for (Source prioritySource in _priorityOrder) {
if (source == prioritySource) {
return true;
}
}
return false;
}
/**
* Remove and return one source from the list of recently used sources whose AST structure can be
* flushed from the cache. The source that will be returned will be the source that has been
* unreferenced for the longest period of time but that is not a priority for analysis.
*
* @return the source that was removed
*/
Source removeAstToFlush() {
for (int i = 0; i < _recentlyUsed.length; i++) {
Source source = _recentlyUsed[i];
if (!isPrioritySource(source)) {
return _recentlyUsed.removeAt(i);
}
}
AnalysisEngine.instance.logger.logError2("Internal error: The number of priority sources (${_priorityOrder.length}) is greater than the maximum cache size (${_maxCacheSize})", new JavaException());
return _recentlyUsed.removeAt(0);
}
}
/**
* The enumeration `CacheState` defines the possible states of cached data.
*/
class CacheState extends Enum<CacheState> {
/**
* The data is not in the cache and the last time an attempt was made to compute the data an
* exception occurred, making it pointless to attempt.
*
* Valid Transitions:
*
* * [INVALID] if a source was modified that might cause the data to be computable
*
*/
static final CacheState ERROR = new CacheState('ERROR', 0);
/**
* The data is not in the cache because it was flushed from the cache in order to control memory
* usage. If the data is recomputed, results do not need to be reported.
*
* Valid Transitions:
*
* * [IN_PROCESS] if the data is being recomputed
* * [INVALID] if a source was modified that causes the data to need to be recomputed
*
*/
static final CacheState FLUSHED = new CacheState('FLUSHED', 1);
/**
* The data might or might not be in the cache but is in the process of being recomputed.
*
* Valid Transitions:
*
* * [ERROR] if an exception occurred while trying to compute the data
* * [VALID] if the data was successfully computed and stored in the cache
*
*/
static final CacheState IN_PROCESS = new CacheState('IN_PROCESS', 2);
/**
* The data is not in the cache and needs to be recomputed so that results can be reported.
*
* Valid Transitions:
*
* * [IN_PROCESS] if an attempt is being made to recompute the data
*
*/
static final CacheState INVALID = new CacheState('INVALID', 3);
/**
* The data is in the cache and up-to-date.
*
* Valid Transitions:
*
* * [FLUSHED] if the data is removed in order to manage memory usage
* * [INVALID] if a source was modified in such a way as to invalidate the previous data
*
*/
static final CacheState VALID = new CacheState('VALID', 4);
static final List<CacheState> values = [ERROR, FLUSHED, IN_PROCESS, INVALID, VALID];
CacheState(String name, int ordinal) : super(name, ordinal);
}
/**
* The interface `DartEntry` defines the behavior of objects that maintain the information
* cached by an analysis context about an individual Dart file.
*
* @coverage dart.engine
*/
abstract class DartEntry implements SourceEntry {
/**
* The data descriptor representing the library element for the library. This data is only
* available for Dart files that are the defining compilation unit of a library.
*/
static final DataDescriptor<LibraryElement> ELEMENT = new DataDescriptor<LibraryElement>("DartEntry.ELEMENT");
/**
* The data descriptor representing the list of exported libraries. This data is only available
* for Dart files that are the defining compilation unit of a library.
*/
static final DataDescriptor<List<Source>> EXPORTED_LIBRARIES = new DataDescriptor<List<Source>>("DartEntry.EXPORTED_LIBRARIES");
/**
* The data descriptor representing the hints resulting from auditing the source.
*/
static final DataDescriptor<List<AnalysisError>> HINTS = new DataDescriptor<List<AnalysisError>>("DartEntry.HINTS");
/**
* The data descriptor representing the list of imported libraries. This data is only available
* for Dart files that are the defining compilation unit of a library.
*/
static final DataDescriptor<List<Source>> IMPORTED_LIBRARIES = new DataDescriptor<List<Source>>("DartEntry.IMPORTED_LIBRARIES");
/**
* The data descriptor representing the list of included parts. This data is only available for
* Dart files that are the defining compilation unit of a library.
*/
static final DataDescriptor<List<Source>> INCLUDED_PARTS = new DataDescriptor<List<Source>>("DartEntry.INCLUDED_PARTS");
/**
* The data descriptor representing the client flag. This data is only available for Dart files
* that are the defining compilation unit of a library.
*/
static final DataDescriptor<bool> IS_CLIENT = new DataDescriptor<bool>("DartEntry.IS_CLIENT");
/**
* The data descriptor representing the launchable flag. This data is only available for Dart
* files that are the defining compilation unit of a library.
*/
static final DataDescriptor<bool> IS_LAUNCHABLE = new DataDescriptor<bool>("DartEntry.IS_LAUNCHABLE");
/**
* The data descriptor representing the errors resulting from parsing the source.
*/
static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS = new DataDescriptor<List<AnalysisError>>("DartEntry.PARSE_ERRORS");
/**
* The data descriptor representing the parsed AST structure.
*/
static final DataDescriptor<CompilationUnit> PARSED_UNIT = new DataDescriptor<CompilationUnit>("DartEntry.PARSED_UNIT");
/**
* The data descriptor representing the public namespace of the library. This data is only
* available for Dart files that are the defining compilation unit of a library.
*/
static final DataDescriptor<Namespace> PUBLIC_NAMESPACE = new DataDescriptor<Namespace>("DartEntry.PUBLIC_NAMESPACE");
/**
* The data descriptor representing the errors resulting from resolving the source.
*/
static final DataDescriptor<List<AnalysisError>> RESOLUTION_ERRORS = new DataDescriptor<List<AnalysisError>>("DartEntry.RESOLUTION_ERRORS");
/**
* The data descriptor representing the resolved AST structure.
*/
static final DataDescriptor<CompilationUnit> RESOLVED_UNIT = new DataDescriptor<CompilationUnit>("DartEntry.RESOLVED_UNIT");
/**
* The data descriptor representing the source kind.
*/
static final DataDescriptor<SourceKind> SOURCE_KIND = new DataDescriptor<SourceKind>("DartEntry.SOURCE_KIND");
/**
* The data descriptor representing the errors resulting from verifying the source.
*/
static final DataDescriptor<List<AnalysisError>> VERIFICATION_ERRORS = new DataDescriptor<List<AnalysisError>>("DartEntry.VERIFICATION_ERRORS");
/**
* Return all of the errors associated with the compilation unit that are currently cached.
*
* @return all of the errors associated with the compilation unit
*/
List<AnalysisError> get allErrors;
/**
* Return a valid parsed compilation unit, either an unresolved AST structure or the result of
* resolving the AST structure in the context of some library, or `null` if there is no
* parsed compilation unit available.
*
* @return a valid parsed compilation unit
*/
CompilationUnit get anyParsedCompilationUnit;
/**
* Return the result of resolving the compilation unit as part of any library, or `null` if
* there is no cached resolved compilation unit.
*
* @return any resolved compilation unit
*/
CompilationUnit get anyResolvedCompilationUnit;
/**
* Return the state of the data represented by the given descriptor in the context of the given
* library.
*
* @param descriptor the descriptor representing the data whose state is to be returned
* @param librarySource the source of the defining compilation unit of the library that is the
* context for the data
* @return the value of the data represented by the given descriptor and library
*/
CacheState getState2(DataDescriptor descriptor, Source librarySource);
/**
* Return the value of the data represented by the given descriptor in the context of the given
* library, or `null` if the data represented by the descriptor is not in the cache.
*
* @param descriptor the descriptor representing which data is to be returned
* @param librarySource the source of the defining compilation unit of the library that is the
* context for the data
* @return the value of the data represented by the given descriptor and library
*/
Object getValue2(DataDescriptor descriptor, Source librarySource);
DartEntryImpl get writableCopy;
}
/**
* Instances of the class `DartEntryImpl` implement a [DartEntry].
*
* @coverage dart.engine
*/
class DartEntryImpl extends SourceEntryImpl implements DartEntry {
/**
* The state of the cached source kind.
*/
CacheState _sourceKindState = CacheState.INVALID;
/**
* The kind of this source.
*/
SourceKind _sourceKind = SourceKind.UNKNOWN;
/**
* The state of the cached parsed compilation unit.
*/
CacheState _parsedUnitState = CacheState.INVALID;
/**
* A flag indicating whether the parsed AST structure has been accessed since it was set. This is
* used to determine whether the structure needs to be copied before it is resolved.
*/
bool _parsedUnitAccessed = false;
/**
* The parsed compilation unit, or `null` if the parsed compilation unit is not currently
* cached.
*/
CompilationUnit _parsedUnit;
/**
* The state of the cached parse errors.
*/
CacheState _parseErrorsState = CacheState.INVALID;
/**
* The errors produced while scanning and parsing the compilation unit, or `null` if the
* errors are not currently cached.
*/
List<AnalysisError> _parseErrors = AnalysisError.NO_ERRORS;
/**
* The state of the cached list of imported libraries.
*/
CacheState _importedLibrariesState = CacheState.INVALID;
/**
* The list of libraries imported by the library, or an empty array if the list is not currently
* cached. The list will be empty if the Dart file is a part rather than a library.
*/
List<Source> _importedLibraries = Source.EMPTY_ARRAY;
/**
* The state of the cached list of exported libraries.
*/
CacheState _exportedLibrariesState = CacheState.INVALID;
/**
* The list of libraries exported by the library, or an empty array if the list is not currently
* cached. The list will be empty if the Dart file is a part rather than a library.
*/
List<Source> _exportedLibraries = Source.EMPTY_ARRAY;
/**
* The state of the cached list of included parts.
*/
CacheState _includedPartsState = CacheState.INVALID;
/**
* The list of parts included in the library, or an empty array if the list is not currently
* cached. The list will be empty if the Dart file is a part rather than a library.
*/
List<Source> _includedParts = Source.EMPTY_ARRAY;
/**
* The information known as a result of resolving this compilation unit as part of the library
* that contains this unit. This field will never be `null`.
*/
DartEntryImpl_ResolutionState _resolutionState = new DartEntryImpl_ResolutionState();
/**
* The state of the cached library element.
*/
CacheState _elementState = CacheState.INVALID;
/**
* The element representing the library, or `null` if the element is not currently cached.
*/
LibraryElement _element;
/**
* The state of the cached public namespace.
*/
CacheState _publicNamespaceState = CacheState.INVALID;
/**
* The public namespace of the library, or `null` if the namespace is not currently cached.
*/
Namespace _publicNamespace;
/**
* The state of the cached client/ server flag.
*/
CacheState _clientServerState = CacheState.INVALID;
/**
* The state of the cached launchable flag.
*/
CacheState _launchableState = CacheState.INVALID;
/**
* An integer holding bit masks such as [LAUNCHABLE] and [CLIENT_CODE].
*/
int _bitmask = 0;
/**
* The index of the bit in the [bitmask] indicating that this library is launchable: that
* the file has a main method.
*/
static int _LAUNCHABLE_INDEX = 1;
/**
* The index of the bit in the [bitmask] indicating that the library is client code: that
* the library depends on the html library. If the library is not "client code", then it is
* referred to as "server code".
*/
static int _CLIENT_CODE_INDEX = 2;
/**
* Flush any AST structures being maintained by this entry.
*/
void flushAstStructures() {
if (identical(_parsedUnitState, CacheState.VALID)) {
_parsedUnitState = CacheState.FLUSHED;
_parsedUnitAccessed = false;
_parsedUnit = null;
}
_resolutionState.flushAstStructures();
}
List<AnalysisError> get allErrors {
List<AnalysisError> errors = new List<AnalysisError>();
for (AnalysisError error in _parseErrors) {
errors.add(error);
}
DartEntryImpl_ResolutionState state = _resolutionState;
while (state != null) {
for (AnalysisError error in state._resolutionErrors) {
errors.add(error);
}
for (AnalysisError error in state._verificationErrors) {
errors.add(error);
}
for (AnalysisError error in state._hints) {
errors.add(error);
}
state = state._nextState;
}
;
if (errors.length == 0) {
return AnalysisError.NO_ERRORS;
}
return new List.from(errors);
}
CompilationUnit get anyParsedCompilationUnit {
if (identical(_parsedUnitState, CacheState.VALID)) {
_parsedUnitAccessed = true;
return _parsedUnit;
}
return anyResolvedCompilationUnit;
}
CompilationUnit get anyResolvedCompilationUnit {
DartEntryImpl_ResolutionState state = _resolutionState;
while (state != null) {
if (identical(state._resolvedUnitState, CacheState.VALID)) {
return state._resolvedUnit;
}
state = state._nextState;
}
;
return null;
}
SourceKind get kind => _sourceKind;
/**
* Return a compilation unit that has not been accessed by any other client and can therefore
* safely be modified by the reconciler.
*
* @return a compilation unit that can be modified by the reconciler
*/
CompilationUnit get resolvableCompilationUnit {
if (identical(_parsedUnitState, CacheState.VALID)) {
if (_parsedUnitAccessed) {
return _parsedUnit.accept(new ASTCloner()) as CompilationUnit;
}
CompilationUnit unit = _parsedUnit;
_parsedUnitState = CacheState.FLUSHED;
_parsedUnitAccessed = false;
_parsedUnit = null;
return unit;
}
DartEntryImpl_ResolutionState state = _resolutionState;
while (state != null) {
if (identical(state._resolvedUnitState, CacheState.VALID)) {
return state._resolvedUnit.accept(new ASTCloner()) as CompilationUnit;
}
state = state._nextState;
}
;
return null;
}
CacheState getState(DataDescriptor descriptor) {
if (identical(descriptor, DartEntry.ELEMENT)) {
return _elementState;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
return _exportedLibrariesState;
} else if (identical(descriptor, DartEntry.IMPORTED_LIBRARIES)) {
return _importedLibrariesState;
} else if (identical(descriptor, DartEntry.INCLUDED_PARTS)) {
return _includedPartsState;
} else if (identical(descriptor, DartEntry.IS_CLIENT)) {
return _clientServerState;
} else if (identical(descriptor, DartEntry.IS_LAUNCHABLE)) {
return _launchableState;
} else if (identical(descriptor, DartEntry.PARSE_ERRORS)) {
return _parseErrorsState;
} else if (identical(descriptor, DartEntry.PARSED_UNIT)) {
return _parsedUnitState;
} else if (identical(descriptor, DartEntry.PUBLIC_NAMESPACE)) {
return _publicNamespaceState;
} else if (identical(descriptor, DartEntry.SOURCE_KIND)) {
return _sourceKindState;
} else {
return super.getState(descriptor);
}
}
CacheState getState2(DataDescriptor descriptor, Source librarySource) {
DartEntryImpl_ResolutionState state = _resolutionState;
while (state != null) {
if (librarySource == state._librarySource) {
if (identical(descriptor, DartEntry.RESOLUTION_ERRORS)) {
return state._resolutionErrorsState;
} else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
return state._resolvedUnitState;
} else if (identical(descriptor, DartEntry.VERIFICATION_ERRORS)) {
return state._verificationErrorsState;
} else if (identical(descriptor, DartEntry.HINTS)) {
return state._hintsState;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
state = state._nextState;
}
;
if (identical(descriptor, DartEntry.RESOLUTION_ERRORS) || identical(descriptor, DartEntry.RESOLVED_UNIT) || identical(descriptor, DartEntry.VERIFICATION_ERRORS) || identical(descriptor, DartEntry.HINTS)) {
return CacheState.INVALID;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
Object getValue(DataDescriptor descriptor) {
if (identical(descriptor, DartEntry.ELEMENT)) {
return _element as Object;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
return _exportedLibraries as Object;
} else if (identical(descriptor, DartEntry.IMPORTED_LIBRARIES)) {
return _importedLibraries as Object;
} else if (identical(descriptor, DartEntry.INCLUDED_PARTS)) {
return _includedParts as Object;
} else if (identical(descriptor, DartEntry.IS_CLIENT)) {
return (BooleanArray.get2(_bitmask, _CLIENT_CODE_INDEX) as bool) as Object;
} else if (identical(descriptor, DartEntry.IS_LAUNCHABLE)) {
return (BooleanArray.get2(_bitmask, _LAUNCHABLE_INDEX) as bool) as Object;
} else if (identical(descriptor, DartEntry.PARSE_ERRORS)) {
return _parseErrors as Object;
} else if (identical(descriptor, DartEntry.PARSED_UNIT)) {
_parsedUnitAccessed = true;
return _parsedUnit as Object;
} else if (identical(descriptor, DartEntry.PUBLIC_NAMESPACE)) {
return _publicNamespace as Object;
} else if (identical(descriptor, DartEntry.SOURCE_KIND)) {
return _sourceKind as Object;
}
return super.getValue(descriptor);
}
Object getValue2(DataDescriptor descriptor, Source librarySource) {
DartEntryImpl_ResolutionState state = _resolutionState;
while (state != null) {
if (librarySource == state._librarySource) {
if (identical(descriptor, DartEntry.RESOLUTION_ERRORS)) {
return state._resolutionErrors as Object;
} else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
return state._resolvedUnit as Object;
} else if (identical(descriptor, DartEntry.VERIFICATION_ERRORS)) {
return state._verificationErrors as Object;
} else if (identical(descriptor, DartEntry.HINTS)) {
return state._hints as Object;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
state = state._nextState;
}
;
if (identical(descriptor, DartEntry.RESOLUTION_ERRORS) || identical(descriptor, DartEntry.VERIFICATION_ERRORS) || identical(descriptor, DartEntry.HINTS)) {
return AnalysisError.NO_ERRORS as Object;
} else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
return null;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
DartEntryImpl get writableCopy {
DartEntryImpl copy = new DartEntryImpl();
copy.copyFrom(this);
return copy;
}
/**
* Invalidate all of the information associated with the compilation unit.
*/
void invalidateAllInformation() {
setState(SourceEntry.LINE_INFO, CacheState.INVALID);
_sourceKind = SourceKind.UNKNOWN;
_sourceKindState = CacheState.INVALID;
_parseErrors = AnalysisError.NO_ERRORS;
_parseErrorsState = CacheState.INVALID;
_parsedUnit = null;
_parsedUnitAccessed = false;
_parsedUnitState = CacheState.INVALID;
invalidateAllResolutionInformation();
}
/**
* Invalidate all of the resolution information associated with the compilation unit.
*/
void invalidateAllResolutionInformation() {
_element = null;
_elementState = CacheState.INVALID;
_includedParts = Source.EMPTY_ARRAY;
_includedPartsState = CacheState.INVALID;
_exportedLibraries = Source.EMPTY_ARRAY;
_exportedLibrariesState = CacheState.INVALID;
_importedLibraries = Source.EMPTY_ARRAY;
_importedLibrariesState = CacheState.INVALID;
_bitmask = 0;
_clientServerState = CacheState.INVALID;
_launchableState = CacheState.INVALID;
_publicNamespace = null;
_publicNamespaceState = CacheState.INVALID;
_resolutionState.invalidateAllResolutionInformation();
}
/**
* Record that an error occurred while attempting to scan or parse the entry represented by this
* entry. This will set the state of all information, including any resolution-based information,
* as being in error.
*/
void recordParseError() {
setState(SourceEntry.LINE_INFO, CacheState.ERROR);
_sourceKind = SourceKind.UNKNOWN;
_sourceKindState = CacheState.ERROR;
_parseErrors = AnalysisError.NO_ERRORS;
_parseErrorsState = CacheState.ERROR;
_parsedUnit = null;
_parsedUnitAccessed = false;
_parsedUnitState = CacheState.ERROR;
_exportedLibraries = Source.EMPTY_ARRAY;
_exportedLibrariesState = CacheState.ERROR;
_importedLibraries = Source.EMPTY_ARRAY;
_importedLibrariesState = CacheState.ERROR;
_includedParts = Source.EMPTY_ARRAY;
_includedPartsState = CacheState.ERROR;
recordResolutionError();
}
/**
* Record that the parse-related information for the associated source is about to be computed by
* the current thread.
*/
void recordParseInProcess() {
if (getState(SourceEntry.LINE_INFO) != CacheState.VALID) {
setState(SourceEntry.LINE_INFO, CacheState.IN_PROCESS);
}
if (_sourceKindState != CacheState.VALID) {
_sourceKindState = CacheState.IN_PROCESS;
}
if (_parseErrorsState != CacheState.VALID) {
_parseErrorsState = CacheState.IN_PROCESS;
}
if (_parsedUnitState != CacheState.VALID) {
_parsedUnitState = CacheState.IN_PROCESS;
}
if (_exportedLibrariesState != CacheState.VALID) {
_exportedLibrariesState = CacheState.IN_PROCESS;
}
if (_importedLibrariesState != CacheState.VALID) {
_importedLibrariesState = CacheState.IN_PROCESS;
}
if (_includedPartsState != CacheState.VALID) {
_includedPartsState = CacheState.IN_PROCESS;
}
}
/**
* Record that an in-process parse has stopped without recording results because the results were
* invalidated before they could be recorded.
*/
void recordParseNotInProcess() {
if (identical(getState(SourceEntry.LINE_INFO), CacheState.IN_PROCESS)) {
setState(SourceEntry.LINE_INFO, CacheState.INVALID);
}
if (identical(_sourceKindState, CacheState.IN_PROCESS)) {
_sourceKindState = CacheState.INVALID;
}
if (identical(_parseErrorsState, CacheState.IN_PROCESS)) {
_parseErrorsState = CacheState.INVALID;
}
if (identical(_parsedUnitState, CacheState.IN_PROCESS)) {
_parsedUnitState = CacheState.INVALID;
}
if (identical(_exportedLibrariesState, CacheState.IN_PROCESS)) {
_exportedLibrariesState = CacheState.INVALID;
}
if (identical(_importedLibrariesState, CacheState.IN_PROCESS)) {
_importedLibrariesState = CacheState.INVALID;
}
if (identical(_includedPartsState, CacheState.IN_PROCESS)) {
_includedPartsState = CacheState.INVALID;
}
}
/**
* Record that an error occurred while attempting to scan or parse the entry represented by this
* entry. This will set the state of all resolution-based information as being in error, but will
* not change the state of any parse results.
*/
void recordResolutionError() {
_element = null;
_elementState = CacheState.ERROR;
_bitmask = 0;
_clientServerState = CacheState.ERROR;
_launchableState = CacheState.ERROR;
_publicNamespace = null;
_publicNamespaceState = CacheState.ERROR;
_resolutionState.recordResolutionError();
}
/**
* Record that an in-process parse has stopped without recording results because the results were
* invalidated before they could be recorded.
*/
void recordResolutionNotInProcess() {
if (identical(_elementState, CacheState.IN_PROCESS)) {
_elementState = CacheState.INVALID;
}
if (identical(_clientServerState, CacheState.IN_PROCESS)) {
_clientServerState = CacheState.INVALID;
}
if (identical(_launchableState, CacheState.IN_PROCESS)) {
_launchableState = CacheState.INVALID;
}
if (identical(_publicNamespaceState, CacheState.IN_PROCESS)) {
_publicNamespaceState = CacheState.INVALID;
}
_resolutionState.recordResolutionNotInProcess();
}
/**
* Remove any resolution information associated with this compilation unit being part of the given
* library, presumably because it is no longer part of the library.
*
* @param librarySource the source of the defining compilation unit of the library that used to
* contain this part but no longer does
*/
void removeResolution(Source librarySource) {
if (librarySource != null) {
if (librarySource == _resolutionState._librarySource) {
if (_resolutionState._nextState == null) {
_resolutionState.invalidateAllResolutionInformation();
} else {
_resolutionState = _resolutionState._nextState;
}
} else {
DartEntryImpl_ResolutionState priorState = _resolutionState;
DartEntryImpl_ResolutionState state = _resolutionState._nextState;
while (state != null) {
if (librarySource == state._librarySource) {
priorState._nextState = state._nextState;
break;
}
priorState = state;
state = state._nextState;
}
}
}
}
/**
* Set the results of parsing the compilation unit at the given time to the given values.
*
* @param modificationStamp the earliest time at which the source was last modified before the
* parsing was started
* @param lineInfo the line information resulting from parsing the compilation unit
* @param unit the AST structure resulting from parsing the compilation unit
* @param errors the parse errors resulting from parsing the compilation unit
*/
void setParseResults(int modificationStamp, LineInfo lineInfo, CompilationUnit unit, List<AnalysisError> errors) {
if (getState(SourceEntry.LINE_INFO) != CacheState.VALID) {
setValue(SourceEntry.LINE_INFO, lineInfo);
}
if (_parsedUnitState != CacheState.VALID) {
_parsedUnit = unit;
_parsedUnitAccessed = false;
_parsedUnitState = CacheState.VALID;
}
if (_parseErrorsState != CacheState.VALID) {
_parseErrors = errors == null ? AnalysisError.NO_ERRORS : errors;
_parseErrorsState = CacheState.VALID;
}
}
void setState(DataDescriptor descriptor, CacheState state) {
if (identical(descriptor, DartEntry.ELEMENT)) {
_element = updatedValue(state, _element, null);
_elementState = state;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
_exportedLibraries = updatedValue(state, _exportedLibraries, Source.EMPTY_ARRAY);
_exportedLibrariesState = state;
} else if (identical(descriptor, DartEntry.IMPORTED_LIBRARIES)) {
_importedLibraries = updatedValue(state, _importedLibraries, Source.EMPTY_ARRAY);
_importedLibrariesState = state;
} else if (identical(descriptor, DartEntry.INCLUDED_PARTS)) {
_includedParts = updatedValue(state, _includedParts, Source.EMPTY_ARRAY);
_includedPartsState = state;
} else if (identical(descriptor, DartEntry.IS_CLIENT)) {
_bitmask = updatedValue2(state, _bitmask, _CLIENT_CODE_INDEX);
_clientServerState = state;
} else if (identical(descriptor, DartEntry.IS_LAUNCHABLE)) {
_bitmask = updatedValue2(state, _bitmask, _LAUNCHABLE_INDEX);
_launchableState = state;
} else if (identical(descriptor, DartEntry.PARSE_ERRORS)) {
_parseErrors = updatedValue(state, _parseErrors, AnalysisError.NO_ERRORS);
_parseErrorsState = state;
} else if (identical(descriptor, DartEntry.PARSED_UNIT)) {
CompilationUnit newUnit = updatedValue(state, _parsedUnit, null);
if (newUnit != _parsedUnit) {
_parsedUnitAccessed = false;
}
_parsedUnit = newUnit;
_parsedUnitState = state;
} else if (identical(descriptor, DartEntry.PUBLIC_NAMESPACE)) {
_publicNamespace = updatedValue(state, _publicNamespace, null);
_publicNamespaceState = state;
} else if (identical(descriptor, DartEntry.SOURCE_KIND)) {
_sourceKind = updatedValue(state, _sourceKind, SourceKind.UNKNOWN);
_sourceKindState = state;
} else {
super.setState(descriptor, state);
}
}
/**
* Set the state of the data represented by the given descriptor in the context of the given
* library to the given state.
*
* @param descriptor the descriptor representing the data whose state is to be set
* @param librarySource the source of the defining compilation unit of the library that is the
* context for the data
* @param cacheState the new state of the data represented by the given descriptor
*/
void setState2(DataDescriptor descriptor, Source librarySource, CacheState cacheState) {
DartEntryImpl_ResolutionState state = getOrCreateResolutionState(librarySource);
if (identical(descriptor, DartEntry.RESOLUTION_ERRORS)) {
state._resolutionErrors = updatedValue(cacheState, state._resolutionErrors, AnalysisError.NO_ERRORS);
state._resolutionErrorsState = cacheState;
} else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
state._resolvedUnit = updatedValue(cacheState, state._resolvedUnit, null);
state._resolvedUnitState = cacheState;
} else if (identical(descriptor, DartEntry.VERIFICATION_ERRORS)) {
state._verificationErrors = updatedValue(cacheState, state._verificationErrors, AnalysisError.NO_ERRORS);
state._verificationErrorsState = cacheState;
} else if (identical(descriptor, DartEntry.HINTS)) {
state._hints = updatedValue(cacheState, state._hints, AnalysisError.NO_ERRORS);
state._hintsState = cacheState;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
void setValue(DataDescriptor descriptor, Object value) {
if (identical(descriptor, DartEntry.ELEMENT)) {
_element = value as LibraryElement;
_elementState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
_exportedLibraries = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
_exportedLibrariesState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.IMPORTED_LIBRARIES)) {
_importedLibraries = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
_importedLibrariesState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.INCLUDED_PARTS)) {
_includedParts = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
_includedPartsState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.IS_CLIENT)) {
_bitmask = BooleanArray.set2(_bitmask, _CLIENT_CODE_INDEX, value as bool);
_clientServerState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.IS_LAUNCHABLE)) {
_bitmask = BooleanArray.set2(_bitmask, _LAUNCHABLE_INDEX, value as bool);
_launchableState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.PARSE_ERRORS)) {
_parseErrors = value == null ? AnalysisError.NO_ERRORS : (value as List<AnalysisError>);
_parseErrorsState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.PARSED_UNIT)) {
_parsedUnit = value as CompilationUnit;
_parsedUnitAccessed = false;
_parsedUnitState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.PUBLIC_NAMESPACE)) {
_publicNamespace = value as Namespace;
_publicNamespaceState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.SOURCE_KIND)) {
_sourceKind = value as SourceKind;
_sourceKindState = CacheState.VALID;
} else {
super.setValue(descriptor, value);
}
}
/**
* Set the value of the data represented by the given descriptor in the context of the given
* library to the given value, and set the state of that data to [CacheState#VALID].
*
* @param descriptor the descriptor representing which data is to have its value set
* @param librarySource the source of the defining compilation unit of the library that is the
* context for the data
* @param value the new value of the data represented by the given descriptor and library
*/
void setValue2(DataDescriptor descriptor, Source librarySource, Object value) {
DartEntryImpl_ResolutionState state = getOrCreateResolutionState(librarySource);
if (identical(descriptor, DartEntry.RESOLUTION_ERRORS)) {
state._resolutionErrors = value == null ? AnalysisError.NO_ERRORS : (value as List<AnalysisError>);
state._resolutionErrorsState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
state._resolvedUnit = value as CompilationUnit;
state._resolvedUnitState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.VERIFICATION_ERRORS)) {
state._verificationErrors = value == null ? AnalysisError.NO_ERRORS : (value as List<AnalysisError>);
state._verificationErrorsState = CacheState.VALID;
} else if (identical(descriptor, DartEntry.HINTS)) {
state._hints = value == null ? AnalysisError.NO_ERRORS : (value as List<AnalysisError>);
state._hintsState = CacheState.VALID;
}
}
void copyFrom(SourceEntryImpl entry) {
super.copyFrom(entry);
DartEntryImpl other = entry as DartEntryImpl;
_sourceKindState = other._sourceKindState;
_sourceKind = other._sourceKind;
_parsedUnitState = other._parsedUnitState;
_parsedUnit = other._parsedUnit;
_parsedUnitAccessed = other._parsedUnitAccessed;
_parseErrorsState = other._parseErrorsState;
_parseErrors = other._parseErrors;
_includedPartsState = other._includedPartsState;
_includedParts = other._includedParts;
_exportedLibrariesState = other._exportedLibrariesState;
_exportedLibraries = other._exportedLibraries;
_importedLibrariesState = other._importedLibrariesState;
_importedLibraries = other._importedLibraries;
_resolutionState.copyFrom(other._resolutionState);
_elementState = other._elementState;
_element = other._element;
_publicNamespaceState = other._publicNamespaceState;
_publicNamespace = other._publicNamespace;
_clientServerState = other._clientServerState;
_launchableState = other._launchableState;
_bitmask = other._bitmask;
}
void writeOn(JavaStringBuilder builder) {
builder.append("Dart: ");
super.writeOn(builder);
builder.append("; sourceKind = ");
builder.append(_sourceKindState);
builder.append("; parsedUnit = ");
builder.append(_parsedUnitState);
builder.append(" (");
builder.append(_parsedUnitAccessed ? "T" : "F");
builder.append("); parseErrors = ");
builder.append(_parseErrorsState);
builder.append("; exportedLibraries = ");
builder.append(_exportedLibrariesState);
builder.append("; importedLibraries = ");
builder.append(_importedLibrariesState);
builder.append("; includedParts = ");
builder.append(_includedPartsState);
builder.append("; element = ");
builder.append(_elementState);
builder.append("; publicNamespace = ");
builder.append(_publicNamespaceState);
builder.append("; clientServer = ");
builder.append(_clientServerState);
builder.append("; launchable = ");
builder.append(_launchableState);
_resolutionState.writeOn(builder);
}
/**
* Return a resolution state for the specified library, creating one as necessary.
*
* @param librarySource the library source (not `null`)
* @return the resolution state (not `null`)
*/
DartEntryImpl_ResolutionState getOrCreateResolutionState(Source librarySource) {
DartEntryImpl_ResolutionState state = _resolutionState;
if (state._librarySource == null) {
state._librarySource = librarySource;
return state;
}
while (state._librarySource != librarySource) {
if (state._nextState == null) {
DartEntryImpl_ResolutionState newState = new DartEntryImpl_ResolutionState();
newState._librarySource = librarySource;
state._nextState = newState;
return newState;
}
state = state._nextState;
}
return state;
}
/**
* Given that one of the flags is being transitioned to the given state, return the value of the
* flags that should be kept in the cache.
*
* @param state the state to which the data is being transitioned
* @param currentValue the value of the flags before the transition
* @param bitMask the mask used to access the bit whose state is being set
* @return the value of the data that should be kept in the cache
*/
int updatedValue2(CacheState state, int currentValue, int bitIndex) {
if (identical(state, CacheState.VALID)) {
throw new IllegalArgumentException("Use setValue() to set the state to VALID");
} else if (identical(state, CacheState.IN_PROCESS)) {
return currentValue;
}
return BooleanArray.set2(currentValue, bitIndex, false);
}
}
/**
* Instances of the class `ResolutionState` represent the information produced by resolving
* a compilation unit as part of a specific library.
*/
class DartEntryImpl_ResolutionState {
/**
* The next resolution state or `null` if none.
*/
DartEntryImpl_ResolutionState _nextState;
/**
* The source for the defining compilation unit of the library that contains this unit. If this
* unit is the defining compilation unit for it's library, then this will be the source for this
* unit.
*/
Source _librarySource;
/**
* The state of the cached resolved compilation unit.
*/
CacheState _resolvedUnitState = CacheState.INVALID;
/**
* The resolved compilation unit, or `null` if the resolved compilation unit is not
* currently cached.
*/
CompilationUnit _resolvedUnit;
/**
* The state of the cached resolution errors.
*/
CacheState _resolutionErrorsState = CacheState.INVALID;
/**
* The errors produced while resolving the compilation unit, or an empty array if the errors are
* not currently cached.
*/
List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
/**
* The state of the cached verification errors.
*/
CacheState _verificationErrorsState = CacheState.INVALID;
/**
* The errors produced while verifying the compilation unit, or an empty array if the errors are
* not currently cached.
*/
List<AnalysisError> _verificationErrors = AnalysisError.NO_ERRORS;
/**
* The state of the cached hints.
*/
CacheState _hintsState = CacheState.INVALID;
/**
* The hints produced while auditing the compilation unit, or an empty array if the hints are
* not currently cached.
*/
List<AnalysisError> _hints = AnalysisError.NO_ERRORS;
/**
* Set this state to be exactly like the given state, recursively copying the next state as
* necessary.
*
* @param other the state to be copied
*/
void copyFrom(DartEntryImpl_ResolutionState other) {
_librarySource = other._librarySource;
_resolvedUnitState = other._resolvedUnitState;
_resolvedUnit = other._resolvedUnit;
_resolutionErrorsState = other._resolutionErrorsState;
_resolutionErrors = other._resolutionErrors;
_verificationErrorsState = other._verificationErrorsState;
_verificationErrors = other._verificationErrors;
_hintsState = other._hintsState;
_hints = other._hints;
if (other._nextState != null) {
_nextState = new DartEntryImpl_ResolutionState();
_nextState.copyFrom(other._nextState);
}
}
/**
* Flush any AST structures being maintained by this state.
*/
void flushAstStructures() {
if (identical(_resolvedUnitState, CacheState.VALID)) {
_resolvedUnitState = CacheState.FLUSHED;
_resolvedUnit = null;
}
if (_nextState != null) {
_nextState.flushAstStructures();
}
}
/**
* Invalidate all of the resolution information associated with the compilation unit.
*/
void invalidateAllResolutionInformation() {
_nextState = null;
_librarySource = null;
_resolvedUnitState = CacheState.INVALID;
_resolvedUnit = null;
_resolutionErrorsState = CacheState.INVALID;
_resolutionErrors = AnalysisError.NO_ERRORS;
_verificationErrorsState = CacheState.INVALID;
_verificationErrors = AnalysisError.NO_ERRORS;
_hintsState = CacheState.INVALID;
_hints = AnalysisError.NO_ERRORS;
}
/**
* Record that an error occurred while attempting to scan or parse the entry represented by this
* entry. This will set the state of all resolution-based information as being in error, but
* will not change the state of any parse results.
*/
void recordResolutionError() {
_nextState = null;
_librarySource = null;
_resolvedUnitState = CacheState.ERROR;
_resolvedUnit = null;
_resolutionErrorsState = CacheState.ERROR;
_resolutionErrors = AnalysisError.NO_ERRORS;
_verificationErrorsState = CacheState.ERROR;
_verificationErrors = AnalysisError.NO_ERRORS;
_hintsState = CacheState.ERROR;
_hints = AnalysisError.NO_ERRORS;
}
/**
* Record that an in-process parse has stopped without recording results because the results
* were invalidated before they could be recorded.
*/
void recordResolutionNotInProcess() {
if (identical(_resolvedUnitState, CacheState.IN_PROCESS)) {
_resolvedUnitState = CacheState.INVALID;
}
if (identical(_resolutionErrorsState, CacheState.IN_PROCESS)) {
_resolutionErrorsState = CacheState.INVALID;
}
if (identical(_verificationErrorsState, CacheState.IN_PROCESS)) {
_verificationErrorsState = CacheState.INVALID;
}
if (identical(_hintsState, CacheState.IN_PROCESS)) {
_hintsState = CacheState.INVALID;
}
if (_nextState != null) {
_nextState.recordResolutionNotInProcess();
}
}
/**
* Write a textual representation of this state to the given builder. The result will only be
* used for debugging purposes.
*
* @param builder the builder to which the text should be written
*/
void writeOn(JavaStringBuilder builder) {
if (_librarySource != null) {
builder.append("; resolvedUnit = ");
builder.append(_resolvedUnitState);
builder.append("; resolutionErrors = ");
builder.append(_resolutionErrorsState);
builder.append("; verificationErrors = ");
builder.append(_verificationErrorsState);
builder.append("; hints = ");
builder.append(_hintsState);
if (_nextState != null) {
_nextState.writeOn(builder);
}
}
}
}
/**
* Instances of the class `DataDescriptor` are immutable constants representing data that can
* be stored in the cache.
*/
class DataDescriptor<E> {
/**
* The name of the descriptor, used for debugging purposes.
*/
String _name;
/**
* Initialize a newly created descriptor to have the given name.
*
* @param name the name of the descriptor
*/
DataDescriptor(String name) {
this._name = name;
}
String toString() => _name;
}
/**
* The interface `HtmlEntry` defines the behavior of objects that maintain the information
* cached by an analysis context about an individual HTML file.
*
* @coverage dart.engine
*/
abstract class HtmlEntry implements SourceEntry {
/**
* The data descriptor representing the HTML element.
*/
static final DataDescriptor<HtmlElement> ELEMENT = new DataDescriptor<HtmlElement>("HtmlEntry.ELEMENT");
/**
* The data descriptor representing the hints resulting from auditing the source.
*/
static final DataDescriptor<List<AnalysisError>> HINTS = new DataDescriptor<List<AnalysisError>>("DartEntry.HINTS");
/**
* The data descriptor representing the parsed AST structure.
*/
static final DataDescriptor<HtmlUnit> PARSED_UNIT = new DataDescriptor<HtmlUnit>("HtmlEntry.PARSED_UNIT");
/**
* The data descriptor representing the list of referenced libraries.
*/
static final DataDescriptor<List<Source>> REFERENCED_LIBRARIES = new DataDescriptor<List<Source>>("HtmlEntry.REFERENCED_LIBRARIES");
/**
* The data descriptor representing the errors resulting from resolving the source.
*/
static final DataDescriptor<List<AnalysisError>> RESOLUTION_ERRORS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.RESOLUTION_ERRORS");
/**
* Return all of the errors associated with the compilation unit that are currently cached.
*
* @return all of the errors associated with the compilation unit
*/
List<AnalysisError> get allErrors;
HtmlEntryImpl get writableCopy;
}
/**
* Instances of the class `HtmlEntryImpl` implement an [HtmlEntry].
*
* @coverage dart.engine
*/
class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
/**
* The state of the cached parsed (but not resolved) HTML unit.
*/
CacheState _parsedUnitState = CacheState.INVALID;
/**
* The parsed HTML unit, or `null` if the parsed HTML unit is not currently cached.
*/
HtmlUnit _parsedUnit;
/**
* The state of the cached resolution errors.
*/
CacheState _resolutionErrorsState = CacheState.INVALID;
/**
* The errors produced while resolving the compilation unit, or `null` if the errors are not
* currently cached.
*/
List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
/**
* The state of the cached list of referenced libraries.
*/
CacheState _referencedLibrariesState = CacheState.INVALID;
/**
* The list of libraries referenced in the HTML, or `null` if the list is not currently
* cached. Note that this list does not include libraries defined directly within the HTML file.
*/
List<Source> _referencedLibraries = Source.EMPTY_ARRAY;
/**
* The state of the cached HTML element.
*/
CacheState _elementState = CacheState.INVALID;
/**
* The element representing the HTML file, or `null` if the element is not currently cached.
*/
HtmlElement _element;
/**
* The state of the cached hints.
*/
CacheState _hintsState = CacheState.INVALID;
/**
* The hints produced while auditing the compilation unit, or an empty array if the hints are not
* currently cached.
*/
List<AnalysisError> _hints = AnalysisError.NO_ERRORS;
List<AnalysisError> get allErrors {
List<AnalysisError> errors = new List<AnalysisError>();
for (AnalysisError error in _resolutionErrors) {
errors.add(error);
}
for (AnalysisError error in _hints) {
errors.add(error);
}
if (errors.length == 0) {
return AnalysisError.NO_ERRORS;
}
return new List.from(errors);
}
SourceKind get kind => SourceKind.HTML;
CacheState getState(DataDescriptor descriptor) {
if (identical(descriptor, HtmlEntry.ELEMENT)) {
return _elementState;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
return _parsedUnitState;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
return _referencedLibrariesState;
} else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
return _resolutionErrorsState;
} else if (identical(descriptor, HtmlEntry.HINTS)) {
return _hintsState;
}
return super.getState(descriptor);
}
Object getValue(DataDescriptor descriptor) {
if (identical(descriptor, HtmlEntry.ELEMENT)) {
return _element as Object;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
return _parsedUnit as Object;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
return _referencedLibraries as Object;
} else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
return _resolutionErrors as Object;
} else if (identical(descriptor, HtmlEntry.HINTS)) {
return _hints as Object;
}
return super.getValue(descriptor);
}
HtmlEntryImpl get writableCopy {
HtmlEntryImpl copy = new HtmlEntryImpl();
copy.copyFrom(this);
return copy;
}
/**
* Invalidate all of the information associated with the HTML file.
*/
void invalidateAllInformation() {
setState(SourceEntry.LINE_INFO, CacheState.INVALID);
_parsedUnit = null;
_parsedUnitState = CacheState.INVALID;
_referencedLibraries = Source.EMPTY_ARRAY;
_referencedLibrariesState = CacheState.INVALID;
invalidateAllResolutionInformation();
}
/**
* Invalidate all of the resolution information associated with the HTML file.
*/
void invalidateAllResolutionInformation() {
_element = null;
_elementState = CacheState.INVALID;
_resolutionErrors = AnalysisError.NO_ERRORS;
_resolutionErrorsState = CacheState.INVALID;
_hints = AnalysisError.NO_ERRORS;
_hintsState = CacheState.INVALID;
}
/**
* Record that an error was encountered while attempting to resolve the source associated with
* this entry.
*/
void recordResolutionError() {
setState(HtmlEntry.ELEMENT, CacheState.ERROR);
setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.ERROR);
}
void setState(DataDescriptor descriptor, CacheState state) {
if (identical(descriptor, HtmlEntry.ELEMENT)) {
_element = updatedValue(state, _element, null);
_elementState = state;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
_parsedUnit = updatedValue(state, _parsedUnit, null);
_parsedUnitState = state;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
_referencedLibraries = updatedValue(state, _referencedLibraries, Source.EMPTY_ARRAY);
_referencedLibrariesState = state;
} else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
_resolutionErrors = updatedValue(state, _resolutionErrors, AnalysisError.NO_ERRORS);
_resolutionErrorsState = state;
} else if (identical(descriptor, HtmlEntry.HINTS)) {
_hints = updatedValue(state, _hints, AnalysisError.NO_ERRORS);
_hintsState = state;
} else {
super.setState(descriptor, state);
}
}
void setValue(DataDescriptor descriptor, Object value) {
if (identical(descriptor, HtmlEntry.ELEMENT)) {
_element = value as HtmlElement;
_elementState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
_parsedUnit = value as HtmlUnit;
_parsedUnitState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
_referencedLibraries = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
_referencedLibrariesState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
_resolutionErrors = value as List<AnalysisError>;
_resolutionErrorsState = CacheState.VALID;
} else if (identical(descriptor, HtmlEntry.HINTS)) {
_hints = value as List<AnalysisError>;
_hintsState = CacheState.VALID;
} else {
super.setValue(descriptor, value);
}
}
void copyFrom(SourceEntryImpl entry) {
super.copyFrom(entry);
HtmlEntryImpl other = entry as HtmlEntryImpl;
_parsedUnitState = other._parsedUnitState;
_parsedUnit = other._parsedUnit;
_referencedLibrariesState = other._referencedLibrariesState;
_referencedLibraries = other._referencedLibraries;
_resolutionErrors = other._resolutionErrors;
_resolutionErrorsState = other._resolutionErrorsState;
_elementState = other._elementState;
_element = other._element;
_hints = other._hints;
_hintsState = other._hintsState;
}
void writeOn(JavaStringBuilder builder) {
builder.append("Html: ");
super.writeOn(builder);
builder.append("; parsedUnit = ");
builder.append(_parsedUnitState);
builder.append("; resolutionErrors = ");
builder.append(_resolutionErrorsState);
builder.append("; referencedLibraries = ");
builder.append(_referencedLibrariesState);
builder.append("; element = ");
builder.append(_elementState);
}
}
/**
* The interface `SourceEntry` defines the behavior of objects that maintain the information
* cached by an analysis context about an individual source, no matter what kind of source it is.
*
* Source entries should be treated as if they were immutable unless a writable copy of the entry
* has been obtained and has not yet been made visible to other threads.
*
* @coverage dart.engine
*/
abstract class SourceEntry {
/**
* The data descriptor representing the line information.
*/
static final DataDescriptor<LineInfo> LINE_INFO = new DataDescriptor<LineInfo>("SourceEntry.LINE_INFO");
/**
* Return the exception that caused one or more values to have a state of [CacheState#ERROR]
* .
*
* @return the exception that caused one or more values to be uncomputable
*/
AnalysisException get exception;
/**
* Return the kind of the source, or `null` if the kind is not currently cached.
*
* @return the kind of the source
*/
SourceKind get kind;
/**
* Return the most recent time at which the state of the source matched the state represented by
* this entry.
*
* @return the modification time of this entry
*/
int get modificationTime;
/**
* Return the state of the data represented by the given descriptor.
*
* @param descriptor the descriptor representing the data whose state is to be returned
* @return the state of the data represented by the given descriptor
*/
CacheState getState(DataDescriptor descriptor);
/**
* Return the value of the data represented by the given descriptor, or `null` if the data
* represented by the descriptor is not in the cache.
*
* @param descriptor the descriptor representing which data is to be returned
* @return the value of the data represented by the given descriptor
*/
Object getValue(DataDescriptor descriptor);
/**
* Return a new entry that is initialized to the same state as this entry but that can be
* modified.
*
* @return a writable copy of this entry
*/
SourceEntryImpl get writableCopy;
}
/**
* Instances of the abstract class `SourceEntryImpl` implement the behavior common to all
* [SourceEntry].
*
* @coverage dart.engine
*/
abstract class SourceEntryImpl implements SourceEntry {
/**
* The most recent time at which the state of the source matched the state represented by this
* entry.
*/
int _modificationTime = 0;
/**
* The exception that caused one or more values to have a state of [CacheState#ERROR].
*/
AnalysisException _exception;
/**
* The state of the cached line information.
*/
CacheState _lineInfoState = CacheState.INVALID;
/**
* The line information computed for the source, or `null` if the line information is not
* currently cached.
*/
LineInfo _lineInfo;
/**
* Return the exception that caused one or more values to have a state of [CacheState#ERROR]
* .
*
* @return the exception that caused one or more values to be uncomputable
*/
AnalysisException get exception => _exception;
int get modificationTime => _modificationTime;
CacheState getState(DataDescriptor descriptor) {
if (identical(descriptor, SourceEntry.LINE_INFO)) {
return _lineInfoState;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
Object getValue(DataDescriptor descriptor) {
if (identical(descriptor, SourceEntry.LINE_INFO)) {
return _lineInfo as Object;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
/**
* Set the exception that caused one or more values to have a state of [CacheState#ERROR] to
* the given exception.
*
* @param exception the exception that caused one or more values to be uncomputable
*/
void set exception(AnalysisException exception) {
this._exception = exception;
}
/**
* Set the most recent time at which the state of the source matched the state represented by this
* entry to the given time.
*
* @param time the new modification time of this entry
*/
void set modificationTime(int time) {
_modificationTime = time;
}
/**
* Set the state of the data represented by the given descriptor to the given state.
*
* @param descriptor the descriptor representing the data whose state is to be set
* @param the new state of the data represented by the given descriptor
*/
void setState(DataDescriptor descriptor, CacheState state) {
if (identical(descriptor, SourceEntry.LINE_INFO)) {
_lineInfo = updatedValue(state, _lineInfo, null);
_lineInfoState = state;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
/**
* Set the value of the data represented by the given descriptor to the given value.
*
* @param descriptor the descriptor representing the data whose value is to be set
* @param value the new value of the data represented by the given descriptor
*/
void setValue(DataDescriptor descriptor, Object value) {
if (identical(descriptor, SourceEntry.LINE_INFO)) {
_lineInfo = value as LineInfo;
_lineInfoState = CacheState.VALID;
} else {
throw new IllegalArgumentException("Invalid descriptor: ${descriptor}");
}
}
String toString() {
JavaStringBuilder builder = new JavaStringBuilder();
writeOn(builder);
return builder.toString();
}
/**
* Copy the information from the given cache entry.
*
* @param entry the cache entry from which information will be copied
*/
void copyFrom(SourceEntryImpl entry) {
_modificationTime = entry._modificationTime;
_lineInfoState = entry._lineInfoState;
_lineInfo = entry._lineInfo;
}
/**
* Given that some data is being transitioned to the given state, return the value that should be
* kept in the cache.
*
* @param state the state to which the data is being transitioned
* @param currentValue the value of the data before the transition
* @param defaultValue the value to be used if the current value is to be removed from the cache
* @return the value of the data that should be kept in the cache
*/
Object updatedValue(CacheState state, Object currentValue, Object defaultValue) {
if (identical(state, CacheState.VALID)) {
throw new IllegalArgumentException("Use setValue() to set the state to VALID");
} else if (identical(state, CacheState.IN_PROCESS)) {
return currentValue;
}
return defaultValue;
}
/**
* Write a textual representation of this entry to the given builder. The result will only be used
* for debugging purposes.
*
* @param builder the builder to which the text should be written
*/
void writeOn(JavaStringBuilder builder) {
builder.append("time = ");
builder.append(_modificationTime.toRadixString(16));
builder.append("; lineInfo = ");
builder.append(_lineInfoState);
}
}
/**
* Implementation of the [AnalysisContentStatistics].
*/
class AnalysisContentStatisticsImpl implements AnalysisContentStatistics {
Map<String, AnalysisContentStatistics_CacheRow> _dataMap = new Map<String, AnalysisContentStatistics_CacheRow>();
Set<AnalysisException> _exceptions = new Set<AnalysisException>();
List<AnalysisContentStatistics_CacheRow> get cacheRows {
Iterable<AnalysisContentStatistics_CacheRow> items = _dataMap.values;
return new List.from(items);
}
List<AnalysisException> get exceptions => new List.from(_exceptions);
void putCacheItem(DartEntry dartEntry, DataDescriptor descriptor) {
putCacheItem3(dartEntry, descriptor, dartEntry.getState(descriptor));
}
void putCacheItem2(DartEntry dartEntry, Source librarySource, DataDescriptor descriptor) {
putCacheItem3(dartEntry, descriptor, dartEntry.getState2(descriptor, librarySource));
}
void putCacheItem3(SourceEntry dartEntry, DataDescriptor rowDesc, CacheState state) {
String rowName = rowDesc.toString();
AnalysisContentStatisticsImpl_CacheRowImpl row = _dataMap[rowName] as AnalysisContentStatisticsImpl_CacheRowImpl;
if (row == null) {
row = new AnalysisContentStatisticsImpl_CacheRowImpl(rowName);
_dataMap[rowName] = row;
}
row.incState(state);
if (identical(state, CacheState.ERROR)) {
AnalysisException exception = dartEntry.exception;
if (exception != null) {
javaSetAdd(_exceptions, exception);
}
}
}
}
class AnalysisContentStatisticsImpl_CacheRowImpl implements AnalysisContentStatistics_CacheRow {
String _name;
int _errorCount = 0;
int _flushedCount = 0;
int _inProcessCount = 0;
int _invalidCount = 0;
int _validCount = 0;
AnalysisContentStatisticsImpl_CacheRowImpl(String name) {
this._name = name;
}
bool operator ==(Object obj) => obj is AnalysisContentStatisticsImpl_CacheRowImpl && ((obj as AnalysisContentStatisticsImpl_CacheRowImpl))._name == _name;
int get errorCount => _errorCount;
int get flushedCount => _flushedCount;
int get inProcessCount => _inProcessCount;
int get invalidCount => _invalidCount;
String get name => _name;
int get validCount => _validCount;
int get hashCode => _name.hashCode;
void incState(CacheState state) {
if (identical(state, CacheState.ERROR)) {
_errorCount++;
}
if (identical(state, CacheState.FLUSHED)) {
_flushedCount++;
}
if (identical(state, CacheState.IN_PROCESS)) {
_inProcessCount++;
}
if (identical(state, CacheState.INVALID)) {
_invalidCount++;
}
if (identical(state, CacheState.VALID)) {
_validCount++;
}
}
}
/**
* Instances of the class `AnalysisContextImpl` implement an [AnalysisContext].
*
* @coverage dart.engine
*/
class AnalysisContextImpl implements InternalAnalysisContext {
/**
* The set of analysis options controlling the behavior of this context.
*/
AnalysisOptions _options = new AnalysisOptionsImpl();
/**
* The source factory used to create the sources that can be analyzed in this context.
*/
SourceFactory _sourceFactory;
/**
* A table mapping the sources known to the context to the information known about the source.
*/
AnalysisCache _cache = new AnalysisCache(_MAX_CACHE_SIZE);
/**
* A table mapping sources to the change notices that are waiting to be returned related to that
* source.
*/
Map<Source, ChangeNoticeImpl> _pendingNotices = new Map<Source, ChangeNoticeImpl>();
/**
* The object used to synchronize access to all of the caches. The rules related to the use of
* this lock object are
*
* * no analysis work is done while holding the lock, and
* * no analysis results can be recorded unless we have obtained the lock and validated that the
* results are for the same version (modification time) of the source as our current cache
* content.
*
*/
Object _cacheLock = new Object();
/**
* The object used to record the results of performing an analysis task.
*/
AnalysisContextImpl_AnalysisTaskResultRecorder _resultRecorder;
/**
* The maximum number of sources for which data should be kept in the cache.
*/
static int _MAX_CACHE_SIZE = 64;
/**
* The maximum number of sources that can be on the priority list. This <b>must</b> be less than
* the [MAX_CACHE_SIZE] in order to prevent an infinite loop in performAnalysisTask().
*
* @see #setAnalysisPriorityOrder(List)
*/
static int _MAX_PRIORITY_LIST_SIZE = _MAX_CACHE_SIZE - 4;
/**
* Initialize a newly created analysis context.
*/
AnalysisContextImpl() : super() {
_resultRecorder = new AnalysisContextImpl_AnalysisTaskResultRecorder(this);
}
void addSourceInfo(Source source, SourceEntry info) {
_cache.put(source, info);
}
void applyChanges(ChangeSet changeSet) {
if (changeSet.isEmpty) {
return;
}
{
List<Source> removedSources = new List<Source>.from(changeSet.removed3);
for (SourceContainer container in changeSet.removedContainers) {
addSourcesInContainer(removedSources, container);
}
bool addedDartSource = false;
for (Source source in changeSet.added3) {
if (sourceAvailable(source)) {
addedDartSource = true;
}
}
for (Source source in changeSet.changed3) {
sourceChanged(source);
}
for (Source source in removedSources) {
sourceRemoved(source);
}
if (addedDartSource) {
for (MapEntry<Source, SourceEntry> mapEntry in _cache.entrySet()) {
SourceEntry sourceEntry = mapEntry.getValue();
if (!mapEntry.getKey().isInSystemLibrary && sourceEntry is DartEntry) {
DartEntryImpl dartCopy = ((sourceEntry as DartEntry)).writableCopy;
dartCopy.invalidateAllResolutionInformation();
mapEntry.setValue(dartCopy);
}
}
}
}
}
String computeDocumentationComment(Element element) {
if (element == null) {
return null;
}
Source source = element.source;
if (source == null) {
return null;
}
CompilationUnit unit = parseCompilationUnit(source);
if (unit == null) {
return null;
}
NodeLocator locator = new NodeLocator.con1(element.nameOffset);
ASTNode nameNode = locator.searchWithin(unit);
while (nameNode != null) {
if (nameNode is AnnotatedNode) {
Comment comment = ((nameNode as AnnotatedNode)).documentationComment;
if (comment == null) {
return null;
}
JavaStringBuilder builder = new JavaStringBuilder();
List<Token> tokens = comment.tokens;
for (int i = 0; i < tokens.length; i++) {
if (i > 0) {
builder.append('\n');
}
builder.append(tokens[i].lexeme);
}
return builder.toString();
}
nameNode = nameNode.parent;
}
return null;
}
List<AnalysisError> computeErrors(Source source) {
bool enableHints = analysisOptions.hint;
SourceEntry sourceEntry = getReadableSourceEntry(source);
if (sourceEntry is DartEntry) {
List<AnalysisError> errors = new List<AnalysisError>();
DartEntry dartEntry = sourceEntry as DartEntry;
ListUtilities.addAll(errors, getDartParseData(source, dartEntry, DartEntry.PARSE_ERRORS));
dartEntry = getReadableDartEntry(source);
if (identical(dartEntry.getValue(DartEntry.SOURCE_KIND), SourceKind.LIBRARY)) {
ListUtilities.addAll(errors, getDartResolutionData(source, source, dartEntry, DartEntry.RESOLUTION_ERRORS));
ListUtilities.addAll(errors, getDartVerificationData(source, source, dartEntry, DartEntry.VERIFICATION_ERRORS));
if (enableHints) {
ListUtilities.addAll(errors, getDartHintData(source, source, dartEntry, DartEntry.HINTS));
}
} else {
List<Source> libraries = getLibrariesContaining(source);
for (Source librarySource in libraries) {
ListUtilities.addAll(errors, getDartResolutionData(source, librarySource, dartEntry, DartEntry.RESOLUTION_ERRORS));
ListUtilities.addAll(errors, getDartVerificationData(source, librarySource, dartEntry, DartEntry.VERIFICATION_ERRORS));
if (enableHints) {
ListUtilities.addAll(errors, getDartHintData(source, librarySource, dartEntry, DartEntry.HINTS));
}
}
}
if (errors.isEmpty) {
return AnalysisError.NO_ERRORS;
}
return new List.from(errors);
} else if (sourceEntry is HtmlEntry) {
HtmlEntry htmlEntry = sourceEntry as HtmlEntry;
return getHtmlResolutionData2(source, htmlEntry, HtmlEntry.RESOLUTION_ERRORS);
}
return AnalysisError.NO_ERRORS;
}
List<Source> computeExportedLibraries(Source source) => getDartParseData2(source, DartEntry.EXPORTED_LIBRARIES, Source.EMPTY_ARRAY);
HtmlElement computeHtmlElement(Source source) => getHtmlResolutionData(source, HtmlEntry.ELEMENT, null);
List<Source> computeImportedLibraries(Source source) => getDartParseData2(source, DartEntry.IMPORTED_LIBRARIES, Source.EMPTY_ARRAY);
SourceKind computeKindOf(Source source) {
SourceEntry sourceEntry = getReadableSourceEntry(source);
if<