Skip to content

Commit

Permalink
[analysis_server] Fix navigation on augmentation directives
Browse files Browse the repository at this point in the history
Change-Id: I0972d6c9aa93f1bac180504da96e63ed9f04e63e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/360260
Commit-Queue: Brian Wilkerson <[email protected]>
Reviewed-by: Konstantin Shcheglov <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
  • Loading branch information
DanTup authored and Commit Queue committed Apr 2, 2024
1 parent 14e2bf8 commit 046f311
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,22 @@ class A {
}
}

Future<void> test_string_augmentLibrary() async {
var augmentedCode = 'import augment "test.dart";';
var augmentedFile =
newFile('$testPackageLibPath/augmented.dart', augmentedCode).path;
addTestFile('library augment "augmented.dart";');
await prepareNavigation();
assertHasRegionString('"augmented.dart"');
assertHasFileTarget(augmentedFile, 0, 0);
}

Future<void> test_string_augmentLibrary_unresolvedUri() async {
addTestFile('library augment "no.dart";');
await prepareNavigation();
assertNoRegionString('"no.dart"');
}

Future<void> test_string_configuration() async {
newFile('$testPackageLibPath/lib.dart', '').path;
var lib2File = newFile('$testPackageLibPath/lib2.dart', '').path;
Expand Down Expand Up @@ -1755,6 +1771,22 @@ class A {
assertNoRegionString('"no.dart"');
}

Future<void> test_string_importAugment() async {
var augmentCode = 'library augment "test.dart";';
var augmentFile =
newFile('$testPackageLibPath/augment.dart', augmentCode).path;
addTestFile('import augment "augment.dart";');
await prepareNavigation();
assertHasRegionString('"augment.dart"');
assertHasFileTarget(augmentFile, 0, 0);
}

Future<void> test_string_importAugment_unresolvedUri() async {
addTestFile('import augment "no.dart";');
await prepareNavigation();
assertNoRegionString('"no.dart"');
}

Future<void> test_string_part() async {
var unitCode = 'part of lib; f() {}';
var unitFile = newFile('$testPackageLibPath/test_unit.dart', unitCode).path;
Expand Down
113 changes: 65 additions & 48 deletions pkg/analysis_server/test/lsp/definition_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,46 @@ class [!A!] {
await testContents(contents);
}

Future<void> test_directive_augmentLibrary() async {
await verifyDirective(
source: "library augment 'destin^ation.dart';",
destination: "import augment 'source.dart';",
);
}

Future<void> test_directive_export() async {
await verifyDirective(
source: "export 'destin^ation.dart';",
);
}

Future<void> test_directive_import() async {
await verifyDirective(
source: "import 'desti^nation.dart';",
);
}

Future<void> test_directive_importAugment() async {
await verifyDirective(
source: "import augment 'destin^ation.dart';",
destination: "library augment 'source.dart';",
);
}

Future<void> test_directive_part() async {
await verifyDirective(
source: "part 'desti^nation.dart';",
destination: "part of 'source.dart';",
);
}

Future<void> test_directive_partOf() async {
await verifyDirective(
source: "part of 'destin^ation.dart';",
destination: "part 'source.dart';",
);
}

Future<void> test_fieldFormalParam() async {
final contents = '''
class A {
Expand Down Expand Up @@ -571,54 +611,6 @@ class A {}
);
}

Future<void> test_partFilename() async {
final mainContents = '''
part 'pa^rt.dart';
''';

final partContents = '''
part of 'main.dart';
''';

final partFilePath = join(projectFolderPath, 'lib', 'part.dart');
final partFileUri = toUri(partFilePath);

final mainCode = TestCode.parse(mainContents);
final partCode = TestCode.parse(partContents);

newFile(mainFilePath, mainCode.code);
newFile(partFilePath, partCode.code);
await initialize();
final res =
await getDefinitionAsLocation(mainFileUri, mainCode.position.position);

expect(res.single.uri, equals(partFileUri));
}

Future<void> test_partOfFilename() async {
final mainContents = '''
part 'part.dart';
''';

final partContents = '''
part of 'ma^in.dart';
''';

final partFilePath = join(projectFolderPath, 'lib', 'part.dart');
final partFileUri = toUri(partFilePath);

final mainCode = TestCode.parse(mainContents);
final partCode = TestCode.parse(partContents);

newFile(mainFilePath, mainCode.code);
newFile(partFilePath, partCode.code);
await initialize();
final res =
await getDefinitionAsLocation(partFileUri, partCode.position.position);

expect(res.single.uri, equals(mainFileUri));
}

Future<void> test_sameLine() async {
final contents = '''
int plusOne(int [!value!]) => 1 + val^ue;
Expand Down Expand Up @@ -714,4 +706,29 @@ foo() {
expect(loc.range, equals(code.range.range));
expect(loc.uri, equals(mainFileUri));
}

/// Verifies that invoking Definition at `^` in [source] (which will be
/// written into `source.dart`) navigate to `destination.dart` (with the
/// content [destination]).
Future<void> verifyDirective({
required String source,
String destination = '',
}) async {
final destinationCode = TestCode.parse(destination);
final sourceCode = TestCode.parse(source);

final sourceFilePath = join(projectFolderPath, 'lib', 'source.dart');
final sourceFileUri = toUri(sourceFilePath);
final destinationFilePath =
join(projectFolderPath, 'lib', 'destination.dart');
final destinationFileUri = toUri(destinationFilePath);

newFile(sourceFilePath, sourceCode.code);
newFile(destinationFilePath, destinationCode.code);
await initialize();
final res = await getDefinitionAsLocation(
sourceFileUri, sourceCode.position.position);

expect(res.single.uri, equals(destinationFileUri));
}
}
12 changes: 2 additions & 10 deletions pkg/analyzer_plugin/lib/utilities/analyzer_converter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -318,21 +318,13 @@ extension ElementExtensions on analyzer.Element? {
/// Return the compilation unit containing the given [element].
analyzer.CompilationUnitElement? get _unitElement {
var currentElement = this;
if (currentElement is analyzer.CompilationUnitElement) {
return currentElement;
}
if (currentElement?.enclosingElement
is analyzer.LibraryOrAugmentationElement) {
currentElement = currentElement?.enclosingElement;
}
if (currentElement is analyzer.LibraryOrAugmentationElement) {
return currentElement.definingCompilationUnit;
}
for (;
currentElement != null;
currentElement = currentElement.enclosingElement) {
if (currentElement is analyzer.CompilationUnitElement) {
return currentElement;
} else if (currentElement is analyzer.LibraryOrAugmentationElement) {
return currentElement.definingCompilationUnit;
}
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,12 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor<void> {
node.rightHandSide.accept(this);
}

@override
void visitAugmentationImportDirective(AugmentationImportDirective node) {
super.visitAugmentationImportDirective(node);
_addUriDirectiveRegion(node, node.element?.importedAugmentation);
}

@override
void visitBinaryExpression(BinaryExpression node) {
node.leftOperand.accept(this);
Expand Down Expand Up @@ -431,6 +437,18 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor<void> {
computer._addRegionForToken(node.rightBracket, element);
}

@override
void visitLibraryAugmentationDirective(LibraryAugmentationDirective node) {
super.visitLibraryAugmentationDirective(node);
var element = node.element;
var library = element?.library;
// If the library URI is unresolved, library will be the augmentation
// itself, so don't create a navigation region in that case.
if (element != library) {
_addUriDirectiveRegion(node, library);
}
}

@override
void visitLibraryDirective(LibraryDirective node) {
computer._addRegionForNode(node.name2, node.element);
Expand Down Expand Up @@ -619,7 +637,10 @@ class _DartNavigationComputerVisitor extends RecursiveAstVisitor<void> {

/// If the source of the given [element] (referenced by the [node]) exists,
/// then add the navigation region from the [node] to the [element].
void _addUriDirectiveRegion(UriBasedDirective node, LibraryElement? element) {
void _addUriDirectiveRegion(
UriBasedDirective node,
LibraryOrAugmentationElement? element,
) {
var source = element?.source;
if (source != null) {
if (resourceProvider.getResource(source.fullName).exists) {
Expand Down

0 comments on commit 046f311

Please sign in to comment.