From f06562cbda2d6cfb79d4e2b5438f8a10358860e5 Mon Sep 17 00:00:00 2001 From: Danny Tuppeny Date: Thu, 19 Feb 2026 13:13:10 -0800 Subject: [PATCH] [analysis_server] Tweak handling of factory keyword without type names in constructors Change-Id: I4d162ef66300caa07fd64f7de338c6ed1df04fc1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/481963 Reviewed-by: Brian Wilkerson Commit-Queue: Samuel Rawlins Reviewed-by: Samuel Rawlins --- .../lib/src/computer/computer_highlights.dart | 10 ++++++ .../notification_highlights2_test.dart | 21 +++++++++++- .../test/lsp/semantic_tokens_test.dart | 33 +++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart index 8818539cabb..6bdefbcca8a 100644 --- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart +++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart @@ -917,6 +917,16 @@ class _DartUnitHighlightsComputerVisitor extends RecursiveAstVisitor { computer._addRegion_token( node.factoryKeyword, HighlightRegionType.BUILT_IN, + // We mark the factory keyword as the declaration when there is no + // type name (otherwise the type name is the declaration). This will allow + // the client/user to customise these differently if they wish, like they + // can with methods / constructors. + semanticTokenModifiers: node.typeName != null + ? null + : { + CustomSemanticTokenModifiers.constructor, + SemanticTokenModifiers.declaration, + }, ); computer._addRegion_token(node.constKeyword, HighlightRegionType.KEYWORD); computer._addRegion_token( diff --git a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart index 995229ba470..803d89538a2 100644 --- a/pkg/analysis_server/test/analysis/notification_highlights2_test.dart +++ b/pkg/analysis_server/test/analysis/notification_highlights2_test.dart @@ -689,6 +689,25 @@ Never nnn() => throw ''; assertHasRegion(HighlightRegionType.CLASS, 'Never nnn'); } + Future test_class_constructor_factoryKeyword() async { + var testCode = TestCode.parseNormalized(r''' +class A { + A._(); +[! + factory () {} + factory named() {} +!] +} +'''); + addTestFile(testCode.code); + await prepareHighlights(); + assertHighlightText(testCode, 0, r''' +4:3 |factory| BUILT_IN +5:3 |factory| BUILT_IN +5:11 |named| CONSTRUCTOR +'''); + } + Future test_class_constructor_fieldFormalParameter() async { var testCode = TestCode.parseNormalized(r''' class A { @@ -710,7 +729,7 @@ class A { '''); } - Future test_class_constructor_new() async { + Future test_class_constructor_newKeyword() async { var testCode = TestCode.parseNormalized(r''' class A { [! diff --git a/pkg/analysis_server/test/lsp/semantic_tokens_test.dart b/pkg/analysis_server/test/lsp/semantic_tokens_test.dart index 96bf5ab7e48..1667e8a7476 100644 --- a/pkg/analysis_server/test/lsp/semantic_tokens_test.dart +++ b/pkg/analysis_server/test/lsp/semantic_tokens_test.dart @@ -550,6 +550,39 @@ const e = const MyClass(); await _initializeAndVerifyTokens(content, expected); } + Future test_class_constructors_factoryKeyword() async { + var content = r''' +class A { + A._(); +[! + factory() => A._(); + factory named() => A._(); +!] +} +'''; + + var expected = [ + _Token('factory', .keyword, [ + CustomSemanticTokenModifiers.constructor, + .declaration, + ]), + _Token('A', .class_, [CustomSemanticTokenModifiers.constructor]), + _Token('_', .method, [CustomSemanticTokenModifiers.constructor]), + _Token('factory', .keyword, [ + CustomSemanticTokenModifiers.constructor, + .declaration, + ]), + _Token('named', .method, [ + CustomSemanticTokenModifiers.constructor, + .declaration, + ]), + _Token('A', .class_, [CustomSemanticTokenModifiers.constructor]), + _Token('_', .method, [CustomSemanticTokenModifiers.constructor]), + ]; + + await _initializeAndVerifyTokensInRange(content, expected); + } + Future test_class_constructors_newKeyword() async { var content = r''' class A {