Merge pull request #656 from dart-lang/master
Merge master into SDK_AT_HEAD
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9a401a..05dbb5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
## Unpublished
+- Refactored how `exports` are handled in a fairly major way.
- Typecheck the results and input of pipe expressions and the existence of a
matching pipe. Optional arguments are not yet typechecked.
- Add typechecking support for `[attr.foo.if]`, and ensure that a corresponding
@@ -7,6 +8,8 @@
- Fixed issues with `<ng-container>`, which resulted in the inner content simply
being ignored instead of being validated (and also caused some problems
with finding inner `<ng-content>` tags).
+- More checks for rejected operators like `+=`, `++` other unary operators and
+ compound assignments.
## 0.0.17+3
diff --git a/README.md b/README.md
index 2b3ed1c..0f5e5e4 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://travis-ci.org/dart-lang/angular_analyzer_plugin)
+[](https://travis-ci.org/dart-lang/angular_analyzer_plugin) [](https://pub.dartlang.org/packages/angular_analyzer_plugin)
**Requires angular-5.0.0\* and dart SDK 2.0.0-dev.31\*\* or higher to work.**
diff --git a/angular_analyzer_plugin/lib/errors.dart b/angular_analyzer_plugin/lib/errors.dart
index 50e964e..1626f97 100644
--- a/angular_analyzer_plugin/lib/errors.dart
+++ b/angular_analyzer_plugin/lib/errors.dart
@@ -56,6 +56,7 @@
AngularWarningCode.MATCHED_LET_BINDING_HAS_WRONG_TYPE,
AngularWarningCode.EXPORTS_MUST_BE_PLAIN_IDENTIFIERS,
AngularWarningCode.DUPLICATE_EXPORT,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
AngularWarningCode.COMPONENTS_CANT_EXPORT_THEMSELVES,
AngularWarningCode.PIPE_SINGLE_NAME_REQUIRED,
AngularWarningCode.TYPE_IS_NOT_A_PIPE,
@@ -450,6 +451,14 @@
static const DUPLICATE_EXPORT = const AngularWarningCode(
'DUPLICATE_EXPORT', 'Duplicate export of identifier {0}');
+ /// An error code indicating that an identifier was used in a template, but
+ /// not exported in the component.
+ static const IDENTIFIER_NOT_EXPORTED = const AngularWarningCode(
+ 'IDENTIFIER_NOT_EXPORTED',
+ 'Identifier {0} was not exported by the component and therefore cannot be'
+ ' used in its template. Add it to the exports property on the component'
+ ' definition to use it here.');
+
/// An error code indicating component Foo exports Foo, which is unnecessary
static const COMPONENTS_CANT_EXPORT_THEMSELVES = const AngularWarningCode(
'COMPONENTS_CANT_EXPORT_THEMSELVES',
diff --git a/angular_analyzer_plugin/lib/src/completion.dart b/angular_analyzer_plugin/lib/src/completion.dart
index c31fedf..124700a 100644
--- a/angular_analyzer_plugin/lib/src/completion.dart
+++ b/angular_analyzer_plugin/lib/src/completion.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
hide AnalysisError;
import 'package:analyzer_plugin/src/utilities/completion/completion_core.dart';
@@ -179,8 +180,10 @@
final templates = request.templates;
for (final template in templates) {
- final typeProvider = template.view.component.classElement.enclosingElement
- .enclosingElement.context.typeProvider;
+ final context = template.view.component.classElement.enclosingElement
+ .enclosingElement.context;
+ final typeProvider = context.typeProvider;
+ final typeSystem = context.typeSystem;
final dartSnippet = request.dartSnippet;
if (dartSnippet != null) {
@@ -193,7 +196,9 @@
final libraryElement = classElement.library;
final dartResolveResult = new _ResolveResultShell(request.path,
- libraryElement: libraryElement, typeProvider: typeProvider);
+ libraryElement: libraryElement,
+ typeProvider: typeProvider,
+ typeSystem: typeSystem);
final dartRequest = new DartCompletionRequestImpl(
request.resourceProvider, request.offset, dartResolveResult);
await _inheritedReferenceContributor.computeSuggestionsForClass(
@@ -1190,9 +1195,13 @@
TypeProvider typeProvider;
@override
+ TypeSystem typeSystem;
+
+ @override
final String path;
- _ResolveResultShell(this.path, {this.libraryElement, this.typeProvider});
+ _ResolveResultShell(this.path,
+ {this.libraryElement, this.typeProvider, this.typeSystem});
@override
String get content => null;
diff --git a/angular_analyzer_plugin/lib/src/facade/exports_compilation_unit_element.dart b/angular_analyzer_plugin/lib/src/facade/exports_compilation_unit_element.dart
deleted file mode 100644
index 752e6ff..0000000
--- a/angular_analyzer_plugin/lib/src/facade/exports_compilation_unit_element.dart
+++ /dev/null
@@ -1,72 +0,0 @@
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/wrapped.dart';
-import 'package:angular_analyzer_plugin/src/model.dart';
-
-/// A facade for a [CompilationUnitElement] which consists only of a component's
-/// exports, and the component itself.
-class ExportsLimitedCompilationUnitFacade
- extends WrappedCompilationUnitElement {
- final Component _component;
- LibraryElement libraryFacade;
-
- ExportsLimitedCompilationUnitFacade(
- CompilationUnitElement wrappedUnit, this._component,
- {this.libraryFacade})
- : super(wrappedUnit);
-
- @override
- List<PropertyAccessorElement> get accessors =>
- new List<PropertyAccessorElement>.from(_component.exports
- .where(_fromThisUnit)
- .map((export) => export.element)
- .where((element) => element is PropertyAccessorElement));
-
- @override
- LibraryElement get enclosingElement => libraryFacade;
-
- @override
- List<ClassElement> get enums => new List<ClassElement>.from(_component.exports
- .where(_fromThisUnit)
- .map((export) => export.element)
- .where((element) => element is ClassElement && element.isEnum));
-
- @override
- List<FunctionElement> get functions =>
- new List<FunctionElement>.from(_component.exports
- .where(_fromThisUnit)
- .map((export) => export.element)
- .where((element) => element is FunctionElement));
-
- @override
- List<FunctionTypeAliasElement> get functionTypeAliases => [];
-
- @override
- bool get hasJS => false;
-
- @override
- bool get isJS => false;
-
- @override
- LibraryElement get library => libraryFacade;
-
- @override
- List<TopLevelVariableElement> get topLevelVariables => [];
-
- @override
- List<ClassElement> get types => new List<ClassElement>.from(_component.exports
- .where(_fromThisUnit)
- .map((export) => export.element)
- .where((element) => element is ClassElement))
- ..add(_component.classElement);
-
- @override
- ClassElement getEnum(String name) =>
- enums.firstWhere((_enum) => _enum.name == name, orElse: () => null);
-
- @override
- ClassElement getType(String className) =>
- types.firstWhere((type) => type.name == name, orElse: () => null);
-
- // CompilationUnitFacade's are not used for imports, which have prefixes
- bool _fromThisUnit(ExportedIdentifier export) => export.prefix == '';
-}
diff --git a/angular_analyzer_plugin/lib/src/facade/exports_import_element.dart b/angular_analyzer_plugin/lib/src/facade/exports_import_element.dart
deleted file mode 100644
index b75876f..0000000
--- a/angular_analyzer_plugin/lib/src/facade/exports_import_element.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/wrapped.dart';
-import 'package:angular_analyzer_plugin/src/facade/exports_library_element.dart';
-import 'package:angular_analyzer_plugin/src/model.dart';
-
-/// A facade for a [ImportElement] which consists only of a component's
-/// exports
-class ExportsImportElementFacade extends WrappedImportElement {
- final Component _component;
- LibraryElement libraryFacade;
-
- ExportsImportElementFacade(ImportElement wrappedImport, this._component,
- {this.libraryFacade})
- : super(wrappedImport);
-
- @override
- LibraryElement get enclosingElement => libraryFacade;
-
- @override
- bool get hasJS => false;
-
- @override
- LibraryElement get importedLibrary => wrappedImport.importedLibrary == null
- ? null
- : new ExportsLibraryFacade(wrappedImport.importedLibrary, _component,
- prefix: prefix?.name);
-
- @override
- bool get isJS => false;
-
- @override
- LibraryElement get library => libraryFacade;
-}
diff --git a/angular_analyzer_plugin/lib/src/facade/exports_library_element.dart b/angular_analyzer_plugin/lib/src/facade/exports_library_element.dart
deleted file mode 100644
index b682329..0000000
--- a/angular_analyzer_plugin/lib/src/facade/exports_library_element.dart
+++ /dev/null
@@ -1,108 +0,0 @@
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/wrapped.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:angular_analyzer_plugin/src/facade/exports_compilation_unit_element.dart';
-import 'package:angular_analyzer_plugin/src/facade/exports_import_element.dart';
-import 'package:angular_analyzer_plugin/src/model.dart';
-
-/// A facade for a [Library] which consists only of a components' exports, and
-/// the component itself.
-class ExportsLibraryFacade extends WrappedLibraryElement {
- final ExportsLimitedCompilationUnitFacade _definingUnit;
- final Component _owningComponent;
-
- factory ExportsLibraryFacade(
- LibraryElement wrappedLib, Component owningComponent,
- {String prefix}) {
- if (prefix != null) {
- return new _PrefixedExportsLibraryFacade(
- wrappedLib, owningComponent, prefix);
- }
- return new ExportsLibraryFacade._(wrappedLib, owningComponent);
- }
-
- ExportsLibraryFacade._(LibraryElement wrappedLib, this._owningComponent)
- : _definingUnit = new ExportsLimitedCompilationUnitFacade(
- wrappedLib.definingCompilationUnit, _owningComponent),
- super(wrappedLib) {
- _definingUnit.libraryFacade = this;
- }
-
- @override
- CompilationUnitElement get definingCompilationUnit => _definingUnit;
-
- @override
- bool get hasJS => false;
-
- @override
- List<ImportElement> get imports => wrappedLib.imports
- .map((import) => new ExportsImportElementFacade(import, _owningComponent,
- libraryFacade: this))
- .toList();
-
- @override
- bool get isDartAsync => false;
-
- @override
- bool get isDartCore => false;
-
- @override
- bool get isInSdk => false;
-
- @override
- bool get isJS => false;
-
- @override
- LibraryElement get library => this;
-
- @override
- List<LibraryElement> get libraryCycle => wrappedLib.libraryCycle
- .map((lib) => new ExportsLibraryFacade(lib, _owningComponent))
- .toList();
-
- @override
- List<CompilationUnitElement> get parts => wrappedLib.parts
- .map((part) => new ExportsLimitedCompilationUnitFacade(
- part, _owningComponent,
- libraryFacade: this))
- .toList();
-
- @override
- List<PrefixElement> get prefixes => wrappedLib.prefixes
- .where((prefix) => _owningComponent.exports
- .any((export) => export.prefix == prefix.name))
- .toList();
-
- @override
- List<CompilationUnitElement> get units => wrappedLib.units
- .map((unit) => new ExportsLimitedCompilationUnitFacade(
- unit, _owningComponent,
- libraryFacade: this))
- .toList();
-
- @override
- List<ImportElement> getImportsWithPrefix(PrefixElement prefix) => wrappedLib
- .getImportsWithPrefix(prefix)
- .map((lib) => new ExportsImportElementFacade(lib, _owningComponent,
- libraryFacade: this))
- .toList();
-
- @override
- ClassElement getType(String className) => wrappedLib.getType(className);
-}
-
-class _PrefixedExportsLibraryFacade extends ExportsLibraryFacade {
- final String _prefix;
- _PrefixedExportsLibraryFacade(
- LibraryElement wrappedLib, Component owningComponent, this._prefix)
- : super._(wrappedLib, owningComponent);
-
- @override
- Namespace get exportNamespace {
- final map = <String, Element>{};
- _owningComponent.exports
- .where((export) => export.prefix == _prefix)
- .forEach((export) => map[export.identifier] = export.element);
- return new Namespace(map);
- }
-}
diff --git a/angular_analyzer_plugin/lib/src/resolver.dart b/angular_analyzer_plugin/lib/src/resolver.dart
index 4817483..86df668 100644
--- a/angular_analyzer_plugin/lib/src/resolver.dart
+++ b/angular_analyzer_plugin/lib/src/resolver.dart
@@ -15,7 +15,6 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:angular_analyzer_plugin/ast.dart';
import 'package:angular_analyzer_plugin/errors.dart';
-import 'package:angular_analyzer_plugin/src/facade/exports_library_element.dart';
import 'package:angular_analyzer_plugin/src/model.dart';
import 'package:angular_analyzer_plugin/src/options.dart';
import 'package:angular_analyzer_plugin/src/selector.dart';
@@ -33,80 +32,29 @@
return parent is ElementInfo && parent.tagMatchedAsCustomTag;
}
-/// Override the standard [ErrorVerifier] class to report unacceptable nodes,
-/// while suppressing secondary errors that would have been raised by
-/// [ErrorVerifier] if we let it see the bogus definitions.
-class AngularErrorVerifier extends _IntermediateErrorVerifier
- with ReportUnacceptableNodesMixin {
- final bool acceptAssignment;
+/// Overrides standard [ErrorVerifier] to prevent issues with analyzing dangling
+/// angular nodes. Not intended as a long-term solution.
+class AngularErrorVerifier extends ErrorVerifier {
+ AngularErrorVerifier(
+ ErrorReporter errorReporter,
+ LibraryElement currentLibrary,
+ TypeProvider typeProvider,
+ InheritanceManager2 inheritanceManager,
+ {@required bool enableSuperMixins})
+ : super(errorReporter, currentLibrary, typeProvider, inheritanceManager,
+ enableSuperMixins);
@override
- ErrorReporter errorReporter;
- @override
- TypeProvider typeProvider;
-
- AngularErrorVerifier(ErrorReporter errorReporter, LibraryElement library,
- TypeProvider typeProvider, InheritanceManager2 inheritanceManager2,
- {@required this.acceptAssignment})
- : errorReporter = errorReporter,
- typeProvider = typeProvider,
- super(errorReporter, library, typeProvider, inheritanceManager2);
-
- @override
- void visitAssignmentExpression(AssignmentExpression exp) {
- final variableElement = ErrorVerifier.getVariableElement(exp.leftHandSide);
- if ((variableElement == null ||
- variableElement is PropertyInducingElement) &&
- acceptAssignment) {
- super.visitAssignmentExpression(exp);
- } else {
- exp.visitChildren(this);
- }
+ void visitFunctionExpression(FunctionExpression func) {
+ // Stop resolving or analyzer will crash.
+ // TODO(mfairhurst): fix the analyzer crash and remove this.
}
-
- @override
- void visitFunctionExpression(FunctionExpression exp) {
- // error reported in [AngularResolverVisitor] but [ErrorVerifier] crashes
- // because it isn't resolved
- }
-
- @override
- void visitInstanceCreationExpression(InstanceCreationExpression exp) =>
- _reportUnacceptableNode(exp, "Usage of new");
-
- @override
- void visitListLiteral(ListLiteral list) {
- if (list.typeArguments != null) {
- _reportUnacceptableNode(list, "Typed list literals");
- } else {
- super.visitListLiteral(list);
- }
- }
-
- @override
- void visitMapLiteral(MapLiteral map) {
- if (map.typeArguments != null) {
- _reportUnacceptableNode(map, "Typed map literals");
- } else {
- super.visitMapLiteral(map);
- }
- }
-
- @override
- void visitRethrowExpression(RethrowExpression exp) =>
- _reportUnacceptableNode(exp, "Rethrow");
-
- @override
- void visitThisExpression(ThisExpression exp) =>
- _reportUnacceptableNode(exp, "This references");
}
-/// Override the standard [ResolverVisitor] class to report unacceptable nodes,
-/// while suppressing secondary errors that would have been raised by
-/// [ResolverVisitor] if we let it see the bogus definitions.
-class AngularResolverVisitor extends _IntermediateResolverVisitor
- with ReportUnacceptableNodesMixin {
- final bool acceptAssignment;
+/// Overrides standard [ResolverVisitor] to prevent issues with analyzing
+/// dangling angular nodes, while also allowing custom resolution of pipes. Not
+/// intended as a long-term solution.
+class AngularResolverVisitor extends _IntermediateResolverVisitor {
final List<Pipe> pipes;
AngularResolverVisitor(
@@ -115,14 +63,14 @@
Source source,
TypeProvider typeProvider,
AnalysisErrorListener errorListener,
- {@required this.acceptAssignment,
- @required this.pipes})
+ {@required this.pipes})
: super(
inheritanceManager2, library, source, typeProvider, errorListener);
@override
void visitAsExpression(AsExpression exp) {
// This means we generated this in a pipe, and its OK.
+ // TODO(mfairhurst): figure out an alternative approach to this.
if (exp.asOperator.offset == 0) {
super.visitAsExpression(exp);
final pipeName = exp.getProperty<SimpleIdentifier>('_ng_pipeName');
@@ -146,60 +94,14 @@
[exp.expression.staticType, matchingPipe.requiredArgumentType]);
}
}
- } else {
- _reportUnacceptableNode(exp, "As expression");
}
}
@override
- void visitAssignmentExpression(AssignmentExpression exp) {
- // Only block reassignment of locals, not poperties. Resolve elements to
- // check that.
- exp.leftHandSide.accept(elementResolver);
- final variableElement = ErrorVerifier.getVariableElement(exp.leftHandSide);
- if ((variableElement == null ||
- variableElement is PropertyInducingElement) &&
- acceptAssignment) {
- super.visitAssignmentExpression(exp);
- } else {
- _reportUnacceptableNode(exp, "Assignment of locals");
- }
+ void visitFunctionExpression(FunctionExpression func) {
+ // Stop resolving or analyzer will crash.
+ // TODO(mfairhurst): fix the analyzer crash and remove this.
}
-
- @override
- void visitAwaitExpression(AwaitExpression exp) =>
- _reportUnacceptableNode(exp, "Await");
-
- @override
- void visitCascadeExpression(CascadeExpression exp) {
- _reportUnacceptableNode(exp, "Cascades", false);
- // Only resolve the target, not the cascade sections.
- exp.target.accept(this);
- }
-
- @override
- void visitFunctionExpression(FunctionExpression exp) =>
- _reportUnacceptableNode(exp, "Anonymous functions", false);
-
- @override
- void visitIsExpression(IsExpression exp) =>
- _reportUnacceptableNode(exp, "Is expression");
-
- @override
- void visitNamedExpression(NamedExpression exp) =>
- _reportUnacceptableNode(exp, "Named arguments");
-
- @override
- void visitSuperExpression(SuperExpression exp) =>
- _reportUnacceptableNode(exp, "Super references");
-
- @override
- void visitSymbolLiteral(SymbolLiteral exp) =>
- _reportUnacceptableNode(exp, "Symbol literal");
-
- @override
- void visitThrowExpression(ThrowExpression exp) =>
- _reportUnacceptableNode(exp, "Throw");
}
/// Probably the most important visitor to understand in how we process angular
@@ -296,6 +198,230 @@
}
}
+/// Find nodes which are not supported in angular (such as compound assignment
+/// and function expressions etc.), as well as terms used in the template that
+/// weren't exported by the component.
+class AngularSubsetVisitor extends RecursiveAstVisitor<Object> {
+ final bool acceptAssignment;
+ final Component owningComponent;
+
+ final ErrorReporter errorReporter;
+
+ AngularSubsetVisitor(
+ {@required this.errorReporter,
+ @required this.owningComponent,
+ @required this.acceptAssignment});
+
+ @override
+ void visitAsExpression(AsExpression exp) {
+ if (exp.asOperator.offset == 0) {
+ // This means we generated this in a pipe, and its OK.
+ } else {
+ _reportDisallowedExpression(exp, "As expression", visitChildren: false);
+ }
+
+ // Don't visit the TypeName or it may suggest exporting it, which is not
+ // possible.
+ exp.expression.accept(this);
+ }
+
+ @override
+ void visitAssignmentExpression(AssignmentExpression exp) {
+ if (exp.operator.type != TokenType.EQ) {
+ _reportDisallowedExpression(exp, 'Compound assignment',
+ visitChildren: false);
+ }
+ // Only block reassignment of locals, not poperties. Resolve elements to
+ // check that.
+ final variableElement = ErrorVerifier.getVariableElement(exp.leftHandSide);
+ final isLocal =
+ variableElement != null && variableElement is! PropertyInducingElement;
+ if (!acceptAssignment || isLocal) {
+ _reportDisallowedExpression(exp, 'Assignment of locals',
+ visitChildren: false);
+ }
+
+ super.visitAssignmentExpression(exp);
+ }
+
+ @override
+ void visitAwaitExpression(AwaitExpression exp) =>
+ _reportDisallowedExpression(exp, "Await");
+
+ @override
+ void visitCascadeExpression(CascadeExpression exp) =>
+ _reportDisallowedExpression(exp, "Cascades");
+
+ @override
+ void visitFunctionExpression(FunctionExpression exp) =>
+ _reportDisallowedExpression(exp, "Anonymous functions");
+
+ /// Only allow access to:
+ /// * current class members
+ /// * inherited class members
+ /// * methods
+ /// * angular references (ie `<h1 #ref id="foo"></h1> {{h1.id}}`)
+ /// * exported members
+ ///
+ /// Flag the rest and give the hint that they should be exported.
+ void visitIdentifier(Identifier id) {
+ final element = id.staticElement;
+ if (id is PrefixedIdentifier && id.prefix.staticElement is! PrefixElement) {
+ // Static methods, enums, etc. Check the LHS.
+ visitIdentifier(id.prefix);
+ return;
+ }
+ if (id.parent is PropertyAccess &&
+ identical(id, (id.parent as PropertyAccess).propertyName)) {
+ // Accessors are always allowed.
+ return;
+ }
+ if (element is PrefixElement) {
+ // Prefixes can't be exported, and analyzer reports a warning for dangling
+ // prefixes.
+ return;
+ }
+ if (element is MethodElement) {
+ // All methods are OK, as in `x.y()`. It's only `x` that may be hidden.
+ return;
+ }
+ if (element is ClassElement && element == owningComponent.classElement) {
+ // Static method calls on the current class are allowed
+ return;
+ }
+ if (element is DynamicElementImpl) {
+ // Usually indicates a resolution error, so don't double report it.
+ return;
+ }
+ if (element == null) {
+ // Also usually indicates an error, don't double report.
+ return;
+ }
+ if (element is LocalVariableElement) {
+ // `$event` variables, `ngFor` variables, these are OK.
+ return;
+ }
+ if (element is ParameterElement) {
+ // Named parameters: not allowed, but flagged in [visitNamedExpression].
+ return;
+ }
+ if (element is AngularElement) {
+ // Variables local to the template
+ return;
+ }
+ if ((element is PropertyInducingElement ||
+ element is PropertyAccessorElement) &&
+ (owningComponent.classElement.lookUpGetter(id.name, null) != null ||
+ owningComponent.classElement.lookUpSetter(id.name, null) != null)) {
+ // Part of the component interface.
+ return;
+ }
+
+ if (id is PrefixedIdentifier) {
+ if (owningComponent.exports.any((export) =>
+ export.prefix == id.prefix.name && id.name == export.identifier)) {
+ // Correct reference to exported prefix identifier
+ return;
+ }
+ } else {
+ if (owningComponent.exports.any(
+ (export) => export.prefix == null && id.name == export.identifier)) {
+ // Correct reference to exported simple identifier
+ return;
+ }
+ }
+
+ errorReporter.reportErrorForNode(
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED, id, [id]);
+ }
+
+ @override
+ void visitInstanceCreationExpression(InstanceCreationExpression exp) {
+ _reportDisallowedExpression(exp, "Usage of new", visitChildren: false);
+ // Don't visit the TypeName or it may suggest exporting it, which is not
+ // possible.
+
+ exp.argumentList.accept(this);
+ }
+
+ @override
+ void visitIsExpression(IsExpression exp) {
+ _reportDisallowedExpression(exp, "Is expression", visitChildren: false);
+ // Don't visit the TypeName or it may suggest exporting it, which is not
+ // possible.
+
+ exp.expression.accept(this);
+ }
+
+ @override
+ void visitListLiteral(ListLiteral list) {
+ if (list.typeArguments != null) {
+ _reportDisallowedExpression(list, "Typed list literals",
+ visitChildren: false);
+ // Don't visit the TypeName or it may suggest exporting it, which is not
+ // possible.e.
+
+ list.elements.accept(this);
+ } else {
+ super.visitListLiteral(list);
+ }
+ }
+
+ @override
+ void visitMapLiteral(MapLiteral map) {
+ if (map.typeArguments != null) {
+ _reportDisallowedExpression(map, "Typed map literals",
+ visitChildren: false);
+ // Don't visit the TypeName or it may suggest exporting it, which is not
+ // possible.e.
+
+ map.entries.accept(this);
+ } else {
+ super.visitMapLiteral(map);
+ }
+ }
+
+ @override
+ void visitNamedExpression(NamedExpression exp) =>
+ _reportDisallowedExpression(exp, "Named arguments");
+
+ @override
+ void visitPostfixExpression(PostfixExpression exp) {
+ _reportDisallowedExpression(exp, exp.operator.lexeme);
+ }
+
+ @override
+ void visitPrefixedIdentifier(PrefixedIdentifier id) => visitIdentifier(id);
+
+ @override
+ void visitPrefixExpression(PrefixExpression exp) {
+ if (exp.operator.type != TokenType.MINUS) {
+ _reportDisallowedExpression(exp, exp.operator.lexeme);
+ }
+ }
+
+ @override
+ void visitSimpleIdentifier(SimpleIdentifier id) => visitIdentifier(id);
+
+ @override
+ void visitSymbolLiteral(SymbolLiteral exp) =>
+ _reportDisallowedExpression(exp, "Symbol literal");
+
+ @override
+ void visitThrowExpression(ThrowExpression exp) =>
+ _reportDisallowedExpression(exp, "Throw");
+
+ void _reportDisallowedExpression(Expression node, String description,
+ {bool visitChildren = true}) {
+ errorReporter.reportErrorForNode(
+ AngularWarningCode.DISALLOWED_EXPRESSION, node, [description]);
+
+ if (visitChildren) {
+ node.visitChildren(this);
+ }
+ }
+}
+
class ComponentContentResolver extends AngularAstVisitor {
final Source templateSource;
final Template template;
@@ -1172,23 +1298,6 @@
type.lookUpInheritedGetter(name)?.returnType;
}
-abstract class ReportUnacceptableNodesMixin
- implements RecursiveAstVisitor<Object> {
- ErrorReporter get errorReporter;
- TypeProvider get typeProvider;
- void _reportUnacceptableNode(Expression node, String description,
- [bool visitChildren = true]) {
- errorReporter.reportErrorForNode(
- AngularWarningCode.DISALLOWED_EXPRESSION, node, [description]);
-
- // "resolve" the node, a null type causes later errors.
- node.propagatedType = node.staticType = typeProvider.dynamicType;
- if (visitChildren) {
- node.visitChildren(this);
- }
- }
-}
-
/// Once all the scopes for all the expressions & statements are prepared, we're
/// ready to resolve all the expressions inside and typecheck everything.
///
@@ -1539,8 +1648,7 @@
/// Resolve the given [AstNode] ([expression] or [statement]) and report errors.
void _resolveDartAstNode(AstNode astNode, bool acceptAssignment) {
final classElement = view.classElement;
- final library =
- new ExportsLibraryFacade(classElement.library, view.component);
+ final library = classElement.library;
{
final visitor = new TypeResolverVisitor(
library, view.source, typeProvider, errorListener);
@@ -1550,7 +1658,7 @@
new InheritanceManager2(typeSystem as StrongTypeSystemImpl);
final resolver = new AngularResolverVisitor(inheritanceManager2, library,
templateSource, typeProvider, errorListener,
- acceptAssignment: acceptAssignment, pipes: pipes);
+ pipes: pipes);
// fill the name scope
final classScope = new ClassScope(resolver.nameScope, classElement);
final localScope = new EnclosedScope(classScope);
@@ -1564,9 +1672,15 @@
// verify
final verifier = new AngularErrorVerifier(
errorReporter, library, typeProvider, inheritanceManager2,
- acceptAssignment: acceptAssignment)
+ enableSuperMixins: true)
..enclosingClass = classElement;
astNode.accept(verifier);
+ // Check for concepts illegal to templates (for instance function literals).
+ final angularSubsetChecker = new AngularSubsetVisitor(
+ errorReporter: errorReporter,
+ acceptAssignment: acceptAssignment,
+ owningComponent: view.component);
+ astNode.accept(angularSubsetChecker);
}
/// Resolve the Dart expression with the given [code] at [offset].
@@ -1914,20 +2028,6 @@
}
/// Workaround for "This mixin application is invalid because all of the
-/// constructors in the base class 'ErrorVerifier' have optional parameters."
-/// in the definition of [AngularErrorVerifier].
-///
-/// See https://github.com/dart-lang/sdk/issues/15101 for details
-class _IntermediateErrorVerifier extends ErrorVerifier {
- _IntermediateErrorVerifier(
- ErrorReporter errorReporter,
- LibraryElement library,
- TypeProvider typeProvider,
- InheritanceManager2 inheritanceManager2,
- ) : super(errorReporter, library, typeProvider, inheritanceManager2, false);
-}
-
-/// Workaround for "This mixin application is invalid because all of the
/// constructors in the base class 'ResolverVisitor' have optional parameters."
/// in the definition of [AngularResolverVisitor].
///
diff --git a/angular_analyzer_plugin/pubspec.yaml b/angular_analyzer_plugin/pubspec.yaml
index 69865cc..d9681cc 100644
--- a/angular_analyzer_plugin/pubspec.yaml
+++ b/angular_analyzer_plugin/pubspec.yaml
@@ -9,10 +9,10 @@
environment:
sdk: '>=2.0.0-dev.0.0 <3.0.0'
dependencies:
- analyzer: '0.32.4'
+ analyzer: '0.33.1'
plugin: '^0.2.0'
# tuple: '^1.0.1' Does not yet support Dart 2
- analyzer_plugin: '0.0.1-alpha.4'
+ analyzer_plugin: '0.0.1-alpha.5'
angular_ast: '^0.5.0'
meta: ^1.0.2
yaml: ^2.1.2
diff --git a/angular_analyzer_plugin/test/abstract_angular.dart b/angular_analyzer_plugin/test/abstract_angular.dart
index 0901d0e..b9573ce 100644
--- a/angular_analyzer_plugin/test/abstract_angular.dart
+++ b/angular_analyzer_plugin/test/abstract_angular.dart
@@ -116,16 +116,22 @@
AbstractAngularTest() : includeQueryList = true;
AbstractAngularTest.future() : includeQueryList = false;
- /// Assert that the [errCode] is reported for [code], highlighting the [snippet].
+ /// Assert that the [errCode] is reported for [code], highlighting the
+ /// [snippet]. Optionally, expect [additionalErrorCodes] to appear at any
+ /// location.
void assertErrorInCodeAtPosition(
- ErrorCode errCode, String code, String snippet) {
+ ErrorCode errCode, String code, String snippet,
+ {List<ErrorCode> additionalErrorCodes}) {
final snippetIndex = code.indexOf(snippet);
expect(snippetIndex, greaterThan(-1),
reason: 'Error in test: snippet $snippet not part of code $code');
- errorListener.assertErrorsWithCodes(<ErrorCode>[errCode]);
- final error = errorListener.errors.single;
+ final expectedErrorCodes = (additionalErrorCodes ?? <ErrorCode>[])
+ ..add(errCode);
+ errorListener.assertErrorsWithCodes(expectedErrorCodes);
+ final error =
+ errorListener.errors.singleWhere((e) => e.errorCode == errCode);
expect(error.offset, snippetIndex);
- expect(errorListener.errors.single.length, snippet.length);
+ expect(error.length, snippet.length);
}
/// For [expectedErrors], it is a List of Tuple4 (1 per error):
diff --git a/angular_analyzer_plugin/test/resolver_test.dart b/angular_analyzer_plugin/test/resolver_test.dart
index a668aea..c6fa8ba 100644
--- a/angular_analyzer_plugin/test/resolver_test.dart
+++ b/angular_analyzer_plugin/test/resolver_test.dart
@@ -143,6 +143,7 @@
// ignore: non_constant_identifier_names
Future test_catchPkgHtmlGithubBug44() async {
+ // see https://github.com/dart-lang/html/issues/44
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
class TestPanel {
@@ -284,40 +285,6 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_as_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1>{{str as String}}</h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "str as String");
- }
-
- // ignore: non_constant_identifier_names
- Future test_expression_assignment_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 #h1 [hidden]="h1 = 4"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "h1 = 4");
- }
-
- // ignore: non_constant_identifier_names
Future test_expression_attrBinding_expressionTypeError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -437,43 +404,6 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_await_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="await str"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- //This actually gets parsed as an identifier, which is OK. Still fails!
- errorListener.assertErrorsWithCodes([
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- AngularWarningCode.TRAILING_EXPRESSION
- ]);
- }
-
- // ignore: non_constant_identifier_names
- Future test_expression_cascade_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="str..x"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "str..x");
- }
-
- // ignore: non_constant_identifier_names
Future test_expression_classBinding_invalidClassName() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -641,41 +571,6 @@
_assertElement('handleClick()').dart.method.at('handleClick(MouseEvent');
}
- // ignore: non_constant_identifier_names
- Future test_expression_func2_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="()=>x"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "()=>x");
- }
-
- // ignore: non_constant_identifier_names
- Future test_expression_func_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="(){}"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "(){}");
- }
-
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_input_genericDirective_lowerBoundChainTypeError() async {
@@ -699,7 +594,6 @@
AngularWarningCode.INPUT_BINDING_TYPE_ERROR, code, "notString");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_input_genericDirective_lowerBoundNestedTypeError() async {
@@ -723,7 +617,6 @@
AngularWarningCode.INPUT_BINDING_TYPE_ERROR, code, "notStringList");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_inputAndOutputBinding_extendGenericUnbounded_ok() async {
@@ -753,7 +646,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_inputAndOutputBinding_genericDirective_chain_ok() async {
@@ -780,7 +672,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_inputAndOutputBinding_genericDirective_nested_ok() async {
@@ -832,7 +723,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_inputAndOutputBinding_genericDirectiveChild_ok() async {
@@ -1101,7 +991,6 @@
AngularWarningCode.EMPTY_BINDING, code, "[title]");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_inputBinding_genericDirective_lowerBoundTypeError() async {
@@ -1370,23 +1259,6 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_is_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="str is int"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "str is int");
- }
-
- // ignore: non_constant_identifier_names
Future test_expression_keyupdownWithKeysOk() async {
_addDartSource(r'''
import 'dart:html';
@@ -1438,23 +1310,6 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_named_args_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- bool callMe({String arg}) => true;
-}
-''');
- final code = r"""
-<h1 [hidden]="callMe(arg: 'bob')"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "arg: 'bob'");
- }
-
- // ignore: non_constant_identifier_names
Future test_expression_nativeEventBindingOnComponent() async {
_addDartSource(r'''
import 'dart:html';
@@ -1501,40 +1356,6 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_nested_as_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1>{{(str.isEmpty as String).isEmpty}}</h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(AngularWarningCode.DISALLOWED_EXPRESSION, code,
- "str.isEmpty as String");
- }
-
- // ignore: non_constant_identifier_names
- Future test_expression_new_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="new String().isEmpty"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "new String()");
- }
-
- // ignore: non_constant_identifier_names
Future test_expression_outputBinding_boundToNothing() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -1551,7 +1372,6 @@
AngularWarningCode.NONEXIST_OUTPUT_BOUND, code, "title");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_outputBinding_genericDirective_lowerBoundTypeError() async {
@@ -1689,8 +1509,8 @@
AngularWarningCode.AMBIGUOUS_PIPE, code, 'ambiguous');
}
- // ignore: non_constant_identifier_names
@failingTest
+ // ignore: non_constant_identifier_names
Future test_expression_pipe_in_moustache_extraArg() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -1710,8 +1530,8 @@
StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS, code, '"extra"');
}
- // ignore: non_constant_identifier_names
@failingTest
+ // ignore: non_constant_identifier_names
Future test_expression_pipe_in_moustache_extraExtraArg() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -1767,8 +1587,8 @@
StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, code, '1');
}
- // ignore: non_constant_identifier_names
@failingTest
+ // ignore: non_constant_identifier_names
Future test_expression_pipe_in_moustache_typeErrorOptionalArg() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html', pipes: [StringPipe])
@@ -1830,8 +1650,8 @@
StaticWarningCode.UNDEFINED_IDENTIFIER, code, "error1");
}
- // ignore: non_constant_identifier_names
@failingTest
+ // ignore: non_constant_identifier_names
Future test_expression_pipe_in_moustache_with_error_inArg() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html', pipes: [Pipe1])
@@ -1893,40 +1713,6 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_rethrow_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="rethrow"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "rethrow");
- }
-
- // ignore: non_constant_identifier_names
- Future test_expression_setter_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="str = 'hey'"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "str = 'hey'");
- }
-
- // ignore: non_constant_identifier_names
Future test_expression_styleBinding_noUnit_expressionTypeError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -1997,6 +1783,7 @@
errorListener.assertNoErrors();
}
+ // ignore: non_constant_identifier_names
Future test_expression_styleBinding_withUnit_invalidPropertyName() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2019,6 +1806,7 @@
]);
}
+ // ignore: non_constant_identifier_names
Future test_expression_styleBinding_withUnit_invalidUnitName() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2041,6 +1829,7 @@
]);
}
+ // ignore: non_constant_identifier_names
Future test_expression_styleBinding_withUnit_nonWidthOrHeightPercent() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2057,6 +1846,7 @@
AngularWarningCode.INVALID_CSS_UNIT_NAME, code, "%");
}
+ // ignore: non_constant_identifier_names
Future test_expression_styleBinding_withUnit_typeError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2073,6 +1863,7 @@
AngularWarningCode.CSS_UNIT_BINDING_NOT_NUMBER, code, "notNumber");
}
+ // ignore: non_constant_identifier_names
Future test_expression_styleBinding_withUnit_widthPercent() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2088,22 +1879,7 @@
errorListener.assertNoErrors();
}
- Future test_expression_super_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="super.x"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "super");
- }
-
+ // ignore: non_constant_identifier_names
Future test_expression_symbol_invoked_noCrash() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2117,59 +1893,12 @@
_addHtmlSource(code);
await _resolveSingleTemplate(dartSource);
assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "#symbol");
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "#symbol",
+ additionalErrorCodes: [
+ StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION
+ ]);
}
- Future test_expression_symbol_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="#symbol"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "#symbol");
- }
-
- Future test_expression_this_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="this"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "this");
- }
-
- // ignore: non_constant_identifier_names
- Future test_expression_throw_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 [hidden]="throw str"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "throw str");
- }
-
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_expression_twoWayBinding_genericDirective_lowerBoundTypeError() async {
@@ -2240,6 +1969,7 @@
AngularWarningCode.EMPTY_BINDING, code, "[(twoWay)]");
}
+ // ignore: non_constant_identifier_names
Future test_expression_twoWayBinding_noInputToBind() async {
_addDartSource(r'''
@Component(selector: 'test-panel', directives: const [TitleComponent],
@@ -2283,6 +2013,7 @@
AngularWarningCode.NONEXIST_TWO_WAY_OUTPUT_BOUND, code, "inputOnly");
}
+ // ignore: non_constant_identifier_names
Future test_expression_twoWayBinding_notAssignableError() async {
_addDartSource(r'''
@Component(selector: 'test-panel',
@@ -2362,7 +2093,415 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_typed_list_not_allowed() async {
+ Future test_expression_unaryMinus_allowed() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+{{-x}}
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ errorListener.assertNoErrors();
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_as() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1>{{str as String}}</h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "str as String");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_await() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="await str"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ //This actually gets parsed as an identifier, which is OK. Still fails!
+ errorListener.assertErrorsWithCodes([
+ StaticWarningCode.UNDEFINED_IDENTIFIER,
+ AngularWarningCode.TRAILING_EXPRESSION
+ ]);
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_cascade() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ bool val;
+}
+''');
+ final code = r"""
+<h1 [hidden]="val..toString"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "val..toString");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_func() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="(){}"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "(){}");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_func2() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="()=>x"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "()=>x");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_is() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="str is int"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "str is int");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_minusEq() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+<h1 (click)="x -= 1"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, 'x -= 1');
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_namedArgs() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ bool callMe({String arg}) => true;
+}
+''');
+ final code = r"""
+<h1 [hidden]="callMe(arg: 'bob')"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "arg: 'bob'");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_nestedAs() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1>{{(str.isEmpty as String).isEmpty}}</h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(AngularWarningCode.DISALLOWED_EXPRESSION, code,
+ "str.isEmpty as String");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_new() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="new TestPanel() != null"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "new TestPanel()");
+ }
+
+ Future test_expressionNotAllowed_plusEq() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+<h1 (click)="x += 1"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, 'x += 1');
+ }
+
+ Future test_expressionNotAllowed_postfixMinusMinus() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+<h1 (click)="x--"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, 'x--');
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_postfixPlusPlus() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+<h1 (click)="x++"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, 'x++');
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_prefixMinusMinus() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+<h1 (click)="--x"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, '--x');
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_prefixPlusPlus() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ int x;
+}
+''');
+ final code = r"""
+<h1 (click)="++x"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, '++x');
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_referenceAssignment() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+ <h1 #h1 [hidden]="(h1 = null) == null"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "h1 = null");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_rethrow() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="rethrow"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, code, "rethrow");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_setter() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="(str = 'hey') == null"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "str = 'hey'");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_statementAssignment() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 #h1 (click)="h1 = null"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "h1 = null");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_super() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="super.x"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, code, "super");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_symbol() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="#symbol == null"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "#symbol");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_this() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="this"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ CompileTimeErrorCode.INVALID_REFERENCE_TO_THIS, code, "this");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_throw() async {
+ _addDartSource(r'''
+@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
+class TestPanel {
+ String str;
+}
+''');
+ final code = r"""
+<h1 [hidden]="throw str"></h1>
+""";
+ _addHtmlSource(code);
+ await _resolveSingleTemplate(dartSource);
+ assertErrorInCodeAtPosition(
+ AngularWarningCode.DISALLOWED_EXPRESSION, code, "throw str");
+ }
+
+ // ignore: non_constant_identifier_names
+ Future test_expressionNotAllowed_typedList() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
class TestPanel {
@@ -2379,7 +2518,7 @@
}
// ignore: non_constant_identifier_names
- Future test_expression_typed_map_not_allowed() async {
+ Future test_expressionNotAllowed_typedMap() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
class TestPanel {
@@ -2525,6 +2664,7 @@
_assertElement("item").local.at('item [');
}
+ // ignore: non_constant_identifier_names
Future test_letVariable_in_nonTemplate() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -2539,6 +2679,7 @@
'let-value');
}
+ // ignore: non_constant_identifier_names
Future test_localVariable_camelCaseName() async {
_addDartSource(r'''
import 'dart:html';
@@ -2563,6 +2704,7 @@
_assertElement("myTargetElement.someString)").local.at("myTargetElement>");
}
+ // ignore: non_constant_identifier_names
Future test_localVariable_exportAs() async {
_addDartSource(r'''
@Directive(selector: '[myDirective]', exportAs: 'exportedValue')
@@ -3280,6 +3422,31 @@
}
// ignore: non_constant_identifier_names
+// Future test_ngFor_variousKinds_useLowerIdentifier() async {
+// _addDartSource(r'''
+//@Component(selector: 'test-panel')
+//@View(templateUrl: 'test_panel.html', directives: const [NgFor])
+//class TestPanel {
+// List<String> items = [];
+//}
+//''');
+// _addHtmlSource(r"""
+//<template ngFor let-item1 [ngForOf]='items' let-i='index' {{lowerEl}}>
+// {{item1.length}}
+//</template>
+//<li template="ngFor let item2 of items; let i=index" {{lowerEl}}>
+// {{item2.length}}
+//</li>
+//<li *ngFor="let item3 of items; let i=index" {{lowerEl}}>
+// {{item3.length}}
+//</li>
+//<div #lowerEl></div>
+//""");
+// await _resolveSingleTemplate(dartSource);
+// errorListener.assertNoErrors();
+// }
+
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_customTagNames() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -3339,31 +3506,6 @@
}
// ignore: non_constant_identifier_names
-// Future test_ngFor_variousKinds_useLowerIdentifier() async {
-// _addDartSource(r'''
-//@Component(selector: 'test-panel')
-//@View(templateUrl: 'test_panel.html', directives: const [NgFor])
-//class TestPanel {
-// List<String> items = [];
-//}
-//''');
-// _addHtmlSource(r"""
-//<template ngFor let-item1 [ngForOf]='items' let-i='index' {{lowerEl}}>
-// {{item1.length}}
-//</template>
-//<li template="ngFor let item2 of items; let i=index" {{lowerEl}}>
-// {{item2.length}}
-//</li>
-//<li *ngFor="let item3 of items; let i=index" {{lowerEl}}>
-// {{item3.length}}
-//</li>
-//<div #lowerEl></div>
-//""");
-// await _resolveSingleTemplate(dartSource);
-// errorListener.assertNoErrors();
-// }
-
- // ignore: non_constant_identifier_names
Future test_resolveTemplate_exportsCantUsePrefixes() async {
newSource('/prefixed.dart', 'const int prefixRequired = 1;');
_addDartSource(r'''
@@ -3427,9 +3569,18 @@
class TestPanel {
static void componentStatic() {
}
+ local();
+ int get getter => null;
+ set setter(int x) => null;
+ int field = null;
}
''');
final code = r'''
+methods/getters/setters on current class ok:
+{{local()}}
+{{getter}}
+{{field}}
+<div (click)="setter = null"></div>
static on current class ok:
{{TestPanel.componentStatic()}}
exports ok:
@@ -3444,7 +3595,7 @@
''';
_addHtmlSource(code);
await _resolveSingleTemplate(dartSource);
- expect(ranges, hasLength(18));
+ expect(ranges, hasLength(23));
_assertElement('TestPanel').dart.at('TestPanel {');
_assertElement('componentStatic').dart.method.at('componentStatic() {');
_assertElement('myAccessor').dart.getter.at('myAccessor = 1');
@@ -3492,7 +3643,6 @@
]);
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_noDashesAroundTranscludedContent_stillError() async {
@@ -3514,7 +3664,6 @@
code, "shouldn't be allowed");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_noDashesAroundTranscludedContent_stillMatchesTag() async {
@@ -3586,24 +3735,22 @@
''';
_addHtmlSource(code);
await _resolveSingleTemplate(dartSource);
- expect(ranges, hasLength(0));
errorListener.assertErrorsWithCodes([
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticTypeWarningCode.UNDEFINED_METHOD,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
- StaticWarningCode.UNDEFINED_IDENTIFIER,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
+ AngularWarningCode.IDENTIFIER_NOT_EXPORTED,
]);
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_componentNotElement() async {
@@ -3633,7 +3780,6 @@
"<some-component #contentChild></some-component>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_componentNotElementRef() async {
@@ -3662,7 +3808,6 @@
"<some-component #contentChild></some-component>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_componentNotTemplateRef() async {
@@ -3691,7 +3836,6 @@
"<some-component #contentChild></some-component>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_directiveNotElement() async {
@@ -3721,7 +3865,6 @@
"<div some-directive #contentChild=\"theDirective\"></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_directiveNotElement_deeplyNested() async {
@@ -3759,7 +3902,6 @@
"<div some-directive #contentChild=\"theDirective\"></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_directiveNotElementRef() async {
@@ -3788,7 +3930,6 @@
"<div some-directive #contentChild=\"theDirective\"></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_directiveNotTemplateRef() async {
@@ -3817,7 +3958,6 @@
"<div some-directive #contentChild></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_element_directiveNotExported() async {
@@ -3846,7 +3986,6 @@
"<div some-directive #contentChild></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_elementNotComponent() async {
@@ -3875,7 +4014,6 @@
"<div #contentChild></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_elementNotDirective() async {
@@ -3904,7 +4042,6 @@
"<div #contentChild></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_elementNotTemplateRef() async {
@@ -3930,7 +4067,6 @@
"<div #contentChild></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_readValueIsAlwaysOk() async {
@@ -3953,8 +4089,6 @@
errorListener.assertNoErrors();
}
- // see https://github.com/dart-lang/html/issues/44
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_templateNotComponent() async {
@@ -3983,7 +4117,6 @@
"<template #contentChild></template>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_templateNotDirective() async {
@@ -4012,7 +4145,6 @@
"<template #contentChild></template>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_templateNotElement() async {
@@ -4039,7 +4171,6 @@
"<template #contentChild></template>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_templateNotElementRef() async {
@@ -4065,7 +4196,6 @@
"<template #contentChild></template>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_wrongComponent() async {
@@ -4098,7 +4228,6 @@
"<some-other-component #contentChild></some-other-component>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentChildLetBound_wrongDirective() async {
@@ -4150,7 +4279,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentMatchingHigherComponentsIsStillNotTranscludedError() async {
@@ -4203,7 +4331,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentMatchingSelectorsAndAllKnowsTag() async {
@@ -4249,7 +4376,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentMatchingSelectorsReportsUnknownTag() async {
@@ -4332,7 +4458,6 @@
AngularWarningCode.CONTENT_NOT_TRANSCLUDED, code, "<div></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentNotMatchingSelectorsButMatchesContentChildElement() async {
@@ -4357,7 +4482,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentNotMatchingSelectorsButMatchesContentChildElementRef() async {
@@ -4477,7 +4601,6 @@
code, "<template></template>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentNotMatchingSelectorsOrContentChildTemplateRef() async {
@@ -4502,7 +4625,6 @@
AngularWarningCode.CONTENT_NOT_TRANSCLUDED, code, "<div></div>");
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_resolveTemplate_provideContentNoTransclusionsButMatchesContentChildDirective() async {
@@ -4767,6 +4889,7 @@
AngularWarningCode.CONTENT_NOT_TRANSCLUDED, code, "<div></div>");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_provideContentWhereInvalid() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -4786,6 +4909,7 @@
AngularWarningCode.CONTENT_NOT_TRANSCLUDED, code, "doesn't belong");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_provideDuplicateContentChildError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -4812,6 +4936,7 @@
"<div second></div>");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_provideDuplicateContentChildNestedOk() async {
_addDartSource(r'''
import 'dart:html';
@@ -4837,6 +4962,7 @@
errorListener.assertNoErrors();
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_provideDuplicateContentChildrenOk() async {
_addDartSource(r'''
import 'dart:html';
@@ -4861,6 +4987,7 @@
errorListener.assertNoErrors();
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_provideTextInfosDontMatchSelectors() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -4881,6 +5008,7 @@
AngularWarningCode.CONTENT_NOT_TRANSCLUDED, code, "doesn't belong");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplate_resolvingBogusImportDoesntCrash() async {
_addDartSource(r'''
import ; // synthetic import
@@ -4930,6 +5058,7 @@
"<template second></template>");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplateWithNgContent_emptySelectorError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -4948,6 +5077,7 @@
AngularWarningCode.CANNOT_PARSE_SELECTOR, code, "\"\"");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplateWithNgContent_hasContentsError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -4969,6 +5099,7 @@
]);
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplateWithNgContent_noSelectorIsNull() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -4986,6 +5117,7 @@
expect(template.view.component.ngContents.first.selector, isNull);
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplateWithNgContent_noValueError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -5004,6 +5136,7 @@
AngularWarningCode.CANNOT_PARSE_SELECTOR, code, "select");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplateWithNgContent_selectorParseError() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -5022,6 +5155,7 @@
AngularWarningCode.CANNOT_PARSE_SELECTOR, code, "+");
}
+ // ignore: non_constant_identifier_names
Future test_resolveTemplateWithNgContentTracksSelectors() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -5038,6 +5172,7 @@
expect(template.view.component.ngContents, hasLength(1));
}
+ // ignore: non_constant_identifier_names
Future test_standardHtmlComponent() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -5062,6 +5197,7 @@
expect(ranges, hasLength(8));
}
+ // ignore: non_constant_identifier_names
Future test_standardHtmlComponentUsingRef() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -5086,6 +5222,7 @@
expect(ranges, hasLength(8));
}
+ // ignore: non_constant_identifier_names
Future test_star_selectTemplateFunctionalDirectiveMatches() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -5103,6 +5240,7 @@
errorListener.assertNoErrors();
}
+ // ignore: non_constant_identifier_names
Future test_star_selectTemplateMatches() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -5122,6 +5260,7 @@
errorListener.assertNoErrors();
}
+ // ignore: non_constant_identifier_names
Future test_starNoDirectives() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html',
@@ -5138,6 +5277,7 @@
AngularWarningCode.TEMPLATE_ATTR_NOT_USED, code, "*foo");
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_all_semicolons() async {
_addDartSource(r'''
import 'dart:html';
@@ -5155,6 +5295,7 @@
errorListener.assertNoErrors();
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_double_statement() async {
_addDartSource(r'''
import 'dart:html';
@@ -5172,6 +5313,7 @@
_assertElement('handleClick').dart.method.at('handleClick(MouseEvent');
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_error_on_assignment_statement() async {
_addDartSource(r'''
import 'dart:html';
@@ -5192,6 +5334,7 @@
"String s");
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_error_on_second_statement() async {
_addDartSource(r'''
import 'dart:html';
@@ -5210,6 +5353,7 @@
StaticTypeWarningCode.UNDEFINED_METHOD, code, "unknownFunction");
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_if_statement_with_semicolon() async {
_addDartSource(r'''
import 'dart:html';
@@ -5228,6 +5372,7 @@
"if(true){}");
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_if_statement_without_semicolon() async {
_addDartSource(r'''
import 'dart:html';
@@ -5246,6 +5391,7 @@
"if(true){}");
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_return_statement_with_semicolon() async {
_addDartSource(r'''
import 'dart:html';
@@ -5284,6 +5430,7 @@
"return 5");
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_single_statement_with_semicolon() async {
_addDartSource(r'''
import 'dart:html';
@@ -5301,7 +5448,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_statement_eventBinding_single_statement_without_semicolon() async {
@@ -5340,7 +5486,6 @@
errorListener.assertNoErrors();
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_statement_eventBinding_typechecking_after_unexpected_bracket() async {
@@ -5364,6 +5509,7 @@
]);
}
+ // ignore: non_constant_identifier_names
Future test_statement_eventBinding_typeError() async {
_addDartSource(r'''
import 'dart:html';
@@ -5382,7 +5528,6 @@
StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, code, '"asdf"');
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_statement_eventBinding_unexpected_closing_brackets_at_end() async {
@@ -5402,7 +5547,6 @@
assertErrorInCodeAtPosition(ParserErrorCode.UNEXPECTED_TOKEN, code, '}}}}');
}
- // ignore: non_constant_identifier_names
Future
// ignore: non_constant_identifier_names
test_statement_eventBinding_unexpected_closing_brackets_at_start() async {
@@ -5423,23 +5567,6 @@
}
// ignore: non_constant_identifier_names
- Future test_statements_assignment_not_allowed() async {
- _addDartSource(r'''
-@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
-class TestPanel {
- String str;
-}
-''');
- final code = r"""
-<h1 #h1 (click)="h1 = 4"></h1>
-""";
- _addHtmlSource(code);
- await _resolveSingleTemplate(dartSource);
- assertErrorInCodeAtPosition(
- AngularWarningCode.DISALLOWED_EXPRESSION, code, "h1 = 4");
- }
-
- // ignore: non_constant_identifier_names
Future test_statements_setter_allowed() async {
_addDartSource(r'''
@Component(selector: 'test-panel', templateUrl: 'test_panel.html')
@@ -5565,6 +5692,7 @@
AngularWarningCode.TEMPLATE_ATTR_NOT_USED, code, 'template');
}
+ // ignore: non_constant_identifier_names
Future test_templateTag_selectTemplateMatches() async {
_addDartSource(r'''
@Component(selector: 'test-panel' templateUrl: 'test_panel.html',