| // Copyright (c) 2014, 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:analysis_server/protocol/protocol_generated.dart'; |
| import 'package:analyzer_plugin/protocol/protocol_common.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_reflective_loader/test_reflective_loader.dart'; |
| |
| import '../support/integration_tests.dart'; |
| |
| void main() { |
| defineReflectiveSuite(() { |
| defineReflectiveTests(AnalysisHighlightsTest); |
| }); |
| } |
| |
| @reflectiveTest |
| class AnalysisHighlightsTest extends AbstractAnalysisServerIntegrationTest { |
| late Map<HighlightRegionType, Set<String>> highlights; |
| |
| void check(HighlightRegionType type, List<String> expected) { |
| expect(highlights[type], equals(expected.toSet())); |
| highlights.remove(type); |
| } |
| |
| Future<void> computeHighlights(String pathname, String text) async { |
| writeFile(pathname, text); |
| await standardAnalysisSetup(); |
| await analysisFinished; |
| await sendAnalysisSetSubscriptions({ |
| AnalysisService.HIGHLIGHTS: [pathname] |
| }); |
| // Map from highlight type to highlighted text |
| onAnalysisHighlights.listen((AnalysisHighlightsParams params) { |
| expect(params.file, equals(pathname)); |
| highlights = <HighlightRegionType, Set<String>>{}; |
| for (var region in params.regions) { |
| var startIndex = region.offset; |
| var endIndex = startIndex + region.length; |
| var highlightedText = text.substring(startIndex, endIndex); |
| var type = region.type; |
| highlights.putIfAbsent(type, () => {}).add(highlightedText); |
| } |
| }); |
| await analysisFinished; |
| } |
| |
| @override |
| Future startServer({ |
| int? diagnosticPort, |
| int? servicesPort, |
| }) { |
| return server.start( |
| dartSdkPath: dartSdkPath, |
| diagnosticPort: diagnosticPort, |
| servicesPort: servicesPort, |
| useAnalysisHighlight2: true); |
| } |
| |
| Future<void> test_highlights() async { |
| var pathname = sourcePath('test.dart'); |
| var text = r''' |
| import 'dart:async' as async; |
| |
| /** |
| * Doc comment |
| */ |
| class Class<TypeParameter> { |
| Class() { |
| field = {1.0: [].toList()}; |
| } |
| |
| Class.constructor() { |
| dynamic local = true; |
| field = {2: local}; |
| } |
| |
| Map field = {3: 4}; |
| static int staticField = 0; |
| |
| method() { |
| // End of line comment |
| /* Block comment */ |
| } |
| |
| static staticMethod() { |
| } |
| |
| get getter { |
| } |
| |
| set setter(int parameter) { |
| print(parameter); |
| } |
| } |
| |
| class Class2<TypeParameter> extends Class<TypeParameter> { |
| @override |
| method() { |
| } |
| } |
| |
| typedef functionType(); |
| typedef genericTypeDef = double; |
| |
| function(dynamicType) { |
| print('string'); |
| unresolvedIdentifier = 42; |
| return async.Future.wait([]); |
| } |
| |
| int topLevelVariable = 0; |
| '''; |
| await computeHighlights(pathname, text); |
| // There should be 1 error due to the fact that unresolvedIdentifier is |
| // unresolved. |
| expect(currentAnalysisErrors[pathname], hasLength(1)); |
| |
| check(HighlightRegionType.ANNOTATION, ['@override']); |
| check(HighlightRegionType.BUILT_IN, |
| ['as', 'get', 'import', 'set', 'static', 'typedef']); |
| check(HighlightRegionType.CLASS, |
| ['Class', 'Class2', 'double', 'Future', 'Map', 'int']); |
| check(HighlightRegionType.COMMENT_BLOCK, ['/* Block comment */']); |
| check(HighlightRegionType.COMMENT_DOCUMENTATION, |
| ['/**\n * Doc comment\n */']); |
| check(HighlightRegionType.COMMENT_END_OF_LINE, ['// End of line comment']); |
| check(HighlightRegionType.CONSTRUCTOR, ['constructor']); |
| check(HighlightRegionType.DIRECTIVE, ["import 'dart:async' as async;"]); |
| check(HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION, ['dynamicType']); |
| check(HighlightRegionType.INSTANCE_FIELD_DECLARATION, ['field']); |
| check(HighlightRegionType.INSTANCE_SETTER_REFERENCE, ['field']); |
| check(HighlightRegionType.STATIC_FIELD_DECLARATION, ['staticField']); |
| check(HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE, ['print']); |
| check(HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION, ['function']); |
| check(HighlightRegionType.FUNCTION_TYPE_ALIAS, ['functionType']); |
| check(HighlightRegionType.TYPE_ALIAS, ['genericTypeDef']); |
| check(HighlightRegionType.INSTANCE_GETTER_DECLARATION, ['getter']); |
| check(HighlightRegionType.IDENTIFIER_DEFAULT, ['unresolvedIdentifier']); |
| check(HighlightRegionType.IMPORT_PREFIX, ['async']); |
| check(HighlightRegionType.KEYWORD, ['class', 'extends', 'true', 'return']); |
| check(HighlightRegionType.LITERAL_BOOLEAN, ['true']); |
| check(HighlightRegionType.LITERAL_DOUBLE, ['1.0']); |
| check(HighlightRegionType.LITERAL_INTEGER, ['2', '3', '4', '0', '42']); |
| check(HighlightRegionType.LITERAL_LIST, ['[]']); |
| check(HighlightRegionType.LITERAL_MAP, |
| ['{1.0: [].toList()}', '{2: local}', '{3: 4}']); |
| check(HighlightRegionType.LITERAL_STRING, ["'dart:async'", "'string'"]); |
| check(HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION, ['local']); |
| check(HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE, ['local']); |
| check(HighlightRegionType.INSTANCE_METHOD_REFERENCE, ['toList']); |
| check(HighlightRegionType.INSTANCE_METHOD_DECLARATION, ['method']); |
| check(HighlightRegionType.STATIC_METHOD_DECLARATION, ['staticMethod']); |
| check(HighlightRegionType.STATIC_METHOD_REFERENCE, ['wait']); |
| check(HighlightRegionType.PARAMETER_DECLARATION, ['parameter']); |
| check(HighlightRegionType.PARAMETER_REFERENCE, ['parameter']); |
| check(HighlightRegionType.INSTANCE_SETTER_DECLARATION, ['setter']); |
| check(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, ['override']); |
| check(HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, |
| ['topLevelVariable']); |
| check(HighlightRegionType.TYPE_NAME_DYNAMIC, ['dynamic']); |
| check(HighlightRegionType.TYPE_PARAMETER, ['TypeParameter']); |
| expect(highlights, isEmpty); |
| } |
| |
| Future<void> test_highlights_mixin() async { |
| var pathname = sourcePath('test.dart'); |
| var text = r''' |
| mixin M on A implements B {} |
| class A {} |
| class B {} |
| '''; |
| await computeHighlights(pathname, text); |
| expect(currentAnalysisErrors[pathname], hasLength(0)); |
| |
| check(HighlightRegionType.BUILT_IN, ['implements', 'mixin', 'on']); |
| check(HighlightRegionType.KEYWORD, ['class']); |
| } |
| } |