Skip to content

Commit

Permalink
[analysis_server] Migrate LSP CodeLens handlers to new element model
Browse files Browse the repository at this point in the history
+ update migrate tool to produce correct output on Windows

Change-Id: I5c75a6310a1f4fdaf4b49062d8a46b663e4fe810
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/389961
Reviewed-by: Konstantin Shcheglov <[email protected]>
Commit-Queue: Brian Wilkerson <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
  • Loading branch information
DanTup authored and Commit Queue committed Oct 16, 2024
1 parent ba4d4d0 commit 286bb78
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 114 deletions.
2 changes: 2 additions & 0 deletions pkg/analysis_server/analyzer_use_new_elements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ lib/src/lsp/handlers/code_actions/abstract_code_actions_producer.dart
lib/src/lsp/handlers/code_actions/analysis_options.dart
lib/src/lsp/handlers/code_actions/plugins.dart
lib/src/lsp/handlers/code_actions/pubspec.dart
lib/src/lsp/handlers/code_lens/abstract_code_lens_provider.dart
lib/src/lsp/handlers/code_lens/augmentations.dart
lib/src/lsp/handlers/commands/fix_all.dart
lib/src/lsp/handlers/commands/fix_all_in_workspace.dart
lib/src/lsp/handlers/commands/log_action.dart
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import 'package:analysis_server/src/lsp/constants.dart';
import 'package:analysis_server/src/lsp/error_or.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/dart/element/element2.dart';

/// A base class for providers that can contribute CodeLenses.
///
Expand All @@ -29,47 +28,44 @@ abstract class AbstractCodeLensProvider
bool clientSupportsGoToLocationCommand(LspClientCapabilities capabilities) =>
capabilities.supportedCommands.contains(ClientCommands.goToLocation);

/// Attempt to compute a [Location] to the declaration of [element].
/// Attempt to compute a [Location] to [fragment].
///
/// If for any reason the location cannot be computed, returns `null`.
Location? getLocation(Element element, Map<String, LineInfo?> lineInfoCache) {
var source = element.source;
if (source == null) {
Location? getLocation(Fragment fragment) {
// We can't produce a location to a name if there isn't one.
var nameOffset = fragment.nameOffset;
var nameLength = fragment.element.displayName.length;
if (nameOffset == null || nameOffset == -1) {
return null;
}

// Map the source onto a URI and only return this item if the client
// can handle the URI.
var source = fragment.libraryFragment.source;
var uri = server.uriConverter.toClientUri(source.fullName);
if (!server.uriConverter.supportedSchemes.contains(uri.scheme)) {
return null;
}

var lineInfo = lineInfoCache.putIfAbsent(
source.fullName, () => server.getLineInfo(source.fullName));
if (lineInfo == null) {
return null;
}

var lineInfo = fragment.libraryFragment.lineInfo;
return Location(
uri: uri,
range: toRange(lineInfo, element.nameOffset, element.nameLength),
range: toRange(lineInfo, nameOffset, nameLength),
);
}

/// Builds a [Command] that with the text [title] that navigate to the
/// declaration of [element].
/// [fragment].
///
/// If for any reason the location cannot be computed, returns `null`.
Command? getNavigationCommand(
LspClientCapabilities clientCapabilities,
String title,
Element element,
Map<String, LineInfo?> lineInfoCache,
Fragment fragment,
) {
assert(clientSupportsGoToLocationCommand(clientCapabilities));

var location = getLocation(element, lineInfoCache);
var location = getLocation(fragment);
if (location == null) {
return null;
}
Expand All @@ -85,7 +81,6 @@ abstract class AbstractCodeLensProvider
CodeLensParams params,
MessageInfo message,
CancellationToken token,
Map<String, LineInfo?> lineInfoCache,
);

bool isAvailable(
Expand Down
114 changes: 33 additions & 81 deletions pkg/analysis_server/lib/src/lsp/handlers/code_lens/augmentations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ import 'package:analysis_server/src/lsp/handlers/code_lens/abstract_code_lens_pr
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer/src/utilities/extensions/element.dart';

class AugmentationCodeLensProvider extends AbstractCodeLensProvider {
AugmentationCodeLensProvider(super.server);
Expand All @@ -28,7 +25,6 @@ class AugmentationCodeLensProvider extends AbstractCodeLensProvider {
CodeLensParams params,
MessageInfo message,
CancellationToken token,
Map<String, LineInfo?> lineInfoCache,
) async {
var clientCapabilities = message.clientCapabilities;
if (clientCapabilities == null) {
Expand All @@ -44,8 +40,8 @@ class AugmentationCodeLensProvider extends AbstractCodeLensProvider {
return await unit.mapResult((result) {
return performance.runAsync(
'_getCodeLenses',
(performance) => _getCodeLenses(
clientCapabilities, result, token, performance, lineInfoCache),
(performance) =>
_getCodeLenses(clientCapabilities, result, token, performance),
);
});
}
Expand All @@ -64,94 +60,50 @@ class AugmentationCodeLensProvider extends AbstractCodeLensProvider {
ResolvedUnitResult result,
CancellationToken token,
OperationPerformanceImpl performance,
Map<String, LineInfo?> lineInfoCache,
) async {
var lineInfo = result.lineInfo;
var codeLenses = <CodeLens>[];

/// Helper to add a CodeLens at [declaration] to [target] for [title].
void addCodeLens(String title, Element declaration, Element target) {
var command = getNavigationCommand(
clientCapabilities, title, target, lineInfoCache);
if (command != null && declaration.nameOffset != -1) {
/// Helper to add a CodeLens at [thisFragment] to [targetFragment] with
/// the text [title].
void addCodeLens(
String title,
Fragment thisFragment,
Fragment targetFragment,
) {
var command =
getNavigationCommand(clientCapabilities, title, targetFragment);
var nameOffset = thisFragment.nameOffset;
var nameLength = thisFragment.element.displayName.length;
if (command != null && nameOffset != null && nameOffset != -1) {
var range = toRange(
lineInfo,
declaration.nameOffset,
declaration.nameLength,
result.lineInfo,
nameOffset,
nameLength,
);
codeLenses.add(CodeLens(range: range, command: command));
}
}

var computer = _AugmentationComputer(result);
if (codeLens.augmented) {
for (var MapEntry(key: declaration, value: augmentated)
in computer.augmenteds.entries) {
addCodeLens('Go to Augmented', declaration, augmentated);
// Helper to add all CodeLenses for a [fragment] and child fragments
// recursively.
void addCodeLenses(Fragment fragment) {
var previousFragment = fragment.previousFragment;
var nextFragment = fragment.nextFragment;
if (codeLens.augmented && previousFragment != null) {
addCodeLens('Go to Augmented', fragment, previousFragment);
}
}
if (codeLens.augmentation) {
for (var MapEntry(key: declaration, value: augmentation)
in computer.augmentations.entries) {
addCodeLens('Go to Augmentation', declaration, augmentation);
}
}

return success(codeLenses);
}
}

class _AugmentationComputer {
/// A mapping of declarations to their augmentations.
final Map<Element, Element> augmentations = {};

/// A mapping of augmentations to their declarations.
final Map<Element, Element> augmenteds = {};

final ResolvedUnitResult result;

_AugmentationComputer(this.result) {
result.unit.declaredElement?.accept(_AugmentationVisitor(this));
}

void recordAugmentation(Element declaration, Element augmentation) {
augmentations[declaration] = augmentation;
}

void recordAugmented(Element declaration, Element augmented) {
augmenteds[declaration] = augmented;
}
}

/// Visits an AST and records mappings from augmentations to the declarations
/// they augment, and from declarations to their augmentations.
class _AugmentationVisitor extends GeneralizingElementVisitor<void> {
final _AugmentationComputer _computer;

_AugmentationVisitor(this._computer);

@override
void visitElement(Element element) {
assert(element.source?.fullName == _computer.result.path);
assert(element == element.declaration);

if (!element.isSynthetic) {
var agumentation = element.augmentation;
if (agumentation != null) {
_computer.recordAugmentation(element, agumentation);
if (codeLens.augmentation && nextFragment != null) {
addCodeLens('Go to Augmentation', fragment, nextFragment);
}

var augmented = switch (element) {
ExecutableElement element => element.augmentationTarget,
InstanceElement element => element.augmentationTarget,
PropertyInducingElement element => element.augmentationTarget,
_ => null,
};
if (augmented != null) {
_computer.recordAugmented(element, augmented);
for (var fragment in fragment.children3) {
addCodeLenses(fragment);
}
}

super.visitElement(element);
// Add fragments starting at the library.
addCodeLenses(result.libraryFragment);

return success(codeLenses);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import 'package:analysis_server/src/lsp/handlers/code_lens/abstract_code_lens_pr
import 'package:analysis_server/src/lsp/handlers/code_lens/augmentations.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/registration/feature_registration.dart';
import 'package:analyzer/source/line_info.dart';

class CodeLensHandler
extends SharedMessageHandler<CodeLensParams, List<CodeLens>> {
Expand Down Expand Up @@ -40,12 +39,10 @@ class CodeLensHandler
}

// Ask all providers to compute their CodeLenses.
var lineInfoCache = <String, LineInfo?>{};
var providerResults = await Future.wait(
codeLensProviders
.where((provider) => provider.isAvailable(clientCapabilities, params))
.map((provider) =>
provider.handle(params, message, token, lineInfoCache)),
.map((provider) => provider.handle(params, message, token)),
);

// Merge the results, but if any errors, propogate the first error.
Expand Down
27 changes: 16 additions & 11 deletions pkg/linter/tool/migrate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,43 @@ main(List<String> args) async {
errorFiles.add(error.source.fullName);
}

var migratedFiles =
filesToMigrate.where((file) => !errorFiles.any((f) => f.endsWith(file)));
var migratedFilesSet = filesToMigrate
.where((file) => !errorFiles.any((f) => f.endsWith(file)))
.toSet();
var migratedFilesSorted = migratedFilesSet.map(asRelativePosix).sorted();
var unmigratedFilesSorted = filesToMigrate
.where((file) => !migratedFilesSet.contains(file))
.map(asRelativePosix)
.sorted();

var options = parser.parse(args);
if (options['write'] == true) {
print("Writing to 'analyzer_use_new_elements.txt'...");
print('-' * 20);
File('analyzer_use_new_elements.txt')
.writeAsStringSync('${migratedFiles.join('\n')}\n');
.writeAsStringSync('${migratedFilesSorted.join('\n')}\n');
} else {
print('Migrated files:\n');
print(migratedFiles.join('\n'));
print(migratedFilesSorted.join('\n'));
print('-' * 20);
print('-' * 20);
print('\n');
}

print('Unmigrated files:\n\n');
for (var file in filesToMigrate) {
if (!migratedFiles.contains(file)) {
print(file);
}
}
print(unmigratedFilesSorted.join('\n'));
}

final Directory directoryToMigrate = Directory.current;

final List<String> filesToMigrate = directoryToMigrate
.listSync(recursive: true)
.where((f) => f.path.endsWith('.dart'))
.map((r) => path.relative(r.path, from: directoryToMigrate.path))
.sorted();
.map((r) => r.path)
.toList();

String asRelativePosix(String fullPath) => path.posix.joinAll(
path.split(path.relative(fullPath, from: directoryToMigrate.path)));

Future<List<AnalysisError>> getOldElementModelAccesses(String directory) async {
var results = await Driver([AnalyzerUseNewElements(useOptInFile: false)])
Expand Down

0 comments on commit 286bb78

Please sign in to comment.