Index: packages/analyzer/test/src/task/dart_test.dart |
diff --git a/packages/analyzer/test/src/task/dart_test.dart b/packages/analyzer/test/src/task/dart_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0f39004e1c77208f0eb03914aef6097e2dd86f1d |
--- /dev/null |
+++ b/packages/analyzer/test/src/task/dart_test.dart |
@@ -0,0 +1,4259 @@ |
+// Copyright (c) 2015, 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 test.src.task.dart_test; |
+ |
+import 'package:analyzer/src/context/cache.dart'; |
+import 'package:analyzer/src/generated/ast.dart'; |
+import 'package:analyzer/src/generated/constant.dart'; |
+import 'package:analyzer/src/generated/element.dart'; |
+import 'package:analyzer/src/generated/engine.dart' |
+ show AnalysisOptionsImpl, CacheState; |
+import 'package:analyzer/src/generated/error.dart'; |
+import 'package:analyzer/src/generated/resolver.dart'; |
+import 'package:analyzer/src/generated/scanner.dart'; |
+import 'package:analyzer/src/generated/sdk.dart'; |
+import 'package:analyzer/src/generated/source.dart'; |
+import 'package:analyzer/src/services/lint.dart'; |
+import 'package:analyzer/src/task/dart.dart'; |
+import 'package:analyzer/src/task/html.dart'; |
+import 'package:analyzer/task/dart.dart'; |
+import 'package:analyzer/task/general.dart'; |
+import 'package:analyzer/task/model.dart'; |
+import 'package:unittest/unittest.dart'; |
+ |
+import '../../generated/resolver_test.dart'; |
+import '../../generated/test_support.dart'; |
+import '../../reflective_tests.dart'; |
+import '../../utils.dart'; |
+import '../context/abstract_context.dart'; |
+ |
+main() { |
+ initializeTestEnvironment(); |
+ runReflectiveTests(BuildCompilationUnitElementTaskTest); |
+ runReflectiveTests(BuildDirectiveElementsTaskTest); |
+ runReflectiveTests(BuildEnumMemberElementsTaskTest); |
+ runReflectiveTests(BuildExportNamespaceTaskTest); |
+ runReflectiveTests(BuildLibraryElementTaskTest); |
+ runReflectiveTests(BuildPublicNamespaceTaskTest); |
+ runReflectiveTests(BuildSourceExportClosureTaskTest); |
+ runReflectiveTests(BuildSourceImportExportClosureTaskTest); |
+ runReflectiveTests(BuildTypeProviderTaskTest); |
+ runReflectiveTests(ComputeConstantDependenciesTaskTest); |
+ runReflectiveTests(ComputeConstantValueTaskTest); |
+ runReflectiveTests(ComputeInferableStaticVariableDependenciesTaskTest); |
+ runReflectiveTests(ComputeLibraryCycleTaskTest); |
+ runReflectiveTests(ContainingLibrariesTaskTest); |
+ runReflectiveTests(DartErrorsTaskTest); |
+ runReflectiveTests(EvaluateUnitConstantsTaskTest); |
+ runReflectiveTests(GatherUsedImportedElementsTaskTest); |
+ runReflectiveTests(GatherUsedLocalElementsTaskTest); |
+ runReflectiveTests(GenerateHintsTaskTest); |
+ runReflectiveTests(GenerateLintsTaskTest); |
+ runReflectiveTests(InferInstanceMembersInUnitTaskTest); |
+ runReflectiveTests(InferStaticVariableTypesInUnitTaskTest); |
+ runReflectiveTests(InferStaticVariableTypeTaskTest); |
+ runReflectiveTests(LibraryErrorsReadyTaskTest); |
+ runReflectiveTests(LibraryUnitErrorsTaskTest); |
+ runReflectiveTests(ParseDartTaskTest); |
+ runReflectiveTests(PartiallyResolveUnitReferencesTaskTest); |
+ runReflectiveTests(ResolveInstanceFieldsInUnitTaskTest); |
+ runReflectiveTests(ResolveLibraryTypeNamesTaskTest); |
+ runReflectiveTests(ResolveUnitTaskTest); |
+ runReflectiveTests(ResolveUnitTypeNamesTaskTest); |
+ runReflectiveTests(ResolveVariableReferencesTaskTest); |
+ runReflectiveTests(ScanDartTaskTest); |
+ runReflectiveTests(StrongModeInferenceTest); |
+ runReflectiveTests(VerifyUnitTaskTest); |
+} |
+ |
+isInstanceOf isBuildCompilationUnitElementTask = |
+ new isInstanceOf<BuildCompilationUnitElementTask>(); |
+isInstanceOf isBuildDirectiveElementsTask = |
+ new isInstanceOf<BuildDirectiveElementsTask>(); |
+isInstanceOf isBuildEnumMemberElementsTask = |
+ new isInstanceOf<BuildEnumMemberElementsTask>(); |
+isInstanceOf isBuildExportNamespaceTask = |
+ new isInstanceOf<BuildExportNamespaceTask>(); |
+isInstanceOf isBuildLibraryElementTask = |
+ new isInstanceOf<BuildLibraryElementTask>(); |
+isInstanceOf isBuildPublicNamespaceTask = |
+ new isInstanceOf<BuildPublicNamespaceTask>(); |
+isInstanceOf isBuildSourceExportClosureTask = |
+ new isInstanceOf<BuildSourceExportClosureTask>(); |
+isInstanceOf isBuildSourceImportExportClosureTask = |
+ new isInstanceOf<BuildSourceImportExportClosureTask>(); |
+isInstanceOf isBuildTypeProviderTask = |
+ new isInstanceOf<BuildTypeProviderTask>(); |
+isInstanceOf isComputeConstantDependenciesTask = |
+ new isInstanceOf<ComputeConstantDependenciesTask>(); |
+isInstanceOf isComputeConstantValueTask = |
+ new isInstanceOf<ComputeConstantValueTask>(); |
+isInstanceOf isComputeInferableStaticVariableDependenciesTask = |
+ new isInstanceOf<ComputeInferableStaticVariableDependenciesTask>(); |
+isInstanceOf isContainingLibrariesTask = |
+ new isInstanceOf<ContainingLibrariesTask>(); |
+isInstanceOf isDartErrorsTask = new isInstanceOf<DartErrorsTask>(); |
+isInstanceOf isEvaluateUnitConstantsTask = |
+ new isInstanceOf<EvaluateUnitConstantsTask>(); |
+isInstanceOf isGatherUsedImportedElementsTask = |
+ new isInstanceOf<GatherUsedImportedElementsTask>(); |
+isInstanceOf isGatherUsedLocalElementsTask = |
+ new isInstanceOf<GatherUsedLocalElementsTask>(); |
+isInstanceOf isGenerateHintsTask = new isInstanceOf<GenerateHintsTask>(); |
+isInstanceOf isGenerateLintsTask = new isInstanceOf<GenerateLintsTask>(); |
+isInstanceOf isInferInstanceMembersInUnitTask = |
+ new isInstanceOf<InferInstanceMembersInUnitTask>(); |
+isInstanceOf isInferStaticVariableTypesInUnitTask = |
+ new isInstanceOf<InferStaticVariableTypesInUnitTask>(); |
+isInstanceOf isInferStaticVariableTypeTask = |
+ new isInstanceOf<InferStaticVariableTypeTask>(); |
+isInstanceOf isLibraryErrorsReadyTask = |
+ new isInstanceOf<LibraryErrorsReadyTask>(); |
+isInstanceOf isLibraryUnitErrorsTask = |
+ new isInstanceOf<LibraryUnitErrorsTask>(); |
+isInstanceOf isParseDartTask = new isInstanceOf<ParseDartTask>(); |
+isInstanceOf isPartiallyResolveUnitReferencesTask = |
+ new isInstanceOf<PartiallyResolveUnitReferencesTask>(); |
+isInstanceOf isResolveLibraryTypeNamesTask = |
+ new isInstanceOf<ResolveLibraryTypeNamesTask>(); |
+isInstanceOf isResolveUnitTask = new isInstanceOf<ResolveUnitTask>(); |
+isInstanceOf isResolveUnitTypeNamesTask = |
+ new isInstanceOf<ResolveUnitTypeNamesTask>(); |
+isInstanceOf isResolveVariableReferencesTask = |
+ new isInstanceOf<ResolveVariableReferencesTask>(); |
+isInstanceOf isScanDartTask = new isInstanceOf<ScanDartTask>(); |
+isInstanceOf isVerifyUnitTask = new isInstanceOf<VerifyUnitTask>(); |
+ |
+final LintCode _testLintCode = new LintCode('test lint', 'test lint code'); |
+ |
+@reflectiveTest |
+class BuildCompilationUnitElementTaskTest extends _AbstractDartTaskTest { |
+ Source source; |
+ LibrarySpecificUnit target; |
+ |
+ test_perform_find_constants() { |
+ _performBuildTask(''' |
+const x = 1; |
+class C { |
+ static const y = 1; |
+ const C([p = 1]); |
+} |
+@x |
+f() { |
+ const z = 1; |
+} |
+'''); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT1]; |
+ CompilationUnitElement unitElement = outputs[COMPILATION_UNIT_ELEMENT]; |
+ Annotation annotation = unit.declarations |
+ .firstWhere((m) => m is FunctionDeclaration) |
+ .metadata[0]; |
+ List<ConstantEvaluationTarget> expectedConstants = [ |
+ unitElement.accessors.firstWhere((e) => e.isGetter).variable, |
+ unitElement.types[0].fields[0], |
+ unitElement.functions[0].localVariables[0], |
+ unitElement.types[0].constructors[0], |
+ new ConstantEvaluationTarget_Annotation( |
+ context, source, source, annotation), |
+ unitElement.types[0].constructors[0].parameters[0] |
+ ]; |
+ expect( |
+ outputs[COMPILATION_UNIT_CONSTANTS].toSet(), expectedConstants.toSet()); |
+ } |
+ |
+ test_perform_library() { |
+ _performBuildTask(r''' |
+library lib; |
+import 'lib2.dart'; |
+export 'lib3.dart'; |
+part 'part.dart'; |
+final x = ''; |
+class A { |
+ static final y = 0; |
+} |
+class B = Object with A; |
+'''); |
+ expect(outputs, hasLength(3)); |
+ expect(outputs[COMPILATION_UNIT_CONSTANTS], isNotNull); |
+ expect(outputs[COMPILATION_UNIT_ELEMENT], isNotNull); |
+ expect(outputs[RESOLVED_UNIT1], isNotNull); |
+ } |
+ |
+ test_perform_reuseElement() { |
+ _performBuildTask(r''' |
+library lib; |
+class A {} |
+class B = Object with A; |
+'''); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT1]; |
+ CompilationUnitElement unitElement = outputs[COMPILATION_UNIT_ELEMENT]; |
+ expect(unit, isNotNull); |
+ expect(unitElement, isNotNull); |
+ // invalidate RESOLVED_UNIT1 |
+ CacheEntry cacheEntry = analysisCache.get(target); |
+ cacheEntry.setState(RESOLVED_UNIT1, CacheState.INVALID); |
+ // compute again |
+ computeResult(target, RESOLVED_UNIT1, |
+ matcher: isBuildCompilationUnitElementTask); |
+ expect(outputs[COMPILATION_UNIT_ELEMENT], same(unitElement)); |
+ expect(outputs[RESOLVED_UNIT1], isNot(same(unit))); |
+ } |
+ |
+ void _performBuildTask(String content) { |
+ source = newSource('/test.dart', content); |
+ target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT1, |
+ matcher: isBuildCompilationUnitElementTask); |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildDirectiveElementsTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ List<Source> sources = newSources({ |
+ '/libA.dart': ''' |
+library libA; |
+import 'libB.dart'; |
+export 'libC.dart'; |
+''', |
+ '/libB.dart': ''' |
+library libB; |
+''', |
+ '/libC.dart': ''' |
+library libC; |
+''' |
+ }); |
+ Source sourceA = sources[0]; |
+ Source sourceB = sources[1]; |
+ Source sourceC = sources[2]; |
+ // perform task |
+ computeResult(sourceA, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // prepare outputs |
+ LibraryElement libraryElementA = outputs[LIBRARY_ELEMENT2]; |
+ LibraryElement libraryElementB = _getImportLibraryInput(sourceB); |
+ LibraryElement libraryElementC = _getExportLibraryInput(sourceC); |
+ // no errors |
+ _assertErrorsWithCodes([]); |
+ // validate directives |
+ CompilationUnit libraryUnitA = context |
+ .getCacheEntry(new LibrarySpecificUnit(sourceA, sourceA)) |
+ .getValue(RESOLVED_UNIT1); |
+ { |
+ ImportDirective importNode = libraryUnitA.directives[1]; |
+ ImportElement importElement = importNode.element; |
+ expect(importElement, isNotNull); |
+ expect(importElement.importedLibrary, libraryElementB); |
+ expect(importElement.prefix, isNull); |
+ expect(importElement.nameOffset, 14); |
+ expect(importElement.uriOffset, 21); |
+ expect(importElement.uriEnd, 32); |
+ } |
+ { |
+ ExportDirective exportNode = libraryUnitA.directives[2]; |
+ ExportElement exportElement = exportNode.element; |
+ expect(exportElement, isNotNull); |
+ expect(exportElement.exportedLibrary, libraryElementC); |
+ expect(exportElement.nameOffset, 34); |
+ expect(exportElement.uriOffset, 41); |
+ expect(exportElement.uriEnd, 52); |
+ } |
+ // validate LibraryElement |
+ expect(libraryElementA.hasExtUri, isFalse); |
+ // has an artificial "dart:core" import |
+ { |
+ List<ImportElement> imports = libraryElementA.imports; |
+ expect(imports, hasLength(2)); |
+ expect(imports[1].importedLibrary.isDartCore, isTrue); |
+ expect(imports[1].isSynthetic, isTrue); |
+ } |
+ } |
+ |
+ test_perform_combinators() { |
+ List<Source> sources = newSources({ |
+ '/libA.dart': ''' |
+library libA; |
+import 'libB.dart' show A, B hide C, D; |
+''', |
+ '/libB.dart': ''' |
+library libB; |
+''' |
+ }); |
+ Source sourceA = sources[0]; |
+ // perform task |
+ computeResult(sourceA, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // prepare outputs |
+ CompilationUnit libraryUnitA = context |
+ .getCacheEntry(new LibrarySpecificUnit(sourceA, sourceA)) |
+ .getValue(RESOLVED_UNIT1); |
+ // no errors |
+ _assertErrorsWithCodes([]); |
+ // validate directives |
+ ImportDirective importNode = libraryUnitA.directives[1]; |
+ ImportElement importElement = importNode.element; |
+ List<NamespaceCombinator> combinators = importElement.combinators; |
+ expect(combinators, hasLength(2)); |
+ { |
+ ShowElementCombinator combinator = combinators[0]; |
+ expect(combinator.offset, 33); |
+ expect(combinator.end, 42); |
+ expect(combinator.shownNames, ['A', 'B']); |
+ } |
+ { |
+ HideElementCombinator combinator = combinators[1]; |
+ expect(combinator.hiddenNames, ['C', 'D']); |
+ } |
+ } |
+ |
+ test_perform_dartCoreContext() { |
+ List<Source> sources = newSources({'/libA.dart': ''}); |
+ Source source = sources[0]; |
+ // perform task |
+ computeResult(source, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // prepare outputs |
+ LibraryElement libraryElement = outputs[LIBRARY_ELEMENT2]; |
+ // verify that dart:core has SDK context |
+ { |
+ LibraryElement coreLibrary = libraryElement.importedLibraries[0]; |
+ DartSdk dartSdk = context.sourceFactory.dartSdk; |
+ expect(coreLibrary.context, same(dartSdk.context)); |
+ } |
+ } |
+ |
+ test_perform_error_exportOfNonLibrary() { |
+ List<Source> sources = newSources({ |
+ '/libA.dart': ''' |
+library libA; |
+export 'part.dart'; |
+''', |
+ '/part.dart': ''' |
+part of notLib; |
+''' |
+ }); |
+ Source sourceA = sources[0]; |
+ // perform task |
+ computeResult(sourceA, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // validate errors |
+ _assertErrorsWithCodes([CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY]); |
+ } |
+ |
+ test_perform_error_importOfNonLibrary() { |
+ List<Source> sources = newSources({ |
+ '/libA.dart': ''' |
+library libA; |
+import 'part.dart'; |
+''', |
+ '/part.dart': ''' |
+part of notLib; |
+''' |
+ }); |
+ Source sourceA = sources[0]; |
+ // perform task |
+ computeResult(sourceA, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // validate errors |
+ _assertErrorsWithCodes([CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY]); |
+ } |
+ |
+ test_perform_explicitDartCoreImport() { |
+ List<Source> sources = newSources({ |
+ '/lib.dart': ''' |
+library lib; |
+import 'dart:core' show List; |
+''' |
+ }); |
+ Source source = sources[0]; |
+ // perform task |
+ computeResult(source, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // prepare outputs |
+ LibraryElement libraryElement = outputs[LIBRARY_ELEMENT2]; |
+ // has an explicit "dart:core" import |
+ { |
+ List<ImportElement> imports = libraryElement.imports; |
+ expect(imports, hasLength(1)); |
+ expect(imports[0].importedLibrary.isDartCore, isTrue); |
+ expect(imports[0].isSynthetic, isFalse); |
+ } |
+ } |
+ |
+ test_perform_hasExtUri() { |
+ List<Source> sources = newSources({ |
+ '/lib.dart': ''' |
+import 'dart-ext:doesNotExist.dart'; |
+''' |
+ }); |
+ Source source = sources[0]; |
+ // perform task |
+ computeResult(source, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // prepare outputs |
+ LibraryElement libraryElement = outputs[LIBRARY_ELEMENT2]; |
+ expect(libraryElement.hasExtUri, isTrue); |
+ } |
+ |
+ test_perform_importPrefix() { |
+ List<Source> sources = newSources({ |
+ '/libA.dart': ''' |
+library libA; |
+import 'libB.dart' as pref; |
+import 'libC.dart' as pref; |
+''', |
+ '/libB.dart': ''' |
+library libB; |
+''', |
+ '/libC.dart': ''' |
+library libC; |
+''' |
+ }); |
+ Source sourceA = sources[0]; |
+ Source sourceB = sources[1]; |
+ // perform task |
+ computeResult(sourceA, LIBRARY_ELEMENT2, |
+ matcher: isBuildDirectiveElementsTask); |
+ // prepare outputs |
+ CompilationUnit libraryUnitA = context |
+ .getCacheEntry(new LibrarySpecificUnit(sourceA, sourceA)) |
+ .getValue(RESOLVED_UNIT1); |
+ // validate directives |
+ ImportDirective importNodeB = libraryUnitA.directives[1]; |
+ SimpleIdentifier prefixNodeB = importNodeB.prefix; |
+ ImportElement importElementB = importNodeB.element; |
+ PrefixElement prefixElement = importElementB.prefix; |
+ expect(importElementB, isNotNull); |
+ expect(importElementB.importedLibrary, _getImportLibraryInput(sourceB)); |
+ expect(prefixElement, isNotNull); |
+ expect(importElementB.prefixOffset, prefixElement.nameOffset); |
+ expect(prefixNodeB.staticElement, prefixElement); |
+ // PrefixElement "pref" is shared |
+ ImportDirective importNodeC = libraryUnitA.directives[2]; |
+ SimpleIdentifier prefixNodeC = importNodeC.prefix; |
+ ImportElement importElementC = importNodeC.element; |
+ expect(prefixNodeC.staticElement, prefixElement); |
+ expect(importElementC.prefix, prefixElement); |
+ } |
+ |
+ void _assertErrorsWithCodes(List<ErrorCode> expectedErrorCodes) { |
+ _fillErrorListener(BUILD_DIRECTIVES_ERRORS); |
+ errorListener.assertErrorsWithCodes(expectedErrorCodes); |
+ } |
+ |
+ _getExportLibraryInput(Source source) { |
+ var key = BuildDirectiveElementsTask.EXPORTS_LIBRARY_ELEMENT_INPUT_NAME; |
+ return task.inputs[key][source]; |
+ } |
+ |
+ _getImportLibraryInput(Source source) { |
+ var key = BuildDirectiveElementsTask.IMPORTS_LIBRARY_ELEMENT_INPUT_NAME; |
+ return task.inputs[key][source]; |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildEnumMemberElementsTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+enum MyEnum { |
+ A, B |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT2, |
+ matcher: isBuildEnumMemberElementsTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT2]; |
+ // validate Element |
+ ClassElement enumElement = unit.element.getEnum('MyEnum'); |
+ List<FieldElement> fields = enumElement.fields; |
+ expect(fields, hasLength(4)); |
+ { |
+ FieldElementImpl index = fields[0]; |
+ expect(index, isNotNull); |
+ expect(index.name, 'index'); |
+ expect(index.isStatic, isFalse); |
+ expect(index.evaluationResult, isNull); |
+ _assertGetter(index); |
+ } |
+ { |
+ ConstFieldElementImpl values = fields[1]; |
+ expect(values, isNotNull); |
+ expect(values.name, 'values'); |
+ expect(values.isStatic, isTrue); |
+ expect(values.evaluationResult, isNotNull); |
+ _assertGetter(values); |
+ } |
+ { |
+ ConstFieldElementImpl constant = fields[2]; |
+ expect(constant, isNotNull); |
+ expect(constant.name, 'A'); |
+ expect(constant.isStatic, isTrue); |
+ expect(constant.evaluationResult, isNotNull); |
+ _assertGetter(constant); |
+ } |
+ { |
+ ConstFieldElementImpl constant = fields[3]; |
+ expect(constant, isNotNull); |
+ expect(constant.name, 'B'); |
+ expect(constant.isStatic, isTrue); |
+ expect(constant.evaluationResult, isNotNull); |
+ _assertGetter(constant); |
+ } |
+ // validate nodes |
+ EnumDeclaration enumNode = unit.declarations[0]; |
+ expect(enumNode.name.staticElement, same(enumElement)); |
+ expect(enumNode.constants[0].element, same(enumElement.getField('A'))); |
+ expect(enumNode.constants[1].element, same(enumElement.getField('B'))); |
+ } |
+ |
+ static void _assertGetter(FieldElement field) { |
+ PropertyAccessorElement getter = field.getter; |
+ expect(getter, isNotNull); |
+ expect(getter.variable, same(field)); |
+ expect(getter.type, isNotNull); |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildExportNamespaceTaskTest extends _AbstractDartTaskTest { |
+ test_perform_entryPoint() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+export 'b.dart'; |
+'''); |
+ Source sourceB = newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+main() {} |
+'''); |
+ computeResult(sourceA, LIBRARY_ELEMENT4, |
+ matcher: isBuildExportNamespaceTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT4]; |
+ FunctionElement entryPoint = library.entryPoint; |
+ expect(entryPoint, isNotNull); |
+ expect(entryPoint.source, sourceB); |
+ } |
+ |
+ test_perform_hideCombinator() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+export 'b.dart' hide B1; |
+class A1 {} |
+class A2 {} |
+class _A3 {} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+class B1 {} |
+class B2 {} |
+class B3 {} |
+class _B4 {} |
+'''); |
+ newSource( |
+ '/c.dart', |
+ ''' |
+library lib_c; |
+class C1 {} |
+class C2 {} |
+class C3 {} |
+'''); |
+ computeResult(sourceA, LIBRARY_ELEMENT4, |
+ matcher: isBuildExportNamespaceTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT4]; |
+ Namespace namespace = library.exportNamespace; |
+ Iterable<String> definedKeys = namespace.definedNames.keys; |
+ expect(definedKeys, unorderedEquals(['A1', 'A2', 'B2', 'B3'])); |
+ } |
+ |
+ test_perform_showCombinator() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+export 'b.dart' show B1; |
+class A1 {} |
+class A2 {} |
+class _A3 {} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+class B1 {} |
+class B2 {} |
+class _B3 {} |
+'''); |
+ computeResult(sourceA, LIBRARY_ELEMENT4, |
+ matcher: isBuildExportNamespaceTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT4]; |
+ Namespace namespace = library.exportNamespace; |
+ Iterable<String> definedKeys = namespace.definedNames.keys; |
+ expect(definedKeys, unorderedEquals(['A1', 'A2', 'B1'])); |
+ } |
+ |
+ test_perform_showCombinator_setter() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+export 'b.dart' show topLevelB; |
+class A {} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+int topLevelB; |
+'''); |
+ computeResult(sourceA, LIBRARY_ELEMENT4, |
+ matcher: isBuildExportNamespaceTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT4]; |
+ Namespace namespace = library.exportNamespace; |
+ Iterable<String> definedKeys = namespace.definedNames.keys; |
+ expect(definedKeys, unorderedEquals(['A', 'topLevelB', 'topLevelB='])); |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildLibraryElementTaskTest extends _AbstractDartTaskTest { |
+ Source librarySource; |
+ CompilationUnit libraryUnit; |
+ CompilationUnitElement libraryUnitElement; |
+ List<CompilationUnit> partUnits; |
+ |
+ LibraryElement libraryElement; |
+ |
+ test_perform() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part1.dart'; |
+part 'part2.dart'; |
+''', |
+ '/part1.dart': ''' |
+part of lib; |
+''', |
+ '/part2.dart': ''' |
+part of lib; |
+''' |
+ }); |
+ expect(outputs, hasLength(3)); |
+ // simple outputs |
+ expect(outputs[BUILD_LIBRARY_ERRORS], isEmpty); |
+ expect(outputs[IS_LAUNCHABLE], isFalse); |
+ // LibraryElement output |
+ expect(libraryElement, isNotNull); |
+ expect(libraryElement.entryPoint, isNull); |
+ expect(libraryElement.source, same(librarySource)); |
+ expect(libraryElement.definingCompilationUnit, libraryUnitElement); |
+ expect(libraryElement.parts, |
+ unorderedEquals([partUnits[0].element, partUnits[1].element])); |
+ // LibraryElement references |
+ expect((libraryUnit.directives[0] as LibraryDirective).element, |
+ same(libraryElement)); |
+ expect((partUnits[0].directives[0] as PartOfDirective).element, |
+ same(libraryElement)); |
+ expect((partUnits[1].directives[0] as PartOfDirective).element, |
+ same(libraryElement)); |
+ // CompilationUnitElement(s) |
+ CompilationUnitElement firstPart; |
+ CompilationUnitElement secondPart; |
+ if (partUnits[0].element.uri == 'part1.dart') { |
+ firstPart = partUnits[0].element; |
+ secondPart = partUnits[1].element; |
+ } else { |
+ firstPart = partUnits[1].element; |
+ secondPart = partUnits[0].element; |
+ } |
+ expect(firstPart.uri, 'part1.dart'); |
+ expect(firstPart.uriOffset, 18); |
+ expect(firstPart.uriEnd, 30); |
+ expect( |
+ (libraryUnit.directives[1] as PartDirective).element, same(firstPart)); |
+ |
+ expect(secondPart.uri, 'part2.dart'); |
+ expect(secondPart.uriOffset, 37); |
+ expect(secondPart.uriEnd, 49); |
+ expect( |
+ (libraryUnit.directives[2] as PartDirective).element, same(secondPart)); |
+ } |
+ |
+ test_perform_error_missingLibraryDirectiveWithPart_hasCommon() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+part 'partA.dart'; |
+part 'partB.dart'; |
+''', |
+ '/partA.dart': ''' |
+part of my_lib; |
+ ''', |
+ '/partB.dart': ''' |
+part of my_lib; |
+''' |
+ }); |
+ _assertErrorsWithCodes( |
+ [ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART]); |
+ AnalysisError error = errorListener.errors[0]; |
+ expect(error.getProperty(ErrorProperty.PARTS_LIBRARY_NAME), 'my_lib'); |
+ } |
+ |
+ test_perform_error_missingLibraryDirectiveWithPart_noCommon() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+part 'partA.dart'; |
+part 'partB.dart'; |
+''', |
+ '/partA.dart': ''' |
+part of libA; |
+ ''', |
+ '/partB.dart': ''' |
+part of libB; |
+''' |
+ }); |
+ _assertErrorsWithCodes( |
+ [ResolverErrorCode.MISSING_LIBRARY_DIRECTIVE_WITH_PART]); |
+ AnalysisError error = errorListener.errors[0]; |
+ expect(error.getProperty(ErrorProperty.PARTS_LIBRARY_NAME), isNull); |
+ } |
+ |
+ test_perform_error_partDoesNotExist() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part.dart'; |
+''' |
+ }); |
+ // we already report URI_DOES_NOT_EXIST, no need to report other errors |
+ _assertErrorsWithCodes([]); |
+ } |
+ |
+ test_perform_error_partOfDifferentLibrary() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part.dart'; |
+''', |
+ '/part.dart': ''' |
+part of someOtherLib; |
+''' |
+ }); |
+ _assertErrorsWithCodes([StaticWarningCode.PART_OF_DIFFERENT_LIBRARY]); |
+ } |
+ |
+ test_perform_error_partOfNonPart() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part.dart'; |
+''', |
+ '/part.dart': ''' |
+// no part of |
+''' |
+ }); |
+ _assertErrorsWithCodes([CompileTimeErrorCode.PART_OF_NON_PART]); |
+ } |
+ |
+ test_perform_invalidUri_part() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part '//////////'; |
+''' |
+ }); |
+ expect(libraryElement.parts, isEmpty); |
+ } |
+ |
+ test_perform_isLaunchable_inDefiningUnit() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+main() { |
+} |
+''' |
+ }); |
+ expect(outputs[IS_LAUNCHABLE], isTrue); |
+ expect(libraryElement.entryPoint, isNotNull); |
+ } |
+ |
+ test_perform_isLaunchable_inPartUnit() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part.dart'; |
+''', |
+ '/part.dart': ''' |
+part of lib; |
+main() { |
+} |
+''' |
+ }); |
+ expect(outputs[IS_LAUNCHABLE], isTrue); |
+ expect(libraryElement.entryPoint, isNotNull); |
+ } |
+ |
+ test_perform_noSuchFilePart() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'no-such-file.dart'; |
+''' |
+ }); |
+ expect(libraryElement.parts, hasLength(1)); |
+ CompilationUnitElement part = libraryElement.parts[0]; |
+ expect(part, isNotNull); |
+ expect(part.source, isNotNull); |
+ expect(part.library, same(libraryElement)); |
+ expect(context.exists(part.source), isFalse); |
+ } |
+ |
+ test_perform_patchTopLevelAccessors() { |
+ _performBuildTask({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part1.dart'; |
+part 'part2.dart'; |
+''', |
+ '/part1.dart': ''' |
+part of lib; |
+int get test => 0; |
+''', |
+ '/part2.dart': ''' |
+part of lib; |
+void set test(_) {} |
+''' |
+ }); |
+ CompilationUnitElement unitElement1 = partUnits[0].element; |
+ CompilationUnitElement unitElement2 = partUnits[1].element; |
+ PropertyAccessorElement getter = unitElement1.accessors[0]; |
+ PropertyAccessorElement setter = unitElement2.accessors[0]; |
+ PropertyInducingElement variable = getter.variable; |
+ expect(getter.isGetter, isTrue); |
+ expect(setter.isSetter, isTrue); |
+ expect(variable, isNotNull); |
+ expect(setter.variable, same(variable)); |
+ expect(unitElement1.topLevelVariables, [variable]); |
+ expect(unitElement2.topLevelVariables, [variable]); |
+ } |
+ |
+ void _assertErrorsWithCodes(List<ErrorCode> expectedErrorCodes) { |
+ _fillErrorListener(BUILD_LIBRARY_ERRORS); |
+ errorListener.assertErrorsWithCodes(expectedErrorCodes); |
+ } |
+ |
+ void _performBuildTask(Map<String, String> sourceMap) { |
+ List<Source> sources = newSources(sourceMap); |
+ Source libSource = sources.first; |
+ computeResult(libSource, LIBRARY_ELEMENT1, |
+ matcher: isBuildLibraryElementTask); |
+ libraryUnit = context |
+ .getCacheEntry(new LibrarySpecificUnit(libSource, libSource)) |
+ .getValue(RESOLVED_UNIT1); |
+ libraryUnitElement = libraryUnit.element; |
+ librarySource = libraryUnitElement.source; |
+ libraryElement = outputs[LIBRARY_ELEMENT1]; |
+ partUnits = task.inputs[BuildLibraryElementTask.PARTS_UNIT_INPUT]; |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildPublicNamespaceTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ List<Source> sources = newSources({ |
+ '/lib.dart': ''' |
+library lib; |
+part 'part.dart'; |
+a() {} |
+_b() {} |
+''', |
+ '/part.dart': ''' |
+part of lib; |
+_c() {} |
+d() {} |
+''' |
+ }); |
+ computeResult(sources.first, LIBRARY_ELEMENT3, |
+ matcher: isBuildPublicNamespaceTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT3]; |
+ Namespace namespace = library.publicNamespace; |
+ expect(namespace.definedNames.keys, unorderedEquals(['a', 'd'])); |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildSourceExportClosureTaskTest extends _AbstractDartTaskTest { |
+ test_perform_exportClosure() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+export 'b.dart'; |
+'''); |
+ Source sourceB = newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+export 'c.dart'; |
+'''); |
+ Source sourceC = newSource( |
+ '/c.dart', |
+ ''' |
+library lib_c; |
+export 'a.dart'; |
+'''); |
+ Source sourceD = newSource( |
+ '/d.dart', |
+ ''' |
+library lib_d; |
+'''); |
+ // a.dart |
+ { |
+ computeResult(sourceA, EXPORT_SOURCE_CLOSURE, |
+ matcher: isBuildSourceExportClosureTask); |
+ List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE]; |
+ expect(closure, unorderedEquals([sourceA, sourceB, sourceC])); |
+ } |
+ // c.dart |
+ { |
+ computeResult(sourceC, EXPORT_SOURCE_CLOSURE, |
+ matcher: isBuildSourceExportClosureTask); |
+ List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE]; |
+ expect(closure, unorderedEquals([sourceA, sourceB, sourceC])); |
+ } |
+ // d.dart |
+ { |
+ computeResult(sourceD, EXPORT_SOURCE_CLOSURE, |
+ matcher: isBuildSourceExportClosureTask); |
+ List<Source> closure = outputs[EXPORT_SOURCE_CLOSURE]; |
+ expect(closure, unorderedEquals([sourceD])); |
+ } |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildSourceImportExportClosureTaskTest extends _AbstractDartTaskTest { |
+ test_perform_importExportClosure() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+'''); |
+ Source sourceB = newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+export 'a.dart'; |
+'''); |
+ Source sourceC = newSource( |
+ '/c.dart', |
+ ''' |
+library lib_c; |
+import 'b.dart'; |
+'''); |
+ Source coreSource = context.sourceFactory.resolveUri(null, 'dart:core'); |
+ // c.dart |
+ { |
+ computeResult(sourceC, IMPORT_EXPORT_SOURCE_CLOSURE, |
+ matcher: isBuildSourceImportExportClosureTask); |
+ List<Source> closure = outputs[IMPORT_EXPORT_SOURCE_CLOSURE]; |
+ expect(closure, contains(sourceA)); |
+ expect(closure, contains(sourceB)); |
+ expect(closure, contains(sourceC)); |
+ expect(closure, contains(coreSource)); |
+ } |
+ // b.dart |
+ { |
+ computeResult(sourceB, IMPORT_EXPORT_SOURCE_CLOSURE, |
+ matcher: isBuildSourceImportExportClosureTask); |
+ List<Source> closure = outputs[IMPORT_EXPORT_SOURCE_CLOSURE]; |
+ expect(closure, contains(sourceA)); |
+ expect(closure, contains(sourceB)); |
+ expect(closure, contains(coreSource)); |
+ } |
+ } |
+ |
+ test_perform_isClient_false() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+import 'b.dart'; |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+'''); |
+ computeResult(sourceA, IS_CLIENT, |
+ matcher: isBuildSourceImportExportClosureTask); |
+ expect(outputs[IS_CLIENT], isFalse); |
+ } |
+ |
+ test_perform_isClient_true_export_indirect() { |
+ newSource( |
+ '/exports_html.dart', |
+ ''' |
+library lib_exports_html; |
+export 'dart:html'; |
+'''); |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+import 'exports_html.dart'; |
+'''); |
+ computeResult(source, IS_CLIENT, |
+ matcher: isBuildSourceImportExportClosureTask); |
+ expect(outputs[IS_CLIENT], isTrue); |
+ } |
+ |
+ test_perform_isClient_true_import_direct() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+import 'dart:html'; |
+'''); |
+ computeResult(sourceA, IS_CLIENT, |
+ matcher: isBuildSourceImportExportClosureTask); |
+ expect(outputs[IS_CLIENT], isTrue); |
+ } |
+ |
+ test_perform_isClient_true_import_indirect() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library lib_a; |
+import 'b.dart'; |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library lib_b; |
+import 'dart:html'; |
+'''); |
+ computeResult(sourceA, IS_CLIENT, |
+ matcher: isBuildSourceImportExportClosureTask); |
+ expect(outputs[IS_CLIENT], isTrue); |
+ } |
+} |
+ |
+@reflectiveTest |
+class BuildTypeProviderTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ computeResult(AnalysisContextTarget.request, TYPE_PROVIDER, |
+ matcher: isBuildTypeProviderTask); |
+ // validate |
+ TypeProvider typeProvider = outputs[TYPE_PROVIDER]; |
+ expect(typeProvider, isNotNull); |
+ expect(typeProvider.boolType, isNotNull); |
+ expect(typeProvider.intType, isNotNull); |
+ expect(typeProvider.futureType, isNotNull); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ComputeConstantDependenciesTaskTest extends _AbstractDartTaskTest { |
+ Annotation findClassAnnotation(CompilationUnit unit, String className) { |
+ for (CompilationUnitMember member in unit.declarations) { |
+ if (member is ClassDeclaration && member.name.name == className) { |
+ expect(member.metadata, hasLength(1)); |
+ return member.metadata[0]; |
+ } |
+ } |
+ fail('Annotation not found'); |
+ return null; |
+ } |
+ |
+ test_annotation_with_args() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+const x = 1; |
+@D(x) class C {} |
+class D { const D(value); } |
+'''); |
+ // First compute the resolved unit for the source. |
+ LibrarySpecificUnit librarySpecificUnit = |
+ new LibrarySpecificUnit(source, source); |
+ computeResult(librarySpecificUnit, RESOLVED_UNIT1); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT1]; |
+ // Find the elements for x and D's constructor, and the annotation on C. |
+ List<PropertyAccessorElement> accessors = unit.element.accessors; |
+ Element x = accessors |
+ .firstWhere((PropertyAccessorElement accessor) => |
+ accessor.isGetter && accessor.name == 'x') |
+ .variable; |
+ List<ClassElement> types = unit.element.types; |
+ Element constructorForD = |
+ types.firstWhere((ClassElement cls) => cls.name == 'D').constructors[0]; |
+ Annotation annotation = findClassAnnotation(unit, 'C'); |
+ // Now compute the dependencies for the annotation, and check that it is |
+ // the set [x, constructorForD]. |
+ // TODO(paulberry): test librarySource != source |
+ computeResult( |
+ new ConstantEvaluationTarget_Annotation( |
+ context, source, source, annotation), |
+ CONSTANT_DEPENDENCIES, |
+ matcher: isComputeConstantDependenciesTask); |
+ expect( |
+ outputs[CONSTANT_DEPENDENCIES].toSet(), [x, constructorForD].toSet()); |
+ } |
+ |
+ test_annotation_without_args() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+const x = 1; |
+@x class C {} |
+'''); |
+ // First compute the resolved unit for the source. |
+ LibrarySpecificUnit librarySpecificUnit = |
+ new LibrarySpecificUnit(source, source); |
+ computeResult(librarySpecificUnit, RESOLVED_UNIT1); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT1]; |
+ // Find the element for x and the annotation on C. |
+ List<PropertyAccessorElement> accessors = unit.element.accessors; |
+ Element x = accessors |
+ .firstWhere((PropertyAccessorElement accessor) => |
+ accessor.isGetter && accessor.name == 'x') |
+ .variable; |
+ Annotation annotation = findClassAnnotation(unit, 'C'); |
+ // Now compute the dependencies for the annotation, and check that it is |
+ // the list [x]. |
+ computeResult( |
+ new ConstantEvaluationTarget_Annotation( |
+ context, source, source, annotation), |
+ CONSTANT_DEPENDENCIES, |
+ matcher: isComputeConstantDependenciesTask); |
+ expect(outputs[CONSTANT_DEPENDENCIES], [x]); |
+ } |
+ |
+ test_enumConstant() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+enum E {A, B, C} |
+'''); |
+ // First compute the resolved unit for the source. |
+ LibrarySpecificUnit librarySpecificUnit = |
+ new LibrarySpecificUnit(source, source); |
+ computeResult(librarySpecificUnit, RESOLVED_UNIT2); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT2]; |
+ // Find the element for 'A' |
+ EnumDeclaration enumDeclaration = unit.declarations[0]; |
+ EnumConstantDeclaration constantDeclaration = enumDeclaration.constants[0]; |
+ FieldElement constantElement = constantDeclaration.element; |
+ // Now compute the dependencies for the constant and check that there are |
+ // none. |
+ computeResult(constantElement, CONSTANT_DEPENDENCIES, |
+ matcher: isComputeConstantDependenciesTask); |
+ expect(outputs[CONSTANT_DEPENDENCIES], isEmpty); |
+ } |
+ |
+ test_perform() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+const x = y; |
+const y = 1; |
+'''); |
+ // First compute the resolved unit for the source. |
+ LibrarySpecificUnit librarySpecificUnit = |
+ new LibrarySpecificUnit(source, source); |
+ computeResult(librarySpecificUnit, RESOLVED_UNIT1); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT1]; |
+ // Find the elements for the constants x and y. |
+ List<PropertyAccessorElement> accessors = unit.element.accessors; |
+ Element x = accessors |
+ .firstWhere((PropertyAccessorElement accessor) => |
+ accessor.isGetter && accessor.name == 'x') |
+ .variable; |
+ Element y = accessors |
+ .firstWhere((PropertyAccessorElement accessor) => |
+ accessor.isGetter && accessor.name == 'y') |
+ .variable; |
+ // Now compute the dependencies for x, and check that it is the list [y]. |
+ computeResult(x, CONSTANT_DEPENDENCIES, |
+ matcher: isComputeConstantDependenciesTask); |
+ expect(outputs[CONSTANT_DEPENDENCIES], [y]); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ComputeConstantValueTaskTest extends _AbstractDartTaskTest { |
+ EvaluationResultImpl computeClassAnnotation( |
+ Source source, CompilationUnit unit, String className) { |
+ for (CompilationUnitMember member in unit.declarations) { |
+ if (member is ClassDeclaration && member.name.name == className) { |
+ expect(member.metadata, hasLength(1)); |
+ Annotation annotation = member.metadata[0]; |
+ ConstantEvaluationTarget_Annotation target = |
+ new ConstantEvaluationTarget_Annotation( |
+ context, source, source, annotation); |
+ computeResult(target, CONSTANT_VALUE, |
+ matcher: isComputeConstantValueTask); |
+ expect(outputs[CONSTANT_VALUE], same(target)); |
+ EvaluationResultImpl evaluationResult = (annotation.elementAnnotation |
+ as ElementAnnotationImpl).evaluationResult; |
+ return evaluationResult; |
+ } |
+ } |
+ fail('Annotation not found'); |
+ return null; |
+ } |
+ |
+ test_annotation_non_const_constructor() { |
+ // Calling a non-const constructor from an annotation that is illegal, but |
+ // shouldn't crash analysis. |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+class A { |
+ final int i; |
+ A(this.i); |
+} |
+ |
+@A(5) |
+class C {} |
+'''); |
+ // First compute the resolved unit for the source. |
+ CompilationUnit unit = _resolveSource(source); |
+ // Compute the constant value of the annotation on C. |
+ EvaluationResultImpl evaluationResult = |
+ computeClassAnnotation(source, unit, 'C'); |
+ // And check that it has no value stored in it. |
+ expect(evaluationResult, isNotNull); |
+ expect(evaluationResult.value, isNull); |
+ } |
+ |
+ test_annotation_with_args() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+const x = 1; |
+@D(x) class C {} |
+class D { |
+ const D(this.value); |
+ final value; |
+} |
+'''); |
+ // First compute the resolved unit for the source. |
+ CompilationUnit unit = _resolveSource(source); |
+ // Compute the constant value of the annotation on C. |
+ EvaluationResultImpl evaluationResult = |
+ computeClassAnnotation(source, unit, 'C'); |
+ // And check that it has the expected value. |
+ expect(evaluationResult, isNotNull); |
+ expect(evaluationResult.value, isNotNull); |
+ expect(evaluationResult.value.type, isNotNull); |
+ expect(evaluationResult.value.type.name, 'D'); |
+ expect(evaluationResult.value.fields, contains('value')); |
+ expect(evaluationResult.value.fields['value'].intValue, 1); |
+ } |
+ |
+ test_annotation_without_args() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+const x = 1; |
+@x class C {} |
+'''); |
+ // First compute the resolved unit for the source. |
+ CompilationUnit unit = _resolveSource(source); |
+ // Compute the constant value of the annotation on C. |
+ EvaluationResultImpl evaluationResult = |
+ computeClassAnnotation(source, unit, 'C'); |
+ // And check that it has the expected value. |
+ expect(evaluationResult, isNotNull); |
+ expect(evaluationResult.value, isNotNull); |
+ expect(evaluationResult.value.intValue, 1); |
+ } |
+ |
+ test_circular_reference() { |
+ _checkCircularities( |
+ 'x', |
+ ['y'], |
+ ''' |
+const x = y + 1; |
+const y = x + 1; |
+'''); |
+ } |
+ |
+ test_circular_reference_one_element() { |
+ // See dartbug.com/23490. |
+ _checkCircularities('x', [], 'const x = x;'); |
+ } |
+ |
+ test_circular_reference_strongly_connected_component() { |
+ // When there is a circularity, all elements in the strongly connected |
+ // component should be marked as having an error. |
+ _checkCircularities( |
+ 'a', |
+ ['b', 'c', 'd'], |
+ ''' |
+const a = b; |
+const b = c + d; |
+const c = a; |
+const d = a; |
+'''); |
+ } |
+ |
+ test_const_constructor_calls_implicit_super_constructor_implicitly() { |
+ // Note: the situation below is a compile-time error (since the synthetic |
+ // constructor for Base is non-const), but we need to handle it without |
+ // throwing an exception. |
+ EvaluationResultImpl evaluationResult = _computeTopLevelVariableConstValue( |
+ 'x', |
+ ''' |
+class Base {} |
+class Derived extends Base { |
+ const Derived(); |
+} |
+const x = const Derived(); |
+'''); |
+ expect(evaluationResult, isNotNull); |
+ } |
+ |
+ test_dependency() { |
+ EvaluationResultImpl evaluationResult = _computeTopLevelVariableConstValue( |
+ 'x', |
+ ''' |
+const x = y + 1; |
+const y = 1; |
+'''); |
+ expect(evaluationResult, isNotNull); |
+ expect(evaluationResult.value, isNotNull); |
+ expect(evaluationResult.value.intValue, 2); |
+ } |
+ |
+ test_external_const_factory() { |
+ EvaluationResultImpl evaluationResult = _computeTopLevelVariableConstValue( |
+ 'x', |
+ ''' |
+const x = const C.foo(); |
+ |
+class C extends B { |
+ external const factory C.foo(); |
+} |
+ |
+class B {} |
+'''); |
+ expect(evaluationResult, isNotNull); |
+ } |
+ |
+ test_simple_constant() { |
+ EvaluationResultImpl evaluationResult = _computeTopLevelVariableConstValue( |
+ 'x', |
+ ''' |
+const x = 1; |
+'''); |
+ expect(evaluationResult, isNotNull); |
+ expect(evaluationResult.value, isNotNull); |
+ expect(evaluationResult.value.intValue, 1); |
+ } |
+ |
+ void _checkCircularities( |
+ String variableName, List<String> otherVariables, String content) { |
+ // Evaluating the first constant should produce an error. |
+ CompilationUnit unit = _resolveUnit(content); |
+ _expectCircularityError(_evaluateConstant(unit, variableName)); |
+ // And all the other constants involved in the strongly connected component |
+ // should be set to the same error state. |
+ for (String otherVariableName in otherVariables) { |
+ PropertyInducingElement otherVariableElement = |
+ _findVariable(unit, otherVariableName); |
+ _expectCircularityError((otherVariableElement |
+ as TopLevelVariableElementImpl).evaluationResult); |
+ } |
+ } |
+ |
+ EvaluationResultImpl _computeTopLevelVariableConstValue( |
+ String variableName, String content) { |
+ return _evaluateConstant(_resolveUnit(content), variableName); |
+ } |
+ |
+ EvaluationResultImpl _evaluateConstant( |
+ CompilationUnit unit, String variableName) { |
+ // Find the element for the given constant. |
+ PropertyInducingElement variableElement = _findVariable(unit, variableName); |
+ // Now compute the value of the constant. |
+ computeResult(variableElement, CONSTANT_VALUE, |
+ matcher: isComputeConstantValueTask); |
+ expect(outputs[CONSTANT_VALUE], same(variableElement)); |
+ EvaluationResultImpl evaluationResult = |
+ (variableElement as TopLevelVariableElementImpl).evaluationResult; |
+ return evaluationResult; |
+ } |
+ |
+ void _expectCircularityError(EvaluationResultImpl evaluationResult) { |
+ expect(evaluationResult, isNotNull); |
+ expect(evaluationResult.value, isNull); |
+ expect(evaluationResult.errors, hasLength(1)); |
+ expect(evaluationResult.errors[0].errorCode, |
+ CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT); |
+ } |
+ |
+ PropertyInducingElement _findVariable( |
+ CompilationUnit unit, String variableName) { |
+ // Find the element for the given constant. |
+ return unit.element.topLevelVariables.firstWhere( |
+ (TopLevelVariableElement variable) => variable.name == variableName); |
+ } |
+ |
+ CompilationUnit _resolveSource(Source source) { |
+ LibrarySpecificUnit librarySpecificUnit = |
+ new LibrarySpecificUnit(source, source); |
+ computeResult(librarySpecificUnit, RESOLVED_UNIT1); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT1]; |
+ return unit; |
+ } |
+ |
+ CompilationUnit _resolveUnit(String content) => |
+ _resolveSource(newSource('/test.dart', content)); |
+} |
+ |
+@reflectiveTest |
+class ComputeInferableStaticVariableDependenciesTaskTest |
+ extends _AbstractDartTaskTest { |
+ @override |
+ void setUp() { |
+ super.setUp(); |
+ // Variable dependencies are only available in strong mode. |
+ enableStrongMode(); |
+ } |
+ |
+ test_perform() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+const a = b; |
+const b = 0; |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ TopLevelVariableElement elementA = unit.element.topLevelVariables[0]; |
+ TopLevelVariableElement elementB = unit.element.topLevelVariables[1]; |
+ |
+ computeResult(elementA, INFERABLE_STATIC_VARIABLE_DEPENDENCIES, |
+ matcher: isComputeInferableStaticVariableDependenciesTask); |
+ expect(outputs, hasLength(1)); |
+ List<VariableElement> dependencies = |
+ outputs[INFERABLE_STATIC_VARIABLE_DEPENDENCIES]; |
+ expect(dependencies, unorderedEquals([elementB])); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ComputeLibraryCycleTaskTest extends _AbstractDartTaskTest { |
+ @override |
+ void setUp() { |
+ super.setUp(); |
+ enableStrongMode(); |
+ } |
+ |
+ void test_library_cycle_linear() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+''', |
+ '/b.dart': ''' |
+import 'a.dart'; |
+ ''' |
+ }); |
+ List<Map<ResultDescriptor, dynamic>> results = |
+ computeLibraryResultsMap(sources, LIBRARY_CYCLE); |
+ List<LibraryElement> component0 = results[0][LIBRARY_CYCLE]; |
+ List<LibraryElement> component1 = results[1][LIBRARY_CYCLE]; |
+ expect(component0, hasLength(1)); |
+ expect(component1, hasLength(1)); |
+ |
+ List<CompilationUnitElement> units0 = results[0][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units1 = results[1][LIBRARY_CYCLE_UNITS]; |
+ expect(units0, hasLength(1)); |
+ expect(units1, hasLength(1)); |
+ |
+ List<CompilationUnitElement> dep0 = results[0][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep1 = results[1][LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(dep0, hasLength(1)); // dart:core |
+ expect(dep1, hasLength(2)); // dart:core, a.dart |
+ } |
+ |
+ void test_library_cycle_loop() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'c.dart'; |
+''', |
+ '/b.dart': ''' |
+ import 'a.dart'; |
+ ''', |
+ '/c.dart': ''' |
+ import 'b.dart'; |
+ ''' |
+ }); |
+ List<Map<ResultDescriptor, dynamic>> results = |
+ computeLibraryResultsMap(sources, LIBRARY_CYCLE).toList(); |
+ List<LibraryElement> component0 = results[0][LIBRARY_CYCLE]; |
+ List<LibraryElement> component1 = results[1][LIBRARY_CYCLE]; |
+ List<LibraryElement> component2 = results[2][LIBRARY_CYCLE]; |
+ |
+ expect(component0, hasLength(3)); |
+ expect(component1, hasLength(3)); |
+ expect(component2, hasLength(3)); |
+ |
+ List<CompilationUnitElement> units0 = results[0][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units1 = results[1][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units2 = results[2][LIBRARY_CYCLE_UNITS]; |
+ expect(units0, hasLength(3)); |
+ expect(units1, hasLength(3)); |
+ expect(units2, hasLength(3)); |
+ |
+ List<CompilationUnitElement> dep0 = results[0][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep1 = results[1][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep2 = results[2][LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(dep0, hasLength(1)); // dart:core |
+ expect(dep1, hasLength(1)); // dart:core |
+ expect(dep2, hasLength(1)); // dart:core |
+ } |
+ |
+ void test_library_cycle_self_loop() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'a.dart'; |
+''' |
+ }); |
+ List<Map<ResultDescriptor, dynamic>> results = |
+ computeLibraryResultsMap(sources, LIBRARY_CYCLE).toList(); |
+ List<LibraryElement> component0 = results[0][LIBRARY_CYCLE]; |
+ expect(component0, hasLength(1)); |
+ |
+ List<CompilationUnitElement> units0 = results[0][LIBRARY_CYCLE_UNITS]; |
+ expect(units0, hasLength(1)); |
+ |
+ List<CompilationUnitElement> dep0 = results[0][LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(dep0, hasLength(1)); // dart:core |
+ } |
+ |
+ void test_library_cycle_singleton() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+import 'dart:core'; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), LIBRARY_CYCLE); |
+ List<LibraryElement> component = outputs[LIBRARY_CYCLE]; |
+ List<CompilationUnitElement> units = outputs[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> deps = outputs[LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(component, hasLength(1)); |
+ expect(units, hasLength(1)); |
+ expect(deps, hasLength(1)); |
+ } |
+ |
+ void test_library_cycle_tree() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+''', |
+ '/b.dart': ''' |
+ ''', |
+ '/c.dart': ''' |
+ import 'a.dart'; |
+ import 'b.dart'; |
+ ''' |
+ }); |
+ List<Map<ResultDescriptor, dynamic>> results = |
+ computeLibraryResultsMap(sources, LIBRARY_CYCLE); |
+ List<LibraryElement> component0 = results[0][LIBRARY_CYCLE]; |
+ List<LibraryElement> component1 = results[1][LIBRARY_CYCLE]; |
+ List<LibraryElement> component2 = results[2][LIBRARY_CYCLE]; |
+ expect(component0, hasLength(1)); |
+ expect(component1, hasLength(1)); |
+ expect(component2, hasLength(1)); |
+ |
+ List<CompilationUnitElement> units0 = results[0][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units1 = results[1][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units2 = results[2][LIBRARY_CYCLE_UNITS]; |
+ expect(units0, hasLength(1)); |
+ expect(units1, hasLength(1)); |
+ expect(units2, hasLength(1)); |
+ |
+ List<CompilationUnitElement> dep0 = results[0][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep1 = results[1][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep2 = results[2][LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(dep0, hasLength(1)); // dart:core |
+ expect(dep1, hasLength(1)); // dart:core, |
+ expect(dep2, hasLength(3)); // dart:core, a.dart, b.dart |
+ } |
+ |
+ void test_library_double_loop() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+''', |
+ '/b.dart': ''' |
+ import 'a.dart'; |
+ ''', |
+ '/c.dart': ''' |
+ import 'd.dart' as foo; |
+ import 'a.dart' as bar; |
+ export 'b.dart'; |
+ ''', |
+ '/d.dart': ''' |
+ import 'c.dart' as foo; |
+ import 'b.dart' as bar; |
+ export 'a.dart'; |
+ ''' |
+ }); |
+ List<Map<ResultDescriptor, dynamic>> results = |
+ computeLibraryResultsMap(sources, LIBRARY_CYCLE).toList(); |
+ List<LibraryElement> component0 = results[0][LIBRARY_CYCLE]; |
+ List<LibraryElement> component1 = results[1][LIBRARY_CYCLE]; |
+ List<LibraryElement> component2 = results[2][LIBRARY_CYCLE]; |
+ List<LibraryElement> component3 = results[3][LIBRARY_CYCLE]; |
+ |
+ expect(component0, hasLength(2)); |
+ expect(component1, hasLength(2)); |
+ expect(component2, hasLength(2)); |
+ expect(component3, hasLength(2)); |
+ |
+ List<CompilationUnitElement> units0 = results[0][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units1 = results[1][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units2 = results[2][LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units3 = results[3][LIBRARY_CYCLE_UNITS]; |
+ expect(units0, hasLength(2)); |
+ expect(units1, hasLength(2)); |
+ expect(units2, hasLength(2)); |
+ expect(units3, hasLength(2)); |
+ |
+ List<CompilationUnitElement> dep0 = results[0][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep1 = results[1][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep2 = results[2][LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep3 = results[3][LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(dep0, hasLength(1)); // dart:core |
+ expect(dep1, hasLength(1)); // dart:core |
+ expect(dep3, hasLength(3)); // dart:core, a.dart, b.dart |
+ expect(dep3, hasLength(3)); // dart:core, a.dart, b.dart |
+ } |
+ |
+ void test_library_double_loop_parts() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ part 'aa.dart'; |
+ part 'ab.dart'; |
+''', |
+ '/b.dart': ''' |
+ import 'a.dart'; |
+''', |
+ '/aa.dart': ''' |
+''', |
+ '/ab.dart': ''' |
+''', |
+ '/c.dart': ''' |
+ import 'd.dart' as foo; |
+ import 'a.dart' as bar; |
+ export 'b.dart'; |
+''', |
+ '/d.dart': ''' |
+ import 'c.dart' as foo; |
+ import 'b.dart' as bar; |
+ export 'a.dart'; |
+ part 'da.dart'; |
+ part 'db.dart'; |
+''', |
+ '/da.dart': ''' |
+''', |
+ '/db.dart': ''' |
+''' |
+ }); |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[0]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results0 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[1], sources[1]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results1 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[2]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results2 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[3]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results3 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[4], sources[4]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results4 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[5], sources[5]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results5 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[5], sources[6]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results6 = outputs; |
+ computeResult( |
+ new LibrarySpecificUnit(sources[5], sources[7]), LIBRARY_CYCLE); |
+ Map<ResultDescriptor, dynamic> results7 = outputs; |
+ |
+ List<LibraryElement> component0 = results0[LIBRARY_CYCLE]; |
+ List<LibraryElement> component1 = results1[LIBRARY_CYCLE]; |
+ List<LibraryElement> component2 = results2[LIBRARY_CYCLE]; |
+ List<LibraryElement> component3 = results3[LIBRARY_CYCLE]; |
+ List<LibraryElement> component4 = results4[LIBRARY_CYCLE]; |
+ List<LibraryElement> component5 = results5[LIBRARY_CYCLE]; |
+ List<LibraryElement> component6 = results6[LIBRARY_CYCLE]; |
+ List<LibraryElement> component7 = results7[LIBRARY_CYCLE]; |
+ |
+ expect(component0, hasLength(2)); |
+ expect(component1, hasLength(2)); |
+ expect(component2, hasLength(2)); |
+ expect(component3, hasLength(2)); |
+ expect(component4, hasLength(2)); |
+ expect(component5, hasLength(2)); |
+ expect(component6, hasLength(2)); |
+ expect(component7, hasLength(2)); |
+ |
+ List<CompilationUnitElement> units0 = results0[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units1 = results1[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units2 = results2[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units3 = results3[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units4 = results4[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units5 = results5[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units6 = results6[LIBRARY_CYCLE_UNITS]; |
+ List<CompilationUnitElement> units7 = results7[LIBRARY_CYCLE_UNITS]; |
+ expect(units0, hasLength(4)); |
+ expect(units1, hasLength(4)); |
+ expect(units2, hasLength(4)); |
+ expect(units3, hasLength(4)); |
+ expect(units4, hasLength(4)); |
+ expect(units5, hasLength(4)); |
+ expect(units6, hasLength(4)); |
+ expect(units7, hasLength(4)); |
+ |
+ List<CompilationUnitElement> dep0 = results0[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep1 = results1[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep2 = results2[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep3 = results3[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep4 = results4[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep5 = results5[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep6 = results6[LIBRARY_CYCLE_DEPENDENCIES]; |
+ List<CompilationUnitElement> dep7 = results7[LIBRARY_CYCLE_DEPENDENCIES]; |
+ expect(dep0, hasLength(1)); // dart:core |
+ expect(dep1, hasLength(1)); // dart:core |
+ expect(dep2, hasLength(1)); // dart:core |
+ expect(dep3, hasLength(1)); // dart:core |
+ expect(dep4, hasLength(5)); // dart:core, a.dart, aa.dart, ab.dart, b.dart |
+ expect(dep5, hasLength(5)); // dart:core, a.dart, aa.dart, ab.dart, b.dart |
+ expect(dep6, hasLength(5)); // dart:core, a.dart, aa.dart, ab.dart, b.dart |
+ expect(dep7, hasLength(5)); // dart:core, a.dart, aa.dart, ab.dart, b.dart |
+ } |
+} |
+ |
+@reflectiveTest |
+class ContainingLibrariesTaskTest extends _AbstractDartTaskTest { |
+ test_perform_definingCompilationUnit() { |
+ AnalysisTarget library = newSource('/test.dart', 'library test;'); |
+ computeResult(library, INCLUDED_PARTS); |
+ computeResult(library, CONTAINING_LIBRARIES, |
+ matcher: isContainingLibrariesTask); |
+ expect(outputs, hasLength(1)); |
+ List<Source> containingLibraries = outputs[CONTAINING_LIBRARIES]; |
+ expect(containingLibraries, unorderedEquals([library])); |
+ } |
+ |
+ test_perform_partInMultipleLibraries() { |
+ AnalysisTarget library1 = |
+ newSource('/lib1.dart', 'library test; part "part.dart";'); |
+ AnalysisTarget library2 = |
+ newSource('/lib2.dart', 'library test; part "part.dart";'); |
+ AnalysisTarget part = newSource('/part.dart', 'part of test;'); |
+ computeResult(library1, INCLUDED_PARTS); |
+ computeResult(library2, INCLUDED_PARTS); |
+ computeResult(part, SOURCE_KIND); |
+ computeResult(part, CONTAINING_LIBRARIES, |
+ matcher: isContainingLibrariesTask); |
+ expect(outputs, hasLength(1)); |
+ List<Source> containingLibraries = outputs[CONTAINING_LIBRARIES]; |
+ expect(containingLibraries, unorderedEquals([library1, library2])); |
+ } |
+ |
+ test_perform_partInSingleLibrary() { |
+ AnalysisTarget library = |
+ newSource('/lib.dart', 'library test; part "part.dart";'); |
+ AnalysisTarget part = newSource('/part.dart', 'part of test;'); |
+ computeResult(library, INCLUDED_PARTS); |
+ computeResult(part, SOURCE_KIND); |
+ computeResult(part, CONTAINING_LIBRARIES, |
+ matcher: isContainingLibrariesTask); |
+ expect(outputs, hasLength(1)); |
+ List<Source> containingLibraries = outputs[CONTAINING_LIBRARIES]; |
+ expect(containingLibraries, unorderedEquals([library])); |
+ } |
+} |
+ |
+@reflectiveTest |
+class DartErrorsTaskTest extends _AbstractDartTaskTest { |
+ test_perform_definingCompilationUnit() { |
+ AnalysisTarget library = |
+ newSource('/test.dart', 'library test; import "dart:math";'); |
+ computeResult(library, INCLUDED_PARTS); |
+ computeResult(library, DART_ERRORS, matcher: isDartErrorsTask); |
+ expect(outputs, hasLength(1)); |
+ List<AnalysisError> errors = outputs[DART_ERRORS]; |
+ expect(errors, hasLength(1)); |
+ } |
+ |
+ test_perform_partInSingleLibrary() { |
+ AnalysisTarget library = newSource( |
+ '/lib.dart', 'library test; import "dart:math"; part "part.dart";'); |
+ AnalysisTarget part = |
+ newSource('/part.dart', 'part of test; class A extends A {}'); |
+ computeResult(library, INCLUDED_PARTS); |
+ computeResult(library, DART_ERRORS); |
+ computeResult(part, DART_ERRORS, matcher: isDartErrorsTask); |
+ expect(outputs, hasLength(1)); |
+ List<AnalysisError> errors = outputs[DART_ERRORS]; |
+ // This should contain only the errors in the part file, not the ones in the |
+ // library. |
+ expect(errors, hasLength(1)); |
+ } |
+} |
+ |
+@reflectiveTest |
+class EvaluateUnitConstantsTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+class C { |
+ const C(); |
+} |
+ |
+@x |
+f() {} |
+ |
+const x = const C(); |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT, matcher: isEvaluateUnitConstantsTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT]; |
+ CompilationUnitElement unitElement = unit.element; |
+ expect( |
+ (unitElement.types[0].constructors[0] as ConstructorElementImpl) |
+ .isCycleFree, |
+ isTrue); |
+ expect( |
+ (unitElement.functions[0].metadata[0] as ElementAnnotationImpl) |
+ .evaluationResult, |
+ isNotNull); |
+ expect( |
+ (unitElement.topLevelVariables[0] as TopLevelVariableElementImpl) |
+ .evaluationResult, |
+ isNotNull); |
+ } |
+} |
+ |
+@reflectiveTest |
+class GatherUsedImportedElementsTaskTest extends _AbstractDartTaskTest { |
+ UsedImportedElements usedElements; |
+ Set<String> usedElementNames; |
+ |
+ test_perform() { |
+ newSource( |
+ '/a.dart', |
+ r''' |
+library lib_a; |
+class A {} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ r''' |
+library lib_b; |
+class B {} |
+'''); |
+ Source source = newSource( |
+ '/test.dart', |
+ r''' |
+import 'a.dart'; |
+import 'b.dart'; |
+main() { |
+ new A(); |
+}'''); |
+ _computeUsedElements(source); |
+ // validate |
+ expect(usedElementNames, unorderedEquals(['A'])); |
+ } |
+ |
+ void _computeUsedElements(Source source) { |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, USED_IMPORTED_ELEMENTS, |
+ matcher: isGatherUsedImportedElementsTask); |
+ usedElements = outputs[USED_IMPORTED_ELEMENTS]; |
+ usedElementNames = usedElements.elements.map((e) => e.name).toSet(); |
+ } |
+} |
+ |
+@reflectiveTest |
+class GatherUsedLocalElementsTaskTest extends _AbstractDartTaskTest { |
+ UsedLocalElements usedElements; |
+ Set<String> usedElementNames; |
+ |
+ fail_perform_forPart_afterLibraryUpdate() { |
+ Source libSource = newSource( |
+ '/my_lib.dart', |
+ ''' |
+library my_lib; |
+part 'my_part.dart'; |
+foo() => null; |
+class _LocalClass {} |
+'''); |
+ Source partSource = newSource( |
+ '/my_part.dart', |
+ ''' |
+part of my_lib; |
+bar() { |
+ print(_LocalClass); |
+} |
+'''); |
+ AnalysisTarget libTarget = new LibrarySpecificUnit(libSource, libSource); |
+ AnalysisTarget partTarget = new LibrarySpecificUnit(libSource, partSource); |
+ computeResult(libTarget, USED_LOCAL_ELEMENTS); |
+ computeResult(partTarget, USED_LOCAL_ELEMENTS); |
+ // _LocalClass is used in my_part.dart |
+ { |
+ UsedLocalElements usedElements = |
+ analysisCache.getValue(partTarget, USED_LOCAL_ELEMENTS); |
+ expect(usedElements.elements, contains(predicate((Element e) { |
+ return e.displayName == '_LocalClass'; |
+ }))); |
+ } |
+ // change my_lib.dart and recompute |
+ context.setContents( |
+ libSource, |
+ ''' |
+library my_lib; |
+part 'my_part.dart'; |
+String foo() => null; |
+class _LocalClass {} |
+'''); |
+ computeResult(libTarget, USED_LOCAL_ELEMENTS); |
+ computeResult(partTarget, USED_LOCAL_ELEMENTS); |
+ // _LocalClass should still be used in my_part.dart |
+ { |
+ UsedLocalElements usedElements = |
+ analysisCache.getValue(partTarget, USED_LOCAL_ELEMENTS); |
+ expect(usedElements.elements, contains(predicate((Element e) { |
+ return e.displayName == '_LocalClass'; |
+ }))); |
+ } |
+ } |
+ |
+ test_perform_localVariable() { |
+ Source source = newSource( |
+ '/test.dart', |
+ r''' |
+main() { |
+ var v1 = 1; |
+ var v2 = 2; |
+ print(v2); |
+}'''); |
+ _computeUsedElements(source); |
+ // validate |
+ expect(usedElementNames, unorderedEquals(['v2'])); |
+ } |
+ |
+ test_perform_method() { |
+ Source source = newSource( |
+ '/test.dart', |
+ r''' |
+class A { |
+ _m1() {} |
+ _m2() {} |
+} |
+ |
+main(A a, p) { |
+ a._m2(); |
+ p._m3(); |
+} |
+'''); |
+ _computeUsedElements(source); |
+ // validate |
+ expect(usedElementNames, unorderedEquals(['A', 'a', 'p', '_m2'])); |
+ expect(usedElements.members, unorderedEquals(['_m2', '_m3'])); |
+ } |
+ |
+ void _computeUsedElements(Source source) { |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, USED_LOCAL_ELEMENTS, |
+ matcher: isGatherUsedLocalElementsTask); |
+ usedElements = outputs[USED_LOCAL_ELEMENTS]; |
+ usedElementNames = usedElements.elements.map((e) => e.name).toSet(); |
+ } |
+} |
+ |
+@reflectiveTest |
+class GenerateHintsTaskTest extends _AbstractDartTaskTest { |
+ test_perform_bestPractices_missingReturn() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+int main() { |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.MISSING_RETURN]); |
+ } |
+ |
+ test_perform_dart2js() { |
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl(); |
+ options.dart2jsHint = true; |
+ prepareAnalysisContext(options); |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main(p) { |
+ if (p is double) { |
+ print('double'); |
+ } |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.IS_DOUBLE]); |
+ } |
+ |
+ test_perform_deadCode() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main() { |
+ if (false) { |
+ print('how?'); |
+ } |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.DEAD_CODE]); |
+ } |
+ |
+ test_perform_disabled() { |
+ context.analysisOptions = |
+ new AnalysisOptionsImpl.from(context.analysisOptions)..hint = false; |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+int main() { |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertNoErrors(); |
+ } |
+ |
+ test_perform_imports_duplicateImport() { |
+ newSource( |
+ '/a.dart', |
+ r''' |
+library lib_a; |
+class A {} |
+'''); |
+ Source source = newSource( |
+ '/test.dart', |
+ r''' |
+import 'a.dart'; |
+import 'a.dart'; |
+main() { |
+ new A(); |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.DUPLICATE_IMPORT]); |
+ } |
+ |
+ test_perform_imports_unusedImport_one() { |
+ newSource( |
+ '/a.dart', |
+ r''' |
+library lib_a; |
+class A {} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ r''' |
+library lib_b; |
+class B {} |
+'''); |
+ Source source = newSource( |
+ '/test.dart', |
+ r''' |
+import 'a.dart'; |
+import 'b.dart'; |
+main() { |
+ new A(); |
+}'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.UNUSED_IMPORT]); |
+ } |
+ |
+ test_perform_imports_unusedImport_zero() { |
+ newSource( |
+ '/a.dart', |
+ r''' |
+library lib_a; |
+class A {} |
+'''); |
+ Source source = newSource( |
+ '/test.dart', |
+ r''' |
+import 'a.dart'; |
+main() { |
+ new A(); |
+}'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertNoErrors(); |
+ } |
+ |
+ test_perform_overrideVerifier() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+class A {} |
+class B { |
+ @override |
+ m() {} |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes( |
+ <ErrorCode>[HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD]); |
+ } |
+ |
+ test_perform_todo() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main() { |
+ // TODO(developer) foo bar |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[TodoCode.TODO]); |
+ } |
+ |
+ test_perform_unusedLocalElements_class() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+class _A {} |
+class _B {} |
+main() { |
+ new _A(); |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[HintCode.UNUSED_ELEMENT]); |
+ } |
+ |
+ test_perform_unusedLocalElements_localVariable() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main() { |
+ var v = 42; |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener |
+ .assertErrorsWithCodes(<ErrorCode>[HintCode.UNUSED_LOCAL_VARIABLE]); |
+ } |
+ |
+ test_perform_unusedLocalElements_method() { |
+ Source source = newSource( |
+ '/my_lib.dart', |
+ ''' |
+library my_lib; |
+part 'my_part.dart'; |
+class A { |
+ _ma() {} |
+ _mb() {} |
+ _mc() {} |
+} |
+'''); |
+ newSource( |
+ '/my_part.dart', |
+ ''' |
+part of my_lib; |
+ |
+f(A a) { |
+ a._mb(); |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, HINTS, matcher: isGenerateHintsTask); |
+ // validate |
+ _fillErrorListener(HINTS); |
+ errorListener.assertErrorsWithCodes( |
+ <ErrorCode>[HintCode.UNUSED_ELEMENT, HintCode.UNUSED_ELEMENT]); |
+ } |
+} |
+ |
+@reflectiveTest |
+class GenerateLintsTaskTest extends _AbstractDartTaskTest { |
+ void enableLints() { |
+ AnalysisOptionsImpl options = context.analysisOptions; |
+ options.lint = true; |
+ context.analysisOptions = options; |
+ } |
+ |
+ @override |
+ void setUp() { |
+ super.setUp(); |
+ enableLints(); |
+ } |
+ |
+ @override |
+ void tearDown() { |
+ LintGenerator.LINTERS.clear(); |
+ super.tearDown(); |
+ } |
+ |
+ test_camel_case_types() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+class a { } |
+'''); |
+ |
+ LintGenerator.LINTERS.clear(); |
+ LintGenerator.LINTERS.add(new GenerateLintsTaskTest_TestLinter()); |
+ |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, LINTS, matcher: isGenerateLintsTask); |
+ // validate |
+ _fillErrorListener(LINTS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[_testLintCode]); |
+ } |
+} |
+ |
+class GenerateLintsTaskTest_AstVisitor extends SimpleAstVisitor { |
+ Linter linter; |
+ GenerateLintsTaskTest_AstVisitor(this.linter); |
+ |
+ @override |
+ visitClassDeclaration(ClassDeclaration node) { |
+ if (!new RegExp(r'^([_]*)([A-Z]+[a-z0-9]*)+$') |
+ .hasMatch(node.name.toString())) { |
+ linter.reporter.reportErrorForNode(_testLintCode, node, []); |
+ } |
+ } |
+} |
+ |
+class GenerateLintsTaskTest_TestLinter extends Linter { |
+ @override |
+ AstVisitor getVisitor() => new GenerateLintsTaskTest_AstVisitor(this); |
+} |
+ |
+@reflectiveTest |
+class InferInstanceMembersInUnitTaskTest extends _AbstractDartTaskTest { |
+ void test_perform() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+class A { |
+ X f; |
+ Y m(Z x) {} |
+} |
+class B extends A { |
+ var f; |
+ m(x) {} |
+} |
+class X {} |
+class Y {} |
+class Z {} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8, |
+ matcher: isInferInstanceMembersInUnitTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT8]; |
+ VariableDeclaration field = getFieldInClass(unit, 'B', 'f'); |
+ MethodDeclaration method = getMethodInClass(unit, 'B', 'm'); |
+ DartType typeX = getClass(unit, 'X').element.type; |
+ DartType typeY = getClass(unit, 'Y').element.type; |
+ DartType typeZ = getClass(unit, 'Z').element.type; |
+ |
+ expect(field.element.type, typeX); |
+ expect(method.element.returnType, typeY); |
+ expect(method.element.parameters[0].type, typeZ); |
+ } |
+ |
+ void test_perform_cross_library_const() { |
+ enableStrongMode(); |
+ AnalysisTarget firstSource = newSource( |
+ '/first.dart', |
+ ''' |
+library first; |
+ |
+const a = 'hello'; |
+'''); |
+ AnalysisTarget secondSource = newSource( |
+ '/second.dart', |
+ ''' |
+import 'first.dart'; |
+ |
+const b = a; |
+class M { |
+ String c = a; |
+} |
+'''); |
+ computeResult( |
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8, |
+ matcher: isInferInstanceMembersInUnitTask); |
+ CompilationUnit firstUnit = outputs[RESOLVED_UNIT8]; |
+ computeResult( |
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8); |
+ CompilationUnit secondUnit = outputs[RESOLVED_UNIT8]; |
+ |
+ VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a'); |
+ VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b'); |
+ VariableDeclaration variableC = getFieldInClass(secondUnit, 'M', 'c'); |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ expect(variableA.element.type, stringType); |
+ expect(variableB.element.type, stringType); |
+ expect(variableB.initializer.staticType, stringType); |
+ expect(variableC.element.type, stringType); |
+ expect(variableC.initializer.staticType, stringType); |
+ } |
+ |
+ void test_perform_reresolution() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+const topLevel = ''; |
+class C { |
+ String field = topLevel; |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT8]; |
+ VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel'); |
+ VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field'); |
+ VariableElement topLevel = topLevelDecl.name.staticElement; |
+ VariableElement field = fieldDecl.name.staticElement; |
+ |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ expect(topLevel.type, stringType); |
+ expect(field.type, stringType); |
+ expect(fieldDecl.initializer.staticType, stringType); |
+ } |
+} |
+ |
+@reflectiveTest |
+class InferStaticVariableTypesInUnitTaskTest extends _AbstractDartTaskTest { |
+ void test_perform_const_field() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+class M { |
+ static const X = ""; |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6, |
+ matcher: isInferStaticVariableTypesInUnitTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT6]; |
+ VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X'); |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ expect(declaration.element.type, stringType); |
+ } |
+ |
+ void test_perform_nestedDeclarations() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var f = (int x) { |
+ int squared(int value) => value * value; |
+ var xSquared = squared(x); |
+ return xSquared; |
+}; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6, |
+ matcher: isInferStaticVariableTypesInUnitTask); |
+ } |
+ |
+ void test_perform_recursive() { |
+ enableStrongMode(); |
+ AnalysisTarget firstSource = newSource( |
+ '/first.dart', |
+ ''' |
+import 'second.dart'; |
+ |
+var a = new M(); |
+var c = b; |
+'''); |
+ AnalysisTarget secondSource = newSource( |
+ '/second.dart', |
+ ''' |
+import 'first.dart'; |
+ |
+var b = a; |
+class M {} |
+'''); |
+ computeResult( |
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT6, |
+ matcher: isInferStaticVariableTypesInUnitTask); |
+ CompilationUnit firstUnit = outputs[RESOLVED_UNIT6]; |
+ computeResult( |
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT6); |
+ CompilationUnit secondUnit = outputs[RESOLVED_UNIT6]; |
+ |
+ VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a'); |
+ VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b'); |
+ VariableDeclaration variableC = getTopLevelVariable(firstUnit, 'c'); |
+ ClassDeclaration classM = getClass(secondUnit, 'M'); |
+ DartType typeM = classM.element.type; |
+ |
+ expect(variableA.element.type, typeM); |
+ expect(variableB.element.type, typeM); |
+ expect(variableB.initializer.staticType, typeM); |
+ expect(variableC.element.type, typeM); |
+ expect(variableC.initializer.staticType, typeM); |
+ } |
+ |
+ void test_perform_simple() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var X = 1; |
+ |
+var Y = () { |
+ return 1 + X; |
+}; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6, |
+ matcher: isInferStaticVariableTypesInUnitTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT6]; |
+ TopLevelVariableDeclaration declaration = unit.declarations[1]; |
+ FunctionExpression function = |
+ declaration.variables.variables[0].initializer; |
+ BlockFunctionBody body = function.body; |
+ ReturnStatement statement = body.block.statements[0]; |
+ Expression expression = statement.expression; |
+ InterfaceType intType = context.typeProvider.intType; |
+ expect(expression.staticType, intType); |
+ } |
+} |
+ |
+@reflectiveTest |
+class InferStaticVariableTypeTaskTest extends _AbstractDartTaskTest { |
+ void test_getDeclaration_staticField() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+class C { |
+ var field = ''; |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableDeclaration declaration = getFieldInClass(unit, 'C', 'field'); |
+ VariableElement variable = declaration.name.staticElement; |
+ InferStaticVariableTypeTask inferTask = |
+ new InferStaticVariableTypeTask(task.context, variable); |
+ expect(inferTask.getDeclaration(unit), declaration); |
+ } |
+ |
+ void test_getDeclaration_topLevel() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var topLevel = ''; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableDeclaration declaration = getTopLevelVariable(unit, 'topLevel'); |
+ VariableElement variable = declaration.name.staticElement; |
+ InferStaticVariableTypeTask inferTask = |
+ new InferStaticVariableTypeTask(task.context, variable); |
+ expect(inferTask.getDeclaration(unit), declaration); |
+ } |
+ |
+ void test_perform() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test3.dart', |
+ ''' |
+var topLevel3 = ''; |
+class C { |
+ var field3 = topLevel3; |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel3'); |
+ VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field3'); |
+ VariableElement topLevel = topLevelDecl.name.staticElement; |
+ VariableElement field = fieldDecl.name.staticElement; |
+ |
+ computeResult(field, INFERRED_STATIC_VARIABLE, |
+ matcher: isInferStaticVariableTypeTask); |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ expect(topLevel.type, stringType); |
+ expect(field.type, stringType); |
+ expect(fieldDecl.initializer.staticType, stringType); |
+ } |
+ |
+ void test_perform_const() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+const topLevel = "hello"; |
+class C { |
+ var field = topLevel; |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableElement topLevel = |
+ getTopLevelVariable(unit, 'topLevel').name.staticElement; |
+ VariableElement field = |
+ getFieldInClass(unit, 'C', 'field').name.staticElement; |
+ |
+ computeResult(field, INFERRED_STATIC_VARIABLE, |
+ matcher: isInferStaticVariableTypeTask); |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ expect(topLevel.type, stringType); |
+ expect(field.type, stringType); |
+ } |
+ |
+ void test_perform_cycle() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var piFirst = true; |
+var pi = piFirst ? 3.14 : tau / 2; |
+var tau = piFirst ? pi * 2 : 6.28; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableElement piFirst = |
+ getTopLevelVariable(unit, 'piFirst').name.staticElement; |
+ VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement; |
+ VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement; |
+ |
+ computeResult(piFirst, INFERRED_STATIC_VARIABLE, |
+ matcher: isInferStaticVariableTypeTask); |
+ expect(piFirst.type, context.typeProvider.boolType); |
+ expect(pi.type.isDynamic, isTrue); |
+ expect(tau.type.isDynamic, isTrue); |
+ } |
+ |
+ void test_perform_error() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var a = '' / null; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableElement a = getTopLevelVariable(unit, 'a').name.staticElement; |
+ |
+ computeResult(a, INFERRED_STATIC_VARIABLE, |
+ matcher: isInferStaticVariableTypeTask); |
+ expect(a.type.isDynamic, isTrue); |
+ } |
+ |
+ void test_perform_null() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var a = null; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ VariableElement a = getTopLevelVariable(unit, 'a').name.staticElement; |
+ |
+ computeResult(a, INFERRED_STATIC_VARIABLE, |
+ matcher: isInferStaticVariableTypeTask); |
+ expect(a.type.isDynamic, isTrue); |
+ } |
+} |
+ |
+@reflectiveTest |
+class LibraryErrorsReadyTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ Source library = newSource( |
+ '/lib.dart', |
+ r''' |
+library lib; |
+part 'part1.dart'; |
+part 'part2.dart'; |
+X v1; |
+'''); |
+ Source part1 = newSource( |
+ '/part1.dart', |
+ r''' |
+part of lib; |
+X v2; |
+'''); |
+ Source part2 = newSource( |
+ '/part2.dart', |
+ r''' |
+part of lib; |
+X v3; |
+'''); |
+ computeResult(library, LIBRARY_ERRORS_READY, |
+ matcher: isLibraryErrorsReadyTask); |
+ expect(outputs, hasLength(1)); |
+ bool ready = outputs[LIBRARY_ERRORS_READY]; |
+ expect(ready, isTrue); |
+ expect(context.getErrors(library).errors, hasLength(1)); |
+ expect(context.getErrors(part1).errors, hasLength(1)); |
+ expect(context.getErrors(part2).errors, hasLength(1)); |
+ } |
+} |
+ |
+@reflectiveTest |
+class LibraryUnitErrorsTaskTest extends _AbstractDartTaskTest { |
+ test_perform_definingCompilationUnit() { |
+ AnalysisTarget library = |
+ newSource('/test.dart', 'library test; import "dart:math";'); |
+ computeResult( |
+ new LibrarySpecificUnit(library, library), LIBRARY_UNIT_ERRORS, |
+ matcher: isLibraryUnitErrorsTask); |
+ expect(outputs, hasLength(1)); |
+ List<AnalysisError> errors = outputs[LIBRARY_UNIT_ERRORS]; |
+ expect(errors, hasLength(1)); |
+ } |
+ |
+ test_perform_partInSingleLibrary() { |
+ AnalysisTarget library = |
+ newSource('/lib.dart', 'library test; part "part.dart";'); |
+ AnalysisTarget part = newSource('/part.dart', 'part of test;'); |
+ computeResult(new LibrarySpecificUnit(library, part), LIBRARY_UNIT_ERRORS, |
+ matcher: isLibraryUnitErrorsTask); |
+ expect(outputs, hasLength(1)); |
+ List<AnalysisError> errors = outputs[LIBRARY_UNIT_ERRORS]; |
+ expect(errors, hasLength(0)); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ParseDartTaskTest extends _AbstractDartTaskTest { |
+ Source source; |
+ |
+ test_perform() { |
+ _performParseTask(r''' |
+part of lib; |
+class B {}'''); |
+ expect(outputs, hasLength(8)); |
+ expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0)); |
+ expect(outputs[EXPORTED_LIBRARIES], hasLength(0)); |
+ _assertHasCore(outputs[IMPORTED_LIBRARIES], 1); |
+ expect(outputs[INCLUDED_PARTS], hasLength(0)); |
+ expect(outputs[PARSE_ERRORS], hasLength(0)); |
+ expect(outputs[PARSED_UNIT], isNotNull); |
+ expect(outputs[SOURCE_KIND], SourceKind.PART); |
+ expect(outputs[UNITS], hasLength(1)); |
+ } |
+ |
+ test_perform_computeSourceKind_noDirectives_hasContainingLibrary() { |
+ // Parse "lib.dart" to let the context know that "test.dart" is included. |
+ computeResult( |
+ newSource( |
+ '/lib.dart', |
+ r''' |
+library lib; |
+part 'test.dart'; |
+'''), |
+ PARSED_UNIT); |
+ // If there are no the "part of" directive, then it is not a part. |
+ _performParseTask(''); |
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
+ } |
+ |
+ test_perform_computeSourceKind_noDirectives_noContainingLibrary() { |
+ _performParseTask(''); |
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
+ } |
+ |
+ test_perform_doesNotExist() { |
+ _performParseTask(null); |
+ expect(outputs, hasLength(8)); |
+ expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0)); |
+ expect(outputs[EXPORTED_LIBRARIES], hasLength(0)); |
+ _assertHasCore(outputs[IMPORTED_LIBRARIES], 1); |
+ expect(outputs[INCLUDED_PARTS], hasLength(0)); |
+ expect(outputs[PARSE_ERRORS], hasLength(0)); |
+ expect(outputs[PARSED_UNIT], isNotNull); |
+ expect(outputs[SOURCE_KIND], SourceKind.UNKNOWN); |
+ expect(outputs[UNITS], hasLength(1)); |
+ } |
+ |
+ test_perform_invalidDirectives() { |
+ _performParseTask(r''' |
+library lib; |
+import '/does/not/exist.dart'; |
+import '://invaliduri.dart'; |
+export '${a}lib3.dart'; |
+part 'part.dart'; |
+class A {}'''); |
+ expect(outputs, hasLength(8)); |
+ expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1)); |
+ expect(outputs[EXPORTED_LIBRARIES], hasLength(0)); |
+ _assertHasCore(outputs[IMPORTED_LIBRARIES], 2); |
+ expect(outputs[INCLUDED_PARTS], hasLength(1)); |
+ expect(outputs[PARSE_ERRORS], hasLength(2)); |
+ expect(outputs[PARSED_UNIT], isNotNull); |
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
+ expect(outputs[UNITS], hasLength(2)); |
+ } |
+ |
+ test_perform_library() { |
+ _performParseTask(r''' |
+library lib; |
+import 'lib2.dart'; |
+export 'lib3.dart'; |
+part 'part.dart'; |
+class A {'''); |
+ expect(outputs, hasLength(8)); |
+ expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1)); |
+ expect(outputs[EXPORTED_LIBRARIES], hasLength(1)); |
+ _assertHasCore(outputs[IMPORTED_LIBRARIES], 2); |
+ expect(outputs[INCLUDED_PARTS], hasLength(1)); |
+ expect(outputs[PARSE_ERRORS], hasLength(1)); |
+ expect(outputs[PARSED_UNIT], isNotNull); |
+ expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
+ expect(outputs[UNITS], hasLength(2)); |
+ } |
+ |
+ test_perform_library_selfReferenceAsPart() { |
+ _performParseTask(r''' |
+library lib; |
+part 'test.dart'; |
+'''); |
+ expect(outputs[INCLUDED_PARTS], unorderedEquals(<Source>[source])); |
+ } |
+ |
+ test_perform_part() { |
+ _performParseTask(r''' |
+part of lib; |
+class B {}'''); |
+ expect(outputs, hasLength(8)); |
+ expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0)); |
+ expect(outputs[EXPORTED_LIBRARIES], hasLength(0)); |
+ _assertHasCore(outputs[IMPORTED_LIBRARIES], 1); |
+ expect(outputs[INCLUDED_PARTS], hasLength(0)); |
+ expect(outputs[PARSE_ERRORS], hasLength(0)); |
+ expect(outputs[PARSED_UNIT], isNotNull); |
+ expect(outputs[SOURCE_KIND], SourceKind.PART); |
+ expect(outputs[UNITS], hasLength(1)); |
+ } |
+ |
+ void _performParseTask(String content) { |
+ source = newSource('/test.dart', content); |
+ computeResult(source, PARSED_UNIT, matcher: isParseDartTask); |
+ } |
+ |
+ static void _assertHasCore(List<Source> sources, int lenght) { |
+ expect(sources, hasLength(lenght)); |
+ expect(sources, contains(predicate((Source s) { |
+ return s.fullName.endsWith('core.dart'); |
+ }))); |
+ } |
+} |
+ |
+@reflectiveTest |
+class PartiallyResolveUnitReferencesTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ enableStrongMode(); |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+int a = b; |
+int b = c; |
+var d = 0; |
+class A {} |
+class C { |
+ static final f = ''; |
+ var g = 0; |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT5, |
+ matcher: isPartiallyResolveUnitReferencesTask); |
+ // Test the outputs |
+ expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(4)); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ expect(unit, same(outputs[RESOLVED_UNIT5])); |
+ // Test the state of the AST |
+ TopLevelVariableDeclaration a = unit.declarations[0]; |
+ VariableDeclaration variableA = a.variables.variables[0]; |
+ SimpleIdentifier initializer = variableA.initializer; |
+ expect(initializer.staticElement, isNotNull); |
+ } |
+ |
+ test_perform_importExport() { |
+ newSource( |
+ '/a.dart', |
+ ''' |
+library a; |
+class A<T> { |
+ T m() {} |
+} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library b; |
+export 'a.dart'; |
+'''); |
+ Source sourceC = newSource( |
+ '/c.dart', |
+ ''' |
+library c; |
+import 'b.dart'; |
+main() { |
+ new A<int>().m(); |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(sourceC, sourceC), RESOLVED_UNIT5, |
+ matcher: isPartiallyResolveUnitReferencesTask); |
+ // validate |
+ expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(0)); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ expect(unit, isNotNull); |
+ |
+ FunctionDeclaration mainFunction = unit.declarations[0]; |
+ expect(mainFunction.element, isNotNull); |
+ BlockFunctionBody body = mainFunction.functionExpression.body; |
+ List<Statement> statements = body.block.statements; |
+ ExpressionStatement statement = statements[0]; |
+ MethodInvocation invocation = statement.expression; |
+ MethodElement methodElement = invocation.methodName.staticElement; |
+ expect(methodElement, isNull); |
+ } |
+ |
+ test_perform_notResolved() { |
+ enableStrongMode(); |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+int A; |
+f1() { |
+ A; |
+} |
+var f2 = () { |
+ A; |
+ void f3() { |
+ A; |
+ } |
+} |
+class C { |
+ C() { |
+ A; |
+ } |
+ m() { |
+ A; |
+ } |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT5, |
+ matcher: isPartiallyResolveUnitReferencesTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
+ NodeList<CompilationUnitMember> declarations = unit.declarations; |
+ |
+ void expectReference(BlockFunctionBody body, bool isResolved) { |
+ ExpressionStatement statement = body.block.statements[0]; |
+ SimpleIdentifier reference = statement.expression; |
+ expect(reference.staticElement, isResolved ? isNotNull : isNull); |
+ } |
+ // |
+ // The reference to 'A' in 'f1' should not be resolved. |
+ // |
+ FunctionDeclaration f1 = declarations[1]; |
+ expectReference(f1.functionExpression.body, false); |
+ // |
+ // The references to 'A' in 'f2' should be resolved. |
+ // |
+ TopLevelVariableDeclaration f2 = declarations[2]; |
+ FunctionExpression expression2 = f2.variables.variables[0].initializer; |
+ BlockFunctionBody body2 = expression2.body; |
+ expectReference(body2, true); |
+ |
+ FunctionDeclarationStatement statement2 = body2.block.statements[1]; |
+ BlockFunctionBody innerBody = |
+ statement2.functionDeclaration.functionExpression.body; |
+ expectReference(innerBody, true); |
+ // |
+ // The references to 'A' in 'C' should not be resolved. |
+ // |
+ ClassDeclaration c = declarations[3]; |
+ NodeList<ClassMember> members = c.members; |
+ |
+ ConstructorDeclaration constructor = members[0]; |
+ expectReference(constructor.body, false); |
+ |
+ MethodDeclaration method = members[1]; |
+ expectReference(method.body, false); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ResolveInstanceFieldsInUnitTaskTest extends _AbstractDartTaskTest { |
+ @override |
+ void setUp() { |
+ super.setUp(); |
+ enableStrongMode(); |
+ } |
+ |
+ // Test inference of instance fields across units |
+ void test_perform_inference_cross_unit_instance() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ class A { |
+ final a2 = new B().b2; |
+ } |
+ ''', |
+ '/b.dart': ''' |
+ class B { |
+ final b2 = 1; |
+ } |
+ ''', |
+ '/main.dart': ''' |
+ import "a.dart"; |
+ |
+ test1() { |
+ int x = 0; |
+ x = new A().a2; |
+ } |
+ ''' |
+ }); |
+ InterfaceType intType = context.typeProvider.intType; |
+ DartType dynamicType = context.typeProvider.dynamicType; |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7); |
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT7]; |
+ |
+ // B.b2 shoud be resolved on the rhs, but not yet inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), dynamicType, intType); |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7); |
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT7]; |
+ |
+ // B.b2 should now be fully resolved and inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), intType, intType); |
+ |
+ // A.a2 should now be resolved on the rhs, but not yet inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), dynamicType, intType); |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7); |
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT7]; |
+ |
+ // A.a2 should now be fully resolved and inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), intType, intType); |
+ } |
+ |
+ // Test inference of instance fields across units |
+ void test_perform_inference_cross_unit_instance_cyclic() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ class A { |
+ final a2 = new B().b2; |
+ } |
+ ''', |
+ '/b.dart': ''' |
+ import 'a.dart'; |
+ class B { |
+ final b2 = 1; |
+ } |
+ ''', |
+ '/main.dart': ''' |
+ import "a.dart"; |
+ |
+ test1() { |
+ int x = 0; |
+ x = new A().a2; |
+ } |
+ ''' |
+ }); |
+ InterfaceType intType = context.typeProvider.intType; |
+ DartType dynamicType = context.typeProvider.dynamicType; |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7); |
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT7]; |
+ |
+ // A.a2 should now be resolved on the rhs, but not yet inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7); |
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT7]; |
+ |
+ // A.a2 should now be fully resolved and inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
+ } |
+ |
+ // Test inference of instance fields across units with cycles |
+ void test_perform_inference_cross_unit_static_instance() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ class A { |
+ static final a1 = B.b1; |
+ final a2 = new B().b2; |
+ } |
+ ''', |
+ '/b.dart': ''' |
+ class B { |
+ static final b1 = 1; |
+ final b2 = 1; |
+ } |
+ ''', |
+ '/main.dart': ''' |
+ import "a.dart"; |
+ |
+ test1() { |
+ int x = 0; |
+ // inference in A now works. |
+ x = A.a1; |
+ x = new A().a2; |
+ } |
+ ''' |
+ }); |
+ InterfaceType intType = context.typeProvider.intType; |
+ DartType dynamicType = context.typeProvider.dynamicType; |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7); |
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT7]; |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), dynamicType, intType); |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7); |
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT7]; |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), dynamicType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), intType, intType); |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7); |
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT7]; |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), intType, intType); |
+ } |
+ |
+ // Test inference between static and instance fields |
+ void test_perform_inference_instance() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ class A { |
+ final a2 = new B().b2; |
+ } |
+ |
+ class B { |
+ final b2 = 1; |
+ } |
+ ''', |
+ '/main.dart': ''' |
+ import "a.dart"; |
+ |
+ test1() { |
+ int x = 0; |
+ x = new A().a2; |
+ } |
+ ''' |
+ }); |
+ InterfaceType intType = context.typeProvider.intType; |
+ DartType dynamicType = context.typeProvider.dynamicType; |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7); |
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT7]; |
+ |
+ // A.a2 should now be resolved on the rhs, but not yet inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
+ |
+ // B.b2 shoud be resolved on the rhs, but not yet inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "B", "b2"), dynamicType, intType); |
+ |
+ computeResult( |
+ new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7); |
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT7]; |
+ |
+ // A.a2 should now be fully resolved and inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
+ |
+ // B.b2 should now be fully resolved and inferred. |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "B", "b2"), intType, intType); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ResolveLibraryTypeNamesTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ Source sourceLib = newSource( |
+ '/my_lib.dart', |
+ ''' |
+library my_lib; |
+part 'my_part.dart'; |
+class A {} |
+class B extends A {} |
+'''); |
+ newSource( |
+ '/my_part.dart', |
+ ''' |
+part of my_lib; |
+class C extends A {} |
+'''); |
+ computeResult(sourceLib, LIBRARY_ELEMENT5, |
+ matcher: isResolveLibraryTypeNamesTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT5]; |
+ { |
+ ClassElement classB = library.getType('B'); |
+ expect(classB.supertype.displayName, 'A'); |
+ } |
+ { |
+ ClassElement classC = library.getType('C'); |
+ expect(classC.supertype.displayName, 'A'); |
+ } |
+ } |
+ |
+ test_perform_external() { |
+ Source sourceA = newSource( |
+ '/a.dart', |
+ ''' |
+library a; |
+import 'b.dart'; |
+class A extends B {} |
+'''); |
+ newSource( |
+ '/b.dart', |
+ ''' |
+library b; |
+class B {} |
+'''); |
+ // The reference A to B should be resolved, but there's no requirement that |
+ // the full class hierarchy be resolved. |
+ computeResult(sourceA, LIBRARY_ELEMENT5, |
+ matcher: isResolveLibraryTypeNamesTask); |
+ // validate |
+ LibraryElement library = outputs[LIBRARY_ELEMENT5]; |
+ { |
+ ClassElement clazz = library.getType('A'); |
+ expect(clazz.displayName, 'A'); |
+ clazz = clazz.supertype.element; |
+ expect(clazz.displayName, 'B'); |
+ } |
+ } |
+} |
+ |
+@reflectiveTest |
+class ResolveUnitTaskTest extends _AbstractDartTaskTest { |
+ void test_perform() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+void f() { |
+ var c = new C(); |
+ c.m(); |
+} |
+class C { |
+ void m() { |
+ f(); |
+ } |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9, |
+ matcher: isResolveUnitTask); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ |
+ FunctionDeclaration f = unit.declarations[0]; |
+ _assertResolved(f.functionExpression.body); |
+ |
+ MethodDeclaration m = (unit.declarations[1] as ClassDeclaration).members[0]; |
+ _assertResolved(m.body); |
+ |
+ expect(outputs[RESOLVE_UNIT_ERRORS], hasLength(0)); |
+ } |
+ |
+ void _assertResolved(FunctionBody body) { |
+ ResolutionVerifier verifier = new ResolutionVerifier(); |
+ body.accept(verifier); |
+ verifier.assertResolved(); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ResolveUnitTypeNamesTaskTest extends _AbstractDartTaskTest { |
+ test_perform() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+class A {} |
+class B extends A {} |
+int f(String p) => p.length; |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT3, matcher: isResolveUnitTypeNamesTask); |
+ // validate |
+ CompilationUnit unit = outputs[RESOLVED_UNIT3]; |
+ { |
+ ClassDeclaration nodeA = unit.declarations[0]; |
+ ClassDeclaration nodeB = unit.declarations[1]; |
+ DartType extendsType = nodeB.extendsClause.superclass.type; |
+ expect(extendsType, nodeA.element.type); |
+ } |
+ { |
+ FunctionDeclaration functionNode = unit.declarations[2]; |
+ DartType returnType = functionNode.returnType.type; |
+ List<FormalParameter> parameters = |
+ functionNode.functionExpression.parameters.parameters; |
+ expect(returnType.displayName, 'int'); |
+ expect(parameters[0].element.type.displayName, 'String'); |
+ } |
+ } |
+ |
+ test_perform_errors() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+NoSuchClass f() => null; |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVE_TYPE_NAMES_ERRORS, |
+ matcher: isResolveUnitTypeNamesTask); |
+ // validate |
+ _fillErrorListener(RESOLVE_TYPE_NAMES_ERRORS); |
+ errorListener |
+ .assertErrorsWithCodes(<ErrorCode>[StaticWarningCode.UNDEFINED_CLASS]); |
+ } |
+ |
+ test_perform_typedef() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+typedef int F(G g); |
+typedef String G(int p); |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT3, matcher: isResolveUnitTypeNamesTask); |
+ // validate |
+ CompilationUnit unit = outputs[RESOLVED_UNIT3]; |
+ FunctionTypeAlias nodeF = unit.declarations[0]; |
+ FunctionTypeAlias nodeG = unit.declarations[1]; |
+ { |
+ FormalParameter parameter = nodeF.parameters.parameters[0]; |
+ DartType parameterType = parameter.element.type; |
+ Element returnTypeElement = nodeF.returnType.type.element; |
+ expect(returnTypeElement.displayName, 'int'); |
+ expect(parameterType.element, nodeG.element); |
+ } |
+ { |
+ FormalParameter parameter = nodeG.parameters.parameters[0]; |
+ DartType parameterType = parameter.element.type; |
+ expect(nodeG.returnType.type.element.displayName, 'String'); |
+ expect(parameterType.element.displayName, 'int'); |
+ } |
+ } |
+ |
+ test_perform_typedef_errors() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+typedef int F(NoSuchType p); |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVE_TYPE_NAMES_ERRORS, |
+ matcher: isResolveUnitTypeNamesTask); |
+ // validate |
+ _fillErrorListener(RESOLVE_TYPE_NAMES_ERRORS); |
+ errorListener |
+ .assertErrorsWithCodes(<ErrorCode>[StaticWarningCode.UNDEFINED_CLASS]); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ResolveVariableReferencesTaskTest extends _AbstractDartTaskTest { |
+ /** |
+ * Verify that the mutated states of the given [variable] correspond to the |
+ * [mutatedInClosure] and [mutatedInScope] matchers. |
+ */ |
+ void expectMutated(VariableElement variable, Matcher mutatedInClosure, |
+ Matcher mutatedInScope) { |
+ expect(variable.isPotentiallyMutatedInClosure, mutatedInClosure); |
+ expect(variable.isPotentiallyMutatedInScope, mutatedInScope); |
+ } |
+ |
+ test_perform_buildClosureLibraryElements() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main() { |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT4, |
+ matcher: isResolveVariableReferencesTask); |
+ } |
+ |
+ test_perform_local() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main() { |
+ var v1 = 1; |
+ var v2 = 1; |
+ var v3 = 1; |
+ var v4 = 1; |
+ v2 = 2; |
+ v4 = 2; |
+ localFunction() { |
+ v3 = 3; |
+ v4 = 3; |
+ } |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT4, |
+ matcher: isResolveVariableReferencesTask); |
+ // validate |
+ CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
+ FunctionElement main = unit.element.functions[0]; |
+ expectMutated(main.localVariables[0], isFalse, isFalse); |
+ expectMutated(main.localVariables[1], isFalse, isTrue); |
+ expectMutated(main.localVariables[2], isTrue, isTrue); |
+ expectMutated(main.localVariables[3], isTrue, isTrue); |
+ } |
+ |
+ test_perform_parameter() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main(p1, p2, p3, p4) { |
+ p2 = 2; |
+ p4 = 2; |
+ localFunction() { |
+ p3 = 3; |
+ p4 = 3; |
+ } |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, RESOLVED_UNIT4, |
+ matcher: isResolveVariableReferencesTask); |
+ // validate |
+ CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
+ FunctionElement main = unit.element.functions[0]; |
+ expectMutated(main.parameters[0], isFalse, isFalse); |
+ expectMutated(main.parameters[1], isFalse, isTrue); |
+ expectMutated(main.parameters[2], isTrue, isTrue); |
+ expectMutated(main.parameters[3], isTrue, isTrue); |
+ } |
+} |
+ |
+@reflectiveTest |
+class ScanDartTaskTest extends _AbstractDartTaskTest { |
+ test_perform_errors() { |
+ _performScanTask('import "'); |
+ expect(outputs, hasLength(3)); |
+ expect(outputs[LINE_INFO], isNotNull); |
+ expect(outputs[SCAN_ERRORS], hasLength(1)); |
+ expect(outputs[TOKEN_STREAM], isNotNull); |
+ } |
+ |
+ test_perform_noErrors() { |
+ _performScanTask('class A {}'); |
+ expect(outputs, hasLength(3)); |
+ expect(outputs[LINE_INFO], isNotNull); |
+ expect(outputs[SCAN_ERRORS], hasLength(0)); |
+ expect(outputs[TOKEN_STREAM], isNotNull); |
+ } |
+ |
+ test_perform_script() { |
+ String scriptContent = ''' |
+ void buttonPressed() { |
+ '''; |
+ String htmlContent = ''' |
+<!DOCTYPE html> |
+<html> |
+ <head> |
+ <title>test page</title> |
+ <script type='application/dart'>$scriptContent</script> |
+ </head> |
+ <body>Test</body> |
+</html> |
+'''; |
+ Source source = newSource('/test.html', htmlContent); |
+ DartScript script = |
+ new DartScript(source, [new ScriptFragment(97, 5, 36, scriptContent)]); |
+ |
+ computeResult(script, TOKEN_STREAM, matcher: isScanDartTask); |
+ expect(outputs[LINE_INFO], isNotNull); |
+ expect(outputs[SCAN_ERRORS], isEmpty); |
+ Token tokenStream = outputs[TOKEN_STREAM]; |
+ expect(tokenStream, isNotNull); |
+ expect(tokenStream.lexeme, 'void'); |
+ } |
+ |
+ void _performScanTask(String content) { |
+ AnalysisTarget target = newSource('/test.dart', content); |
+ computeResult(target, TOKEN_STREAM, matcher: isScanDartTask); |
+ } |
+} |
+ |
+@reflectiveTest |
+class StrongModeInferenceTest extends _AbstractDartTaskTest { |
+ @override |
+ void setUp() { |
+ super.setUp(); |
+ enableStrongMode(); |
+ } |
+ |
+ // Check that even within a static variable cycle, inferred |
+ // types get propagated to the members of the cycle. |
+ void test_perform_cycle() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+var piFirst = true; |
+var pi = piFirst ? 3.14 : tau / 2; |
+var tau = piFirst ? pi * 2 : 6.28; |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ VariableElement piFirst = |
+ getTopLevelVariable(unit, 'piFirst').name.staticElement; |
+ VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement; |
+ VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement; |
+ Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer |
+ as ConditionalExpression).condition; |
+ |
+ expect(piFirstUse.staticType, context.typeProvider.boolType); |
+ expect(piFirst.type, context.typeProvider.boolType); |
+ expect(pi.type.isDynamic, isTrue); |
+ expect(tau.type.isDynamic, isTrue); |
+ } |
+ |
+ void test_perform_inference_cross_unit_cyclic() { |
+ AnalysisTarget firstSource = newSource( |
+ '/a.dart', |
+ ''' |
+ import 'test.dart'; |
+ var x = 2; |
+ class A { static var x = 2; } |
+'''); |
+ AnalysisTarget secondSource = newSource( |
+ '/test.dart', |
+ ''' |
+ import 'a.dart'; |
+ var y = x; |
+ class B { static var y = A.x; } |
+ |
+ test1() { |
+ int t = 3; |
+ t = x; |
+ t = y; |
+ t = A.x; |
+ t = B.y; |
+ } |
+'''); |
+ computeResult( |
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9); |
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT9]; |
+ computeResult( |
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9); |
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit1, "x"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "A", "x"), intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit2, "y"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit2, "B", "y"), intType, intType); |
+ |
+ List<Statement> statements = |
+ getStatementsInTopLevelFunction(unit2, "test1"); |
+ |
+ assertAssignmentStatementTypes(statements[1], intType, intType); |
+ assertAssignmentStatementTypes(statements[2], intType, intType); |
+ assertAssignmentStatementTypes(statements[3], intType, intType); |
+ assertAssignmentStatementTypes(statements[4], intType, intType); |
+ } |
+ |
+ // Test that local variables in method bodies are inferred appropriately |
+ void test_perform_inference_cross_unit_instance() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ class A { |
+ final a2 = new B().b2; |
+ } |
+ ''', |
+ '/b.dart': ''' |
+ class B { |
+ final b2 = 1; |
+ } |
+ ''', |
+ '/main.dart': ''' |
+ import "a.dart"; |
+ |
+ test1() { |
+ int x = 0; |
+ x = new A().a2; |
+ } |
+ ''' |
+ }); |
+ List<dynamic> units = |
+ computeLibraryResults(sources, RESOLVED_UNIT9).toList(); |
+ CompilationUnit unit0 = units[0]; |
+ CompilationUnit unit1 = units[1]; |
+ CompilationUnit unit2 = units[2]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), intType, intType); |
+ |
+ List<Statement> statements = |
+ getStatementsInTopLevelFunction(unit2, "test1"); |
+ |
+ assertAssignmentStatementTypes(statements[1], intType, intType); |
+ } |
+ |
+ // Test inference interactions between local variables and fields |
+ void test_perform_inference_cross_unit_instance_member() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ var bar = new B(); |
+ void foo() { |
+ String x = bar.f.z; |
+ } |
+ ''', |
+ '/b.dart': ''' |
+ class C { |
+ var z = 3; |
+ } |
+ |
+ class B { |
+ var f = new C(); |
+ } |
+ ''', |
+ '/c.dart': ''' |
+ import 'b.dart'; |
+ var bar = new B(); |
+ void foo() { |
+ String x = bar.f.z; |
+ } |
+ ''' |
+ }); |
+ List<dynamic> units = |
+ computeLibraryResults(sources, RESOLVED_UNIT9).toList(); |
+ CompilationUnit unit0 = units[0]; |
+ CompilationUnit unit1 = units[1]; |
+ CompilationUnit unit2 = units[2]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ assertVariableDeclarationStatementTypes( |
+ getStatementsInTopLevelFunction(unit0, "foo")[0], stringType, intType); |
+ assertVariableDeclarationStatementTypes( |
+ getStatementsInTopLevelFunction(unit2, "foo")[0], stringType, intType); |
+ } |
+ |
+ // Test inference interactions between local variables and top level |
+ // variables |
+ void test_perform_inference_cross_unit_non_cyclic() { |
+ AnalysisTarget firstSource = newSource( |
+ '/a.dart', |
+ ''' |
+ var x = 2; |
+ class A { static var x = 2; } |
+'''); |
+ AnalysisTarget secondSource = newSource( |
+ '/test.dart', |
+ ''' |
+ import 'a.dart'; |
+ var y = x; |
+ class B { static var y = A.x; } |
+ |
+ test1() { |
+ x = /*severe:StaticTypeError*/"hi"; |
+ y = /*severe:StaticTypeError*/"hi"; |
+ A.x = /*severe:StaticTypeError*/"hi"; |
+ B.y = /*severe:StaticTypeError*/"hi"; |
+ } |
+'''); |
+ computeResult( |
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9); |
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT9]; |
+ computeResult( |
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9); |
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit1, "x"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "A", "x"), intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit2, "y"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit2, "B", "y"), intType, intType); |
+ |
+ List<Statement> statements = |
+ getStatementsInTopLevelFunction(unit2, "test1"); |
+ |
+ assertAssignmentStatementTypes(statements[0], intType, stringType); |
+ assertAssignmentStatementTypes(statements[1], intType, stringType); |
+ } |
+ |
+ // Test that inference does not propagate from null |
+ void test_perform_inference_cross_unit_static_instance() { |
+ List<Source> sources = newSources({ |
+ '/a.dart': ''' |
+ import 'b.dart'; |
+ class A { |
+ static final a1 = B.b1; |
+ final a2 = new B().b2; |
+ } |
+ ''', |
+ '/b.dart': ''' |
+ class B { |
+ static final b1 = 1; |
+ final b2 = 1; |
+ } |
+ ''', |
+ '/main.dart': ''' |
+ import "a.dart"; |
+ |
+ test1() { |
+ int x = 0; |
+ // inference in A now works. |
+ x = A.a1; |
+ x = new A().a2; |
+ } |
+ ''' |
+ }); |
+ List<dynamic> units = |
+ computeLibraryResults(sources, RESOLVED_UNIT9).toList(); |
+ CompilationUnit unit0 = units[0]; |
+ CompilationUnit unit1 = units[1]; |
+ CompilationUnit unit2 = units[2]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit0, "A", "a2"), intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b1"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit1, "B", "b2"), intType, intType); |
+ |
+ List<Statement> statements = |
+ getStatementsInTopLevelFunction(unit2, "test1"); |
+ |
+ assertAssignmentStatementTypes(statements[1], intType, intType); |
+ assertAssignmentStatementTypes(statements[2], intType, intType); |
+ } |
+ |
+ // Test inference across units (non-cyclic) |
+ void test_perform_inference_local_variables() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+ test() { |
+ int x = 3; |
+ x = "hi"; |
+ var y = 3; |
+ y = "hi"; |
+ } |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test"); |
+ |
+ assertVariableDeclarationStatementTypes(statements[0], intType, intType); |
+ assertAssignmentStatementTypes(statements[1], intType, stringType); |
+ assertVariableDeclarationStatementTypes(statements[2], intType, intType); |
+ assertAssignmentStatementTypes(statements[3], intType, stringType); |
+ } |
+ |
+ // Test inference across units (cyclic) |
+ void test_perform_inference_local_variables_fields() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+ class A { |
+ int x = 0; |
+ |
+ test1() { |
+ var a = x; |
+ a = "hi"; |
+ a = 3; |
+ var b = y; |
+ b = "hi"; |
+ b = 4; |
+ var c = z; |
+ c = "hi"; |
+ c = 4; |
+ } |
+ |
+ int y; // field def after use |
+ final z = 42; // should infer `int` |
+ } |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ List<Statement> statements = getStatementsInMethod(unit, "A", "test1"); |
+ |
+ assertVariableDeclarationStatementTypes(statements[0], intType, intType); |
+ assertAssignmentStatementTypes(statements[1], intType, stringType); |
+ assertAssignmentStatementTypes(statements[2], intType, intType); |
+ |
+ assertVariableDeclarationStatementTypes(statements[3], intType, intType); |
+ assertAssignmentStatementTypes(statements[4], intType, stringType); |
+ assertAssignmentStatementTypes(statements[5], intType, intType); |
+ |
+ assertVariableDeclarationStatementTypes(statements[6], intType, intType); |
+ assertAssignmentStatementTypes(statements[7], intType, stringType); |
+ assertAssignmentStatementTypes(statements[8], intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit, "A", "x"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit, "A", "z"), intType, intType); |
+ } |
+ |
+ // Test inference of instance fields across units |
+ void test_perform_inference_local_variables_topLevel() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+ int x = 0; |
+ |
+ test1() { |
+ var a = x; |
+ a = /*severe:StaticTypeError*/"hi"; |
+ a = 3; |
+ var b = y; |
+ b = /*severe:StaticTypeError*/"hi"; |
+ b = 4; |
+ var c = z; |
+ c = /*severe:StaticTypeError*/"hi"; |
+ c = 4; |
+ } |
+ |
+ int y = 0; // field def after use |
+ final z = 42; // should infer `int` |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1"); |
+ |
+ assertVariableDeclarationStatementTypes(statements[0], intType, intType); |
+ assertAssignmentStatementTypes(statements[1], intType, stringType); |
+ assertAssignmentStatementTypes(statements[2], intType, intType); |
+ |
+ assertVariableDeclarationStatementTypes(statements[3], intType, intType); |
+ assertAssignmentStatementTypes(statements[4], intType, stringType); |
+ assertAssignmentStatementTypes(statements[5], intType, intType); |
+ |
+ assertVariableDeclarationStatementTypes(statements[6], intType, intType); |
+ assertAssignmentStatementTypes(statements[7], intType, stringType); |
+ assertAssignmentStatementTypes(statements[8], intType, intType); |
+ |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit, "x"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit, "y"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit, "z"), intType, intType); |
+ } |
+ |
+ // Test inference between static and instance fields |
+ void test_perform_inference_null() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+ var x = null; |
+ var y = 3; |
+ class A { |
+ static var x = null; |
+ static var y = 3; |
+ |
+ var x2 = null; |
+ var y2 = 3; |
+ } |
+ |
+ test() { |
+ x = "hi"; |
+ y = /*severe:StaticTypeError*/"hi"; |
+ A.x = "hi"; |
+ A.y = /*severe:StaticTypeError*/"hi"; |
+ new A().x2 = "hi"; |
+ new A().y2 = /*severe:StaticTypeError*/"hi"; |
+ } |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ DartType bottomType = context.typeProvider.bottomType; |
+ DartType dynamicType = context.typeProvider.dynamicType; |
+ |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit, "x"), dynamicType, bottomType); |
+ assertVariableDeclarationTypes( |
+ getTopLevelVariable(unit, "y"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit, "A", "x"), dynamicType, bottomType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit, "A", "y"), intType, intType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit, "A", "x2"), dynamicType, bottomType); |
+ assertVariableDeclarationTypes( |
+ getFieldInClass(unit, "A", "y2"), intType, intType); |
+ |
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test"); |
+ |
+ assertAssignmentStatementTypes(statements[0], dynamicType, stringType); |
+ assertAssignmentStatementTypes(statements[1], intType, stringType); |
+ assertAssignmentStatementTypes(statements[2], dynamicType, stringType); |
+ assertAssignmentStatementTypes(statements[3], intType, stringType); |
+ assertAssignmentStatementTypes(statements[4], dynamicType, stringType); |
+ assertAssignmentStatementTypes(statements[5], intType, stringType); |
+ } |
+ |
+ // Test inference between fields and method bodies |
+ void test_perform_local_explicit_disabled() { |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+ test() { |
+ int x = 3; |
+ x = "hi"; |
+ } |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9); |
+ CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
+ |
+ InterfaceType intType = context.typeProvider.intType; |
+ InterfaceType stringType = context.typeProvider.stringType; |
+ |
+ List<Statement> statements = getStatementsInTopLevelFunction(unit, "test"); |
+ VariableDeclaration decl = |
+ (statements[0] as VariableDeclarationStatement).variables.variables[0]; |
+ expect(decl.element.type, intType); |
+ expect(decl.initializer.staticType, intType); |
+ |
+ ExpressionStatement statement = statements[1]; |
+ AssignmentExpression assgn = statement.expression; |
+ expect(assgn.leftHandSide.staticType, intType); |
+ expect(assgn.rightHandSide.staticType, stringType); |
+ } |
+} |
+ |
+@reflectiveTest |
+class VerifyUnitTaskTest extends _AbstractDartTaskTest { |
+ test_perform_constantError() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main(int p) { |
+ const v = p; |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
+ // validate |
+ _fillErrorListener(VERIFY_ERRORS); |
+ errorListener.assertErrorsWithCodes(<ErrorCode>[ |
+ CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE |
+ ]); |
+ } |
+ |
+ test_perform_directiveError() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+import 'no-such-file.dart'; |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
+ // validate |
+ _fillErrorListener(VERIFY_ERRORS); |
+ errorListener.assertErrorsWithCodes( |
+ <ErrorCode>[CompileTimeErrorCode.URI_DOES_NOT_EXIST]); |
+ } |
+ |
+ void test_perform_reresolution() { |
+ enableStrongMode(); |
+ AnalysisTarget source = newSource( |
+ '/test.dart', |
+ ''' |
+const topLevel = 3; |
+class C { |
+ String field = topLevel; |
+} |
+'''); |
+ computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS); |
+ // validate |
+ _fillErrorListener(VERIFY_ERRORS); |
+ errorListener.assertErrorsWithCodes( |
+ <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]); |
+ } |
+ |
+ test_perform_verifyError() { |
+ Source source = newSource( |
+ '/test.dart', |
+ ''' |
+main() { |
+ if (42) { |
+ print('Not bool!'); |
+ } |
+} |
+'''); |
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
+ computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
+ // validate |
+ _fillErrorListener(VERIFY_ERRORS); |
+ errorListener.assertErrorsWithCodes( |
+ <ErrorCode>[StaticTypeWarningCode.NON_BOOL_CONDITION]); |
+ } |
+} |
+ |
+class _AbstractDartTaskTest extends AbstractContextTest { |
+ Source emptySource; |
+ |
+ GatheringErrorListener errorListener = new GatheringErrorListener(); |
+ |
+ void assertAssignmentStatementTypes( |
+ Statement stmt, DartType leftType, DartType rightType) { |
+ AssignmentExpression assgn = (stmt as ExpressionStatement).expression; |
+ expect(assgn.leftHandSide.staticType, leftType); |
+ expect(assgn.rightHandSide.staticType, rightType); |
+ } |
+ |
+ void assertIsInvalid(AnalysisTarget target, ResultDescriptor descriptor) { |
+ CacheEntry entry = context.getCacheEntry(target); |
+ expect(entry.isInvalid(descriptor), isTrue); |
+ } |
+ |
+ void assertIsValid(AnalysisTarget target, ResultDescriptor descriptor) { |
+ CacheEntry entry = context.getCacheEntry(target); |
+ expect(entry.isValid(descriptor), isTrue); |
+ } |
+ |
+ void assertSameResults(List<ResultDescriptor> descriptors) { |
+ descriptors.forEach((descriptor) { |
+ var oldResult = oldOutputs[descriptor]; |
+ var newResult = outputs[descriptor]; |
+ expect(newResult, same(oldResult), reason: descriptor.name); |
+ }); |
+ } |
+ |
+ void assertVariableDeclarationStatementTypes( |
+ Statement stmt, DartType varType, DartType initializerType) { |
+ VariableDeclaration decl = |
+ (stmt as VariableDeclarationStatement).variables.variables[0]; |
+ assertVariableDeclarationTypes(decl, varType, initializerType); |
+ } |
+ |
+ void assertVariableDeclarationTypes( |
+ VariableDeclaration decl, DartType varType, DartType initializerType) { |
+ expect(decl.element.type, varType); |
+ expect(decl.initializer.staticType, initializerType); |
+ } |
+ |
+ List<dynamic> computeLibraryResults( |
+ List<Source> sources, ResultDescriptor result, |
+ {isInstanceOf matcher: null}) { |
+ dynamic compute(Source source) { |
+ computeResult(new LibrarySpecificUnit(source, source), result, |
+ matcher: matcher); |
+ return outputs[result]; |
+ } |
+ return sources.map(compute).toList(); |
+ } |
+ |
+ List<Map<ResultDescriptor, dynamic>> computeLibraryResultsMap( |
+ List<Source> sources, ResultDescriptor result, |
+ {isInstanceOf matcher: null}) { |
+ Map<ResultDescriptor, dynamic> compute(Source source) { |
+ computeResult(new LibrarySpecificUnit(source, source), result, |
+ matcher: matcher); |
+ return outputs; |
+ } |
+ return sources.map(compute).toList(); |
+ } |
+ |
+ /** |
+ * Create a script object with a single fragment containing the given |
+ * [scriptContent]. |
+ */ |
+ DartScript createScript(String scriptContent) { |
+ String htmlContent = ''' |
+<!DOCTYPE html> |
+<html> |
+ <head> |
+ <title>test page</title> |
+ <script type='application/dart'>$scriptContent</script> |
+ </head> |
+ <body>Test</body> |
+</html> |
+'''; |
+ Source source = newSource('/test.html', htmlContent); |
+ return new DartScript( |
+ source, [new ScriptFragment(97, 5, 36, scriptContent)]); |
+ } |
+ |
+ /** |
+ * Enable strong mode in the current analysis context. |
+ */ |
+ void enableStrongMode() { |
+ AnalysisOptionsImpl options = context.analysisOptions; |
+ options.strongMode = true; |
+ context.analysisOptions = options; |
+ } |
+ |
+ /** |
+ * Return the declaration of the class with the given [className] in the given |
+ * compilation [unit]. |
+ */ |
+ ClassDeclaration getClass(CompilationUnit unit, String className) { |
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations; |
+ for (CompilationUnitMember unitMember in unitMembers) { |
+ if (unitMember is ClassDeclaration && unitMember.name.name == className) { |
+ return unitMember; |
+ } |
+ } |
+ fail('No class named $className in ${unit.element.source}'); |
+ return null; |
+ } |
+ |
+ /** |
+ * Return the declaration of the field with the given [fieldName] in the class |
+ * with the given [className] in the given compilation [unit]. |
+ */ |
+ VariableDeclaration getFieldInClass( |
+ CompilationUnit unit, String className, String fieldName) { |
+ ClassDeclaration unitMember = getClass(unit, className); |
+ NodeList<ClassMember> classMembers = unitMember.members; |
+ for (ClassMember classMember in classMembers) { |
+ if (classMember is FieldDeclaration) { |
+ NodeList<VariableDeclaration> fields = classMember.fields.variables; |
+ for (VariableDeclaration field in fields) { |
+ if (field.name.name == fieldName) { |
+ return field; |
+ } |
+ } |
+ } |
+ } |
+ fail('No field named $fieldName in $className'); |
+ return null; |
+ } |
+ |
+ /** |
+ * Return the declaration of the method with the given [methodName] in the |
+ * class with the given [className] in the given compilation [unit]. |
+ */ |
+ MethodDeclaration getMethodInClass( |
+ CompilationUnit unit, String className, String methodName) { |
+ ClassDeclaration unitMember = getClass(unit, className); |
+ NodeList<ClassMember> classMembers = unitMember.members; |
+ for (ClassMember classMember in classMembers) { |
+ if (classMember is MethodDeclaration) { |
+ if (classMember.name.name == methodName) { |
+ return classMember; |
+ } |
+ } |
+ } |
+ fail('No method named $methodName in $className'); |
+ return null; |
+ } |
+ |
+ List<Statement> getStatementsInMethod( |
+ CompilationUnit unit, String className, String methodName) { |
+ MethodDeclaration method = getMethodInClass(unit, className, methodName); |
+ BlockFunctionBody body = method.body; |
+ return body.block.statements; |
+ } |
+ |
+ List<Statement> getStatementsInTopLevelFunction( |
+ CompilationUnit unit, String functionName) { |
+ FunctionDeclaration function = getTopLevelFunction(unit, functionName); |
+ BlockFunctionBody body = function.functionExpression.body; |
+ return body.block.statements; |
+ } |
+ |
+ /** |
+ * Return the declaration of the top-level function with the given |
+ * [functionName] in the given compilation [unit]. |
+ */ |
+ FunctionDeclaration getTopLevelFunction( |
+ CompilationUnit unit, String functionName) { |
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations; |
+ for (CompilationUnitMember unitMember in unitMembers) { |
+ if (unitMember is FunctionDeclaration) { |
+ if (unitMember.name.name == functionName) { |
+ return unitMember; |
+ } |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * Return the declaration of the top-level variable with the given |
+ * [variableName] in the given compilation [unit]. |
+ */ |
+ VariableDeclaration getTopLevelVariable( |
+ CompilationUnit unit, String variableName) { |
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations; |
+ for (CompilationUnitMember unitMember in unitMembers) { |
+ if (unitMember is TopLevelVariableDeclaration) { |
+ NodeList<VariableDeclaration> variables = |
+ unitMember.variables.variables; |
+ for (VariableDeclaration variable in variables) { |
+ if (variable.name.name == variableName) { |
+ return variable; |
+ } |
+ } |
+ } |
+ } |
+ return null; |
+ } |
+ |
+ void setUp() { |
+ super.setUp(); |
+ emptySource = newSource('/test.dart'); |
+ } |
+ |
+ /** |
+ * Fill [errorListener] with [result] errors in the current [task]. |
+ */ |
+ void _fillErrorListener(ResultDescriptor<List<AnalysisError>> result) { |
+ List<AnalysisError> errors = task.outputs[result]; |
+ expect(errors, isNotNull, reason: result.name); |
+ errorListener = new GatheringErrorListener(); |
+ errorListener.addAll(errors); |
+ } |
+} |