| // Copyright (c) 2019, 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. |
| |
| import 'package:analyzer/dart/analysis/analysis_context_collection.dart'; |
| import 'package:analyzer/dart/analysis/results.dart'; |
| import 'package:analyzer/dart/element/element.dart'; |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; |
| import 'package:analyzer/dart/element/type.dart'; |
| import 'package:analyzer/dart/element/type_provider.dart'; |
| import 'package:analyzer/src/dart/element/element.dart'; |
| import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/generated/utilities_dart.dart'; |
| import 'package:analyzer/src/test_utilities/find_element.dart'; |
| import 'package:analyzer/src/test_utilities/find_node.dart'; |
| import 'package:analyzer/src/test_utilities/mock_sdk.dart'; |
| import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart'; |
| import 'package:nnbd_migration/instrumentation.dart'; |
| import 'package:nnbd_migration/src/already_migrated_code_decorator.dart'; |
| import 'package:nnbd_migration/src/decorated_type.dart'; |
| import 'package:nnbd_migration/src/nullability_node.dart'; |
| import 'package:nnbd_migration/src/nullability_node_target.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import 'migration_visitor_test_base.dart'; |
| |
| main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(_AlreadyMigratedCodeDecoratorTestNormal); |
| defineReflectiveTests(_AlreadyMigratedCodeDecoratorTestProvisional); |
| }); |
| } |
| |
| class _AlreadyMigratedCodeDecoratorTestBase { |
| final NullabilitySuffix suffix; |
| |
| final decoratedTypeParameterBounds = DecoratedTypeParameterBounds(); |
| |
| _AlreadyMigratedCodeDecoratorTestBase(this.suffix); |
| |
| DecoratedType? getDecoratedBound(TypeParameterElement element) => |
| decoratedTypeParameterBounds.get(element); |
| |
| void setUp() { |
| DecoratedTypeParameterBounds.current = decoratedTypeParameterBounds; |
| } |
| |
| void tearDown() { |
| DecoratedTypeParameterBounds.current = null; |
| } |
| |
| Future<void> test_decorate_dynamic() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| withElement.checkDynamic( |
| withElement.decorate(withElement.typeProvider.dynamicType), |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_functionType_generic_bounded() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class A<T extends num> {}', |
| ); |
| var typeFormal = withUnit.findElement.typeParameter('T'); |
| var withElement = withUnit.withElement(typeFormal); |
| |
| var decoratedType = withElement.decorate( |
| FunctionTypeImpl( |
| typeFormals: [typeFormal], |
| parameters: const [], |
| returnType: TypeParameterTypeImpl( |
| element: typeFormal, |
| nullabilitySuffix: NullabilitySuffix.star, |
| ), |
| nullabilitySuffix: suffix, |
| ), |
| ); |
| withElement.checkNum( |
| getDecoratedBound(typeFormal)!, |
| withElement.checkExplicitlyNonNullable, |
| 'bound of type formal T of test type'); |
| withElement.checkTypeParameter( |
| decoratedType.returnType!, |
| withElement.checkExplicitlyNonNullable, |
| typeFormal, |
| 'return type of test type'); |
| } |
| |
| Future<void> test_decorate_functionType_generic_no_explicit_bound() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class A<T> {}', |
| ); |
| var typeFormal = withUnit.findElement.typeParameter('T'); |
| var withElement = withUnit.withElement(typeFormal); |
| |
| var decoratedType = withElement.decorate( |
| FunctionTypeImpl( |
| typeFormals: [typeFormal], |
| parameters: const [], |
| returnType: TypeParameterTypeImpl( |
| element: typeFormal, |
| nullabilitySuffix: NullabilitySuffix.star, |
| ), |
| nullabilitySuffix: suffix, |
| ), |
| ); |
| withElement.checkObject( |
| getDecoratedBound(typeFormal)!, |
| withElement.checkExplicitlyNullable, |
| 'bound of type formal T of test type'); |
| withElement.checkTypeParameter( |
| decoratedType.returnType!, |
| withElement.checkExplicitlyNonNullable, |
| typeFormal, |
| 'return type of test type'); |
| } |
| |
| Future<void> test_decorate_functionType_named_parameter() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkDynamic( |
| withElement |
| .decorate( |
| FunctionTypeImpl( |
| typeFormals: const [], |
| parameters: [ |
| ParameterElementImpl.synthetic( |
| 'x', |
| withElement.typeProvider.dynamicType, |
| ParameterKind.NAMED, |
| ) |
| ], |
| returnType: withElement.typeProvider.voidType, |
| nullabilitySuffix: suffix, |
| ), |
| ) |
| .namedParameters!['x'], |
| 'parameter x of test type'); |
| } |
| |
| Future<void> test_decorate_functionType_ordinary_parameters() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| var decoratedType = withElement.decorate( |
| FunctionTypeImpl( |
| typeFormals: const [], |
| parameters: [ |
| ParameterElementImpl.synthetic( |
| 'x', |
| withElement.typeProvider.dynamicType, |
| ParameterKind.REQUIRED, |
| ), |
| ParameterElementImpl.synthetic( |
| 'y', |
| withElement.typeProvider.dynamicType, |
| ParameterKind.REQUIRED, |
| ) |
| ], |
| returnType: withElement.typeProvider.voidType, |
| nullabilitySuffix: suffix, |
| ), |
| ); |
| withElement.checkDynamic( |
| decoratedType.positionalParameters![0], 'parameter 0 of test type'); |
| withElement.checkDynamic( |
| decoratedType.positionalParameters![1], 'parameter 1 of test type'); |
| } |
| |
| Future<void> test_decorate_functionType_positional_parameter() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkDynamic( |
| withElement |
| .decorate( |
| FunctionTypeImpl( |
| typeFormals: const [], |
| parameters: [ |
| ParameterElementImpl.synthetic( |
| 'x', |
| withElement.typeProvider.dynamicType, |
| ParameterKind.POSITIONAL, |
| ) |
| ], |
| returnType: withElement.typeProvider.voidType, |
| nullabilitySuffix: suffix, |
| ), |
| ) |
| .positionalParameters![0], |
| 'parameter 0 of test type'); |
| } |
| |
| Future<void> test_decorate_functionType_question() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkExplicitlyNullable( |
| withElement |
| .decorate( |
| FunctionTypeImpl( |
| typeFormals: const [], |
| parameters: const [], |
| returnType: withElement.typeProvider.voidType, |
| nullabilitySuffix: NullabilitySuffix.question, |
| ), |
| ) |
| .node, |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_functionType_returnType() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkDynamic( |
| withElement |
| .decorate( |
| FunctionTypeImpl( |
| typeFormals: const [], |
| parameters: const [], |
| returnType: withElement.typeProvider.dynamicType, |
| nullabilitySuffix: suffix, |
| ), |
| ) |
| .returnType, |
| 'return type of test type'); |
| } |
| |
| Future<void> test_decorate_functionType_star() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkExplicitlyNonNullable( |
| withElement |
| .decorate( |
| FunctionTypeImpl( |
| typeFormals: const [], |
| parameters: const [], |
| returnType: withElement.typeProvider.voidType, |
| nullabilitySuffix: suffix, |
| ), |
| ) |
| .node, |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_interfaceType_parameters() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| var decoratedType = withElement.decorate(InterfaceTypeImpl( |
| element: withElement.typeProvider.mapElement, |
| typeArguments: [ |
| withElement.typeProvider.intType, |
| withElement.typeProvider.numType |
| ], |
| nullabilitySuffix: suffix)); |
| withElement.checkInt(decoratedType.typeArguments[0]!, |
| withElement.checkExplicitlyNonNullable, 'type argument 0 of test type'); |
| withElement.checkNum(decoratedType.typeArguments[1]!, |
| withElement.checkExplicitlyNonNullable, 'type argument 1 of test type'); |
| } |
| |
| Future<void> test_decorate_interfaceType_simple_question() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkInt( |
| withElement.decorate( |
| InterfaceTypeImpl( |
| element: withElement.typeProvider.intElement, |
| typeArguments: const [], |
| nullabilitySuffix: NullabilitySuffix.question, |
| ), |
| ), |
| withElement.checkExplicitlyNullable, |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_interfaceType_simple_star() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkInt( |
| withElement.decorate( |
| InterfaceTypeImpl( |
| element: withElement.typeProvider.intElement, |
| typeArguments: const [], |
| nullabilitySuffix: suffix, |
| ), |
| ), |
| withElement.checkExplicitlyNonNullable, |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_iterable_dynamic() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| var decorated = |
| withElement.decorate(withElement.typeProvider.iterableDynamicType); |
| withElement.checkIterable(decorated, withElement.checkExplicitlyNonNullable, |
| withElement.checkDynamic, 'test type'); |
| } |
| |
| Future<void> test_decorate_never() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkNever( |
| withElement.decorate(withElement.typeProvider.neverType), 'test type'); |
| } |
| |
| Future<void> test_decorate_typeParameterType_question() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class A<T> {}', |
| ); |
| var element = withUnit.findElement.typeParameter('T'); |
| var withElement = withUnit.withElement(element); |
| |
| withElement.checkTypeParameter( |
| withElement.decorate(TypeParameterTypeImpl( |
| element: element, nullabilitySuffix: NullabilitySuffix.question)), |
| withElement.checkExplicitlyNullable, |
| element, |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_typeParameterType_star() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class A<T> {}', |
| ); |
| var element = withUnit.findElement.typeParameter('T'); |
| var withElement = withUnit.withElement(element); |
| |
| withElement.checkTypeParameter( |
| withElement.decorate( |
| TypeParameterTypeImpl(element: element, nullabilitySuffix: suffix)), |
| withElement.checkExplicitlyNonNullable, |
| element, |
| 'test type'); |
| } |
| |
| Future<void> test_decorate_void() async { |
| var withElement = await _ContextWithFiles().withEmptyUnit(); |
| |
| withElement.checkVoid( |
| withElement.decorate(withElement.typeProvider.voidType), 'test type'); |
| } |
| |
| Future<void> test_getImmediateSupertypes_future() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement(''); |
| var element = withUnit.typeProvider.futureElement; |
| var withElement = withUnit.withElement(element); |
| |
| // var class_ = element = typeProvider.futureElement; |
| var class_ = withElement.typeProvider.futureElement; |
| var decoratedSupertypes = |
| withElement.decorator.getImmediateSupertypes(class_).toList(); |
| var typeParam = class_.typeParameters[0]; |
| expect(decoratedSupertypes, hasLength(2)); |
| // TODO(scheglov) Use location matcher. |
| withElement.checkObject(decoratedSupertypes[0], |
| withElement.checkExplicitlyNonNullable, 'Future (async.dart:7:16)'); |
| // Since Future<T> is a subtype of FutureOr<T>, we consider FutureOr<T> to |
| // be an immediate supertype, even though the class declaration for Future |
| // doesn't mention FutureOr. |
| // TODO(scheglov) Use location matcher. |
| withElement.checkFutureOr( |
| decoratedSupertypes[1], |
| withElement.checkExplicitlyNonNullable, |
| (t, displayName) => withElement.checkTypeParameter( |
| t!, withElement.checkExplicitlyNonNullable, typeParam, displayName), |
| 'Future (async.dart:7:16)'); |
| } |
| |
| Future<void> test_getImmediateSupertypes_generic() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class C<T> extends Iterable<T> {}', |
| ); |
| var unitElement = withUnit.unitElement; |
| var class_ = unitElement.classes.single; |
| var t = class_.typeParameters.single; |
| |
| var withElement = withUnit.withElement(class_); |
| |
| var decoratedSupertypes = |
| withElement.decorator.getImmediateSupertypes(class_).toList(); |
| expect(decoratedSupertypes, hasLength(1)); |
| withElement.checkIterable( |
| decoratedSupertypes[0], |
| withElement.checkExplicitlyNonNullable, |
| (type, displayName) => withElement.checkTypeParameter( |
| type!, withElement.checkExplicitlyNonNullable, t, displayName), |
| 'C (test.dart:1:7)'); |
| } |
| |
| Future<void> test_getImmediateSupertypes_interface() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class C implements num {}', |
| ); |
| var unitElement = withUnit.unitElement; |
| var class_ = unitElement.classes.single; |
| |
| var withElement = withUnit.withElement(class_); |
| |
| var decoratedSupertypes = |
| withElement.decorator.getImmediateSupertypes(class_).toList(); |
| expect(decoratedSupertypes, hasLength(2)); |
| withElement.checkObject(decoratedSupertypes[0], |
| withElement.checkExplicitlyNonNullable, 'C (test.dart:1:7)'); |
| withElement.checkNum(decoratedSupertypes[1], |
| withElement.checkExplicitlyNonNullable, 'C (test.dart:1:7)'); |
| } |
| |
| Future<void> test_getImmediateSupertypes_mixin() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class C with num {}', |
| ); |
| var unitElement = withUnit.unitElement; |
| var class_ = unitElement.classes.single; |
| |
| var withElement = withUnit.withElement(class_); |
| |
| var decoratedSupertypes = |
| withElement.decorator.getImmediateSupertypes(class_).toList(); |
| expect(decoratedSupertypes, hasLength(2)); |
| withElement.checkObject(decoratedSupertypes[0], |
| withElement.checkExplicitlyNonNullable, 'C (test.dart:1:7)'); |
| withElement.checkNum(decoratedSupertypes[1], |
| withElement.checkExplicitlyNonNullable, 'C (test.dart:1:7)'); |
| } |
| |
| Future<void> test_getImmediateSupertypes_superclassConstraint() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'mixin C on num {}', |
| ); |
| var unitElement = withUnit.unitElement; |
| var mixin_ = unitElement.mixins.single; |
| |
| var withElement = withUnit.withElement(mixin_); |
| |
| var decoratedSupertypes = |
| withElement.decorator.getImmediateSupertypes(mixin_).toList(); |
| expect(decoratedSupertypes, hasLength(1)); |
| withElement.checkNum(decoratedSupertypes[0], |
| withElement.checkExplicitlyNonNullable, 'C (test.dart:1:7)'); |
| } |
| |
| Future<void> test_getImmediateSupertypes_supertype() async { |
| var withUnit = await _ContextWithFiles().buildUnitElement( |
| 'class C {}', |
| ); |
| var unitElement = withUnit.unitElement; |
| var class_ = unitElement.classes.single; |
| |
| var withElement = withUnit.withElement(class_); |
| |
| var decoratedSupertypes = |
| withElement.decorator.getImmediateSupertypes(class_).toList(); |
| expect(decoratedSupertypes, hasLength(1)); |
| // TODO(paulberry): displayName should be 'Object supertype of C' |
| withElement.checkObject(decoratedSupertypes[0], |
| withElement.checkExplicitlyNonNullable, 'C (test.dart:1:7)'); |
| } |
| } |
| |
| /// Specialization of [_AlreadyMigratedCodeDecoratorTestBase] for testing the |
| /// situation where the already migrated code does not contain star types. In |
| /// the final product, by definition all already-migrated code will be free of |
| /// star types. However, since we do not yet migrate using a fully NNBD-aware |
| /// SDK, we need to handle both star and non-star variants on a short term |
| /// basis. |
| @reflectiveTest |
| class _AlreadyMigratedCodeDecoratorTestNormal |
| extends _AlreadyMigratedCodeDecoratorTestBase { |
| _AlreadyMigratedCodeDecoratorTestNormal() : super(NullabilitySuffix.none); |
| } |
| |
| /// Specialization of [_AlreadyMigratedCodeDecoratorTestBase] for testing the |
| /// situation where the already migrated code contains star types. In the final |
| /// product, this will never happen. However, since we do not yet migrate using |
| /// a fully NNBD-aware SDK, we need to handle both star and non-star variants on |
| /// a short term basis. |
| @reflectiveTest |
| class _AlreadyMigratedCodeDecoratorTestProvisional |
| extends _AlreadyMigratedCodeDecoratorTestBase { |
| _AlreadyMigratedCodeDecoratorTestProvisional() |
| : super(NullabilitySuffix.star); |
| } |
| |
| class _ContextWithElement with EdgeTester { |
| final _ContextWithUnitElement _withUnit; |
| final Element element; |
| |
| final NullabilityGraphForTesting graph = NullabilityGraphForTesting(); |
| |
| _ContextWithElement(this._withUnit, this.element); |
| |
| NullabilityNode get always => graph.always; |
| |
| AlreadyMigratedCodeDecorator get decorator { |
| return AlreadyMigratedCodeDecorator(graph, typeProvider); |
| } |
| |
| NullabilityNode get never => graph.never; |
| |
| TypeProvider get typeProvider { |
| return _withUnit.typeProvider; |
| } |
| |
| void checkAlwaysNullable(NullabilityNode node, String displayName) { |
| var edge = assertEdge(always, node, hard: true, checkable: false); |
| var origin = graph.getEdgeOrigin(edge)!; |
| expect(origin.kind, EdgeOriginKind.alwaysNullableType); |
| expect(origin.element, same(element)); |
| expect(node.displayName, displayName); |
| } |
| |
| void checkDynamic(DecoratedType? decoratedType, String displayName) { |
| expect(decoratedType!.type, same(typeProvider.dynamicType)); |
| checkAlwaysNullable(decoratedType.node!, displayName); |
| } |
| |
| void checkExplicitlyNonNullable(NullabilityNode? node, String displayName) { |
| var edge = assertEdge(node, never, hard: true, checkable: false); |
| var origin = graph.getEdgeOrigin(edge)!; |
| expect(origin.kind, EdgeOriginKind.alreadyMigratedType); |
| expect(origin.element, same(element)); |
| expect(node!.displayName, displayName); |
| } |
| |
| void checkExplicitlyNullable(NullabilityNode? node, String displayName) { |
| var edge = assertEdge(always, node, hard: true, checkable: false); |
| var origin = graph.getEdgeOrigin(edge)!; |
| expect(origin.kind, EdgeOriginKind.alreadyMigratedType); |
| expect(origin.element, same(element)); |
| expect(node!.displayName, displayName); |
| } |
| |
| void checkFutureOr( |
| DecoratedType decoratedType, |
| void Function(NullabilityNode?, String) checkNullability, |
| void Function(DecoratedType?, String) checkArgument, |
| String displayName, |
| ) { |
| expect(decoratedType.type!.element, typeProvider.futureOrElement); |
| checkNullability(decoratedType.node, displayName); |
| checkArgument( |
| decoratedType.typeArguments[0], 'type argument 0 of $displayName'); |
| } |
| |
| void checkInt( |
| DecoratedType decoratedType, |
| void Function(NullabilityNode?, String) checkNullability, |
| String displayName, |
| ) { |
| expect(decoratedType.type!.element, typeProvider.intType.element); |
| checkNullability(decoratedType.node, displayName); |
| } |
| |
| void checkIterable( |
| DecoratedType decoratedType, |
| void Function(NullabilityNode?, String) checkNullability, |
| void Function(DecoratedType?, String) checkArgument, |
| String displayName, |
| ) { |
| expect( |
| decoratedType.type!.element, typeProvider.iterableDynamicType.element); |
| checkNullability(decoratedType.node, displayName); |
| checkArgument( |
| decoratedType.typeArguments[0], 'type argument 0 of $displayName'); |
| } |
| |
| void checkNever(DecoratedType decoratedType, String displayName) { |
| expect(decoratedType.type, same(typeProvider.neverType)); |
| checkExplicitlyNonNullable(decoratedType.node, displayName); |
| } |
| |
| void checkNum( |
| DecoratedType decoratedType, |
| void Function(NullabilityNode?, String) checkNullability, |
| String displayName, |
| ) { |
| expect(decoratedType.type!.element, typeProvider.numType.element); |
| checkNullability(decoratedType.node, displayName); |
| } |
| |
| void checkObject( |
| DecoratedType decoratedType, |
| void Function(NullabilityNode?, String) checkNullability, |
| String displayName, |
| ) { |
| expect(decoratedType.type!.element, typeProvider.objectType.element); |
| checkNullability(decoratedType.node, displayName); |
| } |
| |
| void checkTypeParameter( |
| DecoratedType decoratedType, |
| void Function(NullabilityNode?, String) checkNullability, |
| TypeParameterElement expectedElement, |
| String displayName, |
| ) { |
| var type = decoratedType.type as TypeParameterTypeImpl; |
| expect(type.element, same(expectedElement)); |
| checkNullability(decoratedType.node, displayName); |
| } |
| |
| void checkVoid(DecoratedType decoratedType, String displayName) { |
| expect(decoratedType.type, same(typeProvider.voidType)); |
| checkAlwaysNullable(decoratedType.node!, displayName); |
| } |
| |
| DecoratedType decorate(DartType type) { |
| var decoratedType = decorator.decorate( |
| type, element, NullabilityNodeTarget.text('test type')); |
| expect(decoratedType.type, same(type)); |
| return decoratedType; |
| } |
| } |
| |
| class _ContextWithFiles with ResourceProviderMixin { |
| Future<_ContextWithUnitElement> buildUnitElement(String content) async { |
| var file = newFile('/home/test/lib/test.dart', content: content); |
| |
| var sdkRoot = newFolder('/sdk'); |
| createMockSdk( |
| resourceProvider: resourceProvider, |
| root: sdkRoot, |
| ); |
| |
| var contextCollection = AnalysisContextCollection( |
| resourceProvider: resourceProvider, |
| includedPaths: [file.path], |
| sdkPath: sdkRoot.path, |
| ); |
| var analysisContext = contextCollection.contextFor(file.path); |
| var analysisSession = analysisContext.currentSession; |
| var result = await analysisSession.getResolvedUnit(file.path); |
| return _ContextWithUnitElement(result as ResolvedUnitResult); |
| } |
| |
| Future<_ContextWithElement> withEmptyUnit() async { |
| var withUnit = await buildUnitElement(''); |
| return withUnit.withElement(withUnit.unitElement); |
| } |
| } |
| |
| class _ContextWithUnitElement { |
| final ResolvedUnitResult _unitResult; |
| |
| _ContextWithUnitElement(this._unitResult); |
| |
| FindElement get findElement { |
| return FindElement(_unitResult.unit); |
| } |
| |
| FindNode get findNode { |
| return FindNode(_unitResult.content, _unitResult.unit); |
| } |
| |
| TypeProvider get typeProvider { |
| return unitElement.library.typeProvider; |
| } |
| |
| CompilationUnitElement get unitElement { |
| return _unitResult.unit.declaredElement!; |
| } |
| |
| _ContextWithElement withElement(Element element) { |
| return _ContextWithElement(this, element); |
| } |
| } |