blob: 6df98514a3b04a381369efffa1a590f026dd4d70 [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>
fragments
#F0 <testLibraryFragment>
element: <testLibrary>
nextFragment: #F1
libraryExports
dart:io
parts
part_0
uri: package:test/a.dart
unit: #F1
#F1 package:test/a.dart
element: <testLibrary>
enclosingFragment: #F0
previousFragment: #F0
libraryExports
dart:math
''');
}
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>
fragments
#F0 <testLibraryFragment>
element: <testLibrary>
nextFragment: #F1
parts
part_0
uri: package:test/a.dart
unit: #F1
#F1 package:test/a.dart
element: <testLibrary>
enclosingFragment: #F0
previousFragment: #F0
libraryExports
dart:math
metadata
Annotation
atSign: @ @21
name: SimpleIdentifier
token: deprecated @22
element: dart:core::@getter::deprecated
staticType: null
element2: dart:core::@getter::deprecated
''');
}
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>
fragments
#F0 <testLibraryFragment>
element: <testLibrary>
nextFragment: #F1
libraryImports
dart:io
parts
part_0
uri: package:test/a.dart
unit: #F1
#F1 package:test/a.dart
element: <testLibrary>
enclosingFragment: #F0
previousFragment: #F0
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>
fragments
#F0 <testLibraryFragment>
element: <testLibrary>
nextFragment: #F1
parts
part_0
uri: package:test/a.dart
unit: #F1
#F1 package:test/a.dart
element: <testLibrary>
enclosingFragment: #F0
previousFragment: #F0
libraryImports
dart:math
metadata
Annotation
atSign: @ @21
name: SimpleIdentifier
token: deprecated @22
element: dart:core::@getter::deprecated
staticType: null
element2: dart:core::@getter::deprecated
''');
}
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::@extension::EnumName
package:test/x.dart::@extension::X
package:test/a.dart
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@extension::X
package:test/y.dart::@extension::Y
package:test/aa.dart
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@extension::X
package:test/y.dart::@extension::Y
package:test/b.dart
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@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::@extension::EnumName
package:test/x.dart::@extension::X
package:test/a.dart
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@extension::X
package:test/y.dart::@extension::Y
package:test/aa.dart
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@extension::X
package:test/y.dart::@extension::Y
package:test/b.dart
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@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>::@extension::A
<testLibrary>::@extension::B
dart:core::@extension::EnumName
<testLibrary>::@extension::Z
package:test/a.dart
accessibleExtensions
<testLibrary>::@extension::A
<testLibrary>::@extension::B
dart:core::@extension::EnumName
<testLibrary>::@extension::Z
package:test/aa.dart
accessibleExtensions
<testLibrary>::@extension::A
<testLibrary>::@extension::B
dart:core::@extension::EnumName
<testLibrary>::@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
<testLibrary>::@extension::0
dart:core::@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>::@prefix2::prefix
getter: dart:io::@getter::exitCode
setter: dart:io::@setter::exitCode
package:test/a.dart
prefix.exitCode
prefix: <testLibraryFragment>::@prefix2::prefix
getter: dart:io::@getter::exitCode
setter: dart:io::@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>::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix2::prefix
getter: <null>
package:test/a.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:math::@class::Random
package:test/aa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:math::@class::Random
package:test/aaa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:math::@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>::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix2::prefix
getter: <null>
package:test/a.dart
prefix.File
prefix: <testLibraryFragment>::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix2::prefix
getter: <null>
package:test/aa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix2::prefix
getter: dart:math::@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>::@prefix2::prefix
getter: dart:io::@class::File
prefix.Random
prefix: <testLibraryFragment>::@prefix2::prefix
getter: <null>
package:test/a.dart
loadLibrary
getter: <null>
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: <null>
prefix.Random
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:math::@class::Random
package:test/aa.dart
loadLibrary
getter: <null>
prefix.File
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix2::prefix
getter: <null>
prefix.Random
prefix: <testLibrary>::@fragment::package:test/aa.dart::@prefix2::prefix
getter: dart:math::@class::Random
''',
);
}
test_scope_hasPrefix_lookup_ambiguous_missingName() async {
newFile('$testPackageLibPath/a.dart', r'''
class {}
''');
newFile('$testPackageLibPath/b.dart', r'''
class {}
''');
var library = await buildLibrary(r'''
import 'a.dart' as prefix;
import 'b.dart' as prefix;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['prefix.A'],
r'''
package:test/test.dart
prefix.A
prefix: <testLibraryFragment>::@prefix2::prefix
getter: <null>
''',
);
}
test_scope_hasPrefix_lookup_ambiguous_notSdk_both() async {
newFile('$testPackageLibPath/a.dart', r'''
var foo = 0;
''');
newFile('$testPackageLibPath/b.dart', r'''
var foo = 1.2;
''');
var library = await buildLibrary(r'''
import 'a.dart' as prefix;
import 'b.dart' as prefix;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['prefix.foo'],
r'''
package:test/test.dart
prefix.foo
prefix: <testLibraryFragment>::@prefix2::prefix
getter: multiplyDefinedElement
package:test/a.dart::@getter::foo
package:test/b.dart::@getter::foo
setter: multiplyDefinedElement
package:test/a.dart::@setter::foo
package:test/b.dart::@setter::foo
''',
);
}
test_scope_hasPrefix_lookup_ambiguous_notSdk_first() async {
newFile('$testPackageLibPath/a.dart', r'''
var pi = 4;
''');
var library = await buildLibrary(r'''
import 'a.dart' as prefix;
import 'dart:math' as prefix;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['prefix.pi'],
r'''
package:test/test.dart
prefix.pi
prefix: <testLibraryFragment>::@prefix2::prefix
getter: package:test/a.dart::@getter::pi
setter: package:test/a.dart::@setter::pi
''',
);
}
test_scope_hasPrefix_lookup_ambiguous_notSdk_second() async {
newFile('$testPackageLibPath/a.dart', r'''
var pi = 4;
''');
var library = await buildLibrary(r'''
import 'dart:math' as prefix;
import 'a.dart' as prefix;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['prefix.pi'],
r'''
package:test/test.dart
prefix.pi
prefix: <testLibraryFragment>::@prefix2::prefix
getter: package:test/a.dart::@getter::pi
setter: package:test/a.dart::@setter::pi
''',
);
}
test_scope_hasPrefix_lookup_ambiguous_same() async {
newFile('$testPackageLibPath/a.dart', r'''
var foo = 0;
''');
newFile('$testPackageLibPath/b.dart', r'''
export 'a.dart';
''');
var library = await buildLibrary(r'''
import 'a.dart' as prefix;
import 'b.dart' as prefix;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['prefix.foo'],
r'''
package:test/test.dart
prefix.foo
prefix: <testLibraryFragment>::@prefix2::prefix
getter: package:test/a.dart::@getter::foo
setter: package:test/a.dart::@setter::foo
''',
);
}
test_scope_hasPrefix_lookup_differentPrefix() async {
newFile('$testPackageLibPath/a.dart', r'''
var foo = 0;
''');
newFile('$testPackageLibPath/b.dart', r'''
var bar = 0;
''');
var library = await buildLibrary(r'''
import 'a.dart' as prefix;
import 'b.dart' as prefix2;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['prefix.foo', 'prefix.bar', 'prefix2.foo', 'prefix2.bar'],
r'''
package:test/test.dart
prefix.foo
prefix: <testLibraryFragment>::@prefix2::prefix
getter: package:test/a.dart::@getter::foo
setter: package:test/a.dart::@setter::foo
prefix.bar
prefix: <testLibraryFragment>::@prefix2::prefix
getter: <null>
prefix2.foo
prefix2: <testLibraryFragment>::@prefix2::prefix2
getter: <null>
prefix2.bar
prefix2: <testLibraryFragment>::@prefix2::prefix2
getter: package:test/b.dart::@getter::bar
setter: package:test/b.dart::@setter::bar
''',
);
}
test_scope_hasPrefix_lookup_notFound() async {
var library = await buildLibrary(r'''
import 'dart:math' as math;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['math.noSuchElement'],
r'''
package:test/test.dart
math.noSuchElement
math: <testLibraryFragment>::@prefix2::math
getter: <null>
''',
);
}
test_scope_hasPrefix_lookup_respectsCombinator_hide() async {
var library = await buildLibrary(r'''
import 'dart:math' as math hide sin;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['math.sin', 'math.cos'],
r'''
package:test/test.dart
math.sin
math: <testLibraryFragment>::@prefix2::math
getter: <null>
math.cos
math: <testLibraryFragment>::@prefix2::math
getter: dart:math::@function::cos
''',
);
}
test_scope_hasPrefix_lookup_respectsCombinator_show() async {
var library = await buildLibrary(r'''
import 'dart:math' as math show sin;
''');
_assertScopeLookups(
library,
[Uri.parse('package:test/test.dart')],
['math.sin', 'math.cos'],
r'''
package:test/test.dart
math.sin
math: <testLibraryFragment>::@prefix2::math
getter: dart:math::@function::sin
math.cos
math: <testLibraryFragment>::@prefix2::math
getter: <null>
''',
);
}
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>::@prefix2::prefix
getter: dart:io::@class::File
prefix.Directory
prefix: <testLibraryFragment>::@prefix2::prefix
getter: dart:io::@class::Directory
package:test/a.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:io::@class::File
prefix.Directory
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: package:test/x.dart::@class::Directory
package:test/aa.dart
prefix.File
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: dart:io::@class::File
prefix.Directory
prefix: <testLibrary>::@fragment::package:test/a.dart::@prefix2::prefix
getter: package:test/x.dart::@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>::@function::foo
package:test/a.dart
foo
getter: <testLibrary>::@function::foo
package:test/b.dart
foo
getter: <testLibrary>::@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::@class::B
C
getter: <null>
D
getter: package:test/x.dart::@class::D
package:test/a.dart
A
getter: <null>
B
getter: package:test/x.dart::@class::B
C
getter: <null>
D
getter: package:test/x.dart::@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::@class::B
C
getter: <null>
D
getter: <null>
package:test/a.dart
A
getter: <null>
B
getter: package:test/x.dart::@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::@class::A
B
getter: <null>
C
getter: package:test/x.dart::@class::C
D
getter: <null>
package:test/a.dart
A
getter: package:test/x.dart::@class::A
B
getter: <null>
C
getter: package:test/x.dart::@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::@class::A
B
getter: <null>
C
getter: <null>
D
getter: <null>
package:test/a.dart
A
getter: package:test/x.dart::@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::@getter::exitCode
setter: dart:io::@setter::exitCode
package:test/a.dart
exitCode
getter: package:test/x.dart::@getter::exitCode
package:test/aa.dart
exitCode
getter: package:test/x.dart::@getter::exitCode
package:test/b.dart
exitCode
getter: dart:io::@getter::exitCode
setter: dart:io::@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::@class::Object
package:test/a.dart
Object
getter: dart:core::@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::@function::exit
exitCode
getter: dart:io::@getter::exitCode
setter: dart:io::@setter::exitCode
package:test/a.dart
exit
getter: dart:io::@function::exit
exitCode
getter: dart:io::@getter::exitCode
setter: dart:io::@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::@getter::exitCode
setter: dart:io::@setter::exitCode
package:test/aa.dart
exitCode
getter: dart:io::@getter::exitCode
setter: dart:io::@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>::@getter::exitCode
package:test/a.dart
exitCode
getter: <testLibrary>::@getter::exitCode
package:test/b.dart
exitCode
getter: <testLibrary>::@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>::@setter::exitCode
package:test/a.dart
exitCode
getter: <null>
setter: <testLibrary>::@setter::exitCode
package:test/b.dart
exitCode
getter: <null>
setter: <testLibrary>::@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>::@class::A
B
getter: <testLibrary>::@class::B
Z
getter: <testLibrary>::@class::Z
package:test/a.dart
A
getter: <testLibrary>::@class::A
B
getter: <testLibrary>::@class::B
Z
getter: <testLibrary>::@class::Z
package:test/aa.dart
A
getter: <testLibrary>::@class::A
B
getter: <testLibrary>::@class::B
Z
getter: <testLibrary>::@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>::@class::_A
_Z
getter: <testLibrary>::@class::_Z
_foo
getter: <null>
setter: <testLibrary>::@setter::_foo
package:test/a.dart
_A
getter: <testLibrary>::@class::_A
_Z
getter: <testLibrary>::@class::_Z
_foo
getter: <null>
setter: <testLibrary>::@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>::@class::_
package:test/a.dart
_
getter: <testLibrary>::@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::@extension::EnumName
package:test/x.dart::@extension::X
package:test/a.dart
_.X
_: <null>
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@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>::@prefix2::_
getter: package:test/x.dart::@extension::X
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@extension::X
package:test/a.dart
_.X
_: <testLibraryFragment>::@prefix2::_
getter: package:test/x.dart::@extension::X
accessibleExtensions
dart:core::@extension::EnumName
package:test/x.dart::@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.writeNamedElement2('getter', result.getter2);
if (result.setter2 case var setter?) {
elementPrinter.writeNamedElement2('setter', setter);
}
});
}
sink.writelnWithIndent(request.ifNotEmptyOrElse('<empty>'));
if (prefixName != null) {
var prefixLookup = fragment.scope.lookup(prefixName);
expect(prefixLookup.setter2, isNull);
var importPrefix = prefixLookup.getter2;
if (importPrefix == null) {
sink.withIndent(() {
elementPrinter.writeNamedElement2(prefixName, importPrefix);
});
} else {
importPrefix as PrefixElementImpl;
sink.withIndent(() {
elementPrinter.writeNamedElement2(prefixName, importPrefix);
});
var result = importPrefix.scope.lookup(rawName);
writeResult(result);
}
} else {
var result = fragment.scope.lookup(rawName);
writeResult(result);
}
}
if (withAccessibleExtensions) {
elementPrinter.writeElementList2(
'accessibleExtensions',
fragment.accessibleExtensions2.sortedBy((e) => e.name3 ?? ''),
);
}
});
}
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;
}