/* * Copyright (c) 2013, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.engine.internal.cache; import com.google.dart.engine.context.AnalysisException; import com.google.dart.engine.element.HtmlElement; import com.google.dart.engine.element.angular.AngularComponentElement; import com.google.dart.engine.error.AnalysisError; import com.google.dart.engine.html.ast.HtmlUnit; import com.google.dart.engine.internal.element.angular.AngularApplication; import com.google.dart.engine.source.Source; import com.google.dart.engine.source.SourceKind; import java.util.ArrayList; /** * Instances of the class {@code HtmlEntryImpl} implement an {@link HtmlEntry}. * * @coverage dart.engine */ public class HtmlEntryImpl extends SourceEntryImpl implements HtmlEntry { /** * The state of the cached parsed (but not resolved) HTML unit. */ private CacheState parsedUnitState = CacheState.INVALID; /** * The parsed HTML unit, or {@code null} if the parsed HTML unit is not currently cached. */ private HtmlUnit parsedUnit; /** * The state of the cached resolved HTML unit. */ private CacheState resolvedUnitState = CacheState.INVALID; /** * The resolved HTML unit, or {@code null} if the resolved HTML unit is not currently cached. */ private HtmlUnit resolvedUnit; /** * The state of the cached parse errors. */ private CacheState parseErrorsState = CacheState.INVALID; /** * The errors produced while scanning and parsing the HTML, or {@code null} if the errors are not * currently cached. */ private AnalysisError[] parseErrors = AnalysisError.NO_ERRORS; /** * The state of the cached resolution errors. */ private CacheState resolutionErrorsState = CacheState.INVALID; /** * The errors produced while resolving the HTML, or {@code null} if the errors are not currently * cached. */ private AnalysisError[] resolutionErrors = AnalysisError.NO_ERRORS; /** * The state of the cached list of referenced libraries. */ private CacheState referencedLibrariesState = CacheState.INVALID; /** * The list of libraries referenced in the HTML, or {@code null} if the list is not currently * cached. Note that this list does not include libraries defined directly within the HTML file. */ private Source[] referencedLibraries = Source.EMPTY_ARRAY; /** * The state of the cached HTML element. */ private CacheState elementState = CacheState.INVALID; /** * The element representing the HTML file, or {@code null} if the element is not currently cached. */ private HtmlElement element; /** * The state of the {@link #angularApplication}. */ private CacheState angularApplicationState = CacheState.VALID; /** * Information about the Angular Application this unit is used in. */ private AngularApplication angularApplication; /** * The state of the {@link #angularEntry}. */ private CacheState angularEntryState = CacheState.INVALID; /** * Information about the Angular Application this unit is entry point for. */ private AngularApplication angularEntry = null; /** * The state of the {@link #angularComponent}. */ private CacheState angularComponentState = CacheState.VALID; /** * Information about the {@link AngularComponentElement} this unit is used as template for. */ private AngularComponentElement angularComponent = null; /** * The state of the Angular resolution errors. */ private CacheState angularErrorsState = CacheState.INVALID; /** * The hints produced while performing Angular resolution, or an empty array if the error are not * currently cached. */ private AnalysisError[] angularErrors = AnalysisError.NO_ERRORS; /** * The state of the cached hints. */ private CacheState hintsState = CacheState.INVALID; /** * The hints produced while auditing the compilation unit, or an empty array if the hints are not * currently cached. */ private AnalysisError[] hints = AnalysisError.NO_ERRORS; /** * The state of the Polymer elements. */ private CacheState polymerBuildErrorsState = CacheState.INVALID; /** * The hints produced while performing Polymer HTML elements building, or an empty array if the * error are not currently cached. */ private AnalysisError[] polymerBuildErrors = AnalysisError.NO_ERRORS; /** * The state of the Polymer resolution errors. */ private CacheState polymerResolutionErrorsState = CacheState.INVALID; /** * The hints produced while performing Polymer resolution, or an empty array if the error are not * currently cached. */ private AnalysisError[] polymerResolutionErrors = AnalysisError.NO_ERRORS; /** * Initialize a newly created cache entry to be empty. */ public HtmlEntryImpl() { super(); } /** * Flush any AST structures being maintained by this entry. */ public void flushAstStructures() { if (parsedUnitState == CacheState.VALID) { parsedUnitState = CacheState.FLUSHED; parsedUnit = null; } if (resolvedUnitState == CacheState.VALID) { resolvedUnitState = CacheState.FLUSHED; resolvedUnit = null; } if (angularEntryState == CacheState.VALID) { angularEntryState = CacheState.FLUSHED; } if (angularErrorsState == CacheState.VALID) { angularErrorsState = CacheState.FLUSHED; } } @Override public AnalysisError[] getAllErrors() { ArrayList<AnalysisError> errors = new ArrayList<AnalysisError>(); if (parseErrors != null) { for (AnalysisError error : parseErrors) { errors.add(error); } } if (resolutionErrors != null) { for (AnalysisError error : resolutionErrors) { errors.add(error); } } if (angularErrors != null) { for (AnalysisError error : angularErrors) { errors.add(error); } } if (hints != null) { for (AnalysisError error : hints) { errors.add(error); } } if (polymerBuildErrors != null) { for (AnalysisError error : polymerBuildErrors) { errors.add(error); } } if (polymerResolutionErrors != null) { for (AnalysisError error : polymerResolutionErrors) { errors.add(error); } } if (errors.size() == 0) { return AnalysisError.NO_ERRORS; } return errors.toArray(new AnalysisError[errors.size()]); } @Override public HtmlUnit getAnyParsedUnit() { if (parsedUnitState == CacheState.VALID) { // parsedUnitAccessed = true; return parsedUnit; } if (resolvedUnitState == CacheState.VALID) { // resovledUnitAccessed = true; return resolvedUnit; } return null; } @Override public SourceKind getKind() { return SourceKind.HTML; } @Override public CacheState getState(DataDescriptor<?> descriptor) { if (descriptor == ANGULAR_APPLICATION) { return angularApplicationState; } else if (descriptor == ANGULAR_COMPONENT) { return angularComponentState; } else if (descriptor == ANGULAR_ENTRY) { return angularEntryState; } else if (descriptor == ANGULAR_ERRORS) { return angularErrorsState; } else if (descriptor == ELEMENT) { return elementState; } else if (descriptor == PARSE_ERRORS) { return parseErrorsState; } else if (descriptor == PARSED_UNIT) { return parsedUnitState; } else if (descriptor == RESOLVED_UNIT) { return resolvedUnitState; } else if (descriptor == REFERENCED_LIBRARIES) { return referencedLibrariesState; } else if (descriptor == RESOLUTION_ERRORS) { return resolutionErrorsState; } else if (descriptor == HINTS) { return hintsState; } else if (descriptor == POLYMER_BUILD_ERRORS) { return polymerBuildErrorsState; } else if (descriptor == POLYMER_RESOLUTION_ERRORS) { return polymerResolutionErrorsState; } return super.getState(descriptor); } @Override @SuppressWarnings("unchecked") public <E> E getValue(DataDescriptor<E> descriptor) { if (descriptor == ANGULAR_APPLICATION) { return (E) angularApplication; } else if (descriptor == ANGULAR_COMPONENT) { return (E) angularComponent; } else if (descriptor == ANGULAR_ENTRY) { return (E) angularEntry; } else if (descriptor == ANGULAR_ERRORS) { return (E) angularErrors; } else if (descriptor == ELEMENT) { return (E) element; } else if (descriptor == PARSE_ERRORS) { return (E) parseErrors; } else if (descriptor == PARSED_UNIT) { return (E) parsedUnit; } else if (descriptor == RESOLVED_UNIT) { return (E) resolvedUnit; } else if (descriptor == REFERENCED_LIBRARIES) { return (E) referencedLibraries; } else if (descriptor == RESOLUTION_ERRORS) { return (E) resolutionErrors; } else if (descriptor == HINTS) { return (E) hints; } else if (descriptor == POLYMER_BUILD_ERRORS) { return (E) polymerBuildErrors; } else if (descriptor == POLYMER_RESOLUTION_ERRORS) { return (E) polymerResolutionErrors; } return super.getValue(descriptor); } @Override public HtmlEntryImpl getWritableCopy() { HtmlEntryImpl copy = new HtmlEntryImpl(); copy.copyFrom(this); return copy; } @Override public void invalidateAllInformation() { super.invalidateAllInformation(); parseErrors = AnalysisError.NO_ERRORS; parseErrorsState = CacheState.INVALID; parsedUnit = null; parsedUnitState = CacheState.INVALID; resolvedUnit = null; resolvedUnitState = CacheState.INVALID; invalidateAllResolutionInformation(true); } /** * Invalidate all of the resolution information associated with the HTML file. * * @param invalidateUris true if the cached results of converting URIs to source files should also * be invalidated. */ public void invalidateAllResolutionInformation(boolean invalidateUris) { angularEntry = null; angularEntryState = CacheState.INVALID; angularErrors = AnalysisError.NO_ERRORS; angularErrorsState = CacheState.INVALID; polymerBuildErrors = AnalysisError.NO_ERRORS; polymerBuildErrorsState = CacheState.INVALID; polymerResolutionErrors = AnalysisError.NO_ERRORS; polymerResolutionErrorsState = CacheState.INVALID; element = null; elementState = CacheState.INVALID; resolutionErrors = AnalysisError.NO_ERRORS; resolutionErrorsState = CacheState.INVALID; hints = AnalysisError.NO_ERRORS; hintsState = CacheState.INVALID; if (invalidateUris) { referencedLibraries = Source.EMPTY_ARRAY; referencedLibrariesState = CacheState.INVALID; } } @Override public void recordContentError(AnalysisException exception) { super.recordContentError(exception); recordParseError(exception); } /** * Record that an error was encountered while attempting to parse the source associated with this * entry. * * @param exception the exception that shows where the error occurred */ public void recordParseError(AnalysisException exception) { // If the scanning and parsing of HTML are separated, the following line can be removed. recordScanError(exception); parseErrors = AnalysisError.NO_ERRORS; parseErrorsState = CacheState.ERROR; parsedUnit = null; parsedUnitState = CacheState.ERROR; referencedLibraries = Source.EMPTY_ARRAY; referencedLibrariesState = CacheState.ERROR; recordResolutionError(exception); } /** * Record that an error was encountered while attempting to resolve the source associated with * this entry. * * @param exception the exception that shows where the error occurred */ public void recordResolutionError(AnalysisException exception) { setException(exception); angularErrors = AnalysisError.NO_ERRORS; angularErrorsState = CacheState.ERROR; resolvedUnit = null; resolvedUnitState = CacheState.ERROR; element = null; elementState = CacheState.ERROR; resolutionErrors = AnalysisError.NO_ERRORS; resolutionErrorsState = CacheState.ERROR; hints = AnalysisError.NO_ERRORS; hintsState = CacheState.ERROR; polymerBuildErrors = AnalysisError.NO_ERRORS; polymerBuildErrorsState = CacheState.ERROR; polymerResolutionErrors = AnalysisError.NO_ERRORS; polymerResolutionErrorsState = CacheState.ERROR; } @Override public void setState(DataDescriptor<?> descriptor, CacheState state) { if (descriptor == ANGULAR_APPLICATION) { angularApplication = updatedValue(state, angularApplication, null); angularApplicationState = state; } else if (descriptor == ANGULAR_COMPONENT) { angularComponent = updatedValue(state, angularComponent, null); angularComponentState = state; } else if (descriptor == ANGULAR_ENTRY) { angularEntry = updatedValue(state, angularEntry, null); angularEntryState = state; } else if (descriptor == ANGULAR_ERRORS) { angularErrors = updatedValue(state, angularErrors, null); angularErrorsState = state; } else if (descriptor == ELEMENT) { element = updatedValue(state, element, null); elementState = state; } else if (descriptor == PARSE_ERRORS) { parseErrors = updatedValue(state, parseErrors, null); parseErrorsState = state; } else if (descriptor == PARSED_UNIT) { parsedUnit = updatedValue(state, parsedUnit, null); parsedUnitState = state; } else if (descriptor == RESOLVED_UNIT) { resolvedUnit = updatedValue(state, resolvedUnit, null); resolvedUnitState = state; } else if (descriptor == REFERENCED_LIBRARIES) { referencedLibraries = updatedValue(state, referencedLibraries, Source.EMPTY_ARRAY); referencedLibrariesState = state; } else if (descriptor == RESOLUTION_ERRORS) { resolutionErrors = updatedValue(state, resolutionErrors, AnalysisError.NO_ERRORS); resolutionErrorsState = state; } else if (descriptor == HINTS) { hints = updatedValue(state, hints, AnalysisError.NO_ERRORS); hintsState = state; } else if (descriptor == POLYMER_BUILD_ERRORS) { polymerBuildErrors = updatedValue(state, polymerBuildErrors, null); polymerBuildErrorsState = state; } else if (descriptor == POLYMER_RESOLUTION_ERRORS) { polymerResolutionErrors = updatedValue(state, polymerResolutionErrors, null); polymerResolutionErrorsState = state; } else { super.setState(descriptor, state); } } @Override public <E> void setValue(DataDescriptor<E> descriptor, E value) { if (descriptor == ANGULAR_APPLICATION) { countTransitionToValid(descriptor, angularApplicationState); angularApplication = (AngularApplication) value; angularApplicationState = CacheState.VALID; } else if (descriptor == ANGULAR_COMPONENT) { countTransitionToValid(descriptor, angularComponentState); angularComponent = (AngularComponentElement) value; angularComponentState = CacheState.VALID; } else if (descriptor == ANGULAR_ENTRY) { countTransitionToValid(descriptor, angularEntryState); angularEntry = (AngularApplication) value; angularEntryState = CacheState.VALID; } else if (descriptor == ANGULAR_ERRORS) { countTransitionToValid(descriptor, angularErrorsState); angularErrors = (AnalysisError[]) value; angularErrorsState = CacheState.VALID; } else if (descriptor == ELEMENT) { countTransitionToValid(descriptor, elementState); element = (HtmlElement) value; elementState = CacheState.VALID; } else if (descriptor == PARSE_ERRORS) { countTransitionToValid(descriptor, parseErrorsState); parseErrors = (AnalysisError[]) value; parseErrorsState = CacheState.VALID; } else if (descriptor == PARSED_UNIT) { countTransitionToValid(descriptor, parsedUnitState); parsedUnit = (HtmlUnit) value; parsedUnitState = CacheState.VALID; } else if (descriptor == RESOLVED_UNIT) { countTransitionToValid(descriptor, resolvedUnitState); resolvedUnit = (HtmlUnit) value; resolvedUnitState = CacheState.VALID; } else if (descriptor == REFERENCED_LIBRARIES) { countTransitionToValid(descriptor, referencedLibrariesState); referencedLibraries = value == null ? Source.EMPTY_ARRAY : (Source[]) value; referencedLibrariesState = CacheState.VALID; } else if (descriptor == RESOLUTION_ERRORS) { countTransitionToValid(descriptor, resolutionErrorsState); resolutionErrors = (AnalysisError[]) value; resolutionErrorsState = CacheState.VALID; } else if (descriptor == HINTS) { countTransitionToValid(descriptor, hintsState); hints = (AnalysisError[]) value; hintsState = CacheState.VALID; } else if (descriptor == POLYMER_BUILD_ERRORS) { countTransitionToValid(descriptor, polymerBuildErrorsState); polymerBuildErrors = (AnalysisError[]) value; polymerBuildErrorsState = CacheState.VALID; } else if (descriptor == POLYMER_RESOLUTION_ERRORS) { countTransitionToValid(descriptor, polymerResolutionErrorsState); polymerResolutionErrors = (AnalysisError[]) value; polymerResolutionErrorsState = CacheState.VALID; } else { super.setValue(descriptor, value); } } @Override protected void copyFrom(SourceEntryImpl entry) { super.copyFrom(entry); HtmlEntryImpl other = (HtmlEntryImpl) entry; angularApplicationState = other.angularApplicationState; angularApplication = other.angularApplication; angularComponentState = other.angularComponentState; angularComponent = other.angularComponent; angularEntryState = other.angularEntryState; angularEntry = other.angularEntry; angularErrorsState = other.angularErrorsState; angularErrors = other.angularErrors; parseErrorsState = other.parseErrorsState; parseErrors = other.parseErrors; parsedUnitState = other.parsedUnitState; parsedUnit = other.parsedUnit; resolvedUnitState = other.resolvedUnitState; resolvedUnit = other.resolvedUnit; referencedLibrariesState = other.referencedLibrariesState; referencedLibraries = other.referencedLibraries; resolutionErrorsState = other.resolutionErrorsState; resolutionErrors = other.resolutionErrors; elementState = other.elementState; element = other.element; hintsState = other.hintsState; hints = other.hints; polymerBuildErrorsState = other.polymerBuildErrorsState; polymerBuildErrors = other.polymerBuildErrors; polymerResolutionErrorsState = other.polymerResolutionErrorsState; polymerResolutionErrors = other.polymerResolutionErrors; } @Override protected boolean hasErrorState() { return super.hasErrorState() || parsedUnitState == CacheState.ERROR || resolvedUnitState == CacheState.ERROR || parseErrorsState == CacheState.ERROR || resolutionErrorsState == CacheState.ERROR || referencedLibrariesState == CacheState.ERROR || elementState == CacheState.ERROR || angularErrorsState == CacheState.ERROR || hintsState == CacheState.ERROR || polymerBuildErrorsState == CacheState.ERROR || polymerResolutionErrorsState == CacheState.ERROR; } @Override protected boolean writeDiffOn(StringBuilder builder, SourceEntry oldEntry) { boolean needsSeparator = super.writeDiffOn(builder, oldEntry); if (!(oldEntry instanceof HtmlEntryImpl)) { if (needsSeparator) { builder.append("; "); } builder.append("entry type changed; was " + oldEntry.getClass().getName()); return true; } needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, PARSE_ERRORS, "parseErrors"); needsSeparator = writeStateDiffOn(builder, needsSeparator, oldEntry, PARSED_UNIT, "parsedUnit"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, RESOLVED_UNIT, "resolvedUnit"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, RESOLUTION_ERRORS, "resolutionErrors"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, REFERENCED_LIBRARIES, "referencedLibraries"); needsSeparator = writeStateDiffOn(builder, needsSeparator, oldEntry, ELEMENT, "element"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, ANGULAR_APPLICATION, "angularApplicationState"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, ANGULAR_COMPONENT, "angularComponent"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, ANGULAR_ENTRY, "angularEntry"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, ANGULAR_ERRORS, "angularErrors"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, POLYMER_BUILD_ERRORS, "polymerBuildErrors"); needsSeparator = writeStateDiffOn( builder, needsSeparator, oldEntry, POLYMER_RESOLUTION_ERRORS, "polymerResolutionErrors"); return needsSeparator; } @Override protected void writeOn(StringBuilder builder) { builder.append("Html: "); super.writeOn(builder); builder.append("; parseErrors = "); builder.append(parseErrorsState); builder.append("; parsedUnit = "); builder.append(parsedUnitState); builder.append("; resolvedUnit = "); builder.append(resolvedUnitState); builder.append("; resolutionErrors = "); builder.append(resolutionErrorsState); builder.append("; referencedLibraries = "); builder.append(referencedLibrariesState); builder.append("; element = "); builder.append(elementState); builder.append("; angularApplication = "); builder.append(angularApplicationState); builder.append("; angularComponent = "); builder.append(angularComponentState); builder.append("; angularEntry = "); builder.append(angularEntryState); builder.append("; angularErrors = "); builder.append(angularErrorsState); builder.append("; polymerBuildErrors = "); builder.append(polymerBuildErrorsState); builder.append("; polymerResolutionErrors = "); builder.append(polymerResolutionErrorsState); } }