| Index: pkg/analyzer/test/generated/resolver_test_case.dart
|
| diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
|
| index f6bd1cf9c66c8e5667c9ab1ff5f20c62191369a8..15575416b448320f96851137f41a3ba9e90ba96c 100644
|
| --- a/pkg/analyzer/test/generated/resolver_test_case.dart
|
| +++ b/pkg/analyzer/test/generated/resolver_test_case.dart
|
| @@ -24,6 +24,279 @@ import 'package:unittest/unittest.dart';
|
| import 'analysis_context_factory.dart';
|
| import 'test_support.dart';
|
|
|
| +/**
|
| + * An AST visitor used to verify that all of the nodes in an AST structure that
|
| + * should have been resolved were resolved.
|
| + */
|
| +class ResolutionVerifier extends RecursiveAstVisitor<Object> {
|
| + /**
|
| + * A set containing nodes that are known to not be resolvable and should
|
| + * therefore not cause the test to fail.
|
| + */
|
| + final Set<AstNode> _knownExceptions;
|
| +
|
| + /**
|
| + * A list containing all of the AST nodes that were not resolved.
|
| + */
|
| + List<AstNode> _unresolvedNodes = new List<AstNode>();
|
| +
|
| + /**
|
| + * A list containing all of the AST nodes that were resolved to an element of
|
| + * the wrong type.
|
| + */
|
| + List<AstNode> _wrongTypedNodes = new List<AstNode>();
|
| +
|
| + /**
|
| + * Initialize a newly created verifier to verify that all of the identifiers
|
| + * in the visited AST structures that are expected to have been resolved have
|
| + * an element associated with them. Nodes in the set of [_knownExceptions] are
|
| + * not expected to have been resolved, even if they normally would have been
|
| + * expected to have been resolved.
|
| + */
|
| + ResolutionVerifier([this._knownExceptions]);
|
| +
|
| + /**
|
| + * Assert that all of the visited identifiers were resolved.
|
| + */
|
| + void assertResolved() {
|
| + if (!_unresolvedNodes.isEmpty || !_wrongTypedNodes.isEmpty) {
|
| + StringBuffer buffer = new StringBuffer();
|
| + if (!_unresolvedNodes.isEmpty) {
|
| + buffer.write("Failed to resolve ");
|
| + buffer.write(_unresolvedNodes.length);
|
| + buffer.writeln(" nodes:");
|
| + _printNodes(buffer, _unresolvedNodes);
|
| + }
|
| + if (!_wrongTypedNodes.isEmpty) {
|
| + buffer.write("Resolved ");
|
| + buffer.write(_wrongTypedNodes.length);
|
| + buffer.writeln(" to the wrong type of element:");
|
| + _printNodes(buffer, _wrongTypedNodes);
|
| + }
|
| + fail(buffer.toString());
|
| + }
|
| + }
|
| +
|
| + @override
|
| + Object visitAnnotation(Annotation node) {
|
| + node.visitChildren(this);
|
| + ElementAnnotation elementAnnotation = node.elementAnnotation;
|
| + if (elementAnnotation == null) {
|
| + if (_knownExceptions == null || !_knownExceptions.contains(node)) {
|
| + _unresolvedNodes.add(node);
|
| + }
|
| + } else if (elementAnnotation is! ElementAnnotation) {
|
| + _wrongTypedNodes.add(node);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitBinaryExpression(BinaryExpression node) {
|
| + node.visitChildren(this);
|
| + if (!node.operator.isUserDefinableOperator) {
|
| + return null;
|
| + }
|
| + DartType operandType = node.leftOperand.staticType;
|
| + if (operandType == null || operandType.isDynamic) {
|
| + return null;
|
| + }
|
| + return _checkResolved(
|
| + node, node.staticElement, (node) => node is MethodElement);
|
| + }
|
| +
|
| + @override
|
| + Object visitCommentReference(CommentReference node) => null;
|
| +
|
| + @override
|
| + Object visitCompilationUnit(CompilationUnit node) {
|
| + node.visitChildren(this);
|
| + return _checkResolved(
|
| + node, node.element, (node) => node is CompilationUnitElement);
|
| + }
|
| +
|
| + @override
|
| + Object visitExportDirective(ExportDirective node) =>
|
| + _checkResolved(node, node.element, (node) => node is ExportElement);
|
| +
|
| + @override
|
| + Object visitFunctionDeclaration(FunctionDeclaration node) {
|
| + node.visitChildren(this);
|
| + if (node.element is LibraryElement) {
|
| + _wrongTypedNodes.add(node);
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + @override
|
| + Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
| + node.visitChildren(this);
|
| + // TODO(brianwilkerson) If we start resolving function expressions, then
|
| + // conditionally check to see whether the node was resolved correctly.
|
| + return null;
|
| + //checkResolved(node, node.getElement(), FunctionElement.class);
|
| + }
|
| +
|
| + @override
|
| + Object visitImportDirective(ImportDirective node) {
|
| + // Not sure how to test the combinators given that it isn't an error if the
|
| + // names are not defined.
|
| + _checkResolved(node, node.element, (node) => node is ImportElement);
|
| + SimpleIdentifier prefix = node.prefix;
|
| + if (prefix == null) {
|
| + return null;
|
| + }
|
| + return _checkResolved(
|
| + prefix, prefix.staticElement, (node) => node is PrefixElement);
|
| + }
|
| +
|
| + @override
|
| + Object visitIndexExpression(IndexExpression node) {
|
| + node.visitChildren(this);
|
| + DartType targetType = node.realTarget.staticType;
|
| + if (targetType == null || targetType.isDynamic) {
|
| + return null;
|
| + }
|
| + return _checkResolved(
|
| + node, node.staticElement, (node) => node is MethodElement);
|
| + }
|
| +
|
| + @override
|
| + Object visitLibraryDirective(LibraryDirective node) =>
|
| + _checkResolved(node, node.element, (node) => node is LibraryElement);
|
| +
|
| + @override
|
| + Object visitNamedExpression(NamedExpression node) =>
|
| + node.expression.accept(this);
|
| +
|
| + @override
|
| + Object visitPartDirective(PartDirective node) => _checkResolved(
|
| + node, node.element, (node) => node is CompilationUnitElement);
|
| +
|
| + @override
|
| + Object visitPartOfDirective(PartOfDirective node) =>
|
| + _checkResolved(node, node.element, (node) => node is LibraryElement);
|
| +
|
| + @override
|
| + Object visitPostfixExpression(PostfixExpression node) {
|
| + node.visitChildren(this);
|
| + if (!node.operator.isUserDefinableOperator) {
|
| + return null;
|
| + }
|
| + DartType operandType = node.operand.staticType;
|
| + if (operandType == null || operandType.isDynamic) {
|
| + return null;
|
| + }
|
| + return _checkResolved(
|
| + node, node.staticElement, (node) => node is MethodElement);
|
| + }
|
| +
|
| + @override
|
| + Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + SimpleIdentifier prefix = node.prefix;
|
| + prefix.accept(this);
|
| + DartType prefixType = prefix.staticType;
|
| + if (prefixType == null || prefixType.isDynamic) {
|
| + return null;
|
| + }
|
| + return _checkResolved(node, node.staticElement, null);
|
| + }
|
| +
|
| + @override
|
| + Object visitPrefixExpression(PrefixExpression node) {
|
| + node.visitChildren(this);
|
| + if (!node.operator.isUserDefinableOperator) {
|
| + return null;
|
| + }
|
| + DartType operandType = node.operand.staticType;
|
| + if (operandType == null || operandType.isDynamic) {
|
| + return null;
|
| + }
|
| + return _checkResolved(
|
| + node, node.staticElement, (node) => node is MethodElement);
|
| + }
|
| +
|
| + @override
|
| + Object visitPropertyAccess(PropertyAccess node) {
|
| + Expression target = node.realTarget;
|
| + target.accept(this);
|
| + DartType targetType = target.staticType;
|
| + if (targetType == null || targetType.isDynamic) {
|
| + return null;
|
| + }
|
| + return node.propertyName.accept(this);
|
| + }
|
| +
|
| + @override
|
| + Object visitSimpleIdentifier(SimpleIdentifier node) {
|
| + if (node.name == "void") {
|
| + return null;
|
| + }
|
| + if (node.staticType != null &&
|
| + node.staticType.isDynamic &&
|
| + node.staticElement == null) {
|
| + return null;
|
| + }
|
| + AstNode parent = node.parent;
|
| + if (parent is MethodInvocation) {
|
| + MethodInvocation invocation = parent;
|
| + if (identical(invocation.methodName, node)) {
|
| + Expression target = invocation.realTarget;
|
| + DartType targetType = target == null ? null : target.staticType;
|
| + if (targetType == null || targetType.isDynamic) {
|
| + return null;
|
| + }
|
| + }
|
| + }
|
| + return _checkResolved(node, node.staticElement, null);
|
| + }
|
| +
|
| + Object _checkResolved(
|
| + AstNode node, Element element, Predicate<Element> predicate) {
|
| + if (element == null) {
|
| + if (_knownExceptions == null || !_knownExceptions.contains(node)) {
|
| + _unresolvedNodes.add(node);
|
| + }
|
| + } else if (predicate != null) {
|
| + if (!predicate(element)) {
|
| + _wrongTypedNodes.add(node);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + String _getFileName(AstNode node) {
|
| + // TODO (jwren) there are two copies of this method, one here and one in
|
| + // StaticTypeVerifier, they should be resolved into a single method
|
| + if (node != null) {
|
| + AstNode root = node.root;
|
| + if (root is CompilationUnit) {
|
| + CompilationUnit rootCU = root;
|
| + if (rootCU.element != null) {
|
| + return rootCU.element.source.fullName;
|
| + } else {
|
| + return "<unknown file- CompilationUnit.getElement() returned null>";
|
| + }
|
| + } else {
|
| + return "<unknown file- CompilationUnit.getRoot() is not a CompilationUnit>";
|
| + }
|
| + }
|
| + return "<unknown file- ASTNode is null>";
|
| + }
|
| +
|
| + void _printNodes(StringBuffer buffer, List<AstNode> nodes) {
|
| + for (AstNode identifier in nodes) {
|
| + buffer.write(" ");
|
| + buffer.write(identifier.toString());
|
| + buffer.write(" (");
|
| + buffer.write(_getFileName(identifier));
|
| + buffer.write(" : ");
|
| + buffer.write(identifier.offset);
|
| + buffer.writeln(")");
|
| + }
|
| + }
|
| +}
|
| +
|
| class ResolverTestCase extends EngineTestCase {
|
| /**
|
| * The analysis context used to parse the compilation units being resolved.
|
| @@ -126,262 +399,38 @@ class ResolverTestCase extends EngineTestCase {
|
| assertErrors(source, errors);
|
| verify([source]);
|
| }
|
| -
|
| - /**
|
| - * Asserts that [code] has errors with the given error codes.
|
| - *
|
| - * Like [assertErrors], but takes a string of source code.
|
| - */
|
| - void assertErrorsInUnverifiedCode(String code, List<ErrorCode> errors) {
|
| - Source source = addSource(code);
|
| - computeLibrarySourceErrors(source);
|
| - assertErrors(source, errors);
|
| - }
|
| -
|
| - /**
|
| - * Assert that no errors have been reported against the given source.
|
| - *
|
| - * @param source the source against which no errors should have been reported
|
| - * @throws AnalysisException if the reported errors could not be computed
|
| - * @throws AssertionFailedError if any errors have been reported
|
| - */
|
| - void assertNoErrors(Source source) {
|
| - assertErrors(source);
|
| - }
|
| -
|
| - /**
|
| - * Asserts that [code] has no errors or warnings.
|
| - */
|
| - // TODO(rnystrom): Use this in more tests that have the same structure.
|
| - void assertNoErrorsInCode(String code) {
|
| - Source source = addSource(code);
|
| - computeLibrarySourceErrors(source);
|
| - assertNoErrors(source);
|
| - verify([source]);
|
| - }
|
| -
|
| - /**
|
| - * Cache the source file content in the source factory but don't add the source to the analysis
|
| - * context. The file path should be absolute.
|
| - *
|
| - * @param filePath the path of the file being cached
|
| - * @param contents the contents to be returned by the content provider for the specified file
|
| - * @return the source object representing the cached file
|
| - */
|
| - Source cacheSource(String filePath, String contents) {
|
| - Source source = new FileBasedSource(FileUtilities2.createFile(filePath));
|
| - analysisContext2.setContents(source, contents);
|
| - return source;
|
| - }
|
| -
|
| - /**
|
| - * Change the contents of the given [source] to the given [contents].
|
| - */
|
| - void changeSource(Source source, String contents) {
|
| - analysisContext2.setContents(source, contents);
|
| - ChangeSet changeSet = new ChangeSet();
|
| - changeSet.changedSource(source);
|
| - analysisContext2.applyChanges(changeSet);
|
| - }
|
| -
|
| - /**
|
| - * Computes errors for the given [librarySource].
|
| - * This assumes that the given [librarySource] and its parts have already
|
| - * been added to the content provider using the method [addNamedSource].
|
| - */
|
| - void computeLibrarySourceErrors(Source librarySource) {
|
| - analysisContext.computeErrors(librarySource);
|
| - }
|
| -
|
| - /**
|
| - * Create a library element that represents a library named `"test"` containing a single
|
| - * empty compilation unit.
|
| - *
|
| - * @return the library element that was created
|
| - */
|
| - LibraryElementImpl createDefaultTestLibrary() =>
|
| - createTestLibrary(AnalysisContextFactory.contextWithCore(), "test");
|
| -
|
| - /**
|
| - * Create a library element that represents a library with the given name containing a single
|
| - * empty compilation unit.
|
| - *
|
| - * @param libraryName the name of the library to be created
|
| - * @return the library element that was created
|
| - */
|
| - LibraryElementImpl createTestLibrary(
|
| - AnalysisContext context, String libraryName,
|
| - [List<String> typeNames]) {
|
| - String fileName = "$libraryName.dart";
|
| - FileBasedSource definingCompilationUnitSource =
|
| - createNamedSource(fileName);
|
| - List<CompilationUnitElement> sourcedCompilationUnits;
|
| - if (typeNames == null) {
|
| - sourcedCompilationUnits = CompilationUnitElement.EMPTY_LIST;
|
| - } else {
|
| - int count = typeNames.length;
|
| - sourcedCompilationUnits = new List<CompilationUnitElement>(count);
|
| - for (int i = 0; i < count; i++) {
|
| - String typeName = typeNames[i];
|
| - ClassElementImpl type =
|
| - new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
|
| - String fileName = "$typeName.dart";
|
| - CompilationUnitElementImpl compilationUnit =
|
| - new CompilationUnitElementImpl(fileName);
|
| - compilationUnit.source = createNamedSource(fileName);
|
| - compilationUnit.librarySource = definingCompilationUnitSource;
|
| - compilationUnit.types = <ClassElement>[type];
|
| - sourcedCompilationUnits[i] = compilationUnit;
|
| - }
|
| - }
|
| - CompilationUnitElementImpl compilationUnit =
|
| - new CompilationUnitElementImpl(fileName);
|
| - compilationUnit.librarySource =
|
| - compilationUnit.source = definingCompilationUnitSource;
|
| - LibraryElementImpl library = new LibraryElementImpl.forNode(
|
| - context, AstFactory.libraryIdentifier2([libraryName]));
|
| - library.definingCompilationUnit = compilationUnit;
|
| - library.parts = sourcedCompilationUnits;
|
| - return library;
|
| - }
|
| -
|
| - Expression findTopLevelConstantExpression(
|
| - CompilationUnit compilationUnit, String name) =>
|
| - findTopLevelDeclaration(compilationUnit, name).initializer;
|
| -
|
| - VariableDeclaration findTopLevelDeclaration(
|
| - CompilationUnit compilationUnit, String name) {
|
| - for (CompilationUnitMember member in compilationUnit.declarations) {
|
| - if (member is TopLevelVariableDeclaration) {
|
| - for (VariableDeclaration variable in member.variables.variables) {
|
| - if (variable.name.name == name) {
|
| - return variable;
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return null;
|
| - // Not found
|
| - }
|
| -
|
| - /**
|
| - * In the rare cases we want to group several tests into single "test_" method, so need a way to
|
| - * reset test instance to reuse it.
|
| - */
|
| - void reset() {
|
| - analysisContext2 = AnalysisContextFactory.contextWithCore();
|
| - }
|
| -
|
| - /**
|
| - * Reset the analysis context to have the given options applied.
|
| - *
|
| - * @param options the analysis options to be applied to the context
|
| - */
|
| - void resetWithOptions(AnalysisOptions options) {
|
| - analysisContext2 =
|
| - AnalysisContextFactory.contextWithCoreAndOptions(options);
|
| - }
|
| -
|
| - /**
|
| - * Given a library and all of its parts, resolve the contents of the library and the contents of
|
| - * the parts. This assumes that the sources for the library and its parts have already been added
|
| - * to the content provider using the method [addNamedSource].
|
| - *
|
| - * @param librarySource the source for the compilation unit that defines the library
|
| - * @return the element representing the resolved library
|
| - * @throws AnalysisException if the analysis could not be performed
|
| - */
|
| - LibraryElement resolve2(Source librarySource) =>
|
| - analysisContext2.computeLibraryElement(librarySource);
|
| -
|
| - /**
|
| - * Return the resolved compilation unit corresponding to the given source in the given library.
|
| - *
|
| - * @param source the source of the compilation unit to be returned
|
| - * @param library the library in which the compilation unit is to be resolved
|
| - * @return the resolved compilation unit
|
| - * @throws Exception if the compilation unit could not be resolved
|
| - */
|
| - CompilationUnit resolveCompilationUnit(
|
| - Source source, LibraryElement library) =>
|
| - analysisContext2.resolveCompilationUnit(source, library);
|
| -
|
| - CompilationUnit resolveSource(String sourceText) =>
|
| - resolveSource2("/test.dart", sourceText);
|
| -
|
| - CompilationUnit resolveSource2(String fileName, String sourceText) {
|
| - Source source = addNamedSource(fileName, sourceText);
|
| - LibraryElement library = analysisContext.computeLibraryElement(source);
|
| - return analysisContext.resolveCompilationUnit(source, library);
|
| - }
|
| -
|
| - Source resolveSources(List<String> sourceTexts) {
|
| - for (int i = 0; i < sourceTexts.length; i++) {
|
| - CompilationUnit unit =
|
| - resolveSource2("/lib${i + 1}.dart", sourceTexts[i]);
|
| - // reference the source if this is the last source
|
| - if (i + 1 == sourceTexts.length) {
|
| - return unit.element.source;
|
| - }
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - void resolveWithAndWithoutExperimental(
|
| - List<String> strSources,
|
| - List<ErrorCode> codesWithoutExperimental,
|
| - List<ErrorCode> codesWithExperimental) {
|
| - // Setup analysis context as non-experimental
|
| - AnalysisOptionsImpl options = new AnalysisOptionsImpl();
|
| -// options.enableDeferredLoading = false;
|
| - resetWithOptions(options);
|
| - // Analysis and assertions
|
| - Source source = resolveSources(strSources);
|
| - assertErrors(source, codesWithoutExperimental);
|
| - verify([source]);
|
| - // Setup analysis context as experimental
|
| - reset();
|
| - // Analysis and assertions
|
| - source = resolveSources(strSources);
|
| - assertErrors(source, codesWithExperimental);
|
| - verify([source]);
|
| - }
|
| -
|
| - void resolveWithErrors(List<String> strSources, List<ErrorCode> codes) {
|
| - // Analysis and assertions
|
| - Source source = resolveSources(strSources);
|
| - assertErrors(source, codes);
|
| - verify([source]);
|
| - }
|
| -
|
| - @override
|
| - void setUp() {
|
| - ElementFactory.flushStaticState();
|
| - super.setUp();
|
| - reset();
|
| +
|
| + /**
|
| + * Asserts that [code] has errors with the given error codes.
|
| + *
|
| + * Like [assertErrors], but takes a string of source code.
|
| + */
|
| + void assertErrorsInUnverifiedCode(String code, List<ErrorCode> errors) {
|
| + Source source = addSource(code);
|
| + computeLibrarySourceErrors(source);
|
| + assertErrors(source, errors);
|
| }
|
|
|
| - @override
|
| - void tearDown() {
|
| - analysisContext2 = null;
|
| - super.tearDown();
|
| + /**
|
| + * Assert that no errors have been reported against the given source.
|
| + *
|
| + * @param source the source against which no errors should have been reported
|
| + * @throws AnalysisException if the reported errors could not be computed
|
| + * @throws AssertionFailedError if any errors have been reported
|
| + */
|
| + void assertNoErrors(Source source) {
|
| + assertErrors(source);
|
| }
|
|
|
| /**
|
| - * Verify that all of the identifiers in the compilation units associated with
|
| - * the given [sources] have been resolved.
|
| + * Asserts that [code] has no errors or warnings.
|
| */
|
| - void verify(List<Source> sources) {
|
| - ResolutionVerifier verifier = new ResolutionVerifier();
|
| - for (Source source in sources) {
|
| - List<Source> libraries = analysisContext2.getLibrariesContaining(source);
|
| - for (Source library in libraries) {
|
| - analysisContext2
|
| - .resolveCompilationUnit2(source, library)
|
| - .accept(verifier);
|
| - }
|
| - }
|
| - verifier.assertResolved();
|
| + // TODO(rnystrom): Use this in more tests that have the same structure.
|
| + void assertNoErrorsInCode(String code) {
|
| + Source source = addSource(code);
|
| + computeLibrarySourceErrors(source);
|
| + assertNoErrors(source);
|
| + verify([source]);
|
| }
|
|
|
| /**
|
| @@ -424,6 +473,48 @@ class ResolverTestCase extends EngineTestCase {
|
| }
|
|
|
| /**
|
| + * Cache the source file content in the source factory but don't add the source to the analysis
|
| + * context. The file path should be absolute.
|
| + *
|
| + * @param filePath the path of the file being cached
|
| + * @param contents the contents to be returned by the content provider for the specified file
|
| + * @return the source object representing the cached file
|
| + */
|
| + Source cacheSource(String filePath, String contents) {
|
| + Source source = new FileBasedSource(FileUtilities2.createFile(filePath));
|
| + analysisContext2.setContents(source, contents);
|
| + return source;
|
| + }
|
| +
|
| + /**
|
| + * Change the contents of the given [source] to the given [contents].
|
| + */
|
| + void changeSource(Source source, String contents) {
|
| + analysisContext2.setContents(source, contents);
|
| + ChangeSet changeSet = new ChangeSet();
|
| + changeSet.changedSource(source);
|
| + analysisContext2.applyChanges(changeSet);
|
| + }
|
| +
|
| + /**
|
| + * Computes errors for the given [librarySource].
|
| + * This assumes that the given [librarySource] and its parts have already
|
| + * been added to the content provider using the method [addNamedSource].
|
| + */
|
| + void computeLibrarySourceErrors(Source librarySource) {
|
| + analysisContext.computeErrors(librarySource);
|
| + }
|
| +
|
| + /**
|
| + * Create a library element that represents a library named `"test"` containing a single
|
| + * empty compilation unit.
|
| + *
|
| + * @return the library element that was created
|
| + */
|
| + LibraryElementImpl createDefaultTestLibrary() =>
|
| + createTestLibrary(AnalysisContextFactory.contextWithCore(), "test");
|
| +
|
| + /**
|
| * Create a source object representing a file with the given [fileName] and
|
| * give it an empty content. Return the source that was created.
|
| */
|
| @@ -435,6 +526,49 @@ class ResolverTestCase extends EngineTestCase {
|
| }
|
|
|
| /**
|
| + * Create a library element that represents a library with the given name containing a single
|
| + * empty compilation unit.
|
| + *
|
| + * @param libraryName the name of the library to be created
|
| + * @return the library element that was created
|
| + */
|
| + LibraryElementImpl createTestLibrary(
|
| + AnalysisContext context, String libraryName,
|
| + [List<String> typeNames]) {
|
| + String fileName = "$libraryName.dart";
|
| + FileBasedSource definingCompilationUnitSource =
|
| + createNamedSource(fileName);
|
| + List<CompilationUnitElement> sourcedCompilationUnits;
|
| + if (typeNames == null) {
|
| + sourcedCompilationUnits = CompilationUnitElement.EMPTY_LIST;
|
| + } else {
|
| + int count = typeNames.length;
|
| + sourcedCompilationUnits = new List<CompilationUnitElement>(count);
|
| + for (int i = 0; i < count; i++) {
|
| + String typeName = typeNames[i];
|
| + ClassElementImpl type =
|
| + new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
|
| + String fileName = "$typeName.dart";
|
| + CompilationUnitElementImpl compilationUnit =
|
| + new CompilationUnitElementImpl(fileName);
|
| + compilationUnit.source = createNamedSource(fileName);
|
| + compilationUnit.librarySource = definingCompilationUnitSource;
|
| + compilationUnit.types = <ClassElement>[type];
|
| + sourcedCompilationUnits[i] = compilationUnit;
|
| + }
|
| + }
|
| + CompilationUnitElementImpl compilationUnit =
|
| + new CompilationUnitElementImpl(fileName);
|
| + compilationUnit.librarySource =
|
| + compilationUnit.source = definingCompilationUnitSource;
|
| + LibraryElementImpl library = new LibraryElementImpl.forNode(
|
| + context, AstFactory.libraryIdentifier2([libraryName]));
|
| + library.definingCompilationUnit = compilationUnit;
|
| + library.parts = sourcedCompilationUnits;
|
| + return library;
|
| + }
|
| +
|
| + /**
|
| * Return the `SimpleIdentifier` marked by `marker`. The source code must have no
|
| * errors and be verifiable.
|
| *
|
| @@ -463,278 +597,144 @@ class ResolverTestCase extends EngineTestCase {
|
| throw new JavaException("Unexexpected assertion failure: $exception");
|
| }
|
| }
|
| -}
|
| -
|
| -/**
|
| - * An AST visitor used to verify that all of the nodes in an AST structure that
|
| - * should have been resolved were resolved.
|
| - */
|
| -class ResolutionVerifier extends RecursiveAstVisitor<Object> {
|
| - /**
|
| - * A set containing nodes that are known to not be resolvable and should
|
| - * therefore not cause the test to fail.
|
| - */
|
| - final Set<AstNode> _knownExceptions;
|
| -
|
| - /**
|
| - * A list containing all of the AST nodes that were not resolved.
|
| - */
|
| - List<AstNode> _unresolvedNodes = new List<AstNode>();
|
| -
|
| - /**
|
| - * A list containing all of the AST nodes that were resolved to an element of
|
| - * the wrong type.
|
| - */
|
| - List<AstNode> _wrongTypedNodes = new List<AstNode>();
|
| -
|
| - /**
|
| - * Initialize a newly created verifier to verify that all of the identifiers
|
| - * in the visited AST structures that are expected to have been resolved have
|
| - * an element associated with them. Nodes in the set of [_knownExceptions] are
|
| - * not expected to have been resolved, even if they normally would have been
|
| - * expected to have been resolved.
|
| - */
|
| - ResolutionVerifier([this._knownExceptions]);
|
| -
|
| - /**
|
| - * Assert that all of the visited identifiers were resolved.
|
| - */
|
| - void assertResolved() {
|
| - if (!_unresolvedNodes.isEmpty || !_wrongTypedNodes.isEmpty) {
|
| - StringBuffer buffer = new StringBuffer();
|
| - if (!_unresolvedNodes.isEmpty) {
|
| - buffer.write("Failed to resolve ");
|
| - buffer.write(_unresolvedNodes.length);
|
| - buffer.writeln(" nodes:");
|
| - _printNodes(buffer, _unresolvedNodes);
|
| - }
|
| - if (!_wrongTypedNodes.isEmpty) {
|
| - buffer.write("Resolved ");
|
| - buffer.write(_wrongTypedNodes.length);
|
| - buffer.writeln(" to the wrong type of element:");
|
| - _printNodes(buffer, _wrongTypedNodes);
|
| - }
|
| - fail(buffer.toString());
|
| - }
|
| - }
|
| -
|
| - @override
|
| - Object visitAnnotation(Annotation node) {
|
| - node.visitChildren(this);
|
| - ElementAnnotation elementAnnotation = node.elementAnnotation;
|
| - if (elementAnnotation == null) {
|
| - if (_knownExceptions == null || !_knownExceptions.contains(node)) {
|
| - _unresolvedNodes.add(node);
|
| - }
|
| - } else if (elementAnnotation is! ElementAnnotation) {
|
| - _wrongTypedNodes.add(node);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @override
|
| - Object visitBinaryExpression(BinaryExpression node) {
|
| - node.visitChildren(this);
|
| - if (!node.operator.isUserDefinableOperator) {
|
| - return null;
|
| - }
|
| - DartType operandType = node.leftOperand.staticType;
|
| - if (operandType == null || operandType.isDynamic) {
|
| - return null;
|
| - }
|
| - return _checkResolved(
|
| - node, node.staticElement, (node) => node is MethodElement);
|
| - }
|
| -
|
| - @override
|
| - Object visitCommentReference(CommentReference node) => null;
|
| -
|
| - @override
|
| - Object visitCompilationUnit(CompilationUnit node) {
|
| - node.visitChildren(this);
|
| - return _checkResolved(
|
| - node, node.element, (node) => node is CompilationUnitElement);
|
| - }
|
| -
|
| - @override
|
| - Object visitExportDirective(ExportDirective node) =>
|
| - _checkResolved(node, node.element, (node) => node is ExportElement);
|
|
|
| - @override
|
| - Object visitFunctionDeclaration(FunctionDeclaration node) {
|
| - node.visitChildren(this);
|
| - if (node.element is LibraryElement) {
|
| - _wrongTypedNodes.add(node);
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - @override
|
| - Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
| - node.visitChildren(this);
|
| - // TODO(brianwilkerson) If we start resolving function expressions, then
|
| - // conditionally check to see whether the node was resolved correctly.
|
| - return null;
|
| - //checkResolved(node, node.getElement(), FunctionElement.class);
|
| - }
|
| + Expression findTopLevelConstantExpression(
|
| + CompilationUnit compilationUnit, String name) =>
|
| + findTopLevelDeclaration(compilationUnit, name).initializer;
|
|
|
| - @override
|
| - Object visitImportDirective(ImportDirective node) {
|
| - // Not sure how to test the combinators given that it isn't an error if the
|
| - // names are not defined.
|
| - _checkResolved(node, node.element, (node) => node is ImportElement);
|
| - SimpleIdentifier prefix = node.prefix;
|
| - if (prefix == null) {
|
| - return null;
|
| + VariableDeclaration findTopLevelDeclaration(
|
| + CompilationUnit compilationUnit, String name) {
|
| + for (CompilationUnitMember member in compilationUnit.declarations) {
|
| + if (member is TopLevelVariableDeclaration) {
|
| + for (VariableDeclaration variable in member.variables.variables) {
|
| + if (variable.name.name == name) {
|
| + return variable;
|
| + }
|
| + }
|
| + }
|
| }
|
| - return _checkResolved(
|
| - prefix, prefix.staticElement, (node) => node is PrefixElement);
|
| + return null;
|
| + // Not found
|
| }
|
|
|
| - @override
|
| - Object visitIndexExpression(IndexExpression node) {
|
| - node.visitChildren(this);
|
| - DartType targetType = node.realTarget.staticType;
|
| - if (targetType == null || targetType.isDynamic) {
|
| - return null;
|
| - }
|
| - return _checkResolved(
|
| - node, node.staticElement, (node) => node is MethodElement);
|
| + /**
|
| + * In the rare cases we want to group several tests into single "test_" method, so need a way to
|
| + * reset test instance to reuse it.
|
| + */
|
| + void reset() {
|
| + analysisContext2 = AnalysisContextFactory.contextWithCore();
|
| }
|
|
|
| - @override
|
| - Object visitLibraryDirective(LibraryDirective node) =>
|
| - _checkResolved(node, node.element, (node) => node is LibraryElement);
|
| + /**
|
| + * Reset the analysis context to have the given options applied.
|
| + *
|
| + * @param options the analysis options to be applied to the context
|
| + */
|
| + void resetWithOptions(AnalysisOptions options) {
|
| + analysisContext2 =
|
| + AnalysisContextFactory.contextWithCoreAndOptions(options);
|
| + }
|
|
|
| - @override
|
| - Object visitNamedExpression(NamedExpression node) =>
|
| - node.expression.accept(this);
|
| + /**
|
| + * Given a library and all of its parts, resolve the contents of the library and the contents of
|
| + * the parts. This assumes that the sources for the library and its parts have already been added
|
| + * to the content provider using the method [addNamedSource].
|
| + *
|
| + * @param librarySource the source for the compilation unit that defines the library
|
| + * @return the element representing the resolved library
|
| + * @throws AnalysisException if the analysis could not be performed
|
| + */
|
| + LibraryElement resolve2(Source librarySource) =>
|
| + analysisContext2.computeLibraryElement(librarySource);
|
|
|
| - @override
|
| - Object visitPartDirective(PartDirective node) => _checkResolved(
|
| - node, node.element, (node) => node is CompilationUnitElement);
|
| + /**
|
| + * Return the resolved compilation unit corresponding to the given source in the given library.
|
| + *
|
| + * @param source the source of the compilation unit to be returned
|
| + * @param library the library in which the compilation unit is to be resolved
|
| + * @return the resolved compilation unit
|
| + * @throws Exception if the compilation unit could not be resolved
|
| + */
|
| + CompilationUnit resolveCompilationUnit(
|
| + Source source, LibraryElement library) =>
|
| + analysisContext2.resolveCompilationUnit(source, library);
|
|
|
| - @override
|
| - Object visitPartOfDirective(PartOfDirective node) =>
|
| - _checkResolved(node, node.element, (node) => node is LibraryElement);
|
| + CompilationUnit resolveSource(String sourceText) =>
|
| + resolveSource2("/test.dart", sourceText);
|
|
|
| - @override
|
| - Object visitPostfixExpression(PostfixExpression node) {
|
| - node.visitChildren(this);
|
| - if (!node.operator.isUserDefinableOperator) {
|
| - return null;
|
| - }
|
| - DartType operandType = node.operand.staticType;
|
| - if (operandType == null || operandType.isDynamic) {
|
| - return null;
|
| - }
|
| - return _checkResolved(
|
| - node, node.staticElement, (node) => node is MethodElement);
|
| + CompilationUnit resolveSource2(String fileName, String sourceText) {
|
| + Source source = addNamedSource(fileName, sourceText);
|
| + LibraryElement library = analysisContext.computeLibraryElement(source);
|
| + return analysisContext.resolveCompilationUnit(source, library);
|
| }
|
|
|
| - @override
|
| - Object visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| - SimpleIdentifier prefix = node.prefix;
|
| - prefix.accept(this);
|
| - DartType prefixType = prefix.staticType;
|
| - if (prefixType == null || prefixType.isDynamic) {
|
| - return null;
|
| + Source resolveSources(List<String> sourceTexts) {
|
| + for (int i = 0; i < sourceTexts.length; i++) {
|
| + CompilationUnit unit =
|
| + resolveSource2("/lib${i + 1}.dart", sourceTexts[i]);
|
| + // reference the source if this is the last source
|
| + if (i + 1 == sourceTexts.length) {
|
| + return unit.element.source;
|
| + }
|
| }
|
| - return _checkResolved(node, node.staticElement, null);
|
| + return null;
|
| }
|
|
|
| - @override
|
| - Object visitPrefixExpression(PrefixExpression node) {
|
| - node.visitChildren(this);
|
| - if (!node.operator.isUserDefinableOperator) {
|
| - return null;
|
| - }
|
| - DartType operandType = node.operand.staticType;
|
| - if (operandType == null || operandType.isDynamic) {
|
| - return null;
|
| - }
|
| - return _checkResolved(
|
| - node, node.staticElement, (node) => node is MethodElement);
|
| + void resolveWithAndWithoutExperimental(
|
| + List<String> strSources,
|
| + List<ErrorCode> codesWithoutExperimental,
|
| + List<ErrorCode> codesWithExperimental) {
|
| + // Setup analysis context as non-experimental
|
| + AnalysisOptionsImpl options = new AnalysisOptionsImpl();
|
| +// options.enableDeferredLoading = false;
|
| + resetWithOptions(options);
|
| + // Analysis and assertions
|
| + Source source = resolveSources(strSources);
|
| + assertErrors(source, codesWithoutExperimental);
|
| + verify([source]);
|
| + // Setup analysis context as experimental
|
| + reset();
|
| + // Analysis and assertions
|
| + source = resolveSources(strSources);
|
| + assertErrors(source, codesWithExperimental);
|
| + verify([source]);
|
| }
|
|
|
| - @override
|
| - Object visitPropertyAccess(PropertyAccess node) {
|
| - Expression target = node.realTarget;
|
| - target.accept(this);
|
| - DartType targetType = target.staticType;
|
| - if (targetType == null || targetType.isDynamic) {
|
| - return null;
|
| - }
|
| - return node.propertyName.accept(this);
|
| + void resolveWithErrors(List<String> strSources, List<ErrorCode> codes) {
|
| + // Analysis and assertions
|
| + Source source = resolveSources(strSources);
|
| + assertErrors(source, codes);
|
| + verify([source]);
|
| }
|
|
|
| @override
|
| - Object visitSimpleIdentifier(SimpleIdentifier node) {
|
| - if (node.name == "void") {
|
| - return null;
|
| - }
|
| - if (node.staticType != null &&
|
| - node.staticType.isDynamic &&
|
| - node.staticElement == null) {
|
| - return null;
|
| - }
|
| - AstNode parent = node.parent;
|
| - if (parent is MethodInvocation) {
|
| - MethodInvocation invocation = parent;
|
| - if (identical(invocation.methodName, node)) {
|
| - Expression target = invocation.realTarget;
|
| - DartType targetType = target == null ? null : target.staticType;
|
| - if (targetType == null || targetType.isDynamic) {
|
| - return null;
|
| - }
|
| - }
|
| - }
|
| - return _checkResolved(node, node.staticElement, null);
|
| + void setUp() {
|
| + ElementFactory.flushStaticState();
|
| + super.setUp();
|
| + reset();
|
| }
|
|
|
| - Object _checkResolved(
|
| - AstNode node, Element element, Predicate<Element> predicate) {
|
| - if (element == null) {
|
| - if (_knownExceptions == null || !_knownExceptions.contains(node)) {
|
| - _unresolvedNodes.add(node);
|
| - }
|
| - } else if (predicate != null) {
|
| - if (!predicate(element)) {
|
| - _wrongTypedNodes.add(node);
|
| - }
|
| - }
|
| - return null;
|
| + @override
|
| + void tearDown() {
|
| + analysisContext2 = null;
|
| + super.tearDown();
|
| }
|
|
|
| - String _getFileName(AstNode node) {
|
| - // TODO (jwren) there are two copies of this method, one here and one in
|
| - // StaticTypeVerifier, they should be resolved into a single method
|
| - if (node != null) {
|
| - AstNode root = node.root;
|
| - if (root is CompilationUnit) {
|
| - CompilationUnit rootCU = root;
|
| - if (rootCU.element != null) {
|
| - return rootCU.element.source.fullName;
|
| - } else {
|
| - return "<unknown file- CompilationUnit.getElement() returned null>";
|
| - }
|
| - } else {
|
| - return "<unknown file- CompilationUnit.getRoot() is not a CompilationUnit>";
|
| + /**
|
| + * Verify that all of the identifiers in the compilation units associated with
|
| + * the given [sources] have been resolved.
|
| + */
|
| + void verify(List<Source> sources) {
|
| + ResolutionVerifier verifier = new ResolutionVerifier();
|
| + for (Source source in sources) {
|
| + List<Source> libraries = analysisContext2.getLibrariesContaining(source);
|
| + for (Source library in libraries) {
|
| + analysisContext2
|
| + .resolveCompilationUnit2(source, library)
|
| + .accept(verifier);
|
| }
|
| }
|
| - return "<unknown file- ASTNode is null>";
|
| - }
|
| -
|
| - void _printNodes(StringBuffer buffer, List<AstNode> nodes) {
|
| - for (AstNode identifier in nodes) {
|
| - buffer.write(" ");
|
| - buffer.write(identifier.toString());
|
| - buffer.write(" (");
|
| - buffer.write(_getFileName(identifier));
|
| - buffer.write(" : ");
|
| - buffer.write(identifier.offset);
|
| - buffer.writeln(")");
|
| - }
|
| + verifier.assertResolved();
|
| }
|
| }
|
|
|
| @@ -808,20 +808,6 @@ class StaticTypeAnalyzer2TestShared extends ResolverTestCase {
|
| }
|
| }
|
|
|
| - /**
|
| - * Validates that [type] matches [expected].
|
| - *
|
| - * If [expected] is a string, validates that the type stringifies to that
|
| - * text. Otherwise, [expected] is used directly a [Matcher] to match the type.
|
| - */
|
| - _expectType(DartType type, expected) {
|
| - if (expected is String) {
|
| - expect(type.toString(), expected);
|
| - } else {
|
| - expect(type, expected);
|
| - }
|
| - }
|
| -
|
| SimpleIdentifier findIdentifier(String search) {
|
| SimpleIdentifier identifier = EngineTestCase.findNode(
|
| testUnit, testCode, search, (node) => node is SimpleIdentifier);
|
| @@ -836,4 +822,18 @@ class StaticTypeAnalyzer2TestShared extends ResolverTestCase {
|
| verify([testSource]);
|
| testUnit = resolveCompilationUnit(testSource, library);
|
| }
|
| +
|
| + /**
|
| + * Validates that [type] matches [expected].
|
| + *
|
| + * If [expected] is a string, validates that the type stringifies to that
|
| + * text. Otherwise, [expected] is used directly a [Matcher] to match the type.
|
| + */
|
| + _expectType(DartType type, expected) {
|
| + if (expected is String) {
|
| + expect(type.toString(), expected);
|
| + } else {
|
| + expect(type, expected);
|
| + }
|
| + }
|
| }
|
|
|