// 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/plugin/protocol/protocol_dart.dart'; import 'package:analyzer/dart/element/element.dart' as engine; import 'package:analyzer/src/dart/element/element.dart' as engine; import 'package:analyzer/src/test_utilities/test_code_format.dart'; import 'package:analyzer_plugin/protocol/protocol_common.dart'; import 'package:test/test.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; import '../abstract_single_unit.dart'; import '../utils/test_code_extensions.dart'; void main() { defineReflectiveSuite(() { defineReflectiveTests(ConvertElementTest); defineReflectiveTests(ElementKindTest); }); } @reflectiveTest class ConvertElementTest extends AbstractSingleUnitTest { Future test_CLASS() async { await resolveTestCode(''' @deprecated abstract class [!_A!] {} class B {}'''); { var engineElement = findElement2.class_('_A'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.CLASS); expect(element.name, '_A'); expect(element.typeParameters, isNull); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, '_A'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, isNull); expect( element.flags, Element.FLAG_ABSTRACT | Element.FLAG_DEPRECATED | Element.FLAG_PRIVATE, ); } { var engineElement = findElement2.class_('B'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.CLASS); expect(element.name, 'B'); expect(element.typeParameters, ''); expect(element.flags, 0); } } Future test_CONSTRUCTOR() async { await resolveTestCode(''' class A { const A.[!myConstructor!](int a, [String? b]); }'''); var engineElement = findElement2.constructor('myConstructor'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.CONSTRUCTOR); expect(element.name, 'A.myConstructor'); expect(element.typeParameters, isNull); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'myConstructor'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, '(int a, [String? b])'); expect(element.returnType, 'A'); expect(element.flags, Element.FLAG_CONST); } Future test_CONSTRUCTOR_required_parameters_1() async { writeTestPackageConfig(meta: true); await resolveTestCode(''' import 'package:meta/meta.dart'; class A { const A.myConstructor(int a, {int? b, required int c}); }'''); var engineElement = findElement2.constructor('myConstructor'); // create notification Element var element = convertElement(engineElement); expect(element.parameters, '(int a, {required int c, int? b})'); } /// Verify parameter re-ordering for required params Future test_CONSTRUCTOR_required_parameters_2() async { writeTestPackageConfig(meta: true); await resolveTestCode(''' import 'package:meta/meta.dart'; class A { const A.myConstructor(int a, {int? b, required int d, required int c}); }'''); var engineElement = findElement2.constructor('myConstructor'); // create notification Element var element = convertElement(engineElement); expect( element.parameters, '(int a, {required int d, required int c, int? b})', ); } /// Verify parameter re-ordering for required params Future test_CONSTRUCTOR_required_parameters_3() async { writeTestPackageConfig(meta: true); verifyNoTestUnitErrors = false; await resolveTestCode(''' import 'package:meta/meta.dart'; class A { const A.myConstructor(int a, {int b, required int d, required int c, int a}); }'''); var engineElement = findElement2.constructor('myConstructor'); // create notification Element var element = convertElement(engineElement); expect( element.parameters, '(int a, {required int d, required int c, int b, int a})', ); } void test_dynamic() { var engineElement = engine.DynamicElementImpl.instance; // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.UNKNOWN); expect(element.name, 'dynamic'); expect(element.location, isNull); expect(element.parameters, isNull); expect(element.returnType, isNull); expect(element.flags, 0); } Future test_ENUM() async { await resolveTestCode(''' @deprecated enum [!_E1!] { one, two } enum E2 { three, four }'''); { var engineElement = findElement2.enum_('_E1'); expect(engineElement.metadata.hasDeprecated, isTrue); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.ENUM); expect(element.name, '_E1'); expect(element.typeParameters, isNull); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, '_E1'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, isNull); expect( element.flags, (engineElement.metadata.hasDeprecated ? Element.FLAG_DEPRECATED : 0) | Element.FLAG_PRIVATE, ); } { var engineElement = findElement2.enum_('E2'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.ENUM); expect(element.name, 'E2'); expect(element.typeParameters, isNull); expect(element.flags, 0); } } Future test_ENUM_CONSTANT() async { await resolveTestCode(''' @deprecated enum _E1 { /*[0*/one/*0]*/, two } enum E2 { /*[1*/three/*1]*/, four }'''); { var engineElement = findElement2.field('one'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.ENUM_CONSTANT); expect(element.name, 'one'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'one'.length); _expectLocation(location, parsedTestCode.ranges[0]); } expect(element.parameters, isNull); expect(element.returnType, '_E1'); var classElement = engineElement.enclosingElement; expect(classElement.metadata.hasDeprecated, isTrue); expect( element.flags, // Element.FLAG_DEPRECATED | Element.FLAG_CONST | Element.FLAG_STATIC, ); } { var engineElement = findElement2.field('three'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.ENUM_CONSTANT); expect(element.name, 'three'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'three'.length); _expectLocation(location, parsedTestCode.ranges[1]); } expect(element.parameters, isNull); expect(element.returnType, 'E2'); expect(element.flags, Element.FLAG_CONST | Element.FLAG_STATIC); } { var engineElement = findElement2.field('values', of: 'E2'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.FIELD); expect(element.name, 'values'); { var location = element.location!; expect(location.file, testFile.path); expect(location.offset, 0); expect(location.length, 'values'.length); expect(location.startLine, 1); expect(location.startColumn, 1); } expect(element.parameters, isNull); expect(element.returnType, 'List'); expect(element.flags, Element.FLAG_CONST | Element.FLAG_STATIC); } } Future test_FIELD() async { await resolveTestCode(''' class A { static const [!myField!] = 42; }'''); var engineElement = findElement2.field('myField'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.FIELD); expect(element.name, 'myField'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'myField'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, isNull); expect(element.returnType, 'int'); expect(element.flags, Element.FLAG_CONST | Element.FLAG_STATIC); } Future test_FUNCTION_TYPE_ALIAS_functionType() async { await resolveTestCode(''' typedef F = int Function(String x); '''); var engineElement = findElement2.typeAlias('F'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.TYPE_ALIAS); expect(element.name, 'F'); expect(element.typeParameters, ''); { var location = element.location!; expect(location.file, testFile.path); expect(location.offset, 8); expect(location.length, 'F'.length); expect(location.startLine, 1); expect(location.startColumn, 9); } expect(element.parameters, '(String x)'); expect(element.returnType, 'int'); expect(element.flags, 0); } Future test_FUNCTION_TYPE_ALIAS_interfaceType() async { await resolveTestCode(''' typedef F = Map; '''); var engineElement = findElement2.typeAlias('F'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.TYPE_ALIAS); expect(element.name, 'F'); expect(element.typeParameters, ''); { var location = element.location!; expect(location.file, testFile.path); expect(location.offset, 8); expect(location.length, 'F'.length); expect(location.startLine, 1); expect(location.startColumn, 9); } expect(element.aliasedType, 'Map'); expect(element.parameters, isNull); expect(element.returnType, isNull); expect(element.flags, 0); } Future test_FUNCTION_TYPE_ALIAS_legacy() async { await resolveTestCode(''' typedef int F(String x); '''); var engineElement = findElement2.typeAlias('F'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.TYPE_ALIAS); expect(element.name, 'F'); expect(element.typeParameters, ''); { var location = element.location!; expect(location.file, testFile.path); expect(location.offset, 12); expect(location.length, 'F'.length); expect(location.startLine, 1); expect(location.startColumn, 13); } expect(element.parameters, '(String x)'); expect(element.returnType, 'int'); expect(element.flags, 0); } Future test_GETTER() async { verifyNoTestUnitErrors = false; await resolveTestCode(''' class A { String get [!myGetter!] => 42; }'''); var engineElement = findElement2.getter('myGetter'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.GETTER); expect(element.name, 'myGetter'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'myGetter'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, isNull); expect(element.returnType, 'String'); expect(element.flags, 0); } Future test_LABEL() async { await resolveTestCode(''' void f() { [!myLabel!]: while (true) { break myLabel; } }'''); var engineElement = findElement2.label('myLabel'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.LABEL); expect(element.name, 'myLabel'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'myLabel'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, isNull); expect(element.returnType, isNull); expect(element.flags, 0); } Future test_METHOD() async { await resolveTestCode(''' class A { static List [!myMethod!](int a, {String? b, int? c}) { return []; } }'''); var engineElement = findElement2.method('myMethod'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.METHOD); expect(element.name, 'myMethod'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'myGetter'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, '(int a, {String? b, int? c})'); expect(element.returnType, 'List'); expect(element.flags, Element.FLAG_STATIC); } Future test_MIXIN() async { await resolveTestCode(''' mixin A {} '''); { var engineElement = findElement2.mixin('A'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.MIXIN); expect(element.name, 'A'); expect(element.typeParameters, isNull); { var location = element.location!; expect(location.file, testFile.path); expect(location.offset, 6); expect(location.length, 'A'.length); expect(location.startLine, 1); expect(location.startColumn, 7); } expect(element.parameters, isNull); expect(element.flags, Element.FLAG_ABSTRACT); } } Future test_SETTER() async { await resolveTestCode(''' class A { set [!mySetter!](String x) {} }'''); var engineElement = findElement2.setter('mySetter'); // create notification Element var element = convertElement(engineElement); expect(element.kind, ElementKind.SETTER); expect(element.name, 'mySetter'); { var location = element.location!; expect(location.file, testFile.path); expect(location.length, 'mySetter'.length); _expectLocation(location, parsedTestCode.range); } expect(element.parameters, '(String x)'); expect(element.returnType, isNull); expect(element.flags, 0); } void _expectLocation(Location actual, TestCodeRange expected) { expect(actual.offset, expected.sourceRange.offset); // LSP uses zero-based line/col, but server does uses one-based. expect(actual.startLine, expected.range.start.line + 1); expect(actual.startColumn, expected.range.start.character + 1); } } @reflectiveTest class ElementKindTest { void test_fromEngine() { expect(convertElementKind(engine.ElementKind.CLASS), ElementKind.CLASS); expect( convertElementKind(engine.ElementKind.COMPILATION_UNIT), ElementKind.COMPILATION_UNIT, ); expect( convertElementKind(engine.ElementKind.CONSTRUCTOR), ElementKind.CONSTRUCTOR, ); expect( convertElementKind(engine.ElementKind.EXTENSION), ElementKind.EXTENSION, ); expect( convertElementKind(engine.ElementKind.EXTENSION_TYPE), ElementKind.EXTENSION_TYPE, ); expect(convertElementKind(engine.ElementKind.FIELD), ElementKind.FIELD); expect( convertElementKind(engine.ElementKind.FUNCTION), ElementKind.FUNCTION, ); expect( convertElementKind(engine.ElementKind.FUNCTION_TYPE_ALIAS), ElementKind.FUNCTION_TYPE_ALIAS, ); expect( convertElementKind(engine.ElementKind.GENERIC_FUNCTION_TYPE), ElementKind.FUNCTION_TYPE_ALIAS, ); expect(convertElementKind(engine.ElementKind.GETTER), ElementKind.GETTER); expect(convertElementKind(engine.ElementKind.LABEL), ElementKind.LABEL); expect(convertElementKind(engine.ElementKind.LIBRARY), ElementKind.LIBRARY); expect( convertElementKind(engine.ElementKind.LOCAL_VARIABLE), ElementKind.LOCAL_VARIABLE, ); expect(convertElementKind(engine.ElementKind.METHOD), ElementKind.METHOD); expect( convertElementKind(engine.ElementKind.PARAMETER), ElementKind.PARAMETER, ); expect(convertElementKind(engine.ElementKind.SETTER), ElementKind.SETTER); expect( convertElementKind(engine.ElementKind.TOP_LEVEL_VARIABLE), ElementKind.TOP_LEVEL_VARIABLE, ); expect( convertElementKind(engine.ElementKind.TYPE_ALIAS), ElementKind.TYPE_ALIAS, ); expect( convertElementKind(engine.ElementKind.TYPE_PARAMETER), ElementKind.TYPE_PARAMETER, ); } void test_toString() { expect(ElementKind.CLASS.toString(), 'ElementKind.CLASS'); expect( ElementKind.COMPILATION_UNIT.toString(), 'ElementKind.COMPILATION_UNIT', ); } }