| Index: pkg/analyzer/lib/src/generated/engine.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
|
| index a63861f16b7ac18f4c231a0910cee985ea6391e1..b6bd31cda94b8bdca7197085f4df6958d09c767f 100644
|
| --- a/pkg/analyzer/lib/src/generated/engine.dart
|
| +++ b/pkg/analyzer/lib/src/generated/engine.dart
|
| @@ -14,13 +14,13 @@ import 'utilities_general.dart';
|
| import 'instrumentation.dart';
|
| import 'error.dart';
|
| import 'source.dart';
|
| -import 'scanner.dart' show Token, Scanner, CharSequenceReader, CharacterReader, IncrementalScanner;
|
| +import 'scanner.dart';
|
| import 'ast.dart';
|
| import 'parser.dart' show Parser, IncrementalParser;
|
| import 'sdk.dart' show DartSdk;
|
| import 'element.dart';
|
| import 'resolver.dart';
|
| -import 'html.dart' show XmlTagNode, XmlAttributeNode, RecursiveXmlVisitor, HtmlScanner, HtmlScanResult, HtmlParser, HtmlParseResult, HtmlScriptTagNode, HtmlUnit;
|
| +import 'html.dart' as ht;
|
|
|
| /**
|
| * The unique instance of the class `AnalysisEngine` serves as the entry point for the
|
| @@ -408,6 +408,16 @@ abstract class AnalysisContext {
|
| List<Source> getLibrariesDependingOn(Source librarySource);
|
|
|
| /**
|
| + * Return the [AngularElement]s accessible in the library defined by the given source, or an
|
| + * empty array if given source is not a library, not resolved or cannot be analyzed for some
|
| + * reason.
|
| + *
|
| + * @param source the source defining the library whose [AngularElement]s is to be returned
|
| + * @return the [AngularElement]s accessible in the library defined by the given source
|
| + */
|
| + List<AngularElement> getLibraryAngularElements(Source source);
|
| +
|
| + /**
|
| * 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.
|
| @@ -477,7 +487,7 @@ abstract class AnalysisContext {
|
| * @return a fully resolved HTML unit
|
| * @see #resolveHtmlUnit(Source)
|
| */
|
| - HtmlUnit getResolvedHtmlUnit(Source htmlSource);
|
| + ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource);
|
|
|
| /**
|
| * Return the source factory used to create the sources that can be analyzed in this context.
|
| @@ -542,7 +552,7 @@ abstract class AnalysisContext {
|
| * @return the parse result (not `null`)
|
| * @throws AnalysisException if the analysis could not be performed
|
| */
|
| - HtmlUnit parseHtmlUnit(Source source);
|
| + ht.HtmlUnit parseHtmlUnit(Source source);
|
|
|
| /**
|
| * Perform the next unit of work required to keep the analysis results up-to-date and return
|
| @@ -587,7 +597,7 @@ abstract class AnalysisContext {
|
| * @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);
|
| + ht.HtmlUnit resolveHtmlUnit(Source htmlSource);
|
|
|
| /**
|
| * Set the set of analysis options controlling the behavior of this context to the given options.
|
| @@ -825,7 +835,7 @@ abstract class ChangeNotice implements AnalysisErrorInfo {
|
| *
|
| * @return the fully resolved HTML that changed as a result of the analysis
|
| */
|
| - HtmlUnit get htmlUnit;
|
| + ht.HtmlUnit get htmlUnit;
|
|
|
| /**
|
| * Return the source for which the result is being reported.
|
| @@ -1045,6 +1055,7 @@ class AnalysisCache {
|
| * @param entry the entry to be associated with the source
|
| */
|
| void put(Source source, SourceEntry entry) {
|
| + (entry as SourceEntryImpl).fixExceptionState();
|
| _sourceMap[source] = entry;
|
| }
|
|
|
| @@ -1214,6 +1225,12 @@ class CacheState extends Enum<CacheState> {
|
| */
|
| abstract class DartEntry implements SourceEntry {
|
| /**
|
| + * The data descriptor representing the Angular elements accessible in the library. This data is
|
| + * only available for Dart files that are the defining compilation unit of a library.
|
| + */
|
| + static final DataDescriptor<List<AngularElement>> ANGULAR_ELEMENTS = new DataDescriptor<List<AngularElement>>("DartEntry.ANGULAR_ELEMENTS");
|
| +
|
| + /**
|
| * 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.
|
| */
|
| @@ -1448,6 +1465,17 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| LibraryElement _element;
|
|
|
| /**
|
| + * The state of the cached [angularElements].
|
| + */
|
| + CacheState _angularElementsState = CacheState.INVALID;
|
| +
|
| + /**
|
| + * The array of Angular elements accessible in the library, or an empty array if the elements are
|
| + * not currently cached.
|
| + */
|
| + List<AngularElement> _angularElements = AngularElement.EMPTY_ARRAY;
|
| +
|
| + /**
|
| * The state of the cached public namespace.
|
| */
|
| CacheState _publicNamespaceState = CacheState.INVALID;
|
| @@ -1588,7 +1616,9 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| }
|
|
|
| CacheState getState(DataDescriptor descriptor) {
|
| - if (identical(descriptor, DartEntry.ELEMENT)) {
|
| + if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
|
| + return _angularElementsState;
|
| + } else if (identical(descriptor, DartEntry.ELEMENT)) {
|
| return _elementState;
|
| } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
|
| return _exportedLibrariesState;
|
| @@ -1640,7 +1670,9 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| }
|
|
|
| Object getValue(DataDescriptor descriptor) {
|
| - if (identical(descriptor, DartEntry.ELEMENT)) {
|
| + if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
|
| + return _angularElements;
|
| + } else if (identical(descriptor, DartEntry.ELEMENT)) {
|
| return _element;
|
| } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
|
| return _exportedLibraries;
|
| @@ -1783,6 +1815,51 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| }
|
|
|
| /**
|
| + * Record that an error occurred while attempting to resolve the directives in the source
|
| + * represented by this entry.
|
| + */
|
| + void recordDependencyError() {
|
| + _exportedLibraries = Source.EMPTY_ARRAY;
|
| + _exportedLibrariesState = CacheState.ERROR;
|
| + _importedLibraries = Source.EMPTY_ARRAY;
|
| + _importedLibrariesState = CacheState.ERROR;
|
| + _includedParts = Source.EMPTY_ARRAY;
|
| + _includedPartsState = CacheState.ERROR;
|
| + }
|
| +
|
| + /**
|
| + * Record that the information related to resolving dependencies for the associated source is
|
| + * about to be computed by the current thread.
|
| + */
|
| + void recordDependencyInProcess() {
|
| + 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 dependency resolution has stopped without recording results because
|
| + * the results were invalidated before they could be recorded.
|
| + */
|
| + void recordDependencyNotInProcess() {
|
| + 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 information, including any resolution-based information,
|
| * as being in error.
|
| @@ -1796,12 +1873,7 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| _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;
|
| + recordDependencyError();
|
| recordResolutionError();
|
| }
|
|
|
| @@ -1822,15 +1894,6 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| 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;
|
| - }
|
| }
|
|
|
| /**
|
| @@ -1850,15 +1913,6 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| 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;
|
| - }
|
| }
|
|
|
| /**
|
| @@ -1867,6 +1921,8 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| * not change the state of any parse results.
|
| */
|
| void recordResolutionError() {
|
| + _angularElements = AngularElement.EMPTY_ARRAY;
|
| + _angularElementsState = CacheState.ERROR;
|
| _element = null;
|
| _elementState = CacheState.ERROR;
|
| _bitmask = 0;
|
| @@ -1882,6 +1938,9 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| * invalidated before they could be recorded.
|
| */
|
| void recordResolutionNotInProcess() {
|
| + if (identical(_angularElementsState, CacheState.IN_PROCESS)) {
|
| + _angularElementsState = CacheState.INVALID;
|
| + }
|
| if (identical(_elementState, CacheState.IN_PROCESS)) {
|
| _elementState = CacheState.INVALID;
|
| }
|
| @@ -1952,7 +2011,10 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| }
|
|
|
| void setState(DataDescriptor descriptor, CacheState state) {
|
| - if (identical(descriptor, DartEntry.ELEMENT)) {
|
| + if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
|
| + _angularElements = updatedValue(state, _angularElements, AngularElement.EMPTY_ARRAY);
|
| + _angularElementsState = state;
|
| + } else if (identical(descriptor, DartEntry.ELEMENT)) {
|
| _element = updatedValue(state, _element, null);
|
| _elementState = state;
|
| } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
|
| @@ -2020,7 +2082,10 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| }
|
|
|
| void setValue(DataDescriptor descriptor, Object value) {
|
| - if (identical(descriptor, DartEntry.ELEMENT)) {
|
| + if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
|
| + _angularElements = value as List<AngularElement>;
|
| + _angularElementsState = CacheState.VALID;
|
| + } else if (identical(descriptor, DartEntry.ELEMENT)) {
|
| _element = value as LibraryElement;
|
| _elementState = CacheState.VALID;
|
| } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
|
| @@ -2105,9 +2170,13 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| _publicNamespace = other._publicNamespace;
|
| _clientServerState = other._clientServerState;
|
| _launchableState = other._launchableState;
|
| + _angularElementsState = other._angularElementsState;
|
| + _angularElements = other._angularElements;
|
| _bitmask = other._bitmask;
|
| }
|
|
|
| + bool hasErrorState() => super.hasErrorState() || identical(_sourceKindState, CacheState.ERROR) || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_importedLibrariesState, CacheState.ERROR) || identical(_exportedLibrariesState, CacheState.ERROR) || identical(_includedPartsState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularElementsState, CacheState.ERROR) || identical(_publicNamespaceState, CacheState.ERROR) || identical(_clientServerState, CacheState.ERROR) || identical(_launchableState, CacheState.ERROR) || _resolutionState.hasErrorState();
|
| +
|
| void writeOn(JavaStringBuilder builder) {
|
| builder.append("Dart: ");
|
| super.writeOn(builder);
|
| @@ -2133,6 +2202,8 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| builder.append(_clientServerState);
|
| builder.append("; launchable = ");
|
| builder.append(_launchableState);
|
| + builder.append("; angularElements = ");
|
| + builder.append(_angularElementsState);
|
| _resolutionState.writeOn(builder);
|
| }
|
|
|
| @@ -2140,6 +2211,8 @@ class DartEntryImpl extends SourceEntryImpl implements DartEntry {
|
| * Invalidate all of the resolution information associated with the compilation unit.
|
| */
|
| void discardCachedResolutionInformation() {
|
| + _angularElements = AngularElement.EMPTY_ARRAY;
|
| + _angularElementsState = CacheState.INVALID;
|
| _element = null;
|
| _elementState = CacheState.INVALID;
|
| _includedParts = Source.EMPTY_ARRAY;
|
| @@ -2298,6 +2371,8 @@ class DartEntryImpl_ResolutionState {
|
| }
|
| }
|
|
|
| + bool hasErrorState() => identical(_resolvedUnitState, CacheState.ERROR) || identical(_resolutionErrorsState, CacheState.ERROR) || identical(_verificationErrorsState, CacheState.ERROR) || identical(_hintsState, CacheState.ERROR) || (_nextState != null && _nextState.hasErrorState());
|
| +
|
| /**
|
| * Invalidate all of the resolution information associated with the compilation unit.
|
| */
|
| @@ -2408,6 +2483,11 @@ class DataDescriptor<E> {
|
| */
|
| abstract class HtmlEntry implements SourceEntry {
|
| /**
|
| + * The data descriptor representing the errors reported during Angular resolution.
|
| + */
|
| + static final DataDescriptor<List<AnalysisError>> ANGULAR_ERRORS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.ANGULAR_ERRORS");
|
| +
|
| + /**
|
| * The data descriptor representing the HTML element.
|
| */
|
| static final DataDescriptor<HtmlElement> ELEMENT = new DataDescriptor<HtmlElement>("HtmlEntry.ELEMENT");
|
| @@ -2425,7 +2505,7 @@ abstract class HtmlEntry implements SourceEntry {
|
| /**
|
| * The data descriptor representing the parsed AST structure.
|
| */
|
| - static final DataDescriptor<HtmlUnit> PARSED_UNIT = new DataDescriptor<HtmlUnit>("HtmlEntry.PARSED_UNIT");
|
| + static final DataDescriptor<ht.HtmlUnit> PARSED_UNIT = new DataDescriptor<ht.HtmlUnit>("HtmlEntry.PARSED_UNIT");
|
|
|
| /**
|
| * The data descriptor representing the list of referenced libraries.
|
| @@ -2461,7 +2541,7 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| /**
|
| * The parsed HTML unit, or `null` if the parsed HTML unit is not currently cached.
|
| */
|
| - HtmlUnit _parsedUnit;
|
| + ht.HtmlUnit _parsedUnit;
|
|
|
| /**
|
| * The state of the cached parse errors.
|
| @@ -2507,6 +2587,17 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| HtmlElement _element;
|
|
|
| /**
|
| + * The state of the Angular resolution errors.
|
| + */
|
| + CacheState _angularErrorsState = CacheState.INVALID;
|
| +
|
| + /**
|
| + * The hints produced while performing Angular resolution, or an empty array if the error are not
|
| + * currently cached.
|
| + */
|
| + List<AnalysisError> _angularErrors = AnalysisError.NO_ERRORS;
|
| +
|
| + /**
|
| * The state of the cached hints.
|
| */
|
| CacheState _hintsState = CacheState.INVALID;
|
| @@ -2519,14 +2610,25 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
|
|
| List<AnalysisError> get allErrors {
|
| List<AnalysisError> errors = new List<AnalysisError>();
|
| - for (AnalysisError error in _parseErrors) {
|
| - errors.add(error);
|
| + if (_parseErrors != null) {
|
| + for (AnalysisError error in _parseErrors) {
|
| + errors.add(error);
|
| + }
|
| }
|
| - for (AnalysisError error in _resolutionErrors) {
|
| - errors.add(error);
|
| + if (_resolutionErrors != null) {
|
| + for (AnalysisError error in _resolutionErrors) {
|
| + errors.add(error);
|
| + }
|
| }
|
| - for (AnalysisError error in _hints) {
|
| - errors.add(error);
|
| + if (_angularErrors != null) {
|
| + for (AnalysisError error in _angularErrors) {
|
| + errors.add(error);
|
| + }
|
| + }
|
| + if (_hints != null) {
|
| + for (AnalysisError error in _hints) {
|
| + errors.add(error);
|
| + }
|
| }
|
| if (errors.length == 0) {
|
| return AnalysisError.NO_ERRORS;
|
| @@ -2537,7 +2639,9 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| SourceKind get kind => SourceKind.HTML;
|
|
|
| CacheState getState(DataDescriptor descriptor) {
|
| - if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| + if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
|
| + return _angularErrorsState;
|
| + } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| return _elementState;
|
| } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
|
| return _parseErrorsState;
|
| @@ -2554,7 +2658,9 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| }
|
|
|
| Object getValue(DataDescriptor descriptor) {
|
| - if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| + if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
|
| + return _angularErrors;
|
| + } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| return _element;
|
| } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
|
| return _parseErrors;
|
| @@ -2591,6 +2697,8 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| * Invalidate all of the resolution information associated with the HTML file.
|
| */
|
| void invalidateAllResolutionInformation() {
|
| + _angularErrors = AnalysisError.NO_ERRORS;
|
| + _angularErrorsState = CacheState.INVALID;
|
| _element = null;
|
| _elementState = CacheState.INVALID;
|
| _resolutionErrors = AnalysisError.NO_ERRORS;
|
| @@ -2616,13 +2724,17 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| * this entry.
|
| */
|
| void recordResolutionError() {
|
| + setState(HtmlEntry.ANGULAR_ERRORS, CacheState.ERROR);
|
| setState(HtmlEntry.ELEMENT, CacheState.ERROR);
|
| setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.ERROR);
|
| setState(HtmlEntry.HINTS, CacheState.ERROR);
|
| }
|
|
|
| void setState(DataDescriptor descriptor, CacheState state) {
|
| - if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| + if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
|
| + _angularErrors = updatedValue(state, _angularErrors, null);
|
| + _angularErrorsState = state;
|
| + } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| _element = updatedValue(state, _element, null);
|
| _elementState = state;
|
| } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
|
| @@ -2646,14 +2758,17 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| }
|
|
|
| void setValue(DataDescriptor descriptor, Object value) {
|
| - if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| + if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
|
| + _angularErrors = value as List<AnalysisError>;
|
| + _angularErrorsState = CacheState.VALID;
|
| + } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
|
| _element = value as HtmlElement;
|
| _elementState = CacheState.VALID;
|
| } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
|
| _parseErrors = value as List<AnalysisError>;
|
| _parseErrorsState = CacheState.VALID;
|
| } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
|
| - _parsedUnit = value as HtmlUnit;
|
| + _parsedUnit = value as ht.HtmlUnit;
|
| _parsedUnitState = CacheState.VALID;
|
| } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
|
| _referencedLibraries = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
|
| @@ -2672,6 +2787,8 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| void copyFrom(SourceEntryImpl entry) {
|
| super.copyFrom(entry);
|
| HtmlEntryImpl other = entry as HtmlEntryImpl;
|
| + _angularErrorsState = other._angularErrorsState;
|
| + _angularErrors = other._angularErrors;
|
| _parseErrorsState = other._parseErrorsState;
|
| _parseErrors = other._parseErrors;
|
| _parsedUnitState = other._parsedUnitState;
|
| @@ -2686,6 +2803,8 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| _hintsState = other._hintsState;
|
| }
|
|
|
| + bool hasErrorState() => super.hasErrorState() || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_resolutionErrorsState, CacheState.ERROR) || identical(_referencedLibrariesState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularErrorsState, CacheState.ERROR) || identical(_hintsState, CacheState.ERROR);
|
| +
|
| void writeOn(JavaStringBuilder builder) {
|
| builder.append("Html: ");
|
| super.writeOn(builder);
|
| @@ -2699,6 +2818,8 @@ class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry {
|
| builder.append(_referencedLibrariesState);
|
| builder.append("; element = ");
|
| builder.append(_elementState);
|
| + builder.append("; angularErrors = ");
|
| + builder.append(_angularErrorsState);
|
| }
|
| }
|
|
|
| @@ -2824,6 +2945,23 @@ abstract class SourceEntryImpl implements SourceEntry {
|
| */
|
| LineInfo _lineInfo;
|
|
|
| + /**
|
| + * Fix the state of the [exception] to match the current state of the entry.
|
| + */
|
| + void fixExceptionState() {
|
| + if (hasErrorState()) {
|
| + if (exception == null) {
|
| + //
|
| + // This code should never be reached, but is a fail-safe in case an exception is not
|
| + // recorded when it should be.
|
| + //
|
| + exception = new AnalysisException.con1("State set to ERROR without setting an exception");
|
| + }
|
| + } else {
|
| + exception = null;
|
| + }
|
| + }
|
| +
|
| int get modificationTime => _modificationTime;
|
|
|
| CacheState getState(DataDescriptor descriptor) {
|
| @@ -2903,11 +3041,19 @@ abstract class SourceEntryImpl implements SourceEntry {
|
| */
|
| void copyFrom(SourceEntryImpl entry) {
|
| _modificationTime = entry._modificationTime;
|
| + exception = entry.exception;
|
| _lineInfoState = entry._lineInfoState;
|
| _lineInfo = entry._lineInfo;
|
| }
|
|
|
| /**
|
| + * Return `true` if the state of any data value is [CacheState#ERROR].
|
| + *
|
| + * @return `true` if the state of any data value is [CacheState#ERROR]
|
| + */
|
| + bool hasErrorState() => identical(_lineInfoState, CacheState.ERROR);
|
| +
|
| + /**
|
| * Given that some data is being transitioned to the given state, return the value that should be
|
| * kept in the cache.
|
| *
|
| @@ -3229,11 +3375,11 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return AnalysisError.NO_ERRORS;
|
| }
|
|
|
| - List<Source> computeExportedLibraries(Source source) => getDartParseData2(source, DartEntry.EXPORTED_LIBRARIES, Source.EMPTY_ARRAY);
|
| + List<Source> computeExportedLibraries(Source source) => getDartDependencyData2(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);
|
| + List<Source> computeImportedLibraries(Source source) => getDartDependencyData2(source, DartEntry.IMPORTED_LIBRARIES, Source.EMPTY_ARRAY);
|
|
|
| SourceKind computeKindOf(Source source) {
|
| SourceEntry sourceEntry = getReadableSourceEntry(source);
|
| @@ -3293,7 +3439,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| throw new AnalysisException.con1("computeResolvableHtmlUnit invoked for non-HTML file: ${source.fullName}");
|
| }
|
| htmlEntry = cacheHtmlParseData(source, htmlEntry, HtmlEntry.PARSED_UNIT);
|
| - HtmlUnit unit = htmlEntry.getValue(HtmlEntry.PARSED_UNIT);
|
| + ht.HtmlUnit unit = htmlEntry.getValue(HtmlEntry.PARSED_UNIT);
|
| if (unit == null) {
|
| throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit could not parse ${source.fullName}");
|
| }
|
| @@ -3477,6 +3623,14 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| }
|
|
|
| + List<AngularElement> getLibraryAngularElements(Source source) {
|
| + SourceEntry sourceEntry = getReadableSourceEntry(source);
|
| + if (sourceEntry is DartEntry) {
|
| + return sourceEntry.getValue(DartEntry.ANGULAR_ELEMENTS);
|
| + }
|
| + return AngularElement.EMPTY_ARRAY;
|
| + }
|
| +
|
| LibraryElement getLibraryElement(Source source) {
|
| SourceEntry sourceEntry = getReadableSourceEntry(source);
|
| if (sourceEntry is DartEntry) {
|
| @@ -3586,7 +3740,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return null;
|
| }
|
|
|
| - HtmlUnit getResolvedHtmlUnit(Source htmlSource) {
|
| + ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) {
|
| SourceEntry sourceEntry = getReadableSourceEntry(htmlSource);
|
| if (sourceEntry is HtmlEntry) {
|
| HtmlEntry htmlEntry = sourceEntry;
|
| @@ -3718,7 +3872,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|
|
| CompilationUnit parseCompilationUnit(Source source) => getDartParseData2(source, DartEntry.PARSED_UNIT, null);
|
|
|
| - HtmlUnit parseHtmlUnit(Source source) => getHtmlParseData(source, HtmlEntry.PARSED_UNIT, null);
|
| + ht.HtmlUnit parseHtmlUnit(Source source) => getHtmlParseData(source, HtmlEntry.PARSED_UNIT, null);
|
|
|
| AnalysisResult performAnalysisTask() {
|
| int getStart = JavaSystem.currentTimeMillis();
|
| @@ -3776,7 +3930,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|
|
| CompilationUnit resolveCompilationUnit2(Source unitSource, Source librarySource) => getDartResolutionData2(unitSource, librarySource, DartEntry.RESOLVED_UNIT, null);
|
|
|
| - HtmlUnit resolveHtmlUnit(Source htmlSource) {
|
| + ht.HtmlUnit resolveHtmlUnit(Source htmlSource) {
|
| computeHtmlElement(htmlSource);
|
| return parseHtmlUnit(htmlSource);
|
| }
|
| @@ -3959,6 +4113,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| dartCopy.setValue2(DartEntry.RESOLUTION_ERRORS, librarySource, errors);
|
| if (identical(source, librarySource)) {
|
| recordElementData(dartCopy, library.libraryElement, htmlSource);
|
| + recordAngularComponents(library, dartCopy);
|
| }
|
| } else {
|
| dartCopy.recordResolutionError();
|
| @@ -4057,7 +4212,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| if (dartEntry == null) {
|
| // This shouldn't be possible because we should never have performed the task if the
|
| // source didn't represent a Dart file, but check to be safe.
|
| - throw new AnalysisException.con1("Internal error: attempting to reolve non-Dart file as a Dart file: ${source.fullName}");
|
| + throw new AnalysisException.con1("Internal error: attempting to resolve non-Dart file as a Dart file: ${source.fullName}");
|
| }
|
| int sourceTime = source.modificationStamp;
|
| int resultTime = library.getModificationTime(source);
|
| @@ -4072,6 +4227,34 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
|
|
| /**
|
| + * Given a source for a Dart file, return a cache entry in which the data represented by the given
|
| + * descriptor is available. This method assumes that the data can be produced by resolving the
|
| + * directives in the source if they are not already cached.
|
| + *
|
| + * @param source the source representing the Dart file
|
| + * @param dartEntry the cache entry associated with the Dart file
|
| + * @param descriptor the descriptor representing the data to be returned
|
| + * @return a cache entry containing the required data
|
| + * @throws AnalysisException if data could not be returned because the source could not be
|
| + * resolved
|
| + */
|
| + DartEntry cacheDartDependencyData(Source source, DartEntry dartEntry, DataDescriptor descriptor) {
|
| + //
|
| + // Check to see whether we already have the information being requested.
|
| + //
|
| + CacheState state = dartEntry.getState(descriptor);
|
| + while (state != CacheState.ERROR && state != CacheState.VALID) {
|
| + //
|
| + // If not, compute the information. Unless the modification date of the source continues to
|
| + // change, this loop will eventually terminate.
|
| + //
|
| + dartEntry = new ResolveDartDependenciesTask(this, source).perform(_resultRecorder) as DartEntry;
|
| + state = dartEntry.getState(descriptor);
|
| + }
|
| + return dartEntry;
|
| + }
|
| +
|
| + /**
|
| * Given a source for a Dart file and the library that contains it, return a cache entry in which
|
| * the data represented by the given descriptor is available. This method assumes that the data
|
| * can be produced by generating hints for the library if the data is not already cached.
|
| @@ -4346,6 +4529,42 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
|
|
| /**
|
| + * Given a source for a Dart file, return the data represented by the given descriptor that is
|
| + * associated with that source. This method assumes that the data can be produced by resolving the
|
| + * directives in the source if they are not already cached.
|
| + *
|
| + * @param source the source representing the Dart file
|
| + * @param dartEntry the cache entry associated with the Dart file
|
| + * @param descriptor the descriptor representing the data to be returned
|
| + * @return the requested data about the given source
|
| + * @throws AnalysisException if data could not be returned because the source could not be parsed
|
| + */
|
| + Object getDartDependencyData(Source source, DartEntry dartEntry, DataDescriptor descriptor) {
|
| + dartEntry = cacheDartDependencyData(source, dartEntry, descriptor);
|
| + return dartEntry.getValue(descriptor);
|
| + }
|
| +
|
| + /**
|
| + * Given a source for a Dart file, return the data represented by the given descriptor that is
|
| + * associated with that source, or the given default value if the source is not a Dart file. This
|
| + * method assumes that the data can be produced by resolving the directives in the source if they
|
| + * are not already cached.
|
| + *
|
| + * @param source the source representing the Dart file
|
| + * @param descriptor the descriptor representing the data to be returned
|
| + * @param defaultValue the value to be returned if the source is not a Dart file
|
| + * @return the requested data about the given source
|
| + * @throws AnalysisException if data could not be returned because the source could not be parsed
|
| + */
|
| + Object getDartDependencyData2(Source source, DataDescriptor descriptor, Object defaultValue) {
|
| + DartEntry dartEntry = getReadableDartEntry(source);
|
| + if (dartEntry == null) {
|
| + return defaultValue;
|
| + }
|
| + return getDartDependencyData(source, dartEntry, descriptor);
|
| + }
|
| +
|
| + /**
|
| * Given a source for a Dart file and the library that contains it, return the data represented by
|
| * the given descriptor that is associated with that source. This method assumes that the data can
|
| * be produced by generating hints for the library if it is not already cached.
|
| @@ -4558,6 +4777,43 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return task;
|
| }
|
| }
|
| + //
|
| + // Look for HTML sources that should be resolved as Angular templates.
|
| + //
|
| + for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
|
| + SourceEntry sourceEntry = entry.getValue();
|
| + if (sourceEntry is DartEntry) {
|
| + DartEntry dartEntry = sourceEntry;
|
| + List<AngularElement> angularElements = dartEntry.getValue(DartEntry.ANGULAR_ELEMENTS);
|
| + for (AngularElement angularElement in angularElements) {
|
| + // prepare Angular component
|
| + if (angularElement is! AngularComponentElement) {
|
| + continue;
|
| + }
|
| + AngularComponentElement component = angularElement as AngularComponentElement;
|
| + // prepare HTML template
|
| + Source templateSource = component.templateSource;
|
| + if (templateSource == null) {
|
| + continue;
|
| + }
|
| + // prepare HTML template entry
|
| + HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
|
| + if (htmlEntry == null) {
|
| + continue;
|
| + }
|
| + // we need an entry with invalid Angular errors
|
| + CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
|
| + if (angularErrorsState != CacheState.INVALID) {
|
| + continue;
|
| + }
|
| + // do Angular component resolution
|
| + HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
|
| + htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
|
| + _cache.put(templateSource, htmlCopy);
|
| + return new ResolveAngularComponentTemplateTask(this, templateSource, component, angularElements);
|
| + }
|
| + }
|
| + }
|
| return null;
|
| }
|
| }
|
| @@ -4601,6 +4857,13 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| return new ParseDartTask(this, source);
|
| }
|
| }
|
| + CacheState exportState = dartEntry.getState(DartEntry.EXPORTED_LIBRARIES);
|
| + if (identical(exportState, CacheState.INVALID) || (isPriority && identical(exportState, CacheState.FLUSHED))) {
|
| + DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + dartCopy.setState(DartEntry.EXPORTED_LIBRARIES, CacheState.IN_PROCESS);
|
| + _cache.put(source, dartCopy);
|
| + return new ResolveDartDependenciesTask(this, source);
|
| + }
|
| for (Source librarySource in getLibrariesContaining(source)) {
|
| SourceEntry libraryEntry = _cache.get(librarySource);
|
| if (libraryEntry is DartEntry) {
|
| @@ -4965,6 +5228,50 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
|
|
| /**
|
| + * Updates [HtmlEntry]s that correspond to the previously known and new Angular components.
|
| + *
|
| + * @param library the [Library] that was resolved
|
| + * @param dartCopy the [DartEntryImpl] to record new Angular components
|
| + */
|
| + void recordAngularComponents(Library library, DartEntryImpl dartCopy) {
|
| + // reset old Angular errors
|
| + List<AngularElement> oldAngularElements = dartCopy.getValue(DartEntry.ANGULAR_ELEMENTS);
|
| + if (oldAngularElements != null) {
|
| + for (AngularElement angularElement in oldAngularElements) {
|
| + if (angularElement is AngularComponentElement) {
|
| + AngularComponentElement component = angularElement;
|
| + Source templateSource = component.templateSource;
|
| + if (templateSource != null) {
|
| + HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
|
| + HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
|
| + htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, AnalysisError.NO_ERRORS);
|
| + _cache.put(templateSource, htmlCopy);
|
| + // notify about (disappeared) HTML errors
|
| + ChangeNoticeImpl notice = getNotice(templateSource);
|
| + notice.setErrors(htmlCopy.allErrors, computeLineInfo(templateSource));
|
| + }
|
| + }
|
| + }
|
| + }
|
| + // invalidate new Angular errors
|
| + List<AngularElement> newAngularElements = library.angularElements;
|
| + for (AngularElement angularElement in newAngularElements) {
|
| + if (angularElement is AngularComponentElement) {
|
| + AngularComponentElement component = angularElement;
|
| + Source templateSource = component.templateSource;
|
| + if (templateSource != null) {
|
| + HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
|
| + HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
|
| + htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
|
| + _cache.put(templateSource, htmlCopy);
|
| + }
|
| + }
|
| + }
|
| + // remember Angular elements to resolve HTML templates later
|
| + dartCopy.setValue(DartEntry.ANGULAR_ELEMENTS, newAngularElements);
|
| + }
|
| +
|
| + /**
|
| * Given a cache entry and a library element, record the library element and other information
|
| * gleaned from the element in the cache entry.
|
| *
|
| @@ -4978,6 +5285,9 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| dartCopy.setValue(DartEntry.IS_CLIENT, isClient(library, htmlSource, new Set<LibraryElement>()));
|
| List<Source> unitSources = new List<Source>();
|
| unitSources.add(library.definingCompilationUnit.source);
|
| + // TODO(brianwilkerson) Understand why we're doing this both here and in
|
| + // ResolveDartDependenciesTask and whether we should also be capturing the imported and exported
|
| + // sources here.
|
| for (CompilationUnitElement part in library.parts) {
|
| Source partSource = part.source;
|
| unitSources.add(partSource);
|
| @@ -5220,9 +5530,6 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| dartCopy.setValue(DartEntry.PARSED_UNIT, task.compilationUnit);
|
| dartCopy.setValue(DartEntry.PARSE_ERRORS, task.errors);
|
| - dartCopy.setValue(DartEntry.EXPORTED_LIBRARIES, task.exportedSources);
|
| - dartCopy.setValue(DartEntry.IMPORTED_LIBRARIES, task.importedSources);
|
| - dartCopy.setValue(DartEntry.INCLUDED_PARTS, task.includedSources);
|
| ChangeNoticeImpl notice = getNotice(source);
|
| notice.setErrors(dartEntry.allErrors, lineInfo);
|
| // Verify that the incrementally parsed and resolved unit in the incremental cache
|
| @@ -5297,7 +5604,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| HtmlEntryImpl htmlCopy = (sourceEntry as HtmlEntry).writableCopy;
|
| if (thrownException == null) {
|
| LineInfo lineInfo = task.lineInfo;
|
| - HtmlUnit unit = task.htmlUnit;
|
| + ht.HtmlUnit unit = task.htmlUnit;
|
| htmlCopy.setValue(SourceEntry.LINE_INFO, lineInfo);
|
| htmlCopy.setValue(HtmlEntry.PARSED_UNIT, unit);
|
| htmlCopy.setValue(HtmlEntry.PARSE_ERRORS, task.errors);
|
| @@ -5349,57 +5656,208 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
|
|
| /**
|
| - * Record the results produced by performing a [ResolveDartUnitTask]. If the results were
|
| - * computed from data that is now out-of-date, then the results will not be recorded.
|
| + * Record the results produced by performing a [ResolveAngularComponentTemplateTask]. If the
|
| + * results were computed from data that is now out-of-date, then the results will not be recorded.
|
| *
|
| * @param task the task that was performed
|
| - * @return an entry containing the computed results
|
| * @throws AnalysisException if the results could not be recorded
|
| */
|
| - SourceEntry recordResolveDartUnitTaskResults(ResolveDartUnitTask task) {
|
| - Source unitSource = task.source;
|
| - Source librarySource = task.librarySource;
|
| + HtmlEntry recordResolveAngularComponentTemplateTaskResults(ResolveAngularComponentTemplateTask task) {
|
| + Source source = task.source;
|
| AnalysisException thrownException = task.exception;
|
| - DartEntry dartEntry = null;
|
| + HtmlEntry htmlEntry = null;
|
| {
|
| - SourceEntry sourceEntry = _cache.get(unitSource);
|
| - if (sourceEntry is! DartEntry) {
|
| + SourceEntry sourceEntry = _cache.get(source);
|
| + if (sourceEntry is! HtmlEntry) {
|
| // This shouldn't be possible because we should never have performed the task if the source
|
| - // didn't represent a Dart file, but check to be safe.
|
| - throw new AnalysisException.con1("Internal error: attempting to reolve non-Dart file as a Dart file: ${unitSource.fullName}");
|
| + // didn't represent an HTML file, but check to be safe.
|
| + throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
|
| }
|
| - dartEntry = sourceEntry as DartEntry;
|
| - _cache.accessed(unitSource);
|
| - int sourceTime = unitSource.modificationStamp;
|
| + htmlEntry = sourceEntry as HtmlEntry;
|
| + _cache.accessed(source);
|
| + int sourceTime = source.modificationStamp;
|
| int resultTime = task.modificationTime;
|
| if (sourceTime == resultTime) {
|
| - if (dartEntry.modificationTime != sourceTime) {
|
| + if (htmlEntry.modificationTime != sourceTime) {
|
| // The source has changed without the context being notified. Simulate notification.
|
| - sourceChanged(unitSource);
|
| - dartEntry = getReadableDartEntry(unitSource);
|
| - if (dartEntry == null) {
|
| - throw new AnalysisException.con1("A Dart file became a non-Dart file: ${unitSource.fullName}");
|
| + sourceChanged(source);
|
| + htmlEntry = getReadableHtmlEntry(source);
|
| + if (htmlEntry == null) {
|
| + throw new AnalysisException.con1("An HTML file became a non-HTML file: ${source.fullName}");
|
| }
|
| }
|
| - DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
|
| if (thrownException == null) {
|
| - dartCopy.setValue2(DartEntry.RESOLVED_UNIT, librarySource, task.resolvedUnit);
|
| + htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, task.resolutionErrors);
|
| + ChangeNoticeImpl notice = getNotice(source);
|
| + notice.htmlUnit = task.resolvedUnit;
|
| + notice.setErrors(htmlCopy.allErrors, htmlCopy.getValue(SourceEntry.LINE_INFO));
|
| } else {
|
| - dartCopy.setState2(DartEntry.RESOLVED_UNIT, librarySource, CacheState.ERROR);
|
| + htmlCopy.recordResolutionError();
|
| }
|
| - dartCopy.exception = thrownException;
|
| - _cache.put(unitSource, dartCopy);
|
| - dartEntry = dartCopy;
|
| + htmlCopy.exception = thrownException;
|
| + _cache.put(source, htmlCopy);
|
| + htmlEntry = htmlCopy;
|
| } else {
|
| - logInformation2("Resolution results discarded for ${debuggingString(unitSource)}; sourceTime = ${sourceTime}, resultTime = ${resultTime}, cacheTime = ${dartEntry.modificationTime}", thrownException);
|
| - DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
|
| if (thrownException == null || resultTime >= 0) {
|
| //
|
| // The analysis was performed on out-of-date sources. Mark the cache so that the sources
|
| // will be re-analyzed using the up-to-date sources.
|
| //
|
| - if (identical(dartCopy.getState(DartEntry.RESOLVED_UNIT), CacheState.IN_PROCESS)) {
|
| - dartCopy.setState2(DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID);
|
| + if (identical(htmlCopy.getState(HtmlEntry.ANGULAR_ERRORS), CacheState.IN_PROCESS)) {
|
| + htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
|
| + }
|
| + if (identical(htmlCopy.getState(HtmlEntry.ELEMENT), CacheState.IN_PROCESS)) {
|
| + htmlCopy.setState(HtmlEntry.ELEMENT, CacheState.INVALID);
|
| + }
|
| + if (identical(htmlCopy.getState(HtmlEntry.RESOLUTION_ERRORS), CacheState.IN_PROCESS)) {
|
| + htmlCopy.setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.INVALID);
|
| + }
|
| + } else {
|
| + //
|
| + // We could not determine whether the sources were up-to-date or out-of-date. Mark the
|
| + // cache so that we won't attempt to re-analyze the sources until there's a good chance
|
| + // that we'll be able to do so without error.
|
| + //
|
| + htmlCopy.recordResolutionError();
|
| + }
|
| + htmlCopy.exception = thrownException;
|
| + _cache.put(source, htmlCopy);
|
| + htmlEntry = htmlCopy;
|
| + }
|
| + }
|
| + if (thrownException != null) {
|
| + throw thrownException;
|
| + }
|
| + return htmlEntry;
|
| + }
|
| +
|
| + /**
|
| + * Record the results produced by performing a [ResolveDartDependenciesTask]. If the results
|
| + * were computed from data that is now out-of-date, then the results will not be recorded.
|
| + *
|
| + * @param task the task that was performed
|
| + * @return an entry containing the computed results
|
| + * @throws AnalysisException if the results could not be recorded
|
| + */
|
| + DartEntry recordResolveDartDependenciesTaskResults(ResolveDartDependenciesTask task) {
|
| + Source source = task.source;
|
| + AnalysisException thrownException = task.exception;
|
| + DartEntry dartEntry = null;
|
| + {
|
| + SourceEntry sourceEntry = _cache.get(source);
|
| + if (sourceEntry is! DartEntry) {
|
| + // This shouldn't be possible because we should never have performed the task if the source
|
| + // didn't represent a Dart file, but check to be safe.
|
| + throw new AnalysisException.con1("Internal error: attempting to resolve Dart dependencies in a non-Dart file: ${source.fullName}");
|
| + }
|
| + dartEntry = sourceEntry as DartEntry;
|
| + _cache.accessed(source);
|
| + int sourceTime = source.modificationStamp;
|
| + int resultTime = task.modificationTime;
|
| + if (sourceTime == resultTime) {
|
| + if (dartEntry.modificationTime != sourceTime) {
|
| + // The source has changed without the context being notified. Simulate notification.
|
| + sourceChanged(source);
|
| + dartEntry = getReadableDartEntry(source);
|
| + if (dartEntry == null) {
|
| + throw new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}");
|
| + }
|
| + }
|
| + DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + if (thrownException == null) {
|
| + dartCopy.setValue(DartEntry.EXPORTED_LIBRARIES, task.exportedSources);
|
| + dartCopy.setValue(DartEntry.IMPORTED_LIBRARIES, task.importedSources);
|
| + dartCopy.setValue(DartEntry.INCLUDED_PARTS, task.includedSources);
|
| + } else {
|
| + dartCopy.recordDependencyError();
|
| + }
|
| + dartCopy.exception = thrownException;
|
| + _cache.put(source, dartCopy);
|
| + dartEntry = dartCopy;
|
| + } else {
|
| + logInformation2("Dependency resolution results discarded for ${debuggingString(source)}; sourceTime = ${sourceTime}, resultTime = ${resultTime}, cacheTime = ${dartEntry.modificationTime}", thrownException);
|
| + DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + if (thrownException == null || resultTime >= 0) {
|
| + //
|
| + // The analysis was performed on out-of-date sources. Mark the cache so that the sources
|
| + // will be re-analyzed using the up-to-date sources.
|
| + //
|
| + dartCopy.recordDependencyNotInProcess();
|
| + } else {
|
| + //
|
| + // We could not determine whether the sources were up-to-date or out-of-date. Mark the
|
| + // cache so that we won't attempt to re-analyze the sources until there's a good chance
|
| + // that we'll be able to do so without error.
|
| + //
|
| + dartCopy.setState(DartEntry.EXPORTED_LIBRARIES, CacheState.ERROR);
|
| + dartCopy.setState(DartEntry.IMPORTED_LIBRARIES, CacheState.ERROR);
|
| + dartCopy.setState(DartEntry.INCLUDED_PARTS, CacheState.ERROR);
|
| + }
|
| + dartCopy.exception = thrownException;
|
| + _cache.put(source, dartCopy);
|
| + dartEntry = dartCopy;
|
| + }
|
| + }
|
| + if (thrownException != null) {
|
| + throw thrownException;
|
| + }
|
| + return dartEntry;
|
| + }
|
| +
|
| + /**
|
| + * Record the results produced by performing a [ResolveDartUnitTask]. If the results were
|
| + * computed from data that is now out-of-date, then the results will not be recorded.
|
| + *
|
| + * @param task the task that was performed
|
| + * @return an entry containing the computed results
|
| + * @throws AnalysisException if the results could not be recorded
|
| + */
|
| + SourceEntry recordResolveDartUnitTaskResults(ResolveDartUnitTask task) {
|
| + Source unitSource = task.source;
|
| + Source librarySource = task.librarySource;
|
| + AnalysisException thrownException = task.exception;
|
| + DartEntry dartEntry = null;
|
| + {
|
| + SourceEntry sourceEntry = _cache.get(unitSource);
|
| + if (sourceEntry is! DartEntry) {
|
| + // This shouldn't be possible because we should never have performed the task if the source
|
| + // didn't represent a Dart file, but check to be safe.
|
| + throw new AnalysisException.con1("Internal error: attempting to resolve non-Dart file as a Dart file: ${unitSource.fullName}");
|
| + }
|
| + dartEntry = sourceEntry as DartEntry;
|
| + _cache.accessed(unitSource);
|
| + int sourceTime = unitSource.modificationStamp;
|
| + int resultTime = task.modificationTime;
|
| + if (sourceTime == resultTime) {
|
| + if (dartEntry.modificationTime != sourceTime) {
|
| + // The source has changed without the context being notified. Simulate notification.
|
| + sourceChanged(unitSource);
|
| + dartEntry = getReadableDartEntry(unitSource);
|
| + if (dartEntry == null) {
|
| + throw new AnalysisException.con1("A Dart file became a non-Dart file: ${unitSource.fullName}");
|
| + }
|
| + }
|
| + DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + if (thrownException == null) {
|
| + dartCopy.setValue2(DartEntry.RESOLVED_UNIT, librarySource, task.resolvedUnit);
|
| + } else {
|
| + dartCopy.setState2(DartEntry.RESOLVED_UNIT, librarySource, CacheState.ERROR);
|
| + }
|
| + dartCopy.exception = thrownException;
|
| + _cache.put(unitSource, dartCopy);
|
| + dartEntry = dartCopy;
|
| + } else {
|
| + logInformation2("Resolution results discarded for ${debuggingString(unitSource)}; sourceTime = ${sourceTime}, resultTime = ${resultTime}, cacheTime = ${dartEntry.modificationTime}", thrownException);
|
| + DartEntryImpl dartCopy = dartEntry.writableCopy;
|
| + if (thrownException == null || resultTime >= 0) {
|
| + //
|
| + // The analysis was performed on out-of-date sources. Mark the cache so that the sources
|
| + // will be re-analyzed using the up-to-date sources.
|
| + //
|
| + if (identical(dartCopy.getState(DartEntry.RESOLVED_UNIT), CacheState.IN_PROCESS)) {
|
| + dartCopy.setState2(DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID);
|
| }
|
| } else {
|
| //
|
| @@ -5437,7 +5895,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
| if (sourceEntry is! HtmlEntry) {
|
| // This shouldn't be possible because we should never have performed the task if the source
|
| // didn't represent an HTML file, but check to be safe.
|
| - throw new AnalysisException.con1("Internal error: attempting to reolve non-HTML file as an HTML file: ${source.fullName}");
|
| + throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
|
| }
|
| htmlEntry = sourceEntry as HtmlEntry;
|
| _cache.accessed(source);
|
| @@ -5644,6 +6102,10 @@ class AnalysisContextImpl_AnalysisTaskResultRecorder implements AnalysisTaskVisi
|
|
|
| HtmlEntry visitParseHtmlTask(ParseHtmlTask task) => AnalysisContextImpl_this.recordParseHtmlTaskResults(task);
|
|
|
| + HtmlEntry visitResolveAngularComponentTemplateTask(ResolveAngularComponentTemplateTask task) => AnalysisContextImpl_this.recordResolveAngularComponentTemplateTaskResults(task);
|
| +
|
| + DartEntry visitResolveDartDependenciesTask(ResolveDartDependenciesTask task) => AnalysisContextImpl_this.recordResolveDartDependenciesTaskResults(task);
|
| +
|
| DartEntry visitResolveDartLibraryTask(ResolveDartLibraryTask task) => AnalysisContextImpl_this.recordResolveDartLibraryTaskResults(task);
|
|
|
| SourceEntry visitResolveDartUnitTask(ResolveDartUnitTask task) => AnalysisContextImpl_this.recordResolveDartUnitTaskResults(task);
|
| @@ -5780,7 +6242,7 @@ class ChangeNoticeImpl implements ChangeNotice {
|
| * The fully resolved HTML that changed as a result of the analysis, or `null` if the HTML
|
| * was not changed.
|
| */
|
| - HtmlUnit htmlUnit;
|
| + ht.HtmlUnit htmlUnit;
|
|
|
| /**
|
| * The errors that changed as a result of the analysis, or `null` if errors were not
|
| @@ -6039,7 +6501,7 @@ class DelegatingAnalysisContextImpl extends AnalysisContextImpl {
|
| }
|
| }
|
|
|
| - HtmlUnit parseHtmlUnit(Source source) {
|
| + ht.HtmlUnit parseHtmlUnit(Source source) {
|
| if (source.isInSystemLibrary) {
|
| return _sdkAnalysisContext.parseHtmlUnit(source);
|
| } else {
|
| @@ -6079,7 +6541,7 @@ class DelegatingAnalysisContextImpl extends AnalysisContextImpl {
|
| }
|
| }
|
|
|
| - HtmlUnit resolveHtmlUnit(Source unitSource) {
|
| + ht.HtmlUnit resolveHtmlUnit(Source unitSource) {
|
| if (unitSource.isInSystemLibrary) {
|
| return _sdkAnalysisContext.resolveHtmlUnit(unitSource);
|
| } else {
|
| @@ -6600,6 +7062,16 @@ class InstrumentedAnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| }
|
|
|
| + List<AngularElement> getLibraryAngularElements(Source source) {
|
| + InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getLibraryAngularElements");
|
| + try {
|
| + instrumentation.metric3("contextId", _contextId);
|
| + return _basis.getLibraryAngularElements(source);
|
| + } finally {
|
| + instrumentation.log();
|
| + }
|
| + }
|
| +
|
| LibraryElement getLibraryElement(Source source) {
|
| InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getLibraryElement");
|
| try {
|
| @@ -6660,7 +7132,7 @@ class InstrumentedAnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| }
|
|
|
| - HtmlUnit getResolvedHtmlUnit(Source htmlSource) {
|
| + ht.HtmlUnit getResolvedHtmlUnit(Source htmlSource) {
|
| InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getResolvedHtmlUnit");
|
| try {
|
| instrumentation.metric3("contextId", _contextId);
|
| @@ -6732,7 +7204,7 @@ class InstrumentedAnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| }
|
|
|
| - HtmlUnit parseHtmlUnit(Source source) {
|
| + ht.HtmlUnit parseHtmlUnit(Source source) {
|
| InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-parseHtmlUnit");
|
| try {
|
| instrumentation.metric3("contextId", _contextId);
|
| @@ -6789,7 +7261,7 @@ class InstrumentedAnalysisContextImpl implements InternalAnalysisContext {
|
| }
|
| }
|
|
|
| - HtmlUnit resolveHtmlUnit(Source htmlSource) {
|
| + ht.HtmlUnit resolveHtmlUnit(Source htmlSource) {
|
| InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-resolveHtmlUnit");
|
| try {
|
| instrumentation.metric3("contextId", _contextId);
|
| @@ -7211,21 +7683,21 @@ class ResolvableCompilationUnit extends TimestampedData<CompilationUnit> {
|
| * by any other objects and for which we have modification stamp information. It is used by the
|
| * [ResolveHtmlTask] to resolve an HTML source.
|
| */
|
| -class ResolvableHtmlUnit extends TimestampedData<HtmlUnit> {
|
| +class ResolvableHtmlUnit extends TimestampedData<ht.HtmlUnit> {
|
| /**
|
| * Initialize a newly created holder to hold the given values.
|
| *
|
| * @param modificationTime the modification time of the source from which the AST was created
|
| * @param unit the AST that was created from the source
|
| */
|
| - ResolvableHtmlUnit(int modificationTime, HtmlUnit unit) : super(modificationTime, unit);
|
| + ResolvableHtmlUnit(int modificationTime, ht.HtmlUnit unit) : super(modificationTime, unit);
|
|
|
| /**
|
| * Return the AST that was created from the source.
|
| *
|
| * @return the AST that was created from the source
|
| */
|
| - HtmlUnit get compilationUnit => data;
|
| + ht.HtmlUnit get compilationUnit => data;
|
| }
|
|
|
| /**
|
| @@ -7253,77 +7725,797 @@ class TimestampedData<E> {
|
| }
|
|
|
| /**
|
| - * The abstract class `AnalysisTask` defines the behavior of objects used to perform an
|
| - * analysis task.
|
| + * Instances of the class [AngularHtmlUnitResolver] resolve Angular specific expressions.
|
| */
|
| -abstract class AnalysisTask {
|
| +class AngularHtmlUnitResolver extends ht.RecursiveXmlVisitor<Object> {
|
| + static int _OPENING_DELIMITER_CHAR = 0x7B;
|
| +
|
| + static int _CLOSING_DELIMITER_CHAR = 0x7D;
|
| +
|
| + static String _OPENING_DELIMITER = "{{";
|
| +
|
| + static String _CLOSING_DELIMITER = "}}";
|
| +
|
| + static int _OPENING_DELIMITER_LENGTH = _OPENING_DELIMITER.length;
|
| +
|
| + static int _CLOSING_DELIMITER_LENGTH = _CLOSING_DELIMITER.length;
|
| +
|
| + static String _NG_APP = "ng-app";
|
| +
|
| /**
|
| - * The context in which the task is to be performed.
|
| + * Checks if given [Element] is an artificial local variable and returns corresponding
|
| + * [AngularElement], or `null` otherwise.
|
| */
|
| - final InternalAnalysisContext context;
|
| + static AngularElement getAngularElement(Element element) {
|
| + // may be artificial local variable, replace with AngularElement
|
| + if (element is LocalVariableElement) {
|
| + LocalVariableElement local = element;
|
| + List<ToolkitObjectElement> toolkitObjects = local.toolkitObjects;
|
| + if (toolkitObjects.length == 1 && toolkitObjects[0] is AngularElement) {
|
| + return toolkitObjects[0] as AngularElement;
|
| + }
|
| + }
|
| + // not a special Element
|
| + return null;
|
| + }
|
|
|
| /**
|
| - * The exception that was thrown while performing this task, or `null` if the task completed
|
| - * successfully.
|
| + * @return `true` if the given [HtmlUnit] has <code>ng-app</code> annotation.
|
| */
|
| - AnalysisException _thrownException;
|
| + static bool hasAngularAnnotation(ht.HtmlUnit htmlUnit) {
|
| + try {
|
| + htmlUnit.accept(new RecursiveXmlVisitor_AngularHtmlUnitResolver_hasAngularAnnotation());
|
| + } on AngularHtmlUnitResolver_FoundAppError catch (e) {
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + static SimpleIdentifier createIdentifier(String name, int offset) {
|
| + StringToken token = createStringToken(name, offset);
|
| + return new SimpleIdentifier(token);
|
| + }
|
| +
|
| + static StringToken createStringToken(String name, int offset) => new StringToken(TokenType.IDENTIFIER, name, offset);
|
| +
|
| + InternalAnalysisContext _context;
|
| +
|
| + TypeProvider _typeProvider;
|
| +
|
| + AnalysisErrorListener _errorListener;
|
| +
|
| + Source _source;
|
| +
|
| + LineInfo _lineInfo;
|
| +
|
| + ht.HtmlUnit _unit;
|
| +
|
| + List<AngularElement> _angularElements;
|
| +
|
| + List<NgProcessor> _processors = [];
|
| +
|
| + LibraryElementImpl _libraryElement;
|
| +
|
| + CompilationUnitElementImpl _unitElement;
|
| +
|
| + FunctionElementImpl _functionElement;
|
| +
|
| + ResolverVisitor _resolver;
|
| +
|
| + bool _isAngular = false;
|
| +
|
| + List<LocalVariableElementImpl> _definedVariables = [];
|
| +
|
| + Set<LibraryElement> _injectedLibraries = new Set();
|
| +
|
| + Scope _topNameScope;
|
| +
|
| + Scope _nameScope;
|
| +
|
| + AngularHtmlUnitResolver(InternalAnalysisContext context, AnalysisErrorListener errorListener, Source source, LineInfo lineInfo, ht.HtmlUnit unit) {
|
| + this._context = context;
|
| + this._typeProvider = context.typeProvider;
|
| + this._errorListener = errorListener;
|
| + this._source = source;
|
| + this._lineInfo = lineInfo;
|
| + this._unit = unit;
|
| + }
|
|
|
| /**
|
| - * Initialize a newly created task to perform analysis within the given context.
|
| + * Resolves [source] as an [AngularComponentElement] template file.
|
| *
|
| - * @param context the context in which the task is to be performed
|
| + * @param angularElements the [AngularElement]s accessible in the component's library, not
|
| + * `null`
|
| + * @param component the [AngularComponentElement] to resolve template for, not `null`
|
| */
|
| - AnalysisTask(this.context);
|
| + void resolveComponentTemplate(List<AngularElement> angularElements, AngularComponentElement component) {
|
| + _isAngular = true;
|
| + resolveInternal(angularElements, component);
|
| + }
|
|
|
| /**
|
| - * Use the given visitor to visit this task.
|
| - *
|
| - * @param visitor the visitor that should be used to visit this task
|
| - * @return the value returned by the visitor
|
| - * @throws AnalysisException if the visitor throws the exception
|
| + * Resolves [source] as an entry-point HTML file, that references an external Dart script.
|
| */
|
| - accept(AnalysisTaskVisitor visitor);
|
| + void resolveEntryPoint() {
|
| + // check if Angular at all
|
| + if (!hasAngularAnnotation(_unit)) {
|
| + return;
|
| + }
|
| + // prepare accessible Angular elements
|
| + List<AngularElement> angularElements;
|
| + {
|
| + // prepare external Dart script source
|
| + Source dartSource = getDartSource(_unit);
|
| + if (dartSource == null) {
|
| + return;
|
| + }
|
| + // ensure resolved
|
| + _context.resolveCompilationUnit2(dartSource, dartSource);
|
| + // get cached Angular elements
|
| + angularElements = _context.getLibraryAngularElements(dartSource);
|
| + }
|
| + // perform resolution
|
| + resolveInternal(angularElements, null);
|
| + }
|
| +
|
| + Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
|
| + parseEmbeddedExpressions2(node);
|
| + resolveExpressions(node.expressions);
|
| + return super.visitXmlAttributeNode(node);
|
| + }
|
| +
|
| + Object visitXmlTagNode(ht.XmlTagNode node) {
|
| + bool wasAngular = _isAngular;
|
| + try {
|
| + // new Angular context
|
| + if (node.getAttribute(_NG_APP) != null) {
|
| + _isAngular = true;
|
| + visitModelDirectives(node);
|
| + }
|
| + // not Angular
|
| + if (!_isAngular) {
|
| + return super.visitXmlTagNode(node);
|
| + }
|
| + // process node in separate name scope
|
| + _nameScope = _resolver.pushNameScope();
|
| + try {
|
| + parseEmbeddedExpressions3(node);
|
| + // apply processors
|
| + for (NgProcessor processor in _processors) {
|
| + if (processor.canApply(node)) {
|
| + processor.apply(this, node);
|
| + }
|
| + }
|
| + // resolve expressions
|
| + resolveExpressions(node.expressions);
|
| + // process children
|
| + return super.visitXmlTagNode(node);
|
| + } finally {
|
| + _resolver.popNameScope();
|
| + }
|
| + } finally {
|
| + _isAngular = wasAngular;
|
| + }
|
| + }
|
|
|
| /**
|
| - * Return the exception that was thrown while performing this task, or `null` if the task
|
| - * completed successfully.
|
| + * Creates new [LocalVariableElementImpl] with given type and identifier.
|
| *
|
| - * @return the exception that was thrown while performing this task
|
| + * @param type the [Type] of the variable
|
| + * @param identifier the identifier to create variable for
|
| + * @return the new [LocalVariableElementImpl]
|
| */
|
| - AnalysisException get exception => _thrownException;
|
| + LocalVariableElementImpl createLocalVariable(Type2 type, SimpleIdentifier identifier) {
|
| + LocalVariableElementImpl variable = new LocalVariableElementImpl(identifier);
|
| + _definedVariables.add(variable);
|
| + variable.type = type;
|
| + return variable;
|
| + }
|
|
|
| /**
|
| - * Perform this analysis task and use the given visitor to visit this task after it has completed.
|
| + * Creates new [LocalVariableElementImpl] with given name and type.
|
| *
|
| - * @param visitor the visitor used to visit this task after it has completed
|
| - * @return the value returned by the visitor
|
| - * @throws AnalysisException if the visitor throws the exception
|
| + * @param type the [Type] of the variable
|
| + * @param name the name of the variable
|
| + * @return the new [LocalVariableElementImpl]
|
| */
|
| - Object perform(AnalysisTaskVisitor visitor) {
|
| - try {
|
| - safelyPerform();
|
| - } on AnalysisException catch (exception) {
|
| - _thrownException = exception;
|
| - AnalysisEngine.instance.logger.logInformation3("Task failed: ${taskDescription}", exception);
|
| - }
|
| - return accept(visitor);
|
| + LocalVariableElementImpl createLocalVariable2(Type2 type, String name) {
|
| + SimpleIdentifier identifier = createIdentifier(name, 0);
|
| + return createLocalVariable(type, identifier);
|
| }
|
|
|
| - String toString() => taskDescription;
|
| -
|
| /**
|
| - * Return a textual description of this task.
|
| - *
|
| - * @return a textual description of this task
|
| + * Declares the given [LocalVariableElementImpl] in the [topNameScope].
|
| */
|
| - String get taskDescription;
|
| + void defineTopVariable(LocalVariableElementImpl variable) {
|
| + recordDefinedVariable(variable);
|
| + _topNameScope.define(variable);
|
| + recordTypeLibraryInjected(variable);
|
| + }
|
|
|
| /**
|
| - * Perform this analysis task, protected by an exception handler.
|
| - *
|
| - * @throws AnalysisException if an exception occurs while performing the task
|
| + * Declares the given [LocalVariableElementImpl] in the current [nameScope].
|
| */
|
| - void internalPerform();
|
| + void defineVariable(LocalVariableElementImpl variable) {
|
| + recordDefinedVariable(variable);
|
| + _nameScope.define(variable);
|
| + recordTypeLibraryInjected(variable);
|
| + }
|
| +
|
| + /**
|
| + * @return the [AngularElement] with the given name, maybe `null`.
|
| + */
|
| + AngularElement findAngularElement(String name) {
|
| + for (AngularElement element in _angularElements) {
|
| + if (name == element.name) {
|
| + return element;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * @return the [TypeProvider] of the [AnalysisContext].
|
| + */
|
| + TypeProvider get typeProvider => _typeProvider;
|
| +
|
| + /**
|
| + * Parses given [String] as an [Expression] at the given offset.
|
| + */
|
| + Expression parseExpression(String contents, int offset) => parseExpression2(contents, 0, contents.length, offset);
|
| +
|
| + Expression parseExpression2(String contents, int startIndex, int endIndex, int offset) {
|
| + Token token = scanDart(contents, startIndex, endIndex, offset);
|
| + return parseExpression3(token);
|
| + }
|
| +
|
| + Expression parseExpression3(Token token) => ht.HtmlParser.parseEmbeddedExpression(_source, token, _errorListener);
|
| +
|
| + /**
|
| + * Reports given [ErrorCode] at the given [ASTNode].
|
| + */
|
| + void reportError(ASTNode node, ErrorCode errorCode, List<Object> arguments) {
|
| + reportError7(node.offset, node.length, errorCode, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Reports given [ErrorCode] at the given position.
|
| + */
|
| + void reportError7(int offset, int length, ErrorCode errorCode, List<Object> arguments) {
|
| + _errorListener.onError(new AnalysisError.con2(_source, offset, length, errorCode, arguments));
|
| + }
|
| +
|
| + /**
|
| + * Resolves given [ASTNode] using [resolver].
|
| + */
|
| + void resolveNode(ASTNode node) {
|
| + node.accept(_resolver);
|
| + }
|
| +
|
| + Token scanDart(String contents, int startIndex, int endIndex, int offset) => ht.HtmlParser.scanDartSource(_source, _lineInfo, contents.substring(startIndex, endIndex), offset + startIndex, _errorListener);
|
| +
|
| + /**
|
| + * Puts into [libraryElement] an artificial [LibraryElementImpl] for this HTML
|
| + * [Source].
|
| + */
|
| + void createLibraryElement() {
|
| + // create CompilationUnitElementImpl
|
| + String unitName = _source.shortName;
|
| + _unitElement = new CompilationUnitElementImpl(unitName);
|
| + _unitElement.source = _source;
|
| + // create LibraryElementImpl
|
| + _libraryElement = new LibraryElementImpl(_context, null);
|
| + _libraryElement.definingCompilationUnit = _unitElement;
|
| + // create FunctionElementImpl
|
| + _functionElement = new FunctionElementImpl.con2(0);
|
| + _unitElement.functions = <FunctionElement> [_functionElement];
|
| + }
|
| +
|
| + /**
|
| + * Creates new [NgProcessor] for the given [AngularElement], maybe `null` if not
|
| + * supported.
|
| + */
|
| + NgProcessor createProcessor(AngularElement element) {
|
| + if (element is AngularComponentElement) {
|
| + AngularComponentElement component = element;
|
| + return new NgComponentElementProcessor(component);
|
| + }
|
| + if (element is AngularControllerElement) {
|
| + AngularControllerElement controller = element;
|
| + return new NgControllerElementProcessor(controller);
|
| + }
|
| + if (element is AngularDirectiveElement) {
|
| + AngularDirectiveElement directive = element;
|
| + return new NgDirectiveElementProcessor(directive);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Puts into [resolver] an [ResolverVisitor] to resolve [Expression]s in
|
| + * [source].
|
| + */
|
| + void createResolver() {
|
| + InheritanceManager inheritanceManager = new InheritanceManager(_libraryElement);
|
| + _resolver = new ResolverVisitor.con2(_libraryElement, _source, _typeProvider, inheritanceManager, _errorListener);
|
| + _topNameScope = _resolver.pushNameScope();
|
| + }
|
| +
|
| + /**
|
| + * Returns the external Dart script [Source] referenced by the given [HtmlUnit].
|
| + */
|
| + Source getDartSource(ht.HtmlUnit unit) {
|
| + for (HtmlScriptElement script in unit.element.scripts) {
|
| + if (script is ExternalHtmlScriptElement) {
|
| + Source scriptSource = script.scriptSource;
|
| + if (scriptSource != null) {
|
| + return scriptSource;
|
| + }
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Parse the value of the given token for embedded expressions, and add any embedded expressions
|
| + * that are found to the given list of expressions.
|
| + *
|
| + * @param expressions the list to which embedded expressions are to be added
|
| + * @param token the token whose value is to be parsed
|
| + */
|
| + void parseEmbeddedExpressions(List<ht.EmbeddedExpression> expressions, ht.Token token) {
|
| + // prepare Token information
|
| + String lexeme = token.lexeme;
|
| + int offset = token.offset;
|
| + // find expressions between {{ and }}
|
| + int startIndex = StringUtilities.indexOf2(lexeme, 0, _OPENING_DELIMITER_CHAR, _OPENING_DELIMITER_CHAR);
|
| + while (startIndex >= 0) {
|
| + int endIndex = StringUtilities.indexOf2(lexeme, startIndex + _OPENING_DELIMITER_LENGTH, _CLOSING_DELIMITER_CHAR, _CLOSING_DELIMITER_CHAR);
|
| + if (endIndex < 0) {
|
| + // TODO(brianwilkerson) Should we report this error or will it be reported by something else?
|
| + return;
|
| + } else if (startIndex + _OPENING_DELIMITER_LENGTH < endIndex) {
|
| + startIndex += _OPENING_DELIMITER_LENGTH;
|
| + Expression expression = parseExpression2(lexeme, startIndex, endIndex, offset);
|
| + expressions.add(new ht.EmbeddedExpression(startIndex, expression, endIndex));
|
| + }
|
| + startIndex = StringUtilities.indexOf2(lexeme, endIndex + _CLOSING_DELIMITER_LENGTH, _OPENING_DELIMITER_CHAR, _OPENING_DELIMITER_CHAR);
|
| + }
|
| + }
|
| +
|
| + void parseEmbeddedExpressions2(ht.XmlAttributeNode node) {
|
| + List<ht.EmbeddedExpression> expressions = new List<ht.EmbeddedExpression>();
|
| + parseEmbeddedExpressions(expressions, node.valueToken);
|
| + if (!expressions.isEmpty) {
|
| + node.expressions = new List.from(expressions);
|
| + }
|
| + }
|
| +
|
| + void parseEmbeddedExpressions3(ht.XmlTagNode node) {
|
| + List<ht.EmbeddedExpression> expressions = new List<ht.EmbeddedExpression>();
|
| + ht.Token token = node.attributeEnd;
|
| + ht.Token endToken = node.endToken;
|
| + bool inChild = false;
|
| + while (token != endToken) {
|
| + for (ht.XmlTagNode child in node.tagNodes) {
|
| + if (identical(token, child.beginToken)) {
|
| + inChild = true;
|
| + break;
|
| + }
|
| + if (identical(token, child.endToken)) {
|
| + inChild = false;
|
| + break;
|
| + }
|
| + }
|
| + if (!inChild && identical(token.type, ht.TokenType.TEXT)) {
|
| + parseEmbeddedExpressions(expressions, token);
|
| + }
|
| + token = token.next;
|
| + }
|
| + node.expressions = new List.from(expressions);
|
| + }
|
| +
|
| + void recordDefinedVariable(LocalVariableElementImpl variable) {
|
| + _definedVariables.add(variable);
|
| + _functionElement.localVariables = new List.from(_definedVariables);
|
| + }
|
| +
|
| + /**
|
| + * When we inject variable, we give access to the library of its type.
|
| + */
|
| + void recordTypeLibraryInjected(LocalVariableElementImpl variable) {
|
| + LibraryElement typeLibrary = variable.type.element.library;
|
| + _injectedLibraries.add(typeLibrary);
|
| + }
|
| +
|
| + void resolveExpressions(List<ht.EmbeddedExpression> expressions) {
|
| + for (ht.EmbeddedExpression embeddedExpression in expressions) {
|
| + Expression expression = embeddedExpression.expression;
|
| + resolveNode(expression);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Resolves Angular specific expressions and elements in the [source].
|
| + *
|
| + * @param angularElements the [AngularElement]s accessible in the component's library, not
|
| + * `null`
|
| + * @param component the [AngularComponentElement] to resolve template for, maybe
|
| + * `null` if not a component template
|
| + */
|
| + void resolveInternal(List<AngularElement> angularElements, AngularComponentElement component) {
|
| + this._angularElements = angularElements;
|
| + // add built-in processors
|
| + _processors.add(NgModelProcessor.INSTANCE);
|
| + // _processors.add(NgRepeatProcessor.INSTANCE);
|
| + // add accessible processors
|
| + for (AngularElement angularElement in angularElements) {
|
| + NgProcessor processor = createProcessor(angularElement);
|
| + if (processor != null) {
|
| + _processors.add(processor);
|
| + }
|
| + }
|
| + // prepare Dart library
|
| + createLibraryElement();
|
| + _unit.compilationUnitElement = _libraryElement.definingCompilationUnit;
|
| + // prepare Dart resolver
|
| + createResolver();
|
| + // may be resolving component template
|
| + LocalVariableElementImpl componentVariable = null;
|
| + if (component != null) {
|
| + ClassElement componentClassElement = component.enclosingElement as ClassElement;
|
| + InterfaceType componentType = componentClassElement.type;
|
| + componentVariable = createLocalVariable2(componentType, component.name);
|
| + defineTopVariable(componentVariable);
|
| + componentVariable.toolkitObjects = <AngularElement> [component];
|
| + }
|
| + // run this HTML visitor
|
| + _unit.accept(this);
|
| + // simulate imports for injects
|
| + {
|
| + List<ImportElement> imports = [];
|
| + for (LibraryElement injectedLibrary in _injectedLibraries) {
|
| + ImportElementImpl importElement = new ImportElementImpl(-1);
|
| + importElement.importedLibrary = injectedLibrary;
|
| + imports.add(importElement);
|
| + }
|
| + _libraryElement.imports = new List.from(imports);
|
| + }
|
| + // push conditional errors
|
| + for (ProxyConditionalAnalysisError conditionalCode in _resolver.proxyConditionalAnalysisErrors) {
|
| + _resolver.reportError(conditionalCode.analysisError);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * The "ng-model" directive is special, it contributes to the top-level name scope. These models
|
| + * can be used before actual "ng-model" attribute in HTML. So, we need to define them once we
|
| + * found [NG_APP] context.
|
| + */
|
| + void visitModelDirectives(ht.XmlTagNode appNode) {
|
| + appNode.accept(new RecursiveXmlVisitor_AngularHtmlUnitResolver_visitModelDirectives(this));
|
| + }
|
| +}
|
| +
|
| +class AngularHtmlUnitResolver_FoundAppError extends Error {
|
| +}
|
| +
|
| +class RecursiveXmlVisitor_AngularHtmlUnitResolver_hasAngularAnnotation extends ht.RecursiveXmlVisitor<Object> {
|
| + Object visitXmlTagNode(ht.XmlTagNode node) {
|
| + if (node.getAttribute(AngularHtmlUnitResolver._NG_APP) != null) {
|
| + throw new AngularHtmlUnitResolver_FoundAppError();
|
| + }
|
| + return super.visitXmlTagNode(node);
|
| + }
|
| +}
|
| +
|
| +class RecursiveXmlVisitor_AngularHtmlUnitResolver_visitModelDirectives extends ht.RecursiveXmlVisitor<Object> {
|
| + final AngularHtmlUnitResolver AngularHtmlUnitResolver_this;
|
| +
|
| + RecursiveXmlVisitor_AngularHtmlUnitResolver_visitModelDirectives(this.AngularHtmlUnitResolver_this) : super();
|
| +
|
| + Object visitXmlTagNode(ht.XmlTagNode node) {
|
| + NgModelProcessor directive = NgModelProcessor.INSTANCE;
|
| + if (directive.canApply(node)) {
|
| + directive.applyTopDeclarations(AngularHtmlUnitResolver_this, node);
|
| + }
|
| + return super.visitXmlTagNode(node);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Recursively visits [HtmlUnit] and every embedded [Expression].
|
| + */
|
| +abstract class ExpressionVisitor extends ht.RecursiveXmlVisitor<Object> {
|
| + /**
|
| + * Visits the given [Expression]s embedded into tag or attribute.
|
| + *
|
| + * @param expression the [Expression] to visit, not `null`
|
| + */
|
| + void visitExpression(Expression expression);
|
| +
|
| + Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
|
| + visitExpressions(node.expressions);
|
| + return super.visitXmlAttributeNode(node);
|
| + }
|
| +
|
| + Object visitXmlTagNode(ht.XmlTagNode node) {
|
| + visitExpressions(node.expressions);
|
| + return super.visitXmlTagNode(node);
|
| + }
|
| +
|
| + /**
|
| + * Visits [Expression]s of the given [EmbeddedExpression]s.
|
| + */
|
| + void visitExpressions(List<ht.EmbeddedExpression> expressions) {
|
| + for (ht.EmbeddedExpression embeddedExpression in expressions) {
|
| + Expression expression = embeddedExpression.expression;
|
| + visitExpression(expression);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * [NgComponentElementProcessor] applies [AngularComponentElement] by parsing mapped
|
| + * attributes as expressions.
|
| + */
|
| +class NgComponentElementProcessor extends NgDirectiveProcessor {
|
| + AngularComponentElement _element;
|
| +
|
| + NgComponentElementProcessor(AngularComponentElement element) {
|
| + this._element = element;
|
| + }
|
| +
|
| + void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
|
| + node.element = _element.selector;
|
| + for (AngularPropertyElement property in _element.properties) {
|
| + String name = property.name;
|
| + ht.XmlAttributeNode attribute = node.getAttribute(name);
|
| + if (attribute != null) {
|
| + attribute.element = property;
|
| + // resolve if binding
|
| + if (property.propertyKind != AngularPropertyKind.ATTR) {
|
| + Expression expression = parseExpression(resolver, attribute);
|
| + resolver.resolveNode(expression);
|
| + setExpression(attribute, expression);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool canApply(ht.XmlTagNode node) => _element.selector.apply(node);
|
| +}
|
| +
|
| +/**
|
| + * [NgControllerElementProcessor] applies [AngularControllerElement].
|
| + */
|
| +class NgControllerElementProcessor extends NgProcessor {
|
| + AngularControllerElement _element;
|
| +
|
| + NgControllerElementProcessor(AngularControllerElement element) {
|
| + this._element = element;
|
| + }
|
| +
|
| + void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
|
| + InterfaceType type = (_element.enclosingElement as ClassElement).type;
|
| + String name = _element.name;
|
| + LocalVariableElementImpl variable = resolver.createLocalVariable2(type, name);
|
| + resolver.defineVariable(variable);
|
| + variable.toolkitObjects = <AngularElement> [_element];
|
| + }
|
| +
|
| + bool canApply(ht.XmlTagNode node) => _element.selector.apply(node);
|
| +}
|
| +
|
| +/**
|
| + * [NgDirectiveElementProcessor] applies [AngularDirectiveElement] by parsing mapped
|
| + * attributes as expressions.
|
| + */
|
| +class NgDirectiveElementProcessor extends NgDirectiveProcessor {
|
| + AngularDirectiveElement _element;
|
| +
|
| + NgDirectiveElementProcessor(AngularDirectiveElement element) {
|
| + this._element = element;
|
| + }
|
| +
|
| + void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
|
| + for (AngularPropertyElement property in _element.properties) {
|
| + // prepare attribute name
|
| + String name = property.name;
|
| + if (name == ".") {
|
| + AngularSelectorElement selector = _element.selector;
|
| + if (selector is HasAttributeSelectorElementImpl) {
|
| + name = selector.name;
|
| + }
|
| + }
|
| + // resolve attribute expression
|
| + ht.XmlAttributeNode attribute = node.getAttribute(name);
|
| + if (attribute != null) {
|
| + attribute.element = property;
|
| + // resolve if binding
|
| + if (property.propertyKind != AngularPropertyKind.ATTR) {
|
| + Expression expression = parseExpression(resolver, attribute);
|
| + resolver.resolveNode(expression);
|
| + setExpression(attribute, expression);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + bool canApply(ht.XmlTagNode node) => _element.selector.apply(node);
|
| +}
|
| +
|
| +/**
|
| + * [NgDirectiveProcessor] describes any <code>NgDirective</code> annotation instance.
|
| + */
|
| +abstract class NgDirectiveProcessor extends NgProcessor {
|
| + static ht.EmbeddedExpression newEmbeddedExpression(Expression e) => new ht.EmbeddedExpression(e.offset, e, e.end);
|
| +
|
| + Expression parseExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
|
| + int offset = attribute.valueToken.offset + 1;
|
| + String value = attribute.text;
|
| + Token token = resolver.scanDart(value, 0, value.length, offset);
|
| + return resolver.parseExpression3(token);
|
| + }
|
| +
|
| + /**
|
| + * Sets single [Expression] for [XmlAttributeNode].
|
| + */
|
| + void setExpression(ht.XmlAttributeNode attribute, Expression expression) {
|
| + attribute.expressions = <ht.EmbeddedExpression> [newEmbeddedExpression(expression)];
|
| + }
|
| +
|
| + /**
|
| + * Sets [Expression]s for [XmlAttributeNode].
|
| + */
|
| + void setExpressions(ht.XmlAttributeNode attribute, List<Expression> expressions) {
|
| + List<ht.EmbeddedExpression> embExpressions = [];
|
| + for (Expression expression in expressions) {
|
| + embExpressions.add(newEmbeddedExpression(expression));
|
| + }
|
| + attribute.expressions = new List.from(embExpressions);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * [NgModelProcessor] describes built-in <code>NgModel</code> directive.
|
| + */
|
| +class NgModelProcessor extends NgDirectiveProcessor {
|
| + static String _NG_MODEL = "ng-model";
|
| +
|
| + static NgModelProcessor INSTANCE = new NgModelProcessor();
|
| +
|
| + void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
|
| + ht.XmlAttributeNode attribute = node.getAttribute(_NG_MODEL);
|
| + Expression expression = parseExpression(resolver, attribute);
|
| + // identifiers have been already handled by "apply top"
|
| + if (expression is SimpleIdentifier) {
|
| + return;
|
| + }
|
| + // resolve
|
| + resolver.resolveNode(expression);
|
| + // remember expression
|
| + setExpression(attribute, expression);
|
| + }
|
| +
|
| + bool canApply(ht.XmlTagNode node) => node.getAttribute(_NG_MODEL) != null;
|
| +
|
| + /**
|
| + * This method is used to define top-level [VariableElement]s for each "ng-model" with
|
| + * simple identifier model.
|
| + */
|
| + void applyTopDeclarations(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
|
| + ht.XmlAttributeNode attribute = node.getAttribute(_NG_MODEL);
|
| + Expression expression = parseExpression(resolver, attribute);
|
| + // if not identifier, then not a top-level model, delay until "apply"
|
| + if (expression is! SimpleIdentifier) {
|
| + return;
|
| + }
|
| + SimpleIdentifier identifier = expression as SimpleIdentifier;
|
| + // define variable Element
|
| + InterfaceType type = resolver.typeProvider.stringType;
|
| + LocalVariableElementImpl element = resolver.createLocalVariable(type, identifier);
|
| + resolver.defineTopVariable(element);
|
| + // remember expression
|
| + identifier.staticElement = element;
|
| + identifier.staticType = type;
|
| + setExpression(attribute, identifier);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * [NgProcessor] is used to apply an Angular feature.
|
| + */
|
| +abstract class NgProcessor {
|
| + /**
|
| + * Applies this [NgProcessor] to the resolver.
|
| + *
|
| + * @param resolver the [AngularHtmlUnitResolver] to apply to, not `null`
|
| + * @param node the [XmlTagNode] to apply within, not `null`
|
| + */
|
| + void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node);
|
| +
|
| + /**
|
| + * Checks if this processor can be applied to the given [XmlTagNode].
|
| + *
|
| + * @param node the [XmlTagNode] to check
|
| + * @return `true` if this processor can be applied, or `false` otherwise
|
| + */
|
| + bool canApply(ht.XmlTagNode node);
|
| +}
|
| +
|
| +/**
|
| + * The abstract class `AnalysisTask` defines the behavior of objects used to perform an
|
| + * analysis task.
|
| + */
|
| +abstract class AnalysisTask {
|
| + /**
|
| + * The context in which the task is to be performed.
|
| + */
|
| + final InternalAnalysisContext context;
|
| +
|
| + /**
|
| + * The exception that was thrown while performing this task, or `null` if the task completed
|
| + * successfully.
|
| + */
|
| + AnalysisException _thrownException;
|
| +
|
| + /**
|
| + * Initialize a newly created task to perform analysis within the given context.
|
| + *
|
| + * @param context the context in which the task is to be performed
|
| + */
|
| + AnalysisTask(this.context);
|
| +
|
| + /**
|
| + * Use the given visitor to visit this task.
|
| + *
|
| + * @param visitor the visitor that should be used to visit this task
|
| + * @return the value returned by the visitor
|
| + * @throws AnalysisException if the visitor throws the exception
|
| + */
|
| + accept(AnalysisTaskVisitor visitor);
|
| +
|
| + /**
|
| + * Return the exception that was thrown while performing this task, or `null` if the task
|
| + * completed successfully.
|
| + *
|
| + * @return the exception that was thrown while performing this task
|
| + */
|
| + AnalysisException get exception => _thrownException;
|
| +
|
| + /**
|
| + * Perform this analysis task and use the given visitor to visit this task after it has completed.
|
| + *
|
| + * @param visitor the visitor used to visit this task after it has completed
|
| + * @return the value returned by the visitor
|
| + * @throws AnalysisException if the visitor throws the exception
|
| + */
|
| + Object perform(AnalysisTaskVisitor visitor) {
|
| + try {
|
| + safelyPerform();
|
| + } on AnalysisException catch (exception) {
|
| + _thrownException = exception;
|
| + AnalysisEngine.instance.logger.logInformation3("Task failed: ${taskDescription}", exception);
|
| + }
|
| + return accept(visitor);
|
| + }
|
| +
|
| + String toString() => taskDescription;
|
| +
|
| + /**
|
| + * Return a textual description of this task.
|
| + *
|
| + * @return a textual description of this task
|
| + */
|
| + String get taskDescription;
|
| +
|
| + /**
|
| + * Perform this analysis task, protected by an exception handler.
|
| + *
|
| + * @throws AnalysisException if an exception occurs while performing the task
|
| + */
|
| + void internalPerform();
|
|
|
| /**
|
| * Perform this analysis task, ensuring that all exceptions are wrapped in an
|
| @@ -7394,6 +8586,24 @@ abstract class AnalysisTaskVisitor<E> {
|
| E visitParseHtmlTask(ParseHtmlTask task);
|
|
|
| /**
|
| + * Visit a [ResolveAngularComponentTemplateTask].
|
| + *
|
| + * @param task the task to be visited
|
| + * @return the result of visiting the task
|
| + * @throws AnalysisException if the visitor throws an exception for some reason
|
| + */
|
| + E visitResolveAngularComponentTemplateTask(ResolveAngularComponentTemplateTask task);
|
| +
|
| + /**
|
| + * Visit a [ResolveDartDependenciesTask].
|
| + *
|
| + * @param task the task to be visited
|
| + * @return the result of visiting the task
|
| + * @throws AnalysisException if the visitor throws an exception for some reason
|
| + */
|
| + E visitResolveDartDependenciesTask(ResolveDartDependenciesTask task);
|
| +
|
| + /**
|
| * Visit a [ResolveDartLibraryTask].
|
| *
|
| * @param task the task to be visited
|
| @@ -7728,21 +8938,6 @@ class ParseDartTask extends AnalysisTask {
|
| bool _hasLibraryDirective2 = false;
|
|
|
| /**
|
| - * A set containing the sources referenced by 'export' directives.
|
| - */
|
| - Set<Source> _exportedSources = new Set<Source>();
|
| -
|
| - /**
|
| - * A set containing the sources referenced by 'import' directives.
|
| - */
|
| - Set<Source> _importedSources = new Set<Source>();
|
| -
|
| - /**
|
| - * A set containing the sources referenced by 'part' directives.
|
| - */
|
| - Set<Source> _includedSources = new Set<Source>();
|
| -
|
| - /**
|
| * Initialize a newly created task to perform analysis within the given context.
|
| *
|
| * @param context the context in which the task is to be performed
|
| @@ -7769,30 +8964,6 @@ class ParseDartTask extends AnalysisTask {
|
| List<AnalysisError> get errors => _errors;
|
|
|
| /**
|
| - * Return an array containing the sources referenced by 'export' directives, or an empty array if
|
| - * the task has not yet been performed or if an exception occurred.
|
| - *
|
| - * @return an array containing the sources referenced by 'export' directives
|
| - */
|
| - List<Source> get exportedSources => toArray(_exportedSources);
|
| -
|
| - /**
|
| - * Return an array containing the sources referenced by 'import' directives, or an empty array if
|
| - * the task has not yet been performed or if an exception occurred.
|
| - *
|
| - * @return an array containing the sources referenced by 'import' directives
|
| - */
|
| - List<Source> get importedSources => toArray(_importedSources);
|
| -
|
| - /**
|
| - * Return an array containing the sources referenced by 'part' directives, or an empty array if
|
| - * the task has not yet been performed or if an exception occurred.
|
| - *
|
| - * @return an array containing the sources referenced by 'part' directives
|
| - */
|
| - List<Source> get includedSources => toArray(_includedSources);
|
| -
|
| - /**
|
| * Return the line information that was produced, or `null` if the task has not yet been
|
| * performed or if an exception occurred.
|
| *
|
| @@ -7852,28 +9023,13 @@ class ParseDartTask extends AnalysisTask {
|
| //
|
| TimeCounter_TimeCounterHandle timeCounterParse = PerformanceStatistics.parse.start();
|
| try {
|
| - Parser parser = new Parser(source, errorListener);
|
| - parser.parseFunctionBodies = context.analysisOptions.analyzeFunctionBodies;
|
| - _unit = parser.parseCompilationUnit(token[0]);
|
| - _errors = errorListener.getErrors2(source);
|
| - for (Directive directive in _unit.directives) {
|
| - if (directive is ExportDirective) {
|
| - Source exportSource = resolveSource(source, directive);
|
| - if (exportSource != null) {
|
| - _exportedSources.add(exportSource);
|
| - }
|
| - } else if (directive is ImportDirective) {
|
| - Source importSource = resolveSource(source, directive);
|
| - if (importSource != null) {
|
| - _importedSources.add(importSource);
|
| - }
|
| - } else if (directive is LibraryDirective) {
|
| + Parser parser = new Parser(source, errorListener);
|
| + parser.parseFunctionBodies = context.analysisOptions.analyzeFunctionBodies;
|
| + _unit = parser.parseCompilationUnit(token[0]);
|
| + _errors = errorListener.getErrors2(source);
|
| + for (Directive directive in _unit.directives) {
|
| + if (directive is LibraryDirective) {
|
| _hasLibraryDirective2 = true;
|
| - } else if (directive is PartDirective) {
|
| - Source partSource = resolveSource(source, directive);
|
| - if (partSource != null) {
|
| - _includedSources.add(partSource);
|
| - }
|
| } else if (directive is PartOfDirective) {
|
| _hasPartOfDirective2 = true;
|
| }
|
| @@ -7883,46 +9039,6 @@ class ParseDartTask extends AnalysisTask {
|
| timeCounterParse.stop();
|
| }
|
| }
|
| -
|
| - /**
|
| - * Return the result of resolving the URI of the given URI-based directive against the URI of the
|
| - * given library, or `null` if the URI is not valid.
|
| - *
|
| - * @param librarySource the source representing the library containing the directive
|
| - * @param directive the directive which URI should be resolved
|
| - * @return the result of resolving the URI against the URI of the library
|
| - */
|
| - Source resolveSource(Source librarySource, UriBasedDirective directive) {
|
| - StringLiteral uriLiteral = directive.uri;
|
| - if (uriLiteral is StringInterpolation) {
|
| - return null;
|
| - }
|
| - String uriContent = uriLiteral.stringValue.trim();
|
| - if (uriContent == null) {
|
| - return null;
|
| - }
|
| - uriContent = Uri.encodeFull(uriContent);
|
| - try {
|
| - parseUriWithException(uriContent);
|
| - return context.sourceFactory.resolveUri(librarySource, uriContent);
|
| - } on URISyntaxException catch (exception) {
|
| - return null;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Efficiently convert the given set of sources to an array.
|
| - *
|
| - * @param sources the set to be converted
|
| - * @return an array containing all of the sources in the given set
|
| - */
|
| - List<Source> toArray(Set<Source> sources) {
|
| - int size = sources.length;
|
| - if (size == 0) {
|
| - return Source.EMPTY_ARRAY;
|
| - }
|
| - return new List.from(sources);
|
| - }
|
| }
|
|
|
| class Source_ContentReceiver_ParseDartTask_internalPerform implements Source_ContentReceiver {
|
| @@ -7978,7 +9094,7 @@ class ParseHtmlTask extends AnalysisTask {
|
| /**
|
| * The HTML unit that was produced by parsing the source.
|
| */
|
| - HtmlUnit _unit;
|
| + ht.HtmlUnit _unit;
|
|
|
| /**
|
| * The errors that were produced by scanning and parsing the source.
|
| @@ -8034,7 +9150,7 @@ class ParseHtmlTask extends AnalysisTask {
|
| *
|
| * @return the HTML unit that was produced by parsing the source
|
| */
|
| - HtmlUnit get htmlUnit => _unit;
|
| + ht.HtmlUnit get htmlUnit => _unit;
|
|
|
| /**
|
| * Return the line information that was produced, or `null` if the task has not yet been
|
| @@ -8067,17 +9183,17 @@ class ParseHtmlTask extends AnalysisTask {
|
| }
|
|
|
| void internalPerform() {
|
| - HtmlScanner scanner = new HtmlScanner(source);
|
| + ht.HtmlScanner scanner = new ht.HtmlScanner(source);
|
| try {
|
| source.getContents(scanner);
|
| } on JavaException catch (exception) {
|
| throw new AnalysisException.con3(exception);
|
| }
|
| - HtmlScanResult scannerResult = scanner.result;
|
| + ht.HtmlScanResult scannerResult = scanner.result;
|
| _modificationTime = scannerResult.modificationTime;
|
| _lineInfo = new LineInfo(scannerResult.lineStarts);
|
| RecordingErrorListener errorListener = new RecordingErrorListener();
|
| - HtmlParseResult result = new HtmlParser(source, errorListener).parse(scannerResult);
|
| + ht.HtmlParseResult result = new ht.HtmlParser(source, errorListener).parse(scannerResult);
|
| _unit = result.htmlUnit;
|
| _errors = errorListener.getErrors2(source);
|
| _referencedLibraries = librarySources;
|
| @@ -8098,16 +9214,16 @@ class ParseHtmlTask extends AnalysisTask {
|
| }
|
| }
|
|
|
| -class RecursiveXmlVisitor_ParseHtmlTask_getLibrarySources extends RecursiveXmlVisitor<Object> {
|
| +class RecursiveXmlVisitor_ParseHtmlTask_getLibrarySources extends ht.RecursiveXmlVisitor<Object> {
|
| final ParseHtmlTask ParseHtmlTask_this;
|
|
|
| List<Source> libraries;
|
|
|
| RecursiveXmlVisitor_ParseHtmlTask_getLibrarySources(this.ParseHtmlTask_this, this.libraries) : super();
|
|
|
| - Object visitHtmlScriptTagNode(HtmlScriptTagNode node) {
|
| - XmlAttributeNode scriptAttribute = null;
|
| - for (XmlAttributeNode attribute in node.attributes) {
|
| + Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
|
| + ht.XmlAttributeNode scriptAttribute = null;
|
| + for (ht.XmlAttributeNode attribute in node.attributes) {
|
| if (javaStringEqualsIgnoreCase(attribute.name, ParseHtmlTask._ATTRIBUTE_SRC)) {
|
| scriptAttribute = attribute;
|
| }
|
| @@ -8128,6 +9244,246 @@ class RecursiveXmlVisitor_ParseHtmlTask_getLibrarySources extends RecursiveXmlVi
|
| }
|
|
|
| /**
|
| + * Instances of the class `ResolveAngularComponentTemplateTask` resolve HTML template
|
| + * referenced by [AngularComponentElement].
|
| + */
|
| +class ResolveAngularComponentTemplateTask extends AnalysisTask {
|
| + /**
|
| + * The [AngularComponentElement] to resolve template for.
|
| + */
|
| + AngularComponentElement _component;
|
| +
|
| + /**
|
| + * All Angular elements accessible in the component library.
|
| + */
|
| + List<AngularElement> _angularElements;
|
| +
|
| + /**
|
| + * The source to be resolved.
|
| + */
|
| + final Source source;
|
| +
|
| + /**
|
| + * The time at which the contents of the source were last modified.
|
| + */
|
| + int _modificationTime = -1;
|
| +
|
| + /**
|
| + * The [HtmlUnit] that was resolved by this task.
|
| + */
|
| + ht.HtmlUnit _resolvedUnit;
|
| +
|
| + /**
|
| + * The resolution errors that were discovered while resolving the source.
|
| + */
|
| + List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
|
| +
|
| + /**
|
| + * Initialize a newly created task to perform analysis within the given context.
|
| + *
|
| + * @param context the context in which the task is to be performed
|
| + * @param source the source to be resolved
|
| + * @param component the component that uses this HTML template, not `null`
|
| + * @param angularElements all Angular elements accessible in the component library
|
| + */
|
| + ResolveAngularComponentTemplateTask(InternalAnalysisContext context, this.source, AngularComponentElement component, List<AngularElement> angularElements) : super(context) {
|
| + this._component = component;
|
| + this._angularElements = angularElements;
|
| + }
|
| +
|
| + accept(AnalysisTaskVisitor visitor) => visitor.visitResolveAngularComponentTemplateTask(this);
|
| +
|
| + /**
|
| + * Return the time at which the contents of the source that was parsed were last modified, or a
|
| + * negative value if the task has not yet been performed or if an exception occurred.
|
| + *
|
| + * @return the time at which the contents of the source that was parsed were last modified
|
| + */
|
| + int get modificationTime => _modificationTime;
|
| +
|
| + List<AnalysisError> get resolutionErrors => _resolutionErrors;
|
| +
|
| + /**
|
| + * Return the [HtmlUnit] that was resolved by this task.
|
| + *
|
| + * @return the [HtmlUnit] that was resolved by this task
|
| + */
|
| + ht.HtmlUnit get resolvedUnit => _resolvedUnit;
|
| +
|
| + String get taskDescription => "resolving Angular template ${source}";
|
| +
|
| + void internalPerform() {
|
| + ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableHtmlUnit(source);
|
| + ht.HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
|
| + if (unit == null) {
|
| + throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit returned a value without a parsed HTML unit");
|
| + }
|
| + _modificationTime = resolvableHtmlUnit.modificationTime;
|
| + // prepare for resolution
|
| + RecordingErrorListener errorListener = new RecordingErrorListener();
|
| + LineInfo lineInfo = context.getLineInfo(source);
|
| + // do resolve
|
| + AngularHtmlUnitResolver resolver = new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit);
|
| + resolver.resolveComponentTemplate(_angularElements, _component);
|
| + // remember errors
|
| + _resolutionErrors = errorListener.getErrors2(source);
|
| + // remember resolved unit
|
| + _resolvedUnit = unit;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `ResolveDartDependenciesTask` resolve the import, export, and part
|
| + * directives in a single source.
|
| + */
|
| +class ResolveDartDependenciesTask extends AnalysisTask {
|
| + /**
|
| + * The source containing the directives to be resolved.
|
| + */
|
| + final Source source;
|
| +
|
| + /**
|
| + * The time at which the contents of the source were last modified.
|
| + */
|
| + int _modificationTime = -1;
|
| +
|
| + /**
|
| + * A set containing the sources referenced by 'export' directives.
|
| + */
|
| + Set<Source> _exportedSources = new Set<Source>();
|
| +
|
| + /**
|
| + * A set containing the sources referenced by 'import' directives.
|
| + */
|
| + Set<Source> _importedSources = new Set<Source>();
|
| +
|
| + /**
|
| + * A set containing the sources referenced by 'part' directives.
|
| + */
|
| + Set<Source> _includedSources = new Set<Source>();
|
| +
|
| + /**
|
| + * Initialize a newly created task to perform analysis within the given context.
|
| + *
|
| + * @param context the context in which the task is to be performed
|
| + * @param source the source to be parsed
|
| + */
|
| + ResolveDartDependenciesTask(InternalAnalysisContext context, this.source) : super(context);
|
| +
|
| + accept(AnalysisTaskVisitor visitor) => visitor.visitResolveDartDependenciesTask(this);
|
| +
|
| + /**
|
| + * Return an array containing the sources referenced by 'export' directives, or an empty array if
|
| + * the task has not yet been performed or if an exception occurred.
|
| + *
|
| + * @return an array containing the sources referenced by 'export' directives
|
| + */
|
| + List<Source> get exportedSources => toArray(_exportedSources);
|
| +
|
| + /**
|
| + * Return an array containing the sources referenced by 'import' directives, or an empty array if
|
| + * the task has not yet been performed or if an exception occurred.
|
| + *
|
| + * @return an array containing the sources referenced by 'import' directives
|
| + */
|
| + List<Source> get importedSources => toArray(_importedSources);
|
| +
|
| + /**
|
| + * Return an array containing the sources referenced by 'part' directives, or an empty array if
|
| + * the task has not yet been performed or if an exception occurred.
|
| + *
|
| + * @return an array containing the sources referenced by 'part' directives
|
| + */
|
| + List<Source> get includedSources => toArray(_includedSources);
|
| +
|
| + /**
|
| + * Return the time at which the contents of the source that was parsed were last modified, or a
|
| + * negative value if the task has not yet been performed or if an exception occurred.
|
| + *
|
| + * @return the time at which the contents of the source that was parsed were last modified
|
| + */
|
| + int get modificationTime => _modificationTime;
|
| +
|
| + String get taskDescription {
|
| + if (source == null) {
|
| + return "resolve dart dependencies null source";
|
| + }
|
| + return "resolve dart dependencies ${source.fullName}";
|
| + }
|
| +
|
| + void internalPerform() {
|
| + ResolvableCompilationUnit unit = context.computeResolvableCompilationUnit(source);
|
| + _modificationTime = unit.modificationTime;
|
| + //
|
| + // Then parse the token stream.
|
| + //
|
| + TimeCounter_TimeCounterHandle timeCounterParse = PerformanceStatistics.parse.start();
|
| + try {
|
| + for (Directive directive in unit.compilationUnit.directives) {
|
| + if (directive is ExportDirective) {
|
| + Source exportSource = resolveSource(source, directive);
|
| + if (exportSource != null) {
|
| + _exportedSources.add(exportSource);
|
| + }
|
| + } else if (directive is ImportDirective) {
|
| + Source importSource = resolveSource(source, directive);
|
| + if (importSource != null) {
|
| + _importedSources.add(importSource);
|
| + }
|
| + } else if (directive is PartDirective) {
|
| + Source partSource = resolveSource(source, directive);
|
| + if (partSource != null) {
|
| + _includedSources.add(partSource);
|
| + }
|
| + }
|
| + }
|
| + } finally {
|
| + timeCounterParse.stop();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Return the result of resolving the URI of the given URI-based directive against the URI of the
|
| + * given library, or `null` if the URI is not valid.
|
| + *
|
| + * @param librarySource the source representing the library containing the directive
|
| + * @param directive the directive which URI should be resolved
|
| + * @return the result of resolving the URI against the URI of the library
|
| + */
|
| + Source resolveSource(Source librarySource, UriBasedDirective directive) {
|
| + StringLiteral uriLiteral = directive.uri;
|
| + if (uriLiteral is StringInterpolation) {
|
| + return null;
|
| + }
|
| + String uriContent = uriLiteral.stringValue.trim();
|
| + if (uriContent == null) {
|
| + return null;
|
| + }
|
| + uriContent = Uri.encodeFull(uriContent);
|
| + try {
|
| + parseUriWithException(uriContent);
|
| + return context.sourceFactory.resolveUri(librarySource, uriContent);
|
| + } on URISyntaxException catch (exception) {
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Efficiently convert the given set of sources to an array.
|
| + *
|
| + * @param sources the set to be converted
|
| + * @return an array containing all of the sources in the given set
|
| + */
|
| + List<Source> toArray(Set<Source> sources) {
|
| + int size = sources.length;
|
| + if (size == 0) {
|
| + return Source.EMPTY_ARRAY;
|
| + }
|
| + return new List.from(sources);
|
| + }
|
| +}
|
| +
|
| +/**
|
| * Instances of the class `ResolveDartLibraryTask` parse a specific Dart library.
|
| */
|
| class ResolveDartLibraryTask extends AnalysisTask {
|
| @@ -8334,7 +9690,7 @@ class ResolveHtmlTask extends AnalysisTask {
|
| /**
|
| * The [HtmlUnit] that was resolved by this task.
|
| */
|
| - HtmlUnit _resolvedUnit;
|
| + ht.HtmlUnit _resolvedUnit;
|
|
|
| /**
|
| * The element produced by resolving the source.
|
| @@ -8373,7 +9729,7 @@ class ResolveHtmlTask extends AnalysisTask {
|
| *
|
| * @return the [HtmlUnit] that was resolved by this task
|
| */
|
| - HtmlUnit get resolvedUnit => _resolvedUnit;
|
| + ht.HtmlUnit get resolvedUnit => _resolvedUnit;
|
|
|
| String get taskDescription {
|
| if (source == null) {
|
| @@ -8384,7 +9740,7 @@ class ResolveHtmlTask extends AnalysisTask {
|
|
|
| void internalPerform() {
|
| ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableHtmlUnit(source);
|
| - HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
|
| + ht.HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
|
| if (unit == null) {
|
| throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit returned a value without a parsed HTML unit");
|
| }
|
| @@ -8394,7 +9750,7 @@ class ResolveHtmlTask extends AnalysisTask {
|
| _element = builder.buildHtmlElement2(source, _modificationTime, unit);
|
| // resolve toolkit-specific features
|
| LineInfo lineInfo = context.getLineInfo(source);
|
| -// new AngularHtmlUnitResolver(context, builder.errorListener, source, lineInfo).resolve(unit);
|
| + new AngularHtmlUnitResolver(context, builder.errorListener, source, lineInfo, unit).resolveEntryPoint();
|
| // record all resolution errors
|
| _resolutionErrors = builder.errorListener.getErrors2(source);
|
| // remember resolved unit
|
|
|