Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1015)

Unified Diff: pkg/analyzer/test/generated/resolver_test_case.dart

Issue 1782463002: Split resolver_test.dart into smaller files. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
new file mode 100644
index 0000000000000000000000000000000000000000..f6bd1cf9c66c8e5667c9ab1ff5f20c62191369a8
--- /dev/null
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -0,0 +1,839 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.generated.resolver_test_case;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/java_engine_io.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:unittest/unittest.dart';
+
+import 'analysis_context_factory.dart';
+import 'test_support.dart';
+
+class ResolverTestCase extends EngineTestCase {
+ /**
+ * The analysis context used to parse the compilation units being resolved.
+ */
+ InternalAnalysisContext analysisContext2;
+
+ /**
+ * Specifies if [assertErrors] should check for [HintCode.UNUSED_ELEMENT] and
+ * [HintCode.UNUSED_FIELD].
+ */
+ bool enableUnusedElement = false;
+
+ /**
+ * Specifies if [assertErrors] should check for [HintCode.UNUSED_LOCAL_VARIABLE].
+ */
+ bool enableUnusedLocalVariable = false;
+
+ AnalysisContext get analysisContext => analysisContext2;
+
+ /**
+ * Return a type provider that can be used to test the results of resolution.
+ *
+ * @return a type provider
+ * @throws AnalysisException if dart:core cannot be resolved
+ */
+ TypeProvider get typeProvider => analysisContext2.typeProvider;
+
+ /**
+ * Return a type system that can be used to test the results of resolution.
+ *
+ * @return a type system
+ */
+ TypeSystem get typeSystem => analysisContext2.typeSystem;
+
+ /**
+ * Add a source file to the content provider. The file path should be absolute.
+ *
+ * @param filePath the path of the file being added
+ * @param contents the contents to be returned by the content provider for the specified file
+ * @return the source object representing the added file
+ */
+ Source addNamedSource(String filePath, String contents) {
+ Source source = cacheSource(filePath, contents);
+ ChangeSet changeSet = new ChangeSet();
+ changeSet.addedSource(source);
+ analysisContext2.applyChanges(changeSet);
+ return source;
+ }
+
+ /**
+ * Add a source file to the content provider.
+ *
+ * @param contents the contents to be returned by the content provider for the specified file
+ * @return the source object representing the added file
+ */
+ Source addSource(String contents) => addNamedSource("/test.dart", contents);
+
+ /**
+ * Assert that the number of errors reported against the given source matches the number of errors
+ * that are given and that they have the expected error codes. The order in which the errors were
+ * gathered is ignored.
+ *
+ * @param source the source against which the errors should have been reported
+ * @param expectedErrorCodes the error codes of the errors that should have been reported
+ * @throws AnalysisException if the reported errors could not be computed
+ * @throws AssertionFailedError if a different number of errors have been reported than were
+ * expected
+ */
+ void assertErrors(Source source,
+ [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
+ GatheringErrorListener errorListener = new GatheringErrorListener();
+ for (AnalysisError error in analysisContext2.computeErrors(source)) {
+ expect(error.source, source);
+ ErrorCode errorCode = error.errorCode;
+ if (!enableUnusedElement &&
+ (errorCode == HintCode.UNUSED_ELEMENT ||
+ errorCode == HintCode.UNUSED_FIELD)) {
+ continue;
+ }
+ if (!enableUnusedLocalVariable &&
+ (errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
+ errorCode == HintCode.UNUSED_CATCH_STACK ||
+ errorCode == HintCode.UNUSED_LOCAL_VARIABLE)) {
+ continue;
+ }
+ errorListener.onError(error);
+ }
+ errorListener.assertErrorsWithCodes(expectedErrorCodes);
+ }
+
+ /**
+ * Asserts that [code] verifies, but has errors with the given error codes.
+ *
+ * Like [assertErrors], but takes a string of source code.
+ */
+ // TODO(rnystrom): Use this in more tests that have the same structure.
+ void assertErrorsInCode(String code, List<ErrorCode> errors) {
+ Source source = addSource(code);
+ computeLibrarySourceErrors(source);
+ 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();
+ }
+
+ @override
+ void tearDown() {
+ analysisContext2 = null;
+ super.tearDown();
+ }
+
+ /**
+ * 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);
+ }
+ }
+ verifier.assertResolved();
+ }
+
+ /**
+ * @param code the code that assigns the value to the variable "v", no matter how. We check that
+ * "v" has expected static and propagated type.
+ */
+ void assertPropagatedAssignedType(String code, DartType expectedStaticType,
+ DartType expectedPropagatedType) {
+ SimpleIdentifier identifier = findMarkedIdentifier(code, "v = ");
+ expect(identifier.staticType, same(expectedStaticType));
+ expect(identifier.propagatedType, same(expectedPropagatedType));
+ }
+
+ /**
+ * @param code the code that iterates using variable "v". We check that
+ * "v" has expected static and propagated type.
+ */
+ void assertPropagatedIterationType(String code, DartType expectedStaticType,
+ DartType expectedPropagatedType) {
+ SimpleIdentifier identifier = findMarkedIdentifier(code, "v in ");
+ expect(identifier.staticType, same(expectedStaticType));
+ expect(identifier.propagatedType, same(expectedPropagatedType));
+ }
+
+ /**
+ * Check the static and propagated types of the expression marked with "; // marker" comment.
+ *
+ * @param code source code to analyze, with the expression to check marked with "// marker".
+ * @param expectedStaticType if non-null, check actual static type is equal to this.
+ * @param expectedPropagatedType if non-null, check actual static type is equal to this.
+ * @throws Exception
+ */
+ void assertTypeOfMarkedExpression(String code, DartType expectedStaticType,
+ DartType expectedPropagatedType) {
+ SimpleIdentifier identifier = findMarkedIdentifier(code, "; // marker");
+ if (expectedStaticType != null) {
+ expect(identifier.staticType, expectedStaticType);
+ }
+ expect(identifier.propagatedType, expectedPropagatedType);
+ }
+
+ /**
+ * Create a source object representing a file with the given [fileName] and
+ * give it an empty content. Return the source that was created.
+ */
+ FileBasedSource createNamedSource(String fileName) {
+ FileBasedSource source =
+ new FileBasedSource(FileUtilities2.createFile(fileName));
+ analysisContext2.setContents(source, "");
+ return source;
+ }
+
+ /**
+ * Return the `SimpleIdentifier` marked by `marker`. The source code must have no
+ * errors and be verifiable.
+ *
+ * @param code source code to analyze.
+ * @param marker marker identifying sought after expression in source code.
+ * @return expression marked by the marker.
+ * @throws Exception
+ */
+ SimpleIdentifier findMarkedIdentifier(String code, String marker) {
+ try {
+ Source source = addSource(code);
+ LibraryElement library = resolve2(source);
+ assertNoErrors(source);
+ verify([source]);
+ CompilationUnit unit = resolveCompilationUnit(source, library);
+ // Could generalize this further by making [SimpleIdentifier.class] a
+ // parameter.
+ return EngineTestCase.findNode(
+ unit, code, marker, (node) => node is SimpleIdentifier);
+ } catch (exception) {
+ // Is there a better exception to throw here? The point is that an
+ // assertion failure here should be a failure, in both "test_*" and
+ // "fail_*" tests. However, an assertion failure is success for the
+ // purpose of "fail_*" tests, so without catching them here "fail_*" tests
+ // can succeed by failing for the wrong reason.
+ 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);
+ }
+
+ @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(")");
+ }
+ }
+}
+
+/**
+ * Shared infrastructure for [StaticTypeAnalyzer2Test] and
+ * [StrongModeStaticTypeAnalyzer2Test].
+ */
+class StaticTypeAnalyzer2TestShared extends ResolverTestCase {
+ String testCode;
+ Source testSource;
+ CompilationUnit testUnit;
+
+ /**
+ * Looks up the identifier with [name] and validates that its type type
+ * stringifies to [type] and that its generics match the given stringified
+ * output.
+ */
+ expectFunctionType(String name, String type,
+ {String elementTypeParams: '[]',
+ String typeParams: '[]',
+ String typeArgs: '[]',
+ String typeFormals: '[]'}) {
+ SimpleIdentifier identifier = findIdentifier(name);
+ // Element is either ExecutableElement or ParameterElement.
+ var element = identifier.staticElement;
+ FunctionTypeImpl functionType = identifier.staticType;
+ expect(functionType.toString(), type);
+ expect(element.typeParameters.toString(), elementTypeParams);
+ expect(functionType.typeParameters.toString(), typeParams);
+ expect(functionType.typeArguments.toString(), typeArgs);
+ expect(functionType.typeFormals.toString(), typeFormals);
+ }
+
+ /**
+ * Looks up the identifier with [name] and validates its static [type].
+ *
+ * If [type] is a string, validates that the identifier's static type
+ * stringifies to that text. Otherwise, [type] is used directly a [Matcher]
+ * to match the type.
+ *
+ * If [propagatedType] is given, also validate's the identifier's propagated
+ * type.
+ */
+ void expectIdentifierType(String name, type, [propagatedType]) {
+ SimpleIdentifier identifier = findIdentifier(name);
+ _expectType(identifier.staticType, type);
+ if (propagatedType != null) {
+ _expectType(identifier.propagatedType, propagatedType);
+ }
+ }
+
+ /**
+ * Looks up the initializer for the declaration containing [identifier] and
+ * validates its static [type].
+ *
+ * If [type] is a string, validates that the identifier's static type
+ * stringifies to that text. Otherwise, [type] is used directly a [Matcher]
+ * to match the type.
+ *
+ * If [propagatedType] is given, also validate's the identifier's propagated
+ * type.
+ */
+ void expectInitializerType(String name, type, [propagatedType]) {
+ SimpleIdentifier identifier = findIdentifier(name);
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ Expression initializer = declaration.initializer;
+ _expectType(initializer.staticType, type);
+ if (propagatedType != null) {
+ _expectType(initializer.propagatedType, propagatedType);
+ }
+ }
+
+ /**
+ * 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);
+ return identifier;
+ }
+
+ void resolveTestUnit(String code) {
+ testCode = code;
+ testSource = addSource(testCode);
+ LibraryElement library = resolve2(testSource);
+ assertNoErrors(testSource);
+ verify([testSource]);
+ testUnit = resolveCompilationUnit(testSource, library);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698