blob: 07e26678e394057b5f739de3364bdfa6e9e0ef0d [file] [log] [blame]
// Copyright (c) 2024, 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/element/scope.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/utilities/extensions/string.dart';
import 'package:analyzer_utilities/testing/tree_string_sink.dart';
import 'package:collection/collection.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../../util/element_printer.dart';
import '../../dart/resolution/node_text_expectations.dart';
import '../elements_base.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(LibraryFragmentElementTest_keepLinking);
defineReflectiveTests(LibraryFragmentElementTest_fromBytes);
defineReflectiveTests(UpdateNodeTextExpectations);
});
}
abstract class LibraryFragmentElementTest extends ElementsBaseTest {
test_libraryExports() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
export 'dart:math';
''');
var library = await buildLibrary(r'''
export 'dart:io';
part 'a.dart';
''');
checkElementText(library, r'''
library
reference: <testLibrary>
definingUnit: <testLibraryFragment>
units
<testLibraryFragment>
enclosingElement3: <null>
libraryExports
dart:io
enclosingElement3: <testLibraryFragment>
parts
part_0
uri: package:test/a.dart
enclosingElement3: <testLibraryFragment>
unit: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
enclosingElement3: <testLibraryFragment>
libraryExports
dart:math
enclosingElement3: <testLibrary>::@fragment::package:test/a.dart
----------------------------------------
library
reference: <testLibrary>
fragments
<testLibraryFragment>
element: <testLibrary>
nextFragment: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
element: <testLibrary>
enclosingFragment: <testLibraryFragment>
previousFragment: <testLibraryFragment>
''');
}
test_libraryExports_metadata() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
@deprecated
export 'dart:math';
''');
var library = await buildLibrary(r'''
part 'a.dart';
''');
checkElementText(library, r'''
library
reference: <testLibrary>
definingUnit: <testLibraryFragment>
units
<testLibraryFragment>
enclosingElement3: <null>
parts
part_0
uri: package:test/a.dart
enclosingElement3: <testLibraryFragment>
unit: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
enclosingElement3: <testLibraryFragment>
libraryExports
dart:math
enclosingElement3: <testLibrary>::@fragment::package:test/a.dart
metadata
Annotation
atSign: @ @21
name: SimpleIdentifier
token: deprecated @22
staticElement: dart:core::<fragment>::@getter::deprecated
element: dart:core::<fragment>::@getter::deprecated#element
staticType: null
element: dart:core::<fragment>::@getter::deprecated
element2: dart:core::<fragment>::@getter::deprecated#element
----------------------------------------
library
reference: <testLibrary>
fragments
<testLibraryFragment>
element: <testLibrary>
nextFragment: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
element: <testLibrary>
enclosingFragment: <testLibraryFragment>
previousFragment: <testLibraryFragment>
''');
}
test_libraryImports() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'dart:math';
''');
var library = await buildLibrary(r'''
import 'dart:io';
part 'a.dart';
''');
checkElementText(library, r'''
library
reference: <testLibrary>
definingUnit: <testLibraryFragment>
units
<testLibraryFragment>
enclosingElement3: <null>
libraryImports
dart:io
enclosingElement3: <testLibraryFragment>
parts
part_0
uri: package:test/a.dart
enclosingElement3: <testLibraryFragment>
unit: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
enclosingElement3: <testLibraryFragment>
libraryImports
dart:math
enclosingElement3: <testLibrary>::@fragment::package:test/a.dart
----------------------------------------
library
reference: <testLibrary>
fragments
<testLibraryFragment>
element: <testLibrary>
nextFragment: <testLibrary>::@fragment::package:test/a.dart
libraryImports
dart:io
<testLibrary>::@fragment::package:test/a.dart
element: <testLibrary>
enclosingFragment: <testLibraryFragment>
previousFragment: <testLibraryFragment>
libraryImports
dart:math
''');
}
test_libraryImports_metadata() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
@deprecated
import 'dart:math';
''');
var library = await buildLibrary(r'''
part 'a.dart';
''');
checkElementText(library, r'''
library
reference: <testLibrary>
definingUnit: <testLibraryFragment>
units
<testLibraryFragment>
enclosingElement3: <null>
parts
part_0
uri: package:test/a.dart
enclosingElement3: <testLibraryFragment>
unit: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
enclosingElement3: <testLibraryFragment>
libraryImports
dart:math
enclosingElement3: <testLibrary>::@fragment::package:test/a.dart
metadata
Annotation
atSign: @ @21
name: SimpleIdentifier
token: deprecated @22
staticElement: dart:core::<fragment>::@getter::deprecated
element: dart:core::<fragment>::@getter::deprecated#element
staticType: null
element: dart:core::<fragment>::@getter::deprecated
element2: dart:core::<fragment>::@getter::deprecated#element
----------------------------------------
library
reference: <testLibrary>
fragments
<testLibraryFragment>
element: <testLibrary>
nextFragment: <testLibrary>::@fragment::package:test/a.dart
<testLibrary>::@fragment::package:test/a.dart
element: <testLibrary>
enclosingFragment: <testLibraryFragment>
previousFragment: <testLibraryFragment>
libraryImports
dart:math
metadata
Annotation
atSign: @ @21
name: SimpleIdentifier
token: deprecated @22
staticElement: dart:core::<fragment>::@getter::deprecated
element: dart:core::<fragment>::@getter::deprecated#element
staticType: null
element: dart:core::<fragment>::@getter::deprecated
element2: dart:core::<fragment>::@getter::deprecated#element
''');
}
test_scope_accessibleExtensions_imported() async {
newFile('$testPackageLibPath/x.dart', r'''
extension X on int {}
''');
newFile('$testPackageLibPath/y.dart', r'''
extension Y on int {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'y.dart';
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart';
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(withAccessibleExtensions: true, library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
Uri.parse('package:test/b.dart'),
], [], r'''
package:test/test.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/a.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/y.dart::<fragment>::@extension::Y
package:test/aa.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/y.dart::<fragment>::@extension::Y
package:test/b.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
''');
}
test_scope_accessibleExtensions_imported_withPrefix() async {
newFile('$testPackageLibPath/x.dart', r'''
extension X on int {}
''');
newFile('$testPackageLibPath/y.dart', r'''
extension Y on int {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'y.dart' as y;
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart' as x;
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(withAccessibleExtensions: true, library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
Uri.parse('package:test/b.dart'),
], [], r'''
package:test/test.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/a.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/y.dart::<fragment>::@extension::Y
package:test/aa.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/y.dart::<fragment>::@extension::Y
package:test/b.dart
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
''');
}
test_scope_accessibleExtensions_local() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
part 'aa.dart';
extension A on int {}
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
extension B on int {}
''');
var library = await buildLibrary(r'''
part 'a.dart';
extension Z on int {}
''');
_assertScopeLookups(withAccessibleExtensions: true, library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
], [], r'''
package:test/test.dart
accessibleExtensions
<testLibrary>::@fragment::package:test/a.dart::@extension::A
<testLibrary>::@fragment::package:test/aa.dart::@extension::B
dart:core::<fragment>::@extension::EnumName
<testLibraryFragment>::@extension::Z
package:test/a.dart
accessibleExtensions
<testLibrary>::@fragment::package:test/a.dart::@extension::A
<testLibrary>::@fragment::package:test/aa.dart::@extension::B
dart:core::<fragment>::@extension::EnumName
<testLibraryFragment>::@extension::Z
package:test/aa.dart
accessibleExtensions
<testLibrary>::@fragment::package:test/a.dart::@extension::A
<testLibrary>::@fragment::package:test/aa.dart::@extension::B
dart:core::<fragment>::@extension::EnumName
<testLibraryFragment>::@extension::Z
''');
}
test_scope_accessibleExtensions_unnamed() async {
var library = await buildLibrary(r'''
part 'a.dart';
extension on int {}
''');
_assertScopeLookups(withAccessibleExtensions: true, library, [
Uri.parse('package:test/test.dart'),
], [
''
], r'''
package:test/test.dart
<empty>
getter: <null>
accessibleExtensions
<testLibraryFragment>::@extension::0
dart:core::<fragment>::@extension::EnumName
''');
}
test_scope_hasPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io' as prefix;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'prefix.exitCode',
], r'''
package:test/test.dart
prefix.exitCode
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
package:test/a.dart
prefix.exitCode
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
''');
}
test_scope_hasPrefix_append() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'dart:math' as prefix;
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
part 'aaa.dart';
''');
newFile('$testPackageLibPath/aaa.dart', r'''
part of 'aa.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io' as prefix;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
Uri.parse('package:test/aaa.dart'),
], [
'prefix.File',
'prefix.Random',
], r'''
package:test/test.dart
prefix.File
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix::prefix
getter: <null>
package:test/a.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:math::<fragment>::@class::Random
package:test/aa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:math::<fragment>::@class::Random
package:test/aaa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:math::<fragment>::@class::Random
''');
}
test_scope_hasPrefix_append_skipFile() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
import 'dart:math' as prefix;
''');
var library = await buildLibrary(r'''
import 'dart:io' as prefix;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
], [
'prefix.File',
'prefix.Random',
], r'''
package:test/test.dart
prefix.File
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix::prefix
getter: <null>
package:test/a.dart
prefix.File
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix::prefix
getter: <null>
package:test/aa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix::prefix
getter: dart:math::<fragment>::@class::Random
''');
}
test_scope_hasPrefix_deferred() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'dart:math' deferred as prefix;
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
import 'dart:math' deferred as prefix;
''');
var library = await buildLibrary(r'''
import 'dart:io' deferred as prefix;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
], [
'loadLibrary',
'prefix.File',
'prefix.Random',
], r'''
package:test/test.dart
loadLibrary
getter: <null>
prefix.File
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix::prefix
getter: <null>
package:test/a.dart
loadLibrary
getter: <null>
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: <null>
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:math::<fragment>::@class::Random
package:test/aa.dart
loadLibrary
getter: <null>
prefix.File
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix::prefix
getter: <null>
prefix.Random
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix::prefix
getter: dart:math::<fragment>::@class::Random
''');
}
test_scope_hasPrefix_shadow() async {
newFile('$testPackageLibPath/x.dart', r'''
class Directory {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'x.dart' as prefix;
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
part 'aaa.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io' as prefix;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
], [
'prefix.File',
'prefix.Directory',
], r'''
package:test/test.dart
prefix.File
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Directory
prefix: <testLibraryFragment>::@prefix::prefix
getter: dart:io::<fragment>::@class::Directory
package:test/a.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Directory
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: package:test/x.dart::<fragment>::@class::Directory
package:test/aa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: dart:io::<fragment>::@class::File
prefix.Directory
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix::prefix
getter: package:test/x.dart::<fragment>::@class::Directory
''');
}
test_scope_localShadowsPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
void foo() {}
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io' as foo;
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/b.dart'),
], [
'foo'
], r'''
package:test/test.dart
foo
getter: <testLibrary>::@fragment::package:test/a.dart::@function::foo
package:test/a.dart
foo
getter: <testLibrary>::@fragment::package:test/a.dart::@function::foo
package:test/b.dart
foo
getter: <testLibrary>::@fragment::package:test/a.dart::@function::foo
''');
}
test_scope_noPrefix_combinators_hide() async {
newFile('$testPackageLibPath/x.dart', r'''
class A {}
class B {}
class C {}
class D {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart' hide A, C;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'A',
'B',
'C',
'D',
], r'''
package:test/test.dart
A
getter: <null>
B
getter: package:test/x.dart::<fragment>::@class::B
C
getter: <null>
D
getter: package:test/x.dart::<fragment>::@class::D
package:test/a.dart
A
getter: <null>
B
getter: package:test/x.dart::<fragment>::@class::B
C
getter: <null>
D
getter: package:test/x.dart::<fragment>::@class::D
''');
}
test_scope_noPrefix_combinators_hide_show() async {
newFile('$testPackageLibPath/x.dart', r'''
class A {}
class B {}
class C {}
class D {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart' hide A, C show B;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'A',
'B',
'C',
'D',
], r'''
package:test/test.dart
A
getter: <null>
B
getter: package:test/x.dart::<fragment>::@class::B
C
getter: <null>
D
getter: <null>
package:test/a.dart
A
getter: <null>
B
getter: package:test/x.dart::<fragment>::@class::B
C
getter: <null>
D
getter: <null>
''');
}
test_scope_noPrefix_combinators_show() async {
newFile('$testPackageLibPath/x.dart', r'''
class A {}
class B {}
class C {}
class D {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart' show A, C;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'A',
'B',
'C',
'D',
], r'''
package:test/test.dart
A
getter: package:test/x.dart::<fragment>::@class::A
B
getter: <null>
C
getter: package:test/x.dart::<fragment>::@class::C
D
getter: <null>
package:test/a.dart
A
getter: package:test/x.dart::<fragment>::@class::A
B
getter: <null>
C
getter: package:test/x.dart::<fragment>::@class::C
D
getter: <null>
''');
}
test_scope_noPrefix_combinators_show_gide() async {
newFile('$testPackageLibPath/x.dart', r'''
class A {}
class B {}
class C {}
class D {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart' show A, C hide B, C;
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'A',
'B',
'C',
'D',
], r'''
package:test/test.dart
A
getter: package:test/x.dart::<fragment>::@class::A
B
getter: <null>
C
getter: <null>
D
getter: <null>
package:test/a.dart
A
getter: package:test/x.dart::<fragment>::@class::A
B
getter: <null>
C
getter: <null>
D
getter: <null>
''');
}
test_scope_noPrefix_fragmentImportShadowsParent() async {
newFile('$testPackageLibPath/x.dart', r'''
int get exitCode => 0;
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'x.dart';
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io';
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
Uri.parse('package:test/b.dart'),
], [
'exitCode',
], r'''
package:test/test.dart
exitCode
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
package:test/a.dart
exitCode
getter: package:test/x.dart::<fragment>::@getter::exitCode
package:test/aa.dart
exitCode
getter: package:test/x.dart::<fragment>::@getter::exitCode
package:test/b.dart
exitCode
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
''');
}
test_scope_noPrefix_implicitDartCore() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'Object',
], r'''
package:test/test.dart
Object
getter: dart:core::<fragment>::@class::Object
package:test/a.dart
Object
getter: dart:core::<fragment>::@class::Object
''');
}
test_scope_noPrefix_inheritsFromParentFragment_fromDefining() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io';
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'exit',
'exitCode',
], r'''
package:test/test.dart
exit
getter: dart:io::<fragment>::@function::exit
exitCode
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
package:test/a.dart
exit
getter: dart:io::<fragment>::@function::exit
exitCode
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
''');
}
test_scope_noPrefix_inheritsFromParentFragment_fromPart() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
import 'dart:io';
part 'aa.dart';
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
Uri.parse('package:test/b.dart'),
], [
'exitCode',
], r'''
package:test/test.dart
exitCode
getter: <null>
package:test/a.dart
exitCode
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
package:test/aa.dart
exitCode
getter: dart:io::<fragment>::@getter::exitCode
setter: dart:io::<fragment>::@setter::exitCode
package:test/b.dart
exitCode
getter: <null>
''');
}
test_scope_noPrefix_localShadowsImported_getter() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
int get exitCode => 0;
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io';
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/b.dart'),
], [
'exitCode',
], r'''
package:test/test.dart
exitCode
getter: <testLibrary>::@fragment::package:test/a.dart::@getter::exitCode
package:test/a.dart
exitCode
getter: <testLibrary>::@fragment::package:test/a.dart::@getter::exitCode
package:test/b.dart
exitCode
getter: <testLibrary>::@fragment::package:test/a.dart::@getter::exitCode
''');
}
test_scope_noPrefix_localShadowsImported_setter() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
set exitCode(int _) {}
''');
newFile('$testPackageLibPath/b.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'dart:io';
part 'a.dart';
part 'b.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/b.dart'),
], [
'exitCode',
], r'''
package:test/test.dart
exitCode
getter: <null>
setter: <testLibrary>::@fragment::package:test/a.dart::@setter::exitCode
package:test/a.dart
exitCode
getter: <null>
setter: <testLibrary>::@fragment::package:test/a.dart::@setter::exitCode
package:test/b.dart
exitCode
getter: <null>
setter: <testLibrary>::@fragment::package:test/a.dart::@setter::exitCode
''');
}
test_scope_noPrefix_localsOfFragments() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
part 'aa.dart';
class A {}
''');
newFile('$testPackageLibPath/aa.dart', r'''
part of 'a.dart';
class B {}
''');
var library = await buildLibrary(r'''
part 'a.dart';
class Z {}
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
Uri.parse('package:test/aa.dart'),
], [
'A',
'B',
'Z',
], r'''
package:test/test.dart
A
getter: <testLibrary>::@fragment::package:test/a.dart::@class::A
B
getter: <testLibrary>::@fragment::package:test/aa.dart::@class::B
Z
getter: <testLibraryFragment>::@class::Z
package:test/a.dart
A
getter: <testLibrary>::@fragment::package:test/a.dart::@class::A
B
getter: <testLibrary>::@fragment::package:test/aa.dart::@class::B
Z
getter: <testLibraryFragment>::@class::Z
package:test/aa.dart
A
getter: <testLibrary>::@fragment::package:test/a.dart::@class::A
B
getter: <testLibrary>::@fragment::package:test/aa.dart::@class::B
Z
getter: <testLibraryFragment>::@class::Z
''');
}
test_scope_noPrefix_localsOfFragments_private() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
class _A {}
set _foo(int _) {}
''');
var library = await buildLibrary(r'''
part 'a.dart';
class _Z {}
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'_A',
'_Z',
'_foo',
], r'''
package:test/test.dart
_A
getter: <testLibrary>::@fragment::package:test/a.dart::@class::_A
_Z
getter: <testLibraryFragment>::@class::_Z
_foo
getter: <null>
setter: <testLibrary>::@fragment::package:test/a.dart::@setter::_foo
package:test/a.dart
_A
getter: <testLibrary>::@fragment::package:test/a.dart::@class::_A
_Z
getter: <testLibraryFragment>::@class::_Z
_foo
getter: <null>
setter: <testLibrary>::@fragment::package:test/a.dart::@setter::_foo
''');
}
test_scope_wildcardName_class() async {
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
class _ {}
''');
var library = await buildLibrary(r'''
part 'a.dart';
''');
_assertScopeLookups(library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'_'
], r'''
package:test/test.dart
_
getter: <testLibrary>::@fragment::package:test/a.dart::@class::_
package:test/a.dart
_
getter: <testLibrary>::@fragment::package:test/a.dart::@class::_
''');
}
test_scope_wildcardName_importPrefix() async {
newFile('$testPackageLibPath/x.dart', r'''
extension X on int {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
import 'x.dart' as _;
part 'a.dart';
''');
_assertScopeLookups(withAccessibleExtensions: true, library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'_.X'
], r'''
package:test/test.dart
_.X
_: <null>
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/a.dart
_.X
_: <null>
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
''');
}
test_scope_wildcardName_importPrefix_preWildcardVariables() async {
newFile('$testPackageLibPath/x.dart', r'''
extension X on int {}
''');
newFile('$testPackageLibPath/a.dart', r'''
part of 'test.dart';
''');
var library = await buildLibrary(r'''
// @dart=3.5
import 'x.dart' as _;
part 'a.dart';
''');
_assertScopeLookups(withAccessibleExtensions: true, library, [
Uri.parse('package:test/test.dart'),
Uri.parse('package:test/a.dart'),
], [
'_.X'
], r'''
package:test/test.dart
_.X
_: <testLibraryFragment>::@prefix::_
getter: package:test/x.dart::<fragment>::@extension::X
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
package:test/a.dart
_.X
_: <testLibraryFragment>::@prefix::_
getter: package:test/x.dart::<fragment>::@extension::X
accessibleExtensions
dart:core::<fragment>::@extension::EnumName
package:test/x.dart::<fragment>::@extension::X
''');
}
void _assertScopeLookups(
LibraryElementImpl library,
List<Uri> fragmentUris,
List<String> requests,
String expected, {
bool withAccessibleExtensions = false,
}) {
var buffer = StringBuffer();
var sink = TreeStringSink(
sink: buffer,
indent: '',
);
var elementPrinter = ElementPrinter(
sink: sink,
configuration: ElementPrinterConfiguration(),
);
for (var fragmentUri in fragmentUris) {
sink.writelnWithIndent(fragmentUri);
sink.withIndent(() {
var fragment = library.units.singleWhere((fragment) {
return fragment.source.uri == fragmentUri;
});
for (var request in requests) {
var periodIndex = request.indexOf('.');
var (prefixName, rawName) = switch (periodIndex) {
> 0 => (
request.substring(0, periodIndex),
request.substring(periodIndex + 1),
),
_ => (null, request),
};
void writeResult(ScopeLookupResult result) {
sink.withIndent(() {
elementPrinter.writeNamedElement('getter', result.getter);
if (result.setter case var setter?) {
elementPrinter.writeNamedElement('setter', setter);
}
});
}
sink.writelnWithIndent(
request.ifNotEmptyOrElse('<empty>'),
);
if (prefixName != null) {
var prefixLookup = fragment.scope.lookup(prefixName);
expect(prefixLookup.setter, isNull);
var importPrefix = prefixLookup.getter;
if (importPrefix == null) {
sink.withIndent(() {
elementPrinter.writeNamedElement(prefixName, importPrefix);
});
} else {
importPrefix as PrefixElementImpl;
sink.withIndent(() {
elementPrinter.writeNamedElement(prefixName, importPrefix);
});
var result = importPrefix.scope.lookup(rawName);
writeResult(result);
}
} else {
var result = fragment.scope.lookup(rawName);
writeResult(result);
}
}
if (withAccessibleExtensions) {
elementPrinter.writeElementList(
'accessibleExtensions',
fragment.accessibleExtensions.sortedBy((e) => e.name ?? ''),
);
}
});
}
var actual = buffer.toString();
if (actual != expected) {
print('-------- Actual --------');
print('$actual------------------------');
NodeTextExpectationsCollector.add(actual);
}
expect(actual, expected);
}
}
@reflectiveTest
class LibraryFragmentElementTest_fromBytes extends LibraryFragmentElementTest {
@override
bool get keepLinkingLibraries => false;
}
@reflectiveTest
class LibraryFragmentElementTest_keepLinking
extends LibraryFragmentElementTest {
@override
bool get keepLinkingLibraries => true;
}