| // 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 analyzer.test.src.task.dart_test; |
| |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/dart/ast/visitor.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/src/context/cache.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/generated/constant.dart'; |
| import 'package:analyzer/src/generated/engine.dart' |
| show AnalysisOptions, AnalysisOptionsImpl, CacheState; |
| import 'package:analyzer/src/generated/error.dart'; |
| import 'package:analyzer/src/generated/resolver.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/src/task/strong/info.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_case.dart'; |
| import '../../generated/test_support.dart'; |
| import '../../reflective_tests.dart'; |
| import '../../utils.dart'; |
| import '../context/abstract_context.dart'; |
| import '../context/mock_sdk.dart'; |
| |
| main() { |
| initializeTestEnvironment(); |
| runReflectiveTests(BuildCompilationUnitElementTaskTest); |
| runReflectiveTests(BuildDirectiveElementsTaskTest); |
| runReflectiveTests(BuildEnumMemberElementsTaskTest); |
| runReflectiveTests(BuildExportNamespaceTaskTest); |
| runReflectiveTests(BuildLibraryElementTaskTest); |
| runReflectiveTests(BuildPublicNamespaceTaskTest); |
| runReflectiveTests(BuildSourceExportClosureTaskTest); |
| runReflectiveTests(BuildTypeProviderTaskTest); |
| runReflectiveTests(BuildTypeProviderTaskTest_noAsync); |
| runReflectiveTests(ComputeConstantDependenciesTaskTest); |
| runReflectiveTests(ComputeConstantValueTaskTest); |
| runReflectiveTests(ComputeInferableStaticVariableDependenciesTaskTest); |
| runReflectiveTests(ComputeLibraryCycleTaskTest); |
| runReflectiveTests(ComputePropagableVariableDependenciesTaskTest); |
| 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(PropagateVariableTypesInUnitTaskTest); |
| runReflectiveTests(PropagateVariableTypeTaskTest); |
| runReflectiveTests(ResolveDirectiveElementsTaskTest); |
| runReflectiveTests(ResolveInstanceFieldsInUnitTaskTest); |
| runReflectiveTests(ResolveLibraryTaskTest); |
| runReflectiveTests(ResolveLibraryTypeNamesTaskTest); |
| runReflectiveTests(ResolveTopLevelUnitTypeBoundsTaskTest); |
| runReflectiveTests(ResolveUnitTaskTest); |
| runReflectiveTests(ResolveUnitTypeNamesTaskTest); |
| runReflectiveTests(ResolveVariableReferencesTaskTest); |
| runReflectiveTests(ScanDartTaskTest); |
| runReflectiveTests(StrongModeInferenceTest); |
| runReflectiveTests(StrongModeVerifyUnitTaskTest); |
| 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 isBuildTypeProviderTask = |
| new isInstanceOf<BuildTypeProviderTask>(); |
| isInstanceOf isComputeConstantDependenciesTask = |
| new isInstanceOf<ComputeConstantDependenciesTask>(); |
| isInstanceOf isComputeConstantValueTask = |
| new isInstanceOf<ComputeConstantValueTask>(); |
| isInstanceOf isComputeInferableStaticVariableDependenciesTask = |
| new isInstanceOf<ComputeInferableStaticVariableDependenciesTask>(); |
| isInstanceOf isComputePropagableVariableDependenciesTask = |
| new isInstanceOf<ComputePropagableVariableDependenciesTask>(); |
| 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 isPropagateVariableTypesInUnitTask = |
| new isInstanceOf<PropagateVariableTypesInUnitTask>(); |
| isInstanceOf isPropagateVariableTypeTask = |
| new isInstanceOf<PropagateVariableTypeTask>(); |
| isInstanceOf isResolveDirectiveElementsTask = |
| new isInstanceOf<ResolveDirectiveElementsTask>(); |
| isInstanceOf isResolveLibraryTask = new isInstanceOf<ResolveLibraryTask>(); |
| isInstanceOf isResolveLibraryTypeNamesTask = |
| new isInstanceOf<ResolveLibraryTypeNamesTask>(); |
| isInstanceOf isResolveTopLevelUnitTypeBoundsTask = |
| new isInstanceOf<ResolveTopLevelUnitTypeBoundsTask>(); |
| isInstanceOf isResolveUnitTask = new isInstanceOf<ResolveUnitTask>(); |
| isInstanceOf isResolveUnitTypeNamesTask = |
| new isInstanceOf<ResolveUnitTypeNamesTask>(); |
| isInstanceOf isResolveVariableReferencesTask = |
| new isInstanceOf<ResolveVariableReferencesTask>(); |
| isInstanceOf isScanDartTask = new isInstanceOf<ScanDartTask>(); |
| isInstanceOf isStrongModeVerifyUnitTask = |
| new isInstanceOf<StrongModeVerifyUnitTask>(); |
| 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_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT1); |
| expect(outputs[RESOLVED_UNIT1], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT1], isTrue); |
| } |
| |
| 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], |
| annotation.elementAnnotation, |
| 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(4)); |
| expect(outputs[COMPILATION_UNIT_CONSTANTS], isNotNull); |
| expect(outputs[COMPILATION_UNIT_ELEMENT], isNotNull); |
| expect(outputs[RESOLVED_UNIT1], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT1], isTrue); |
| } |
| |
| 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 { |
| /** |
| * Verify that the given [element] has exactly one annotation, and that its |
| * [ElementAnnotationImpl] is unresolved and points back to [element]. |
| * |
| * The compilation unit stored in the [ElementAnnotationImpl] should be |
| * [compilationUnit]. |
| */ |
| void checkMetadata(Element element, CompilationUnitElement compilationUnit) { |
| expect(element.metadata, hasLength(1)); |
| expect(element.metadata[0], new isInstanceOf<ElementAnnotationImpl>()); |
| ElementAnnotationImpl elementAnnotation = element.metadata[0]; |
| expect(elementAnnotation.element, isNull); // Not yet resolved |
| expect(elementAnnotation.compilationUnit, isNotNull); |
| expect(elementAnnotation.compilationUnit, compilationUnit); |
| } |
| |
| 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); |
| } |
| |
| test_perform_metadata() { |
| List<Source> sources = newSources({ |
| '/libA.dart': ''' |
| @a library libA; |
| @b import 'libB.dart'; |
| @c export 'libC.dart'; |
| @d part 'part.dart';''', |
| '/libB.dart': 'library libB;', |
| '/libC.dart': 'library libC;', |
| '/part.dart': 'part of libA;' |
| }); |
| Source sourceA = sources[0]; |
| // perform task |
| computeResult(sourceA, LIBRARY_ELEMENT2, |
| matcher: isBuildDirectiveElementsTask); |
| // Get outputs |
| LibraryElement libraryA = |
| context.getCacheEntry(sourceA).getValue(LIBRARY_ELEMENT2); |
| // Validate metadata |
| checkMetadata(libraryA, libraryA.definingCompilationUnit); |
| checkMetadata(libraryA.imports[0], libraryA.definingCompilationUnit); |
| checkMetadata(libraryA.exports[0], libraryA.definingCompilationUnit); |
| checkMetadata(libraryA.parts[0], libraryA.definingCompilationUnit); |
| } |
| |
| test_perform_metadata_partOf() { |
| // We don't record annotations on `part of` directives because the element |
| // associated with a `part of` directive is the library, and the convention |
| // is to annotate the library at the site of the `library` declaration. |
| List<Source> sources = newSources({ |
| '/libA.dart': ''' |
| library libA; |
| part 'part.dart';''', |
| '/part.dart': '@a part of libA;' |
| }); |
| Source sourceA = sources[0]; |
| Source sourcePart = sources[1]; |
| // perform task |
| computeResult(sourceA, LIBRARY_ELEMENT2, |
| matcher: isBuildDirectiveElementsTask); |
| // Get outputs |
| LibraryElement libraryA = |
| context.getCacheEntry(sourceA).getValue(LIBRARY_ELEMENT2); |
| CompilationUnit part = context |
| .getCacheEntry(new LibrarySpecificUnit(sourceA, sourcePart)) |
| .getValue(RESOLVED_UNIT1); |
| // Validate metadata |
| expect(part.directives[0], new isInstanceOf<PartOfDirective>()); |
| expect(part.directives[0].element, same(libraryA)); |
| expect(part.directives[0].element.metadata, isEmpty); |
| } |
| |
| 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_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT3); |
| expect(outputs[RESOLVED_UNIT3], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT3], isTrue); |
| } |
| |
| test_perform() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| enum MyEnum { |
| A, B |
| } |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT3, |
| matcher: isBuildEnumMemberElementsTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT3]; |
| // 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 |
| .singleWhere((u) => u.element.name.endsWith('part1.dart')) |
| .element; |
| CompilationUnitElement unitElement2 = partUnits |
| .singleWhere((u) => u.element.name.endsWith('part2.dart')) |
| .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] |
| as List<CompilationUnit>; |
| } |
| } |
| |
| @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 { |
| List<Source> getExportSourceClosure(Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[EXPORT_SOURCE_CLOSURE] as List<Source>; |
| } |
| |
| 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 = getExportSourceClosure(outputs); |
| expect(closure, unorderedEquals([sourceA, sourceB, sourceC])); |
| } |
| // c.dart |
| { |
| computeResult(sourceC, EXPORT_SOURCE_CLOSURE, |
| matcher: isBuildSourceExportClosureTask); |
| List<Source> closure = getExportSourceClosure(outputs); |
| expect(closure, unorderedEquals([sourceA, sourceB, sourceC])); |
| } |
| // d.dart |
| { |
| computeResult(sourceD, EXPORT_SOURCE_CLOSURE, |
| matcher: isBuildSourceExportClosureTask); |
| List<Source> closure = getExportSourceClosure(outputs); |
| expect(closure, unorderedEquals([sourceD])); |
| } |
| } |
| } |
| |
| @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 BuildTypeProviderTaskTest_noAsync extends _AbstractDartTaskTest { |
| DartSdk createDartSdk() => new MockSdk(dartAsync: false); |
| |
| void prepareAnalysisContext([AnalysisOptions options]) { |
| AnalysisOptionsImpl newOptions = new AnalysisOptionsImpl(); |
| newOptions.enableAsync = false; |
| super.prepareAnalysisContext(newOptions); |
| } |
| |
| test_perform_noAsync() { |
| expect(context, isNotNull); |
| 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(annotation.elementAnnotation, CONSTANT_DEPENDENCIES, |
| matcher: isComputeConstantDependenciesTask); |
| expect( |
| outputs[CONSTANT_DEPENDENCIES].toSet(), [x, constructorForD].toSet()); |
| } |
| |
| test_annotation_with_nonConstArg() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class A { |
| const A(x); |
| } |
| class C { |
| @A(const [(_) => null]) |
| String s; |
| } |
| '''); |
| // 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 annotation on the field. |
| ClassDeclaration classC = unit.declarations[1]; |
| Annotation annotation = classC.members[0].metadata[0]; |
| // Now compute the dependencies for the annotation, and check that it is |
| // the right size. |
| computeResult(annotation.elementAnnotation, CONSTANT_DEPENDENCIES, |
| matcher: isComputeConstantDependenciesTask); |
| expect(outputs[CONSTANT_DEPENDENCIES], hasLength(1)); |
| } |
| |
| 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(annotation.elementAnnotation, 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_UNIT3); |
| CompilationUnit unit = outputs[RESOLVED_UNIT3]; |
| // 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]; |
| ElementAnnotationImpl target = annotation.elementAnnotation; |
| 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'].toIntValue(), 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.toIntValue(), 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.toIntValue(), 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.toIntValue(), 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 = |
| AstFinder.getTopLevelVariableElement(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 = |
| AstFinder.getTopLevelVariableElement(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); |
| } |
| |
| 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_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT7); |
| expect(outputs[RESOLVED_UNIT7], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT7], isTrue); |
| } |
| |
| test_perform() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| const a = b; |
| const b = 0; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| 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] as List<VariableElement>; |
| expect(dependencies, unorderedEquals([elementB])); |
| } |
| } |
| |
| @reflectiveTest |
| class ComputeLibraryCycleTaskTest extends _AbstractDartTaskTest { |
| List<LibraryElement> getLibraryCycle(Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[LIBRARY_CYCLE] as List<LibraryElement>; |
| } |
| |
| List<CompilationUnitElement> getLibraryCycleDependencies( |
| Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[LIBRARY_CYCLE_DEPENDENCIES] as List<CompilationUnitElement>; |
| } |
| |
| List<CompilationUnitElement> getLibraryCycleUnits( |
| Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[LIBRARY_CYCLE_UNITS] as List<CompilationUnitElement>; |
| } |
| |
| @override |
| void setUp() { |
| super.setUp(); |
| enableStrongMode(); |
| } |
| |
| void test_library_cycle_incremental() { |
| enableStrongMode(); |
| Source lib1Source = newSource( |
| '/my_lib1.dart', |
| ''' |
| library my_lib1; |
| '''); |
| Source lib2Source = newSource( |
| '/my_lib2.dart', |
| ''' |
| library my_lib2; |
| import 'my_lib1.dart'; |
| '''); |
| Source lib3Source = newSource( |
| '/my_lib3.dart', |
| ''' |
| library my_lib3; |
| import 'my_lib2.dart'; |
| '''); |
| AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source); |
| AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source); |
| AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source); |
| computeResult(lib1Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| computeResult(lib2Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| computeResult(lib3Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| |
| // complete the cycle |
| context.setContents( |
| lib1Source, |
| ''' |
| library my_lib1; |
| import 'my_lib3.dart'; |
| '''); |
| computeResult(lib1Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(3)); |
| computeResult(lib2Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(3)); |
| computeResult(lib3Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(3)); |
| |
| // break the cycle again |
| context.setContents( |
| lib1Source, |
| ''' |
| library my_lib1; |
| '''); |
| computeResult(lib1Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| computeResult(lib2Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| computeResult(lib3Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| } |
| |
| void test_library_cycle_incremental_partial() { |
| enableStrongMode(); |
| Source lib1Source = newSource( |
| '/my_lib1.dart', |
| ''' |
| library my_lib1; |
| '''); |
| Source lib2Source = newSource( |
| '/my_lib2.dart', |
| ''' |
| library my_lib2; |
| import 'my_lib1.dart'; |
| '''); |
| Source lib3Source = newSource( |
| '/my_lib3.dart', |
| ''' |
| library my_lib3; |
| import 'my_lib2.dart'; |
| '''); |
| AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source); |
| AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source); |
| AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source); |
| computeResult(lib1Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| computeResult(lib2Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(1)); |
| // lib3 is not reachable, so we have not yet computed its library |
| // cycles |
| |
| // complete the cycle, via lib3 |
| context.setContents( |
| lib1Source, |
| ''' |
| library my_lib1; |
| import 'my_lib3.dart'; |
| '''); |
| // Ensure that invalidation correctly invalidated everything reachable |
| // through lib3 |
| computeResult(lib1Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(3)); |
| computeResult(lib2Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(3)); |
| computeResult(lib3Target, LIBRARY_CYCLE); |
| expect(outputs[LIBRARY_CYCLE], hasLength(3)); |
| } |
| |
| 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 = getLibraryCycle(results[0]); |
| List<LibraryElement> component1 = getLibraryCycle(results[1]); |
| expect(component0, hasLength(1)); |
| expect(component1, hasLength(1)); |
| |
| List<CompilationUnitElement> units0 = getLibraryCycleUnits(results[0]); |
| List<CompilationUnitElement> units1 = getLibraryCycleUnits(results[1]); |
| expect(units0, hasLength(1)); |
| expect(units1, hasLength(1)); |
| |
| List<CompilationUnitElement> dep0 = getLibraryCycleDependencies(results[0]); |
| List<CompilationUnitElement> dep1 = getLibraryCycleDependencies(results[1]); |
| 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 = getLibraryCycle(results[0]); |
| List<LibraryElement> component1 = getLibraryCycle(results[1]); |
| List<LibraryElement> component2 = getLibraryCycle(results[2]); |
| |
| expect(component0, hasLength(3)); |
| expect(component1, hasLength(3)); |
| expect(component2, hasLength(3)); |
| |
| List<CompilationUnitElement> units0 = getLibraryCycleUnits(results[0]); |
| List<CompilationUnitElement> units1 = getLibraryCycleUnits(results[1]); |
| List<CompilationUnitElement> units2 = getLibraryCycleUnits(results[2]); |
| expect(units0, hasLength(3)); |
| expect(units1, hasLength(3)); |
| expect(units2, hasLength(3)); |
| |
| List<CompilationUnitElement> dep0 = getLibraryCycleDependencies(results[0]); |
| List<CompilationUnitElement> dep1 = getLibraryCycleDependencies(results[1]); |
| List<CompilationUnitElement> dep2 = getLibraryCycleDependencies(results[2]); |
| expect(dep0, hasLength(1)); // dart:core |
| expect(dep1, hasLength(1)); // dart:core |
| expect(dep2, hasLength(1)); // dart:core |
| } |
| |
| void test_library_cycle_override_inference_incremental() { |
| enableStrongMode(); |
| Source lib1Source = newSource( |
| '/my_lib1.dart', |
| ''' |
| library my_lib1; |
| import 'my_lib3.dart'; |
| '''); |
| Source lib2Source = newSource( |
| '/my_lib2.dart', |
| ''' |
| library my_lib2; |
| import 'my_lib1.dart'; |
| '''); |
| Source lib3Source = newSource( |
| '/my_lib3.dart', |
| ''' |
| library my_lib3; |
| import 'my_lib2.dart'; |
| |
| class A { |
| int foo(int x) => null; |
| } |
| class B extends A { |
| foo(x) => null; |
| } |
| '''); |
| AnalysisTarget lib1Target = new LibrarySpecificUnit(lib1Source, lib1Source); |
| AnalysisTarget lib2Target = new LibrarySpecificUnit(lib2Source, lib2Source); |
| AnalysisTarget lib3Target = new LibrarySpecificUnit(lib3Source, lib3Source); |
| |
| computeResult(lib1Target, RESOLVED_UNIT); |
| computeResult(lib2Target, RESOLVED_UNIT); |
| computeResult(lib3Target, RESOLVED_UNIT); |
| CompilationUnit unit = outputs[RESOLVED_UNIT]; |
| ClassElement b = unit.declarations[1].element; |
| expect(b.getMethod('foo').returnType.toString(), 'int'); |
| |
| // add a dummy edit. |
| context.setContents( |
| lib1Source, |
| ''' |
| library my_lib1; |
| import 'my_lib3.dart'; |
| var foo = 123; |
| '''); |
| |
| computeResult(lib1Target, RESOLVED_UNIT); |
| computeResult(lib2Target, RESOLVED_UNIT); |
| computeResult(lib3Target, RESOLVED_UNIT); |
| unit = outputs[RESOLVED_UNIT]; |
| b = unit.declarations[1].element; |
| expect(b.getMethod('foo').returnType.toString(), 'int', |
| reason: 'edit should not affect member inference'); |
| } |
| |
| 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 = getLibraryCycle(results[0]); |
| expect(component0, hasLength(1)); |
| |
| List<CompilationUnitElement> units0 = getLibraryCycleUnits(results[0]); |
| expect(units0, hasLength(1)); |
| |
| List<CompilationUnitElement> dep0 = getLibraryCycleDependencies(results[0]); |
| 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 = getLibraryCycle(outputs); |
| List<CompilationUnitElement> units = getLibraryCycleUnits(outputs); |
| List<CompilationUnitElement> deps = getLibraryCycleDependencies(outputs); |
| 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 = getLibraryCycle(results[0]); |
| List<LibraryElement> component1 = getLibraryCycle(results[1]); |
| List<LibraryElement> component2 = getLibraryCycle(results[2]); |
| expect(component0, hasLength(1)); |
| expect(component1, hasLength(1)); |
| expect(component2, hasLength(1)); |
| |
| List<CompilationUnitElement> units0 = getLibraryCycleUnits(results[0]); |
| List<CompilationUnitElement> units1 = getLibraryCycleUnits(results[1]); |
| List<CompilationUnitElement> units2 = getLibraryCycleUnits(results[2]); |
| expect(units0, hasLength(1)); |
| expect(units1, hasLength(1)); |
| expect(units2, hasLength(1)); |
| |
| List<CompilationUnitElement> dep0 = getLibraryCycleDependencies(results[0]); |
| List<CompilationUnitElement> dep1 = getLibraryCycleDependencies(results[1]); |
| List<CompilationUnitElement> dep2 = getLibraryCycleDependencies(results[2]); |
| 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 = getLibraryCycle(results[0]); |
| List<LibraryElement> component1 = getLibraryCycle(results[1]); |
| List<LibraryElement> component2 = getLibraryCycle(results[2]); |
| List<LibraryElement> component3 = getLibraryCycle(results[3]); |
| |
| expect(component0, hasLength(2)); |
| expect(component1, hasLength(2)); |
| expect(component2, hasLength(2)); |
| expect(component3, hasLength(2)); |
| |
| List<CompilationUnitElement> units0 = getLibraryCycleUnits(results[0]); |
| List<CompilationUnitElement> units1 = getLibraryCycleUnits(results[1]); |
| List<CompilationUnitElement> units2 = getLibraryCycleUnits(results[2]); |
| List<CompilationUnitElement> units3 = getLibraryCycleUnits(results[3]); |
| expect(units0, hasLength(2)); |
| expect(units1, hasLength(2)); |
| expect(units2, hasLength(2)); |
| expect(units3, hasLength(2)); |
| |
| List<CompilationUnitElement> dep0 = getLibraryCycleDependencies(results[0]); |
| List<CompilationUnitElement> dep1 = getLibraryCycleDependencies(results[1]); |
| List<CompilationUnitElement> dep2 = getLibraryCycleDependencies(results[2]); |
| List<CompilationUnitElement> dep3 = getLibraryCycleDependencies(results[3]); |
| expect(dep0, hasLength(1)); // dart:core |
| expect(dep1, hasLength(1)); // dart:core |
| expect(dep2, 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 = getLibraryCycle(results0); |
| List<LibraryElement> component1 = getLibraryCycle(results1); |
| List<LibraryElement> component2 = getLibraryCycle(results2); |
| List<LibraryElement> component3 = getLibraryCycle(results3); |
| List<LibraryElement> component4 = getLibraryCycle(results4); |
| List<LibraryElement> component5 = getLibraryCycle(results5); |
| List<LibraryElement> component6 = getLibraryCycle(results6); |
| List<LibraryElement> component7 = getLibraryCycle(results7); |
| |
| 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 = getLibraryCycleUnits(results0); |
| List<CompilationUnitElement> units1 = getLibraryCycleUnits(results1); |
| List<CompilationUnitElement> units2 = getLibraryCycleUnits(results2); |
| List<CompilationUnitElement> units3 = getLibraryCycleUnits(results3); |
| List<CompilationUnitElement> units4 = getLibraryCycleUnits(results4); |
| List<CompilationUnitElement> units5 = getLibraryCycleUnits(results5); |
| List<CompilationUnitElement> units6 = getLibraryCycleUnits(results6); |
| List<CompilationUnitElement> units7 = getLibraryCycleUnits(results7); |
| 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 = getLibraryCycleDependencies(results0); |
| List<CompilationUnitElement> dep1 = getLibraryCycleDependencies(results1); |
| List<CompilationUnitElement> dep2 = getLibraryCycleDependencies(results2); |
| List<CompilationUnitElement> dep3 = getLibraryCycleDependencies(results3); |
| List<CompilationUnitElement> dep4 = getLibraryCycleDependencies(results4); |
| List<CompilationUnitElement> dep5 = getLibraryCycleDependencies(results5); |
| List<CompilationUnitElement> dep6 = getLibraryCycleDependencies(results6); |
| List<CompilationUnitElement> dep7 = getLibraryCycleDependencies(results7); |
| 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 ComputePropagableVariableDependenciesTaskTest |
| extends _AbstractDartTaskTest { |
| List<VariableElement> getPropagableVariableDependencies( |
| Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[PROPAGABLE_VARIABLE_DEPENDENCIES] as List<VariableElement>; |
| } |
| |
| test_perform_instanceField() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| class A { |
| final a = a1 + a2 + a3 + a4 + B.b1 + B.b2 + B.b3 + B.b4; |
| static const a1 = 1; |
| final a2 = 2; |
| final a3; |
| var a4 = 4; |
| } |
| class B { |
| static const b1 = 1; |
| static final b2 = 2; |
| static final b3; |
| static var b4 = 4; |
| } |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| FieldElement elementA = AstFinder.getFieldInClassElement(unit, 'A', 'a'); |
| // compute |
| computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES, |
| matcher: isComputePropagableVariableDependenciesTask); |
| // verify |
| expect(outputs, hasLength(1)); |
| List<VariableElement> dependencies = |
| getPropagableVariableDependencies(outputs); |
| expect( |
| dependencies, |
| unorderedEquals([ |
| AstFinder.getFieldInClassElement(unit, 'A', 'a1'), |
| AstFinder.getFieldInClassElement(unit, 'A', 'a2'), |
| AstFinder.getFieldInClassElement(unit, 'B', 'b1'), |
| AstFinder.getFieldInClassElement(unit, 'B', 'b2') |
| ])); |
| } |
| |
| test_perform_topLevel() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| const a = d1 + d2 + d3 + d4; |
| const d1 = 1; |
| final d2 = 2; |
| final d3; |
| var d4 = 4; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| TopLevelVariableElement elementA = |
| AstFinder.getTopLevelVariableElement(unit, 'a'); |
| // compute |
| computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES, |
| matcher: isComputePropagableVariableDependenciesTask); |
| // verify |
| expect(outputs, hasLength(1)); |
| List<VariableElement> dependencies = |
| getPropagableVariableDependencies(outputs); |
| expect( |
| dependencies, |
| unorderedEquals([ |
| AstFinder.getTopLevelVariableElement(unit, 'd1'), |
| AstFinder.getTopLevelVariableElement(unit, 'd2') |
| ])); |
| } |
| |
| test_perform_topLevel_ignoreLocal() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| final a = () { |
| const b = 2; |
| const c = 3; |
| return b + c; |
| }() + d; |
| final d = 4; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| TopLevelVariableElement elementA = |
| AstFinder.getTopLevelVariableElement(unit, 'a'); |
| // compute |
| computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES, |
| matcher: isComputePropagableVariableDependenciesTask); |
| // verify |
| expect(outputs, hasLength(1)); |
| List<VariableElement> dependencies = |
| getPropagableVariableDependencies(outputs); |
| expect(dependencies, |
| unorderedEquals([AstFinder.getTopLevelVariableElement(unit, 'd')])); |
| } |
| |
| test_perform_topLevel_withoutSpaceAfterType() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| const List<int>a=[b, c]; |
| const b = 1; |
| const c = 2; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| TopLevelVariableElement elementA = |
| AstFinder.getTopLevelVariableElement(unit, 'a'); |
| // compute |
| computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES, |
| matcher: isComputePropagableVariableDependenciesTask); |
| // verify |
| expect(outputs, hasLength(1)); |
| List<VariableElement> dependencies = |
| getPropagableVariableDependencies(outputs); |
| expect( |
| dependencies, |
| unorderedEquals([ |
| AstFinder.getTopLevelVariableElement(unit, 'b'), |
| AstFinder.getTopLevelVariableElement(unit, 'c') |
| ])); |
| } |
| } |
| |
| @reflectiveTest |
| class ContainingLibrariesTaskTest extends _AbstractDartTaskTest { |
| List<Source> getContainingLibraries(Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[CONTAINING_LIBRARIES] as List<Source>; |
| } |
| |
| 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 = getContainingLibraries(outputs); |
| 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 = getContainingLibraries(outputs); |
| 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 = getContainingLibraries(outputs); |
| expect(containingLibraries, unorderedEquals([library])); |
| } |
| } |
| |
| @reflectiveTest |
| class DartErrorsTaskTest extends _AbstractDartTaskTest { |
| List<AnalysisError> getDartErrors(Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[DART_ERRORS] as List<AnalysisError>; |
| } |
| |
| 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 = getDartErrors(outputs); |
| 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 = getDartErrors(outputs); |
| // 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_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT13); |
| expect(outputs[RESOLVED_UNIT13], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT13], isTrue); |
| } |
| |
| 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_UNIT13, |
| matcher: isEvaluateUnitConstantsTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT13]; |
| 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_inBody() { |
| 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'])); |
| } |
| |
| test_perform_inComment_exportDirective() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| import 'dart:async'; |
| /// Use [Future]. |
| export 'dart:math'; |
| '''); |
| _computeUsedElements(source); |
| expect(usedElementNames, unorderedEquals(['Future'])); |
| } |
| |
| test_perform_inComment_importDirective() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| import 'dart:async'; |
| /// Use [Future]. |
| import 'dart:math'; |
| '''); |
| _computeUsedElements(source); |
| expect(usedElementNames, unorderedEquals(['Future'])); |
| } |
| |
| test_perform_inComment_libraryDirective() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| /// Use [Future]. |
| library test; |
| import 'dart:async'; |
| '''); |
| _computeUsedElements(source); |
| expect(usedElementNames, unorderedEquals(['Future'])); |
| } |
| |
| test_perform_inComment_topLevelFunction() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| import 'dart:async'; |
| /// Use [Future]. |
| main() {} |
| '''); |
| _computeUsedElements(source); |
| expect(usedElementNames, unorderedEquals(['Future'])); |
| } |
| |
| 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; |
| |
| test_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(); |
| setLints(context, [new GenerateLintsTaskTest_TestLinter()]); |
| } |
| |
| @override |
| void tearDown() { |
| setLints(context, []); |
| super.tearDown(); |
| } |
| |
| test_camel_case_types() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class a { } |
| '''); |
| |
| 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 |
| String get name => 'GenerateLintsTaskTest_TestLinter'; |
| |
| @override |
| AstVisitor getVisitor() => new GenerateLintsTaskTest_AstVisitor(this); |
| } |
| |
| @reflectiveTest |
| class InferInstanceMembersInUnitTaskTest extends _AbstractDartTaskTest { |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT11); |
| expect(outputs[RESOLVED_UNIT11], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT11], isTrue); |
| } |
| |
| 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_UNIT11, |
| matcher: isInferInstanceMembersInUnitTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT11]; |
| VariableDeclaration field = AstFinder.getFieldInClass(unit, 'B', 'f'); |
| MethodDeclaration method = AstFinder.getMethodInClass(unit, 'B', 'm'); |
| DartType typeX = AstFinder.getClass(unit, 'X').element.type; |
| DartType typeY = AstFinder.getClass(unit, 'Y').element.type; |
| DartType typeZ = AstFinder.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_UNIT11, |
| matcher: isInferInstanceMembersInUnitTask); |
| CompilationUnit firstUnit = outputs[RESOLVED_UNIT11]; |
| computeResult( |
| new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT11); |
| CompilationUnit secondUnit = outputs[RESOLVED_UNIT11]; |
| |
| VariableDeclaration variableA = |
| AstFinder.getTopLevelVariable(firstUnit, 'a'); |
| VariableDeclaration variableB = |
| AstFinder.getTopLevelVariable(secondUnit, 'b'); |
| VariableDeclaration variableC = |
| AstFinder.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_UNIT11); |
| CompilationUnit unit = outputs[RESOLVED_UNIT11]; |
| VariableDeclaration topLevelDecl = |
| AstFinder.getTopLevelVariable(unit, 'topLevel'); |
| VariableDeclaration fieldDecl = |
| AstFinder.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 { |
| @override |
| void setUp() { |
| super.setUp(); |
| enableStrongMode(); |
| } |
| |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT9); |
| expect(outputs[RESOLVED_UNIT9], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT9], isTrue); |
| } |
| |
| void test_perform_const_field() { |
| enableStrongMode(); |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| class M { |
| static const X = ""; |
| } |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9, |
| matcher: isInferStaticVariableTypesInUnitTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
| VariableDeclaration declaration = AstFinder.getFieldInClass(unit, 'M', 'X'); |
| InterfaceType stringType = context.typeProvider.stringType; |
| expect(declaration.element.type, stringType); |
| } |
| |
| test_perform_hasParseError() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| @(i $= |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT9); |
| expect(outputs[RESOLVED_UNIT9], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT9], isTrue); |
| } |
| |
| 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_UNIT9, |
| 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_UNIT9, |
| matcher: isInferStaticVariableTypesInUnitTask); |
| CompilationUnit firstUnit = outputs[RESOLVED_UNIT9]; |
| computeResult( |
| new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9); |
| CompilationUnit secondUnit = outputs[RESOLVED_UNIT9]; |
| |
| VariableDeclaration variableA = |
| AstFinder.getTopLevelVariable(firstUnit, 'a'); |
| VariableDeclaration variableB = |
| AstFinder.getTopLevelVariable(secondUnit, 'b'); |
| VariableDeclaration variableC = |
| AstFinder.getTopLevelVariable(firstUnit, 'c'); |
| ClassDeclaration classM = AstFinder.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_UNIT9, |
| matcher: isInferStaticVariableTypesInUnitTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT9]; |
| 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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableDeclaration declaration = |
| AstFinder.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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableDeclaration declaration = |
| AstFinder.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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableDeclaration topLevelDecl = |
| AstFinder.getTopLevelVariable(unit, 'topLevel3'); |
| VariableDeclaration fieldDecl = |
| AstFinder.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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableElement topLevel = |
| AstFinder.getTopLevelVariable(unit, 'topLevel').name.staticElement; |
| VariableElement field = |
| AstFinder.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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableElement piFirst = |
| AstFinder.getTopLevelVariable(unit, 'piFirst').name.staticElement; |
| VariableElement pi = |
| AstFinder.getTopLevelVariable(unit, 'pi').name.staticElement; |
| VariableElement tau = |
| AstFinder.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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableElement a = |
| AstFinder.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_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| VariableElement a = |
| AstFinder.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 { |
| List<AnalysisError> getLibraryUnitErrors( |
| Map<ResultDescriptor, dynamic> outputs) { |
| return outputs[LIBRARY_UNIT_ERRORS] as List<AnalysisError>; |
| } |
| |
| 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 = getLibraryUnitErrors(outputs); |
| 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 = getLibraryUnitErrors(outputs); |
| expect(errors, hasLength(0)); |
| } |
| } |
| |
| @reflectiveTest |
| class ParseDartTaskTest extends _AbstractDartTaskTest { |
| Source source; |
| |
| test_perform() { |
| _performParseTask(r''' |
| part of lib; |
| class B {}'''); |
| expect(outputs, hasLength(10)); |
| 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[LIBRARY_SPECIFIC_UNITS], hasLength(1)); |
| expect(outputs[PARSE_ERRORS], hasLength(0)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.PART); |
| expect(outputs[UNITS], hasLength(1)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(2)); |
| } |
| |
| 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(10)); |
| 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[LIBRARY_SPECIFIC_UNITS], hasLength(1)); |
| expect(outputs[PARSE_ERRORS], hasLength(0)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
| expect(outputs[UNITS], hasLength(1)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(2)); |
| } |
| |
| test_perform_enableAsync_false() { |
| AnalysisOptionsImpl options = new AnalysisOptionsImpl(); |
| options.enableAsync = false; |
| prepareAnalysisContext(options); |
| _performParseTask(r''' |
| import 'dart:async'; |
| class B {void foo() async {}}'''); |
| expect(outputs, hasLength(10)); |
| expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1)); |
| expect(outputs[EXPORTED_LIBRARIES], hasLength(0)); |
| _assertHasCore(outputs[IMPORTED_LIBRARIES], 2); |
| expect(outputs[INCLUDED_PARTS], hasLength(0)); |
| expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1)); |
| expect(outputs[PARSE_ERRORS], hasLength(1)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
| expect(outputs[UNITS], hasLength(1)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(3)); |
| } |
| |
| test_perform_enableAsync_true() { |
| _performParseTask(r''' |
| import 'dart:async'; |
| class B {void foo() async {}}'''); |
| expect(outputs, hasLength(10)); |
| expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1)); |
| expect(outputs[EXPORTED_LIBRARIES], hasLength(0)); |
| _assertHasCore(outputs[IMPORTED_LIBRARIES], 2); |
| expect(outputs[INCLUDED_PARTS], hasLength(0)); |
| expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1)); |
| expect(outputs[PARSE_ERRORS], hasLength(0)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
| expect(outputs[UNITS], hasLength(1)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(3)); |
| } |
| |
| test_perform_flushTokenStream() { |
| _performParseTask(r''' |
| class Test {} |
| '''); |
| expect(analysisCache.getState(source, TOKEN_STREAM), CacheState.FLUSHED); |
| } |
| |
| 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(10)); |
| 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[LIBRARY_SPECIFIC_UNITS], hasLength(2)); |
| expect(outputs[PARSE_ERRORS], hasLength(2)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
| expect(outputs[UNITS], hasLength(2)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(4)); |
| } |
| |
| test_perform_library() { |
| _performParseTask(r''' |
| library lib; |
| import 'lib2.dart'; |
| export 'lib3.dart'; |
| part 'part.dart'; |
| class A {'''); |
| expect(outputs, hasLength(10)); |
| 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[LIBRARY_SPECIFIC_UNITS], hasLength(2)); |
| expect(outputs[PARSE_ERRORS], hasLength(1)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.LIBRARY); |
| expect(outputs[UNITS], hasLength(2)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(5)); |
| } |
| |
| 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(10)); |
| 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[LIBRARY_SPECIFIC_UNITS], hasLength(1)); |
| expect(outputs[PARSE_ERRORS], hasLength(0)); |
| expect(outputs[PARSED_UNIT], isNotNull); |
| expect(outputs[SOURCE_KIND], SourceKind.PART); |
| expect(outputs[UNITS], hasLength(1)); |
| expect(outputs[REFERENCED_SOURCES], hasLength(2)); |
| } |
| |
| void _performParseTask(String content) { |
| if (content == null) { |
| source = resourceProvider.getFile('/test.dart').createSource(); |
| } else { |
| source = newSource('/test.dart', content); |
| } |
| computeResult(source, PARSED_UNIT, matcher: isParseDartTask); |
| } |
| |
| static void _assertHasCore(dynamic sourceList, int lenght) { |
| List<Source> sources = sourceList as List<Source>; |
| expect(sources, hasLength(lenght)); |
| expect(sources, contains(predicate((Source s) { |
| return s.fullName.endsWith('core.dart'); |
| }))); |
| } |
| } |
| |
| @reflectiveTest |
| class PartiallyResolveUnitReferencesTaskTest extends _AbstractDartTaskTest { |
| test_perform_propagable() { |
| enableStrongMode(); |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| const t1 = 1; |
| final t2 = 2; |
| var t3 = 3; |
| final t4; |
| class C { |
| static const fs1 = 1; |
| static final fs2 = 2; |
| static var fs3 = 3; |
| static final fs4; |
| const fi1 = 1; |
| final fi2 = 2; |
| var fi3 = 3; |
| final fi4; |
| } |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, PROPAGABLE_VARIABLES_IN_UNIT, |
| matcher: isPartiallyResolveUnitReferencesTask); |
| // PROPAGABLE_VARIABLES_IN_UNIT |
| List<VariableElement> variables = |
| outputs[PROPAGABLE_VARIABLES_IN_UNIT] as List<VariableElement>; |
| expect(variables.map((v) => v.displayName), |
| unorderedEquals(['t1', 't2', 'fs1', 'fs2', 'fi1', 'fi2'])); |
| } |
| |
| test_perform_strong_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_UNIT7, |
| matcher: isPartiallyResolveUnitReferencesTask); |
| // validate |
| expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(0)); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| 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_strong_inferable() { |
| 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_UNIT7, |
| matcher: isPartiallyResolveUnitReferencesTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| // INFERABLE_STATIC_VARIABLES_IN_UNIT |
| { |
| List<VariableElement> variables = |
| outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] as List<VariableElement>; |
| expect(variables, hasLength(4)); |
| expect(variables.map((v) => v.displayName), |
| unorderedEquals(['a', 'b', 'd', 'f'])); |
| } |
| // 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_strong_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_UNIT7, |
| matcher: isPartiallyResolveUnitReferencesTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| 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 PropagateVariableTypesInUnitTaskTest extends _AbstractDartTaskTest { |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT8); |
| expect(outputs[RESOLVED_UNIT8], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT8], isTrue); |
| } |
| |
| void test_perform_cycle() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| final piFirst = true; |
| final pi = piFirst ? 3.14 : tau / 2; |
| final tau = piFirst ? pi * 2 : 6.28; |
| '''); |
| // compute |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8, |
| matcher: isPropagateVariableTypesInUnitTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT8]; |
| // verify |
| TopLevelVariableElement piFirst = |
| AstFinder.getTopLevelVariableElement(unit, 'piFirst'); |
| TopLevelVariableElement pi = |
| AstFinder.getTopLevelVariableElement(unit, 'pi'); |
| TopLevelVariableElement tau = |
| AstFinder.getTopLevelVariableElement(unit, 'tau'); |
| expect(piFirst.propagatedType, context.typeProvider.boolType); |
| expect(pi.propagatedType, isNull); |
| expect(tau.propagatedType, isNull); |
| } |
| |
| void test_perform_topLevel() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| //final a = b + c.length; |
| final a = b; |
| final b = 1; |
| final c = '2'; |
| '''); |
| // compute |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8, |
| matcher: isPropagateVariableTypesInUnitTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT8]; |
| // verify |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| expect(AstFinder.getTopLevelVariableElement(unit, 'a').propagatedType, |
| intType); |
| expect(AstFinder.getTopLevelVariableElement(unit, 'b').propagatedType, |
| intType); |
| expect(AstFinder.getTopLevelVariableElement(unit, 'c').propagatedType, |
| stringType); |
| } |
| } |
| |
| @reflectiveTest |
| class PropagateVariableTypeTaskTest extends _AbstractDartTaskTest { |
| void test_perform_cycle() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| final piFirst = true; |
| final pi = piFirst ? 3.14 : tau / 2; |
| final tau = piFirst ? pi * 2 : 6.28; |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| TopLevelVariableElement piFirst = |
| AstFinder.getTopLevelVariableElement(unit, 'piFirst'); |
| TopLevelVariableElement pi = |
| AstFinder.getTopLevelVariableElement(unit, 'pi'); |
| TopLevelVariableElement tau = |
| AstFinder.getTopLevelVariableElement(unit, 'tau'); |
| // compute |
| computeResult(piFirst, PROPAGATED_VARIABLE, |
| matcher: isPropagateVariableTypeTask); |
| expect(piFirst.propagatedType, context.typeProvider.boolType); |
| expect(pi.propagatedType, isNull); |
| expect(tau.propagatedType, isNull); |
| } |
| |
| void test_perform_null() { |
| enableStrongMode(); |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| var a = null; |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| TopLevelVariableElement a = AstFinder.getTopLevelVariableElement(unit, 'a'); |
| // compute |
| computeResult(a, PROPAGATED_VARIABLE, matcher: isPropagateVariableTypeTask); |
| expect(a.propagatedType, isNull); |
| } |
| |
| void test_perform_topLevel() { |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| final a = b + c.length; |
| final b = 1; |
| final c = '2'; |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7); |
| CompilationUnit unit = outputs[RESOLVED_UNIT7]; |
| TopLevelVariableElement elementA = |
| AstFinder.getTopLevelVariableElement(unit, 'a'); |
| TopLevelVariableElement elementB = |
| AstFinder.getTopLevelVariableElement(unit, 'b'); |
| TopLevelVariableElement elementC = |
| AstFinder.getTopLevelVariableElement(unit, 'c'); |
| // compute |
| computeResult(elementA, PROPAGATED_VARIABLE, |
| matcher: isPropagateVariableTypeTask); |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| expect(elementA.propagatedType, intType); |
| expect(elementB.propagatedType, intType); |
| expect(elementC.propagatedType, stringType); |
| } |
| } |
| |
| @reflectiveTest |
| class ResolveDirectiveElementsTaskTest 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]; |
| LibrarySpecificUnit targetA = new LibrarySpecificUnit(sourceA, sourceA); |
| // build directive elements |
| computeResult(sourceA, LIBRARY_ELEMENT2, |
| matcher: isBuildDirectiveElementsTask); |
| // prepare outputs |
| LibraryElement libraryElementA = outputs[LIBRARY_ELEMENT2]; |
| LibraryElement libraryElementB = libraryElementA.imports[0].importedLibrary; |
| LibraryElement libraryElementC = libraryElementA.exports[0].exportedLibrary; |
| // clear elements in directive ASTs |
| { |
| CompilationUnit unitA = context.getResult(targetA, RESOLVED_UNIT1); |
| unitA.directives[1].element = null; |
| unitA.directives[2].element = null; |
| } |
| // resolve directive ASTs |
| computeResult(targetA, RESOLVED_UNIT2, |
| matcher: isResolveDirectiveElementsTask); |
| // validate that directive ASTs have elements |
| CompilationUnit unitA = context.getResult(targetA, RESOLVED_UNIT2); |
| { |
| ImportDirective importNode = unitA.directives[1]; |
| ImportElement importElement = importNode.element; |
| expect(importElement, isNotNull); |
| expect(importElement.importedLibrary, libraryElementB); |
| } |
| { |
| ExportDirective exportNode = unitA.directives[2]; |
| ExportElement exportElement = exportNode.element; |
| expect(exportElement, isNotNull); |
| expect(exportElement.exportedLibrary, libraryElementC); |
| } |
| } |
| } |
| |
| @reflectiveTest |
| class ResolveInstanceFieldsInUnitTaskTest extends _AbstractDartTaskTest { |
| @override |
| void setUp() { |
| super.setUp(); |
| enableStrongMode(); |
| } |
| |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT10); |
| expect(outputs[RESOLVED_UNIT10], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT10], isTrue); |
| } |
| |
| // 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_UNIT10); |
| CompilationUnit unit1 = outputs[RESOLVED_UNIT10]; |
| |
| // B.b2 shoud be resolved on the rhs, but not yet inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b2"), dynamicType, intType); |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT10); |
| CompilationUnit unit0 = outputs[RESOLVED_UNIT10]; |
| |
| // B.b2 should now be fully resolved and inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType); |
| |
| // A.a2 should now be resolved on the rhs, but not yet inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, intType); |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT10); |
| |
| // A.a2 should now be fully resolved and inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.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; |
| } |
| ''' |
| }); |
| DartType dynamicType = context.typeProvider.dynamicType; |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT10); |
| CompilationUnit unit0 = outputs[RESOLVED_UNIT10]; |
| |
| // A.a2 should now be resolved on the rhs, but not yet inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT10); |
| |
| // A.a2 should now be fully resolved and inferred (but not re-resolved). |
| assertVariableDeclarationTypes( |
| AstFinder.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_UNIT10); |
| CompilationUnit unit1 = outputs[RESOLVED_UNIT10]; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b2"), dynamicType, intType); |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT10); |
| CompilationUnit unit0 = outputs[RESOLVED_UNIT10]; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType); |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT10); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.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_UNIT10); |
| CompilationUnit unit0 = outputs[RESOLVED_UNIT10]; |
| |
| // A.a2 should now be resolved on the rhs, but not yet inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
| |
| // B.b2 shoud be resolved on the rhs, but not yet inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "B", "b2"), dynamicType, intType); |
| |
| computeResult( |
| new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT10); |
| |
| // A.a2 should now be fully resolved and inferred (but not re-resolved). |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType); |
| |
| // B.b2 should now be fully resolved and inferred. |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "B", "b2"), intType, intType); |
| } |
| } |
| |
| @reflectiveTest |
| class ResolveLibraryTaskTest extends _AbstractDartTaskTest { |
| test_perform() { |
| Source sourceLib = newSource( |
| '/my_lib.dart', |
| ''' |
| library my_lib; |
| const a = new A(); |
| class A { |
| const A(); |
| } |
| @a |
| class C {} |
| '''); |
| computeResult(sourceLib, LIBRARY_ELEMENT, matcher: isResolveLibraryTask); |
| // validate |
| LibraryElement library = outputs[LIBRARY_ELEMENT]; |
| ClassElement classC = library.getType('C'); |
| List<ElementAnnotation> metadata = classC.metadata; |
| expect(metadata, hasLength(1)); |
| ElementAnnotation annotation = metadata[0]; |
| expect(annotation, isNotNull); |
| expect((annotation as ElementAnnotationImpl).evaluationResult, isNotNull); |
| } |
| } |
| |
| @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_ELEMENT6, |
| matcher: isResolveLibraryTypeNamesTask); |
| // validate |
| LibraryElement library = outputs[LIBRARY_ELEMENT6]; |
| { |
| ClassElement classB = library.getType('B'); |
| expect(classB.supertype.displayName, 'A'); |
| } |
| { |
| ClassElement classC = library.getType('C'); |
| expect(classC.supertype.displayName, 'A'); |
| } |
| expect(library.loadLibraryFunction, isNotNull); |
| } |
| |
| 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_ELEMENT6, |
| matcher: isResolveLibraryTypeNamesTask); |
| // validate |
| LibraryElement library = outputs[LIBRARY_ELEMENT6]; |
| { |
| ClassElement clazz = library.getType('A'); |
| expect(clazz.displayName, 'A'); |
| clazz = clazz.supertype.element; |
| expect(clazz.displayName, 'B'); |
| } |
| } |
| } |
| |
| @reflectiveTest |
| class ResolveTopLevelUnitTypeBoundsTaskTest extends _AbstractDartTaskTest { |
| test_perform_boundIsGenericType() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class C<T extends Map<String, List<int>>> {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT4, |
| matcher: isResolveTopLevelUnitTypeBoundsTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
| ClassDeclaration nodeC = unit.declarations[0]; |
| _assertTypeParameterBound(nodeC.typeParameters.typeParameters[0], |
| 'Map<String, List<int>>', 'Map'); |
| } |
| |
| test_perform_errors() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class C<T extends NoSuchClass> {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVE_TYPE_BOUNDS_ERRORS, |
| matcher: isResolveTopLevelUnitTypeBoundsTask); |
| // validate |
| _fillErrorListener(RESOLVE_TYPE_BOUNDS_ERRORS); |
| errorListener |
| .assertErrorsWithCodes(<ErrorCode>[StaticWarningCode.UNDEFINED_CLASS]); |
| } |
| |
| test_perform_ignoreBoundsOfBounds() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class A<T1 extends num> {} |
| class B<T2 extends A> {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT4, |
| matcher: isResolveTopLevelUnitTypeBoundsTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
| ClassDeclaration nodeB = unit.declarations[1]; |
| _assertTypeParameterBound( |
| nodeB.typeParameters.typeParameters[0], 'A<dynamic>', 'A'); |
| } |
| |
| test_perform_outputs() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| class C<T extends int> {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT4); |
| expect(outputs[RESOLVED_UNIT4], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT4], isTrue); |
| expect(outputs[RESOLVE_TYPE_BOUNDS_ERRORS], isNotNull); |
| } |
| |
| test_perform_unitMember_ClassDeclaration() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class C<T extends int> extends Object {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT4, |
| matcher: isResolveTopLevelUnitTypeBoundsTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
| ClassDeclaration nodeC = unit.declarations[0]; |
| // 'extends Object' is not resolved |
| expect(nodeC.extendsClause.superclass.name.staticElement, isNull); |
| // but 'T extends int' is resolved |
| _assertTypeParameterBound( |
| nodeC.typeParameters.typeParameters[0], 'int', 'int'); |
| } |
| |
| test_perform_unitMember_ClassTypeAlias() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class C<T extends double> = Object; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT4, |
| matcher: isResolveTopLevelUnitTypeBoundsTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
| ClassTypeAlias nodeC = unit.declarations[0]; |
| // '= Object' is not resolved |
| expect(nodeC.superclass.name.staticElement, isNull); |
| // but 'T extends int' is resolved |
| _assertTypeParameterBound( |
| nodeC.typeParameters.typeParameters[0], 'double', 'double'); |
| } |
| |
| test_perform_unitMember_FunctionTypeAlias() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| typedef F<T extends String>(); |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT4, |
| matcher: isResolveTopLevelUnitTypeBoundsTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT4]; |
| FunctionTypeAlias nodeF = unit.declarations[0]; |
| // but 'T extends String' is resolved |
| _assertTypeParameterBound( |
| nodeF.typeParameters.typeParameters[0], 'String', 'String'); |
| } |
| |
| void _assertTypeParameterBound(TypeParameter typeParameter, |
| String expectedBoundTypeString, String expectedBoundElementName) { |
| TypeName boundNode = typeParameter.bound; |
| Identifier boundName = boundNode.name; |
| expect(boundNode.type.toString(), expectedBoundTypeString); |
| expect(boundName.staticType.toString(), expectedBoundTypeString); |
| expect(boundName.staticElement.displayName, expectedBoundElementName); |
| } |
| } |
| |
| @reflectiveTest |
| class ResolveUnitTaskTest extends _AbstractDartTaskTest { |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT12); |
| expect(outputs[RESOLVED_UNIT12], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT12], isTrue); |
| } |
| |
| 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_UNIT12, |
| matcher: isResolveUnitTask); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| |
| 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 test_perform_ensurePropagatedVariableTypes() { |
| newSource( |
| '/lib.dart', |
| ''' |
| class A { |
| final v = 1; |
| } |
| '''); |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| import 'lib.dart'; |
| main(A a) { |
| a.v.isEven; |
| } |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT12, |
| matcher: isResolveUnitTask); |
| expect(outputs[RESOLVE_UNIT_ERRORS], hasLength(0)); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| FunctionDeclaration main = unit.declarations[0]; |
| BlockFunctionBody body = main.functionExpression.body; |
| ExpressionStatement statement = body.block.statements.single; |
| Expression expression = statement.expression; |
| expect(expression.bestType, context.typeProvider.boolType); |
| } |
| |
| void _assertResolved(FunctionBody body) { |
| ResolutionVerifier verifier = new ResolutionVerifier(); |
| body.accept(verifier); |
| verifier.assertResolved(); |
| } |
| } |
| |
| @reflectiveTest |
| class ResolveUnitTypeNamesTaskTest extends _AbstractDartTaskTest { |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT5); |
| expect(outputs[RESOLVED_UNIT5], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT5], isTrue); |
| } |
| |
| 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_UNIT5, matcher: isResolveUnitTypeNamesTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
| { |
| 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_UNIT5, matcher: isResolveUnitTypeNamesTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT5]; |
| 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(FunctionBody body, VariableElement variable, |
| bool mutatedInClosure, bool mutatedInScope) { |
| expect(body.isPotentiallyMutatedInClosure(variable), mutatedInClosure); |
| expect(body.isPotentiallyMutatedInScope(variable), mutatedInScope); |
| } |
| |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT6); |
| expect(outputs[RESOLVED_UNIT6], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT6], isTrue); |
| } |
| |
| test_perform_buildClosureLibraryElements() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| main() { |
| } |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT6, |
| 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_UNIT6, |
| matcher: isResolveVariableReferencesTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT6]; |
| FunctionDeclaration mainDeclaration = unit.declarations[0]; |
| FunctionBody body = mainDeclaration.functionExpression.body; |
| FunctionElement main = mainDeclaration.element; |
| expectMutated(body, main.localVariables[0], false, false); |
| expectMutated(body, main.localVariables[1], false, true); |
| expectMutated(body, main.localVariables[2], true, true); |
| expectMutated(body, main.localVariables[3], true, true); |
| } |
| |
| 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_UNIT6, |
| matcher: isResolveVariableReferencesTask); |
| // validate |
| CompilationUnit unit = outputs[RESOLVED_UNIT6]; |
| FunctionDeclaration mainDeclaration = unit.declarations[0]; |
| FunctionBody body = mainDeclaration.functionExpression.body; |
| FunctionElement main = mainDeclaration.element; |
| expectMutated(body, main.parameters[0], false, false); |
| expectMutated(body, main.parameters[1], false, true); |
| expectMutated(body, main.parameters[2], true, true); |
| expectMutated(body, main.parameters[3], true, true); |
| } |
| } |
| |
| @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_UNIT12); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| VariableElement piFirst = |
| AstFinder.getTopLevelVariable(unit, 'piFirst').name.staticElement; |
| VariableElement pi = |
| AstFinder.getTopLevelVariable(unit, 'pi').name.staticElement; |
| VariableElement tau = |
| AstFinder.getTopLevelVariable(unit, 'tau').name.staticElement; |
| Expression piFirstUse = (AstFinder |
| .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_UNIT12); |
| CompilationUnit unit1 = outputs[RESOLVED_UNIT12]; |
| computeResult( |
| new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT12); |
| CompilationUnit unit2 = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit1, "x"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "A", "x"), intType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit2, "y"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit2, "B", "y"), intType, intType); |
| |
| List<Statement> statements = |
| AstFinder.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_UNIT12).toList(); |
| CompilationUnit unit0 = units[0]; |
| CompilationUnit unit1 = units[1]; |
| CompilationUnit unit2 = units[2]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType); |
| |
| List<Statement> statements = |
| AstFinder.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_UNIT12).toList(); |
| CompilationUnit unit0 = units[0]; |
| CompilationUnit unit2 = units[2]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| |
| assertVariableDeclarationStatementTypes( |
| AstFinder.getStatementsInTopLevelFunction(unit0, "foo")[0], |
| stringType, |
| intType); |
| assertVariableDeclarationStatementTypes( |
| AstFinder.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_UNIT12); |
| CompilationUnit unit1 = outputs[RESOLVED_UNIT12]; |
| computeResult( |
| new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT12); |
| CompilationUnit unit2 = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit1, "x"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "A", "x"), intType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit2, "y"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit2, "B", "y"), intType, intType); |
| |
| List<Statement> statements = |
| AstFinder.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_UNIT12).toList(); |
| CompilationUnit unit0 = units[0]; |
| CompilationUnit unit1 = units[1]; |
| CompilationUnit unit2 = units[2]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType); |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType); |
| |
| List<Statement> statements = |
| AstFinder.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_UNIT12); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| |
| List<Statement> statements = |
| AstFinder.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_UNIT12); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| |
| List<Statement> statements = |
| AstFinder.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( |
| AstFinder.getFieldInClass(unit, "A", "x"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.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_UNIT12); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| |
| List<Statement> statements = |
| AstFinder.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( |
| AstFinder.getTopLevelVariable(unit, "x"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit, "y"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.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_UNIT12); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| DartType bottomType = context.typeProvider.bottomType; |
| DartType dynamicType = context.typeProvider.dynamicType; |
| |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit, "x"), dynamicType, bottomType); |
| assertVariableDeclarationTypes( |
| AstFinder.getTopLevelVariable(unit, "y"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit, "A", "x"), dynamicType, bottomType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit, "A", "y"), intType, intType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit, "A", "x2"), dynamicType, bottomType); |
| assertVariableDeclarationTypes( |
| AstFinder.getFieldInClass(unit, "A", "y2"), intType, intType); |
| |
| List<Statement> statements = |
| AstFinder.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_UNIT12); |
| CompilationUnit unit = outputs[RESOLVED_UNIT12]; |
| |
| InterfaceType intType = context.typeProvider.intType; |
| InterfaceType stringType = context.typeProvider.stringType; |
| |
| List<Statement> statements = |
| AstFinder.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 StrongModeVerifyUnitTaskTest extends _AbstractDartTaskTest { |
| @override |
| void setUp() { |
| super.setUp(); |
| enableStrongMode(); |
| } |
| |
| test_created_resolved_unit() { |
| Source source = newSource( |
| '/test.dart', |
| r''' |
| library lib; |
| class A {} |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, RESOLVED_UNIT); |
| expect(outputs[RESOLVED_UNIT], isNotNull); |
| expect(outputs[CREATED_RESOLVED_UNIT], isTrue); |
| } |
| |
| void test_perform_recordDynamicInvoke() { |
| enableStrongMode(); |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| void main() { |
| dynamic a = []; |
| a[0]; |
| } |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), STRONG_MODE_ERRORS); |
| CompilationUnit unit = outputs[RESOLVED_UNIT]; |
| |
| // validate |
| _fillErrorListener(STRONG_MODE_ERRORS); |
| expect(errorListener.errors, isEmpty); |
| |
| List<Statement> statements = |
| AstFinder.getStatementsInTopLevelFunction(unit, "main"); |
| ExpressionStatement statement = statements[1]; |
| IndexExpression idx = statement.expression; |
| expect(DynamicInvoke.get(idx.target), isNotNull); |
| expect(DynamicInvoke.get(idx.target), isNotNull); |
| expect(DynamicInvoke.get(idx.target), isTrue); |
| } |
| |
| void test_perform_verifyError() { |
| enableStrongMode(); |
| AnalysisTarget source = newSource( |
| '/test.dart', |
| ''' |
| class A {} |
| class B extends A {} |
| B b = new A(); |
| '''); |
| computeResult(new LibrarySpecificUnit(source, source), STRONG_MODE_ERRORS); |
| // validate |
| _fillErrorListener(STRONG_MODE_ERRORS); |
| |
| var errors = errorListener.errors; |
| expect(errors.length, 1); |
| expect(errors[0].errorCode.name, "STRONG_MODE_STATIC_TYPE_ERROR"); |
| } |
| } |
| |
| @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_ConstantValidator_declaredIdentifier() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| void main() { |
| for (const foo in []) { |
| print(foo); |
| } |
| } |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
| // validate |
| _fillErrorListener(VERIFY_ERRORS); |
| errorListener.assertNoErrors(); |
| } |
| |
| test_perform_ConstantValidator_dependencyCycle() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| const int a = b; |
| const int b = c; |
| const int c = a; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
| // validate |
| _fillErrorListener(VERIFY_ERRORS); |
| errorListener.assertErrorsWithCodes(<ErrorCode>[ |
| CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, |
| CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, |
| CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT |
| ]); |
| } |
| |
| test_perform_ConstantValidator_duplicateFields() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| class Test { |
| final int x = 1; |
| final int x = 2; |
| const Test(); |
| } |
| |
| main() { |
| const Test(); |
| } |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
| // validate |
| _fillErrorListener(VERIFY_ERRORS); |
| errorListener.assertNoErrors(); |
| } |
| |
| test_perform_ConstantValidator_noInitializer() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| const x; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
| // validate |
| _fillErrorListener(VERIFY_ERRORS); |
| errorListener.assertErrorsWithCodes( |
| <ErrorCode>[CompileTimeErrorCode.CONST_NOT_INITIALIZED]); |
| } |
| |
| test_perform_ConstantValidator_unknownValue() { |
| Source source = newSource( |
| '/test.dart', |
| ''' |
| import 'no-such-file.dart' as p; |
| |
| const int x = p.y; |
| '''); |
| LibrarySpecificUnit target = new LibrarySpecificUnit(source, source); |
| computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask); |
| // validate |
| _fillErrorListener(VERIFY_ERRORS); |
| errorListener.assertErrorsWithCodes(<ErrorCode>[ |
| CompileTimeErrorCode.URI_DOES_NOT_EXIST, |
| 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); |
| |
| var errors = errorListener.errors; |
| expect(errors.length, 1); |
| expect(errors[0].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; |
| } |
| |
| 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] as List<AnalysisError>; |
| expect(errors, isNotNull, reason: result.name); |
| errorListener = new GatheringErrorListener(); |
| errorListener.addAll(errors); |
| } |
| } |