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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library analyzer.test.generated.resolver_test_case;
6
7 import 'package:analyzer/dart/ast/ast.dart';
8 import 'package:analyzer/dart/ast/visitor.dart';
9 import 'package:analyzer/dart/element/element.dart';
10 import 'package:analyzer/dart/element/type.dart';
11 import 'package:analyzer/src/dart/element/element.dart';
12 import 'package:analyzer/src/dart/element/type.dart';
13 import 'package:analyzer/src/generated/engine.dart';
14 import 'package:analyzer/src/generated/error.dart';
15 import 'package:analyzer/src/generated/java_core.dart';
16 import 'package:analyzer/src/generated/java_engine.dart';
17 import 'package:analyzer/src/generated/java_engine_io.dart';
18 import 'package:analyzer/src/generated/resolver.dart';
19 import 'package:analyzer/src/generated/source_io.dart';
20 import 'package:analyzer/src/generated/testing/ast_factory.dart';
21 import 'package:analyzer/src/generated/testing/element_factory.dart';
22 import 'package:unittest/unittest.dart';
23
24 import 'analysis_context_factory.dart';
25 import 'test_support.dart';
26
27 class ResolverTestCase extends EngineTestCase {
28 /**
29 * The analysis context used to parse the compilation units being resolved.
30 */
31 InternalAnalysisContext analysisContext2;
32
33 /**
34 * Specifies if [assertErrors] should check for [HintCode.UNUSED_ELEMENT] and
35 * [HintCode.UNUSED_FIELD].
36 */
37 bool enableUnusedElement = false;
38
39 /**
40 * Specifies if [assertErrors] should check for [HintCode.UNUSED_LOCAL_VARIABL E].
41 */
42 bool enableUnusedLocalVariable = false;
43
44 AnalysisContext get analysisContext => analysisContext2;
45
46 /**
47 * Return a type provider that can be used to test the results of resolution.
48 *
49 * @return a type provider
50 * @throws AnalysisException if dart:core cannot be resolved
51 */
52 TypeProvider get typeProvider => analysisContext2.typeProvider;
53
54 /**
55 * Return a type system that can be used to test the results of resolution.
56 *
57 * @return a type system
58 */
59 TypeSystem get typeSystem => analysisContext2.typeSystem;
60
61 /**
62 * Add a source file to the content provider. The file path should be absolute .
63 *
64 * @param filePath the path of the file being added
65 * @param contents the contents to be returned by the content provider for the specified file
66 * @return the source object representing the added file
67 */
68 Source addNamedSource(String filePath, String contents) {
69 Source source = cacheSource(filePath, contents);
70 ChangeSet changeSet = new ChangeSet();
71 changeSet.addedSource(source);
72 analysisContext2.applyChanges(changeSet);
73 return source;
74 }
75
76 /**
77 * Add a source file to the content provider.
78 *
79 * @param contents the contents to be returned by the content provider for the specified file
80 * @return the source object representing the added file
81 */
82 Source addSource(String contents) => addNamedSource("/test.dart", contents);
83
84 /**
85 * Assert that the number of errors reported against the given source matches the number of errors
86 * that are given and that they have the expected error codes. The order in wh ich the errors were
87 * gathered is ignored.
88 *
89 * @param source the source against which the errors should have been reported
90 * @param expectedErrorCodes the error codes of the errors that should have be en reported
91 * @throws AnalysisException if the reported errors could not be computed
92 * @throws AssertionFailedError if a different number of errors have been repo rted than were
93 * expected
94 */
95 void assertErrors(Source source,
96 [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
97 GatheringErrorListener errorListener = new GatheringErrorListener();
98 for (AnalysisError error in analysisContext2.computeErrors(source)) {
99 expect(error.source, source);
100 ErrorCode errorCode = error.errorCode;
101 if (!enableUnusedElement &&
102 (errorCode == HintCode.UNUSED_ELEMENT ||
103 errorCode == HintCode.UNUSED_FIELD)) {
104 continue;
105 }
106 if (!enableUnusedLocalVariable &&
107 (errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
108 errorCode == HintCode.UNUSED_CATCH_STACK ||
109 errorCode == HintCode.UNUSED_LOCAL_VARIABLE)) {
110 continue;
111 }
112 errorListener.onError(error);
113 }
114 errorListener.assertErrorsWithCodes(expectedErrorCodes);
115 }
116
117 /**
118 * Asserts that [code] verifies, but has errors with the given error codes.
119 *
120 * Like [assertErrors], but takes a string of source code.
121 */
122 // TODO(rnystrom): Use this in more tests that have the same structure.
123 void assertErrorsInCode(String code, List<ErrorCode> errors) {
124 Source source = addSource(code);
125 computeLibrarySourceErrors(source);
126 assertErrors(source, errors);
127 verify([source]);
128 }
129
130 /**
131 * Asserts that [code] has errors with the given error codes.
132 *
133 * Like [assertErrors], but takes a string of source code.
134 */
135 void assertErrorsInUnverifiedCode(String code, List<ErrorCode> errors) {
136 Source source = addSource(code);
137 computeLibrarySourceErrors(source);
138 assertErrors(source, errors);
139 }
140
141 /**
142 * Assert that no errors have been reported against the given source.
143 *
144 * @param source the source against which no errors should have been reported
145 * @throws AnalysisException if the reported errors could not be computed
146 * @throws AssertionFailedError if any errors have been reported
147 */
148 void assertNoErrors(Source source) {
149 assertErrors(source);
150 }
151
152 /**
153 * Asserts that [code] has no errors or warnings.
154 */
155 // TODO(rnystrom): Use this in more tests that have the same structure.
156 void assertNoErrorsInCode(String code) {
157 Source source = addSource(code);
158 computeLibrarySourceErrors(source);
159 assertNoErrors(source);
160 verify([source]);
161 }
162
163 /**
164 * Cache the source file content in the source factory but don't add the sourc e to the analysis
165 * context. The file path should be absolute.
166 *
167 * @param filePath the path of the file being cached
168 * @param contents the contents to be returned by the content provider for the specified file
169 * @return the source object representing the cached file
170 */
171 Source cacheSource(String filePath, String contents) {
172 Source source = new FileBasedSource(FileUtilities2.createFile(filePath));
173 analysisContext2.setContents(source, contents);
174 return source;
175 }
176
177 /**
178 * Change the contents of the given [source] to the given [contents].
179 */
180 void changeSource(Source source, String contents) {
181 analysisContext2.setContents(source, contents);
182 ChangeSet changeSet = new ChangeSet();
183 changeSet.changedSource(source);
184 analysisContext2.applyChanges(changeSet);
185 }
186
187 /**
188 * Computes errors for the given [librarySource].
189 * This assumes that the given [librarySource] and its parts have already
190 * been added to the content provider using the method [addNamedSource].
191 */
192 void computeLibrarySourceErrors(Source librarySource) {
193 analysisContext.computeErrors(librarySource);
194 }
195
196 /**
197 * Create a library element that represents a library named `"test"` containin g a single
198 * empty compilation unit.
199 *
200 * @return the library element that was created
201 */
202 LibraryElementImpl createDefaultTestLibrary() =>
203 createTestLibrary(AnalysisContextFactory.contextWithCore(), "test");
204
205 /**
206 * Create a library element that represents a library with the given name cont aining a single
207 * empty compilation unit.
208 *
209 * @param libraryName the name of the library to be created
210 * @return the library element that was created
211 */
212 LibraryElementImpl createTestLibrary(
213 AnalysisContext context, String libraryName,
214 [List<String> typeNames]) {
215 String fileName = "$libraryName.dart";
216 FileBasedSource definingCompilationUnitSource =
217 createNamedSource(fileName);
218 List<CompilationUnitElement> sourcedCompilationUnits;
219 if (typeNames == null) {
220 sourcedCompilationUnits = CompilationUnitElement.EMPTY_LIST;
221 } else {
222 int count = typeNames.length;
223 sourcedCompilationUnits = new List<CompilationUnitElement>(count);
224 for (int i = 0; i < count; i++) {
225 String typeName = typeNames[i];
226 ClassElementImpl type =
227 new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
228 String fileName = "$typeName.dart";
229 CompilationUnitElementImpl compilationUnit =
230 new CompilationUnitElementImpl(fileName);
231 compilationUnit.source = createNamedSource(fileName);
232 compilationUnit.librarySource = definingCompilationUnitSource;
233 compilationUnit.types = <ClassElement>[type];
234 sourcedCompilationUnits[i] = compilationUnit;
235 }
236 }
237 CompilationUnitElementImpl compilationUnit =
238 new CompilationUnitElementImpl(fileName);
239 compilationUnit.librarySource =
240 compilationUnit.source = definingCompilationUnitSource;
241 LibraryElementImpl library = new LibraryElementImpl.forNode(
242 context, AstFactory.libraryIdentifier2([libraryName]));
243 library.definingCompilationUnit = compilationUnit;
244 library.parts = sourcedCompilationUnits;
245 return library;
246 }
247
248 Expression findTopLevelConstantExpression(
249 CompilationUnit compilationUnit, String name) =>
250 findTopLevelDeclaration(compilationUnit, name).initializer;
251
252 VariableDeclaration findTopLevelDeclaration(
253 CompilationUnit compilationUnit, String name) {
254 for (CompilationUnitMember member in compilationUnit.declarations) {
255 if (member is TopLevelVariableDeclaration) {
256 for (VariableDeclaration variable in member.variables.variables) {
257 if (variable.name.name == name) {
258 return variable;
259 }
260 }
261 }
262 }
263 return null;
264 // Not found
265 }
266
267 /**
268 * In the rare cases we want to group several tests into single "test_" method , so need a way to
269 * reset test instance to reuse it.
270 */
271 void reset() {
272 analysisContext2 = AnalysisContextFactory.contextWithCore();
273 }
274
275 /**
276 * Reset the analysis context to have the given options applied.
277 *
278 * @param options the analysis options to be applied to the context
279 */
280 void resetWithOptions(AnalysisOptions options) {
281 analysisContext2 =
282 AnalysisContextFactory.contextWithCoreAndOptions(options);
283 }
284
285 /**
286 * Given a library and all of its parts, resolve the contents of the library a nd the contents of
287 * the parts. This assumes that the sources for the library and its parts have already been added
288 * to the content provider using the method [addNamedSource].
289 *
290 * @param librarySource the source for the compilation unit that defines the l ibrary
291 * @return the element representing the resolved library
292 * @throws AnalysisException if the analysis could not be performed
293 */
294 LibraryElement resolve2(Source librarySource) =>
295 analysisContext2.computeLibraryElement(librarySource);
296
297 /**
298 * Return the resolved compilation unit corresponding to the given source in t he given library.
299 *
300 * @param source the source of the compilation unit to be returned
301 * @param library the library in which the compilation unit is to be resolved
302 * @return the resolved compilation unit
303 * @throws Exception if the compilation unit could not be resolved
304 */
305 CompilationUnit resolveCompilationUnit(
306 Source source, LibraryElement library) =>
307 analysisContext2.resolveCompilationUnit(source, library);
308
309 CompilationUnit resolveSource(String sourceText) =>
310 resolveSource2("/test.dart", sourceText);
311
312 CompilationUnit resolveSource2(String fileName, String sourceText) {
313 Source source = addNamedSource(fileName, sourceText);
314 LibraryElement library = analysisContext.computeLibraryElement(source);
315 return analysisContext.resolveCompilationUnit(source, library);
316 }
317
318 Source resolveSources(List<String> sourceTexts) {
319 for (int i = 0; i < sourceTexts.length; i++) {
320 CompilationUnit unit =
321 resolveSource2("/lib${i + 1}.dart", sourceTexts[i]);
322 // reference the source if this is the last source
323 if (i + 1 == sourceTexts.length) {
324 return unit.element.source;
325 }
326 }
327 return null;
328 }
329
330 void resolveWithAndWithoutExperimental(
331 List<String> strSources,
332 List<ErrorCode> codesWithoutExperimental,
333 List<ErrorCode> codesWithExperimental) {
334 // Setup analysis context as non-experimental
335 AnalysisOptionsImpl options = new AnalysisOptionsImpl();
336 // options.enableDeferredLoading = false;
337 resetWithOptions(options);
338 // Analysis and assertions
339 Source source = resolveSources(strSources);
340 assertErrors(source, codesWithoutExperimental);
341 verify([source]);
342 // Setup analysis context as experimental
343 reset();
344 // Analysis and assertions
345 source = resolveSources(strSources);
346 assertErrors(source, codesWithExperimental);
347 verify([source]);
348 }
349
350 void resolveWithErrors(List<String> strSources, List<ErrorCode> codes) {
351 // Analysis and assertions
352 Source source = resolveSources(strSources);
353 assertErrors(source, codes);
354 verify([source]);
355 }
356
357 @override
358 void setUp() {
359 ElementFactory.flushStaticState();
360 super.setUp();
361 reset();
362 }
363
364 @override
365 void tearDown() {
366 analysisContext2 = null;
367 super.tearDown();
368 }
369
370 /**
371 * Verify that all of the identifiers in the compilation units associated with
372 * the given [sources] have been resolved.
373 */
374 void verify(List<Source> sources) {
375 ResolutionVerifier verifier = new ResolutionVerifier();
376 for (Source source in sources) {
377 List<Source> libraries = analysisContext2.getLibrariesContaining(source);
378 for (Source library in libraries) {
379 analysisContext2
380 .resolveCompilationUnit2(source, library)
381 .accept(verifier);
382 }
383 }
384 verifier.assertResolved();
385 }
386
387 /**
388 * @param code the code that assigns the value to the variable "v", no matter how. We check that
389 * "v" has expected static and propagated type.
390 */
391 void assertPropagatedAssignedType(String code, DartType expectedStaticType,
392 DartType expectedPropagatedType) {
393 SimpleIdentifier identifier = findMarkedIdentifier(code, "v = ");
394 expect(identifier.staticType, same(expectedStaticType));
395 expect(identifier.propagatedType, same(expectedPropagatedType));
396 }
397
398 /**
399 * @param code the code that iterates using variable "v". We check that
400 * "v" has expected static and propagated type.
401 */
402 void assertPropagatedIterationType(String code, DartType expectedStaticType,
403 DartType expectedPropagatedType) {
404 SimpleIdentifier identifier = findMarkedIdentifier(code, "v in ");
405 expect(identifier.staticType, same(expectedStaticType));
406 expect(identifier.propagatedType, same(expectedPropagatedType));
407 }
408
409 /**
410 * Check the static and propagated types of the expression marked with "; // m arker" comment.
411 *
412 * @param code source code to analyze, with the expression to check marked wit h "// marker".
413 * @param expectedStaticType if non-null, check actual static type is equal to this.
414 * @param expectedPropagatedType if non-null, check actual static type is equa l to this.
415 * @throws Exception
416 */
417 void assertTypeOfMarkedExpression(String code, DartType expectedStaticType,
418 DartType expectedPropagatedType) {
419 SimpleIdentifier identifier = findMarkedIdentifier(code, "; // marker");
420 if (expectedStaticType != null) {
421 expect(identifier.staticType, expectedStaticType);
422 }
423 expect(identifier.propagatedType, expectedPropagatedType);
424 }
425
426 /**
427 * Create a source object representing a file with the given [fileName] and
428 * give it an empty content. Return the source that was created.
429 */
430 FileBasedSource createNamedSource(String fileName) {
431 FileBasedSource source =
432 new FileBasedSource(FileUtilities2.createFile(fileName));
433 analysisContext2.setContents(source, "");
434 return source;
435 }
436
437 /**
438 * Return the `SimpleIdentifier` marked by `marker`. The source code must have no
439 * errors and be verifiable.
440 *
441 * @param code source code to analyze.
442 * @param marker marker identifying sought after expression in source code.
443 * @return expression marked by the marker.
444 * @throws Exception
445 */
446 SimpleIdentifier findMarkedIdentifier(String code, String marker) {
447 try {
448 Source source = addSource(code);
449 LibraryElement library = resolve2(source);
450 assertNoErrors(source);
451 verify([source]);
452 CompilationUnit unit = resolveCompilationUnit(source, library);
453 // Could generalize this further by making [SimpleIdentifier.class] a
454 // parameter.
455 return EngineTestCase.findNode(
456 unit, code, marker, (node) => node is SimpleIdentifier);
457 } catch (exception) {
458 // Is there a better exception to throw here? The point is that an
459 // assertion failure here should be a failure, in both "test_*" and
460 // "fail_*" tests. However, an assertion failure is success for the
461 // purpose of "fail_*" tests, so without catching them here "fail_*" tests
462 // can succeed by failing for the wrong reason.
463 throw new JavaException("Unexexpected assertion failure: $exception");
464 }
465 }
466 }
467
468 /**
469 * An AST visitor used to verify that all of the nodes in an AST structure that
470 * should have been resolved were resolved.
471 */
472 class ResolutionVerifier extends RecursiveAstVisitor<Object> {
473 /**
474 * A set containing nodes that are known to not be resolvable and should
475 * therefore not cause the test to fail.
476 */
477 final Set<AstNode> _knownExceptions;
478
479 /**
480 * A list containing all of the AST nodes that were not resolved.
481 */
482 List<AstNode> _unresolvedNodes = new List<AstNode>();
483
484 /**
485 * A list containing all of the AST nodes that were resolved to an element of
486 * the wrong type.
487 */
488 List<AstNode> _wrongTypedNodes = new List<AstNode>();
489
490 /**
491 * Initialize a newly created verifier to verify that all of the identifiers
492 * in the visited AST structures that are expected to have been resolved have
493 * an element associated with them. Nodes in the set of [_knownExceptions] are
494 * not expected to have been resolved, even if they normally would have been
495 * expected to have been resolved.
496 */
497 ResolutionVerifier([this._knownExceptions]);
498
499 /**
500 * Assert that all of the visited identifiers were resolved.
501 */
502 void assertResolved() {
503 if (!_unresolvedNodes.isEmpty || !_wrongTypedNodes.isEmpty) {
504 StringBuffer buffer = new StringBuffer();
505 if (!_unresolvedNodes.isEmpty) {
506 buffer.write("Failed to resolve ");
507 buffer.write(_unresolvedNodes.length);
508 buffer.writeln(" nodes:");
509 _printNodes(buffer, _unresolvedNodes);
510 }
511 if (!_wrongTypedNodes.isEmpty) {
512 buffer.write("Resolved ");
513 buffer.write(_wrongTypedNodes.length);
514 buffer.writeln(" to the wrong type of element:");
515 _printNodes(buffer, _wrongTypedNodes);
516 }
517 fail(buffer.toString());
518 }
519 }
520
521 @override
522 Object visitAnnotation(Annotation node) {
523 node.visitChildren(this);
524 ElementAnnotation elementAnnotation = node.elementAnnotation;
525 if (elementAnnotation == null) {
526 if (_knownExceptions == null || !_knownExceptions.contains(node)) {
527 _unresolvedNodes.add(node);
528 }
529 } else if (elementAnnotation is! ElementAnnotation) {
530 _wrongTypedNodes.add(node);
531 }
532 return null;
533 }
534
535 @override
536 Object visitBinaryExpression(BinaryExpression node) {
537 node.visitChildren(this);
538 if (!node.operator.isUserDefinableOperator) {
539 return null;
540 }
541 DartType operandType = node.leftOperand.staticType;
542 if (operandType == null || operandType.isDynamic) {
543 return null;
544 }
545 return _checkResolved(
546 node, node.staticElement, (node) => node is MethodElement);
547 }
548
549 @override
550 Object visitCommentReference(CommentReference node) => null;
551
552 @override
553 Object visitCompilationUnit(CompilationUnit node) {
554 node.visitChildren(this);
555 return _checkResolved(
556 node, node.element, (node) => node is CompilationUnitElement);
557 }
558
559 @override
560 Object visitExportDirective(ExportDirective node) =>
561 _checkResolved(node, node.element, (node) => node is ExportElement);
562
563 @override
564 Object visitFunctionDeclaration(FunctionDeclaration node) {
565 node.visitChildren(this);
566 if (node.element is LibraryElement) {
567 _wrongTypedNodes.add(node);
568 }
569 return null;
570 }
571
572 @override
573 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
574 node.visitChildren(this);
575 // TODO(brianwilkerson) If we start resolving function expressions, then
576 // conditionally check to see whether the node was resolved correctly.
577 return null;
578 //checkResolved(node, node.getElement(), FunctionElement.class);
579 }
580
581 @override
582 Object visitImportDirective(ImportDirective node) {
583 // Not sure how to test the combinators given that it isn't an error if the
584 // names are not defined.
585 _checkResolved(node, node.element, (node) => node is ImportElement);
586 SimpleIdentifier prefix = node.prefix;
587 if (prefix == null) {
588 return null;
589 }
590 return _checkResolved(
591 prefix, prefix.staticElement, (node) => node is PrefixElement);
592 }
593
594 @override
595 Object visitIndexExpression(IndexExpression node) {
596 node.visitChildren(this);
597 DartType targetType = node.realTarget.staticType;
598 if (targetType == null || targetType.isDynamic) {
599 return null;
600 }
601 return _checkResolved(
602 node, node.staticElement, (node) => node is MethodElement);
603 }
604
605 @override
606 Object visitLibraryDirective(LibraryDirective node) =>
607 _checkResolved(node, node.element, (node) => node is LibraryElement);
608
609 @override
610 Object visitNamedExpression(NamedExpression node) =>
611 node.expression.accept(this);
612
613 @override
614 Object visitPartDirective(PartDirective node) => _checkResolved(
615 node, node.element, (node) => node is CompilationUnitElement);
616
617 @override
618 Object visitPartOfDirective(PartOfDirective node) =>
619 _checkResolved(node, node.element, (node) => node is LibraryElement);
620
621 @override
622 Object visitPostfixExpression(PostfixExpression node) {
623 node.visitChildren(this);
624 if (!node.operator.isUserDefinableOperator) {
625 return null;
626 }
627 DartType operandType = node.operand.staticType;
628 if (operandType == null || operandType.isDynamic) {
629 return null;
630 }
631 return _checkResolved(
632 node, node.staticElement, (node) => node is MethodElement);
633 }
634
635 @override
636 Object visitPrefixedIdentifier(PrefixedIdentifier node) {
637 SimpleIdentifier prefix = node.prefix;
638 prefix.accept(this);
639 DartType prefixType = prefix.staticType;
640 if (prefixType == null || prefixType.isDynamic) {
641 return null;
642 }
643 return _checkResolved(node, node.staticElement, null);
644 }
645
646 @override
647 Object visitPrefixExpression(PrefixExpression node) {
648 node.visitChildren(this);
649 if (!node.operator.isUserDefinableOperator) {
650 return null;
651 }
652 DartType operandType = node.operand.staticType;
653 if (operandType == null || operandType.isDynamic) {
654 return null;
655 }
656 return _checkResolved(
657 node, node.staticElement, (node) => node is MethodElement);
658 }
659
660 @override
661 Object visitPropertyAccess(PropertyAccess node) {
662 Expression target = node.realTarget;
663 target.accept(this);
664 DartType targetType = target.staticType;
665 if (targetType == null || targetType.isDynamic) {
666 return null;
667 }
668 return node.propertyName.accept(this);
669 }
670
671 @override
672 Object visitSimpleIdentifier(SimpleIdentifier node) {
673 if (node.name == "void") {
674 return null;
675 }
676 if (node.staticType != null &&
677 node.staticType.isDynamic &&
678 node.staticElement == null) {
679 return null;
680 }
681 AstNode parent = node.parent;
682 if (parent is MethodInvocation) {
683 MethodInvocation invocation = parent;
684 if (identical(invocation.methodName, node)) {
685 Expression target = invocation.realTarget;
686 DartType targetType = target == null ? null : target.staticType;
687 if (targetType == null || targetType.isDynamic) {
688 return null;
689 }
690 }
691 }
692 return _checkResolved(node, node.staticElement, null);
693 }
694
695 Object _checkResolved(
696 AstNode node, Element element, Predicate<Element> predicate) {
697 if (element == null) {
698 if (_knownExceptions == null || !_knownExceptions.contains(node)) {
699 _unresolvedNodes.add(node);
700 }
701 } else if (predicate != null) {
702 if (!predicate(element)) {
703 _wrongTypedNodes.add(node);
704 }
705 }
706 return null;
707 }
708
709 String _getFileName(AstNode node) {
710 // TODO (jwren) there are two copies of this method, one here and one in
711 // StaticTypeVerifier, they should be resolved into a single method
712 if (node != null) {
713 AstNode root = node.root;
714 if (root is CompilationUnit) {
715 CompilationUnit rootCU = root;
716 if (rootCU.element != null) {
717 return rootCU.element.source.fullName;
718 } else {
719 return "<unknown file- CompilationUnit.getElement() returned null>";
720 }
721 } else {
722 return "<unknown file- CompilationUnit.getRoot() is not a CompilationUni t>";
723 }
724 }
725 return "<unknown file- ASTNode is null>";
726 }
727
728 void _printNodes(StringBuffer buffer, List<AstNode> nodes) {
729 for (AstNode identifier in nodes) {
730 buffer.write(" ");
731 buffer.write(identifier.toString());
732 buffer.write(" (");
733 buffer.write(_getFileName(identifier));
734 buffer.write(" : ");
735 buffer.write(identifier.offset);
736 buffer.writeln(")");
737 }
738 }
739 }
740
741 /**
742 * Shared infrastructure for [StaticTypeAnalyzer2Test] and
743 * [StrongModeStaticTypeAnalyzer2Test].
744 */
745 class StaticTypeAnalyzer2TestShared extends ResolverTestCase {
746 String testCode;
747 Source testSource;
748 CompilationUnit testUnit;
749
750 /**
751 * Looks up the identifier with [name] and validates that its type type
752 * stringifies to [type] and that its generics match the given stringified
753 * output.
754 */
755 expectFunctionType(String name, String type,
756 {String elementTypeParams: '[]',
757 String typeParams: '[]',
758 String typeArgs: '[]',
759 String typeFormals: '[]'}) {
760 SimpleIdentifier identifier = findIdentifier(name);
761 // Element is either ExecutableElement or ParameterElement.
762 var element = identifier.staticElement;
763 FunctionTypeImpl functionType = identifier.staticType;
764 expect(functionType.toString(), type);
765 expect(element.typeParameters.toString(), elementTypeParams);
766 expect(functionType.typeParameters.toString(), typeParams);
767 expect(functionType.typeArguments.toString(), typeArgs);
768 expect(functionType.typeFormals.toString(), typeFormals);
769 }
770
771 /**
772 * Looks up the identifier with [name] and validates its static [type].
773 *
774 * If [type] is a string, validates that the identifier's static type
775 * stringifies to that text. Otherwise, [type] is used directly a [Matcher]
776 * to match the type.
777 *
778 * If [propagatedType] is given, also validate's the identifier's propagated
779 * type.
780 */
781 void expectIdentifierType(String name, type, [propagatedType]) {
782 SimpleIdentifier identifier = findIdentifier(name);
783 _expectType(identifier.staticType, type);
784 if (propagatedType != null) {
785 _expectType(identifier.propagatedType, propagatedType);
786 }
787 }
788
789 /**
790 * Looks up the initializer for the declaration containing [identifier] and
791 * validates its static [type].
792 *
793 * If [type] is a string, validates that the identifier's static type
794 * stringifies to that text. Otherwise, [type] is used directly a [Matcher]
795 * to match the type.
796 *
797 * If [propagatedType] is given, also validate's the identifier's propagated
798 * type.
799 */
800 void expectInitializerType(String name, type, [propagatedType]) {
801 SimpleIdentifier identifier = findIdentifier(name);
802 VariableDeclaration declaration =
803 identifier.getAncestor((node) => node is VariableDeclaration);
804 Expression initializer = declaration.initializer;
805 _expectType(initializer.staticType, type);
806 if (propagatedType != null) {
807 _expectType(initializer.propagatedType, propagatedType);
808 }
809 }
810
811 /**
812 * Validates that [type] matches [expected].
813 *
814 * If [expected] is a string, validates that the type stringifies to that
815 * text. Otherwise, [expected] is used directly a [Matcher] to match the type.
816 */
817 _expectType(DartType type, expected) {
818 if (expected is String) {
819 expect(type.toString(), expected);
820 } else {
821 expect(type, expected);
822 }
823 }
824
825 SimpleIdentifier findIdentifier(String search) {
826 SimpleIdentifier identifier = EngineTestCase.findNode(
827 testUnit, testCode, search, (node) => node is SimpleIdentifier);
828 return identifier;
829 }
830
831 void resolveTestUnit(String code) {
832 testCode = code;
833 testSource = addSource(testCode);
834 LibraryElement library = resolve2(testSource);
835 assertNoErrors(testSource);
836 verify([testSource]);
837 testUnit = resolveCompilationUnit(testSource, library);
838 }
839 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698