blob: 41f8554cca4870752c9ac7816ff7d96ab24dcdaf [file] [log] [blame]
/*
* 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);
}
}