| Index: pkg/analyzer_experimental/lib/src/generated/engine.dart
|
| diff --git a/pkg/analyzer_experimental/lib/src/generated/engine.dart b/pkg/analyzer_experimental/lib/src/generated/engine.dart
|
| index 1570f8cfd14e6e79ee164b268ecc29efbe699794..2b2709ee9e1e70ad07fd6db429052e0b3c7159d2 100644
|
| --- a/pkg/analyzer_experimental/lib/src/generated/engine.dart
|
| +++ b/pkg/analyzer_experimental/lib/src/generated/engine.dart
|
| @@ -800,6 +800,181 @@ class ChangeSet {
|
| }
|
| }
|
| /**
|
| + * 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 set containing all of the map entries mapping sources to cache entries. Clients should
|
| + * not modify the returned set.
|
| + *
|
| + * @return a set containing all of the map entries mapping sources to cache entries
|
| + */
|
| + Set<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;
|
| + }
|
| +
|
| + /**
|
| + * 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 interface `DartEntry` defines the behavior of objects that maintain the information
|
| * cached by an analysis context about an individual Dart file.
|
| *
|
| @@ -1049,6 +1224,17 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| * If the library is not "client code", then it is referenced as "server code".
|
| */
|
| static int _CLIENT_CODE = 1 << 2;
|
| +
|
| + /**
|
| + * Flush any AST structures being maintained by this entry.
|
| + */
|
| + void flushAstStructures() {
|
| + if (identical(_parsedUnitState, CacheState.VALID)) {
|
| + _parsedUnitState = CacheState.FLUSHED;
|
| + _parsedUnit = null;
|
| + }
|
| + _resolutionState.flushAstStructures();
|
| + }
|
| List<AnalysisError> get allErrors {
|
| List<AnalysisError> errors = new List<AnalysisError>();
|
| for (AnalysisError error in _parseErrors) {
|
| @@ -1633,6 +1819,19 @@ class DartEntryImpl_ResolutionState {
|
| }
|
|
|
| /**
|
| + * 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() {
|
| @@ -2418,7 +2617,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| return null;
|
| }
|
| - CompilationUnit computeResolvableCompilationUnit(Source source) {
|
| + ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) {
|
| DartEntry dartEntry = getReadableDartEntry(source);
|
| if (dartEntry == null) {
|
| return null;
|
| @@ -2426,12 +2625,16 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| CompilationUnit unit = dartEntry.anyParsedCompilationUnit;
|
| if (unit == null) {
|
| try {
|
| - unit = parseCompilationUnit(source);
|
| + dartEntry = internalParseDart(source);
|
| + unit = dartEntry.anyParsedCompilationUnit;
|
| + if (unit == null) {
|
| + return null;
|
| + }
|
| } on AnalysisException catch (exception) {
|
| return null;
|
| }
|
| }
|
| - return unit.accept(new ASTCloner()) as CompilationUnit;
|
| + return new ResolvableCompilationUnit(dartEntry.modificationTime, (unit.accept(new ASTCloner()) as CompilationUnit));
|
| }
|
| AnalysisContext extractContext(SourceContainer container) => extractContextInto(container, (AnalysisEngine.instance.createAnalysisContext() as InternalAnalysisContext));
|
| InternalAnalysisContext extractContextInto(SourceContainer container, InternalAnalysisContext newContext) {
|
| @@ -2812,7 +3015,8 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| Source coreLibrarySource = libraryElement.context.sourceFactory.forUri(DartSdk.DART_CORE);
|
| LibraryElement coreElement = computeLibraryElement(coreLibrarySource);
|
| TypeProvider typeProvider = new TypeProviderImpl(coreElement);
|
| - CompilationUnit unitAST = computeResolvableCompilationUnit(unitSource);
|
| + ResolvableCompilationUnit resolvableUnit = computeResolvableCompilationUnit(unitSource);
|
| + CompilationUnit unitAST = resolvableUnit.compilationUnit;
|
| new DeclarationResolver().resolve(unitAST, find(libraryElement, unitSource));
|
| RecordingErrorListener errorListener = new RecordingErrorListener();
|
| TypeResolverVisitor typeResolverVisitor = new TypeResolverVisitor.con2(libraryElement, unitSource, typeProvider, errorListener);
|
| @@ -3809,7 +4013,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| resultTime = htmlEntry.modificationTime;
|
| HtmlUnitBuilder builder = new HtmlUnitBuilder(this);
|
| - element = builder.buildHtmlElement2(source, unit);
|
| + element = builder.buildHtmlElement2(source, resultTime, unit);
|
| resolutionErrors = builder.errorListener.getErrors2(source);
|
| } on AnalysisException catch (exception) {
|
| thrownException = exception;
|
| @@ -4124,7 +4328,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return null;
|
| }
|
| String uriContent = uriLiteral.stringValue.trim();
|
| - if (uriContent == null) {
|
| + if (uriContent == null || uriContent.isEmpty) {
|
| return null;
|
| }
|
| uriContent = Uri.encodeFull(uriContent);
|
| @@ -4515,21 +4719,25 @@ class RecursiveXmlVisitor_6 extends RecursiveXmlVisitor<Object> {
|
| if (javaStringEqualsIgnoreCase(attribute.name.lexeme, AnalysisContextImpl._ATTRIBUTE_SRC)) {
|
| scriptAttribute = attribute;
|
| } else if (javaStringEqualsIgnoreCase(attribute.name.lexeme, AnalysisContextImpl._ATTRIBUTE_TYPE)) {
|
| - if (javaStringEqualsIgnoreCase(attribute.text, AnalysisContextImpl._TYPE_DART)) {
|
| + String text = attribute.text;
|
| + if (text != null && javaStringEqualsIgnoreCase(text, AnalysisContextImpl._TYPE_DART)) {
|
| isDartScript = true;
|
| }
|
| }
|
| }
|
| if (isDartScript && scriptAttribute != null) {
|
| - try {
|
| - Uri uri = new Uri(path: scriptAttribute.text);
|
| - String fileName = uri.path;
|
| - Source librarySource = AnalysisContextImpl_this._sourceFactory.resolveUri(htmlSource, fileName);
|
| - if (librarySource.exists()) {
|
| - libraries.add(librarySource);
|
| + String text = scriptAttribute.text;
|
| + if (text != null) {
|
| + try {
|
| + Uri uri = new Uri(path: text);
|
| + String fileName = uri.path;
|
| + Source librarySource = AnalysisContextImpl_this._sourceFactory.resolveUri(htmlSource, fileName);
|
| + if (librarySource != null && librarySource.exists()) {
|
| + libraries.add(librarySource);
|
| + }
|
| + } catch (exception) {
|
| + AnalysisEngine.instance.logger.logInformation2("Invalid URI ('${text}') in script tag in '${htmlSource.fullName}'", exception);
|
| }
|
| - } catch (exception) {
|
| - AnalysisEngine.instance.logger.logInformation2("Invalid URL ('${scriptAttribute.text}') in script tag in '${htmlSource.fullName}'", exception);
|
| }
|
| }
|
| }
|
| @@ -4606,7 +4814,7 @@ class AnalysisOptionsImpl implements AnalysisOptions {
|
| * A flag indicating whether analysis is to use strict mode. In strict mode, error reporting is
|
| * based exclusively on the static type information.
|
| */
|
| - bool _strictMode = false;
|
| + bool _strictMode = true;
|
|
|
| /**
|
| * A flag indicating whether analysis is to generate hint results (e.g. type inference based
|
| @@ -4883,7 +5091,7 @@ class DelegatingAnalysisContextImpl extends AnalysisContextImpl {
|
| return super.computeLineInfo(source);
|
| }
|
| }
|
| - CompilationUnit computeResolvableCompilationUnit(Source source) {
|
| + ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) {
|
| if (source.isInSystemLibrary) {
|
| return _sdkAnalysisContext.computeResolvableCompilationUnit(source);
|
| } else {
|
| @@ -5196,7 +5404,7 @@ class InstrumentedAnalysisContextImpl implements InternalAnalysisContext {
|
| instrumentation.log();
|
| }
|
| }
|
| - CompilationUnit computeResolvableCompilationUnit(Source source) => _basis.computeResolvableCompilationUnit(source);
|
| + ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) => _basis.computeResolvableCompilationUnit(source);
|
| AnalysisContext extractContext(SourceContainer container) {
|
| InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-extractContext");
|
| try {
|
| @@ -5599,7 +5807,7 @@ abstract class InternalAnalysisContext implements AnalysisContext {
|
| * @return the AST structure representing the content of the source
|
| * @throws AnalysisException if the analysis could not be performed
|
| */
|
| - CompilationUnit computeResolvableCompilationUnit(Source source);
|
| + ResolvableCompilationUnit computeResolvableCompilationUnit(Source source);
|
|
|
| /**
|
| * Initialize the specified context by removing the specified sources from the receiver and adding
|
| @@ -5796,6 +6004,48 @@ class ResolutionEraser extends GeneralizingASTVisitor<Object> {
|
| }
|
| }
|
| /**
|
| + * Instances of the class `ResolvableCompilationUnit` represent a compilation unit that is not
|
| + * referenced by any other objects and for which we have modification stamp information. It is used
|
| + * by the [LibraryResolver] to resolve a library.
|
| + */
|
| +class ResolvableCompilationUnit {
|
| +
|
| + /**
|
| + * The modification time of the source from which the AST was created.
|
| + */
|
| + int _modificationStamp = 0;
|
| +
|
| + /**
|
| + * The AST that was created from the source.
|
| + */
|
| + CompilationUnit _unit;
|
| +
|
| + /**
|
| + * Initialize a newly created holder to hold the given values.
|
| + *
|
| + * @param modificationStamp the modification time of the source from which the AST was created
|
| + * @param unit the AST that was created from the source
|
| + */
|
| + ResolvableCompilationUnit(int modificationStamp, CompilationUnit unit) {
|
| + this._modificationStamp = modificationStamp;
|
| + this._unit = unit;
|
| + }
|
| +
|
| + /**
|
| + * Return the AST that was created from the source.
|
| + *
|
| + * @return the AST that was created from the source
|
| + */
|
| + CompilationUnit get compilationUnit => _unit;
|
| +
|
| + /**
|
| + * Return the modification time of the source from which the AST was created.
|
| + *
|
| + * @return the modification time of the source from which the AST was created
|
| + */
|
| + int get modificationStamp => _modificationStamp;
|
| +}
|
| +/**
|
| * The interface `Logger` defines the behavior of objects that can be used to receive
|
| * information about errors within the analysis engine. Implementations usually write this
|
| * information to a file, but can also record the information for later use (such as during testing)
|
|
|