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

Side by Side Diff: pkg/analyzer/test/generated/resolver_test_case.dart

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

Powered by Google App Engine
This is Rietveld 408576698