mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
[analysis_server] Improve coloring of invalid/unresolved methods in LSP semantic tokens
See https://github.com/Dart-Code/Dart-Code/issues/3412. Change-Id: Icc44ff0537122d6d2211d64037666ecb58a28bd6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/203940 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
dc6875b64a
commit
75bcd5ca33
3 changed files with 96 additions and 1 deletions
|
@ -100,6 +100,9 @@ class DartUnitHighlightsComputer {
|
|||
if (_addIdentifierRegion_class(node)) {
|
||||
return;
|
||||
}
|
||||
if (_addIdentifierRegion_extension(node)) {
|
||||
return;
|
||||
}
|
||||
if (_addIdentifierRegion_constructor(node)) {
|
||||
return;
|
||||
}
|
||||
|
@ -223,6 +226,29 @@ class DartUnitHighlightsComputer {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool _addIdentifierRegion_extension(SimpleIdentifier node) {
|
||||
var element = node.writeOrReadElement;
|
||||
if (element is! ExtensionElement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(dantup): Right now there is no highlight type for extension, so
|
||||
// bail out and do the default thing (which will be to return
|
||||
// IDENTIFIER_DEFAULT). Adding EXTENSION requires coordination with
|
||||
// IntelliJ + bumping protocol version.
|
||||
if (!_computeSemanticTokens) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _addRegion_node(
|
||||
node,
|
||||
// TODO(dantup): Change this to EXTENSION and add to LSP mapping when
|
||||
// we have it, but for now use CLASS (which is probably what we'll map it
|
||||
// to for LSP semantic tokens anyway).
|
||||
HighlightRegionType.CLASS,
|
||||
);
|
||||
}
|
||||
|
||||
bool _addIdentifierRegion_field(SimpleIdentifier node) {
|
||||
var element = node.writeOrReadElement;
|
||||
if (element is FieldFormalParameterElement) {
|
||||
|
|
|
@ -97,6 +97,7 @@ final highlightRegionTokenTypes = {
|
|||
HighlightRegionType.ENUM: SemanticTokenTypes.enum_,
|
||||
HighlightRegionType.ENUM_CONSTANT: SemanticTokenTypes.enumMember,
|
||||
HighlightRegionType.FUNCTION_TYPE_ALIAS: SemanticTokenTypes.type,
|
||||
HighlightRegionType.IDENTIFIER_DEFAULT: CustomSemanticTokenTypes.source,
|
||||
HighlightRegionType.INSTANCE_FIELD_DECLARATION: SemanticTokenTypes.variable,
|
||||
HighlightRegionType.INSTANCE_FIELD_REFERENCE: SemanticTokenTypes.variable,
|
||||
HighlightRegionType.INSTANCE_GETTER_DECLARATION: SemanticTokenTypes.property,
|
||||
|
@ -137,7 +138,7 @@ final highlightRegionTokenTypes = {
|
|||
HighlightRegionType.TYPE_NAME_DYNAMIC: SemanticTokenTypes.type,
|
||||
HighlightRegionType.TYPE_PARAMETER: SemanticTokenTypes.typeParameter,
|
||||
HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE:
|
||||
SemanticTokenTypes.variable,
|
||||
CustomSemanticTokenTypes.source,
|
||||
HighlightRegionType.VALID_STRING_ESCAPE: SemanticTokenTypes.string,
|
||||
};
|
||||
|
||||
|
|
|
@ -396,9 +396,15 @@ class SemanticTokensTest extends AbstractLspAnalysisServerTest {
|
|||
_Token("'../file.dart'", SemanticTokenTypes.string),
|
||||
_Token('if', SemanticTokenTypes.keyword,
|
||||
[CustomSemanticTokenModifiers.control]),
|
||||
_Token('dart', CustomSemanticTokenTypes.source),
|
||||
_Token('library', CustomSemanticTokenTypes.source),
|
||||
_Token('io', CustomSemanticTokenTypes.source),
|
||||
_Token("'file_io.dart'", SemanticTokenTypes.string),
|
||||
_Token('if', SemanticTokenTypes.keyword,
|
||||
[CustomSemanticTokenModifiers.control]),
|
||||
_Token('dart', CustomSemanticTokenTypes.source),
|
||||
_Token('library', CustomSemanticTokenTypes.source),
|
||||
_Token('html', CustomSemanticTokenTypes.source),
|
||||
_Token("'file_html.dart'", SemanticTokenTypes.string),
|
||||
_Token('library', SemanticTokenTypes.keyword),
|
||||
_Token('foo', SemanticTokenTypes.namespace),
|
||||
|
@ -412,6 +418,26 @@ class SemanticTokensTest extends AbstractLspAnalysisServerTest {
|
|||
expect(decoded, equals(expected));
|
||||
}
|
||||
|
||||
Future<void> test_extension() async {
|
||||
final content = '''
|
||||
extension A on String {}
|
||||
''';
|
||||
|
||||
final expected = [
|
||||
_Token('extension', SemanticTokenTypes.keyword),
|
||||
_Token('A', SemanticTokenTypes.class_),
|
||||
_Token('on', SemanticTokenTypes.keyword),
|
||||
_Token('String', SemanticTokenTypes.class_)
|
||||
];
|
||||
|
||||
await initialize();
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
|
||||
final tokens = await getSemanticTokens(mainFileUri);
|
||||
final decoded = decodeSemanticTokens(content, tokens);
|
||||
expect(decoded, equals(expected));
|
||||
}
|
||||
|
||||
Future<void> test_fromPlugin() async {
|
||||
final pluginAnalyzedFilePath = join(projectFolderPath, 'lib', 'foo.foo');
|
||||
final pluginAnalyzedFileUri = Uri.file(pluginAnalyzedFilePath);
|
||||
|
@ -1002,6 +1028,48 @@ const string3 = 'unicode \u1234\u123499\u{123456}\u{12345699}';
|
|||
final decoded = decodeSemanticTokens(content, tokens);
|
||||
expect(decoded, equals(expected));
|
||||
}
|
||||
|
||||
Future<void> test_unresolvedOrInvalid() async {
|
||||
// Unresolved/invalid names should be marked as "source", which is used to
|
||||
// mark up code the server thinks should be uncolored (without this, a
|
||||
// clients other grammars would show through, losing the benefit from having
|
||||
// resolved the code).
|
||||
final content = '''
|
||||
main() {
|
||||
int a;
|
||||
a.foo().bar.baz();
|
||||
|
||||
dynamic b;
|
||||
b.foo().bar.baz();
|
||||
}
|
||||
''';
|
||||
|
||||
final expected = [
|
||||
_Token('main', SemanticTokenTypes.function,
|
||||
[SemanticTokenModifiers.declaration, SemanticTokenModifiers.static]),
|
||||
_Token('int', SemanticTokenTypes.class_),
|
||||
_Token('a', SemanticTokenTypes.variable,
|
||||
[SemanticTokenModifiers.declaration]),
|
||||
_Token('a', SemanticTokenTypes.variable),
|
||||
_Token('foo', CustomSemanticTokenTypes.source),
|
||||
_Token('bar', CustomSemanticTokenTypes.source),
|
||||
_Token('baz', CustomSemanticTokenTypes.source),
|
||||
_Token('dynamic', SemanticTokenTypes.type),
|
||||
_Token('b', SemanticTokenTypes.variable,
|
||||
[SemanticTokenModifiers.declaration]),
|
||||
_Token('b', SemanticTokenTypes.variable),
|
||||
_Token('foo', CustomSemanticTokenTypes.source),
|
||||
_Token('bar', CustomSemanticTokenTypes.source),
|
||||
_Token('baz', CustomSemanticTokenTypes.source),
|
||||
];
|
||||
|
||||
await initialize();
|
||||
await openFile(mainFileUri, withoutMarkers(content));
|
||||
|
||||
final tokens = await getSemanticTokens(mainFileUri);
|
||||
final decoded = decodeSemanticTokens(content, tokens);
|
||||
expect(decoded, equals(expected));
|
||||
}
|
||||
}
|
||||
|
||||
class _Token {
|
||||
|
|
Loading…
Reference in a new issue