diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart index 77e997076ee..506cab6a6b3 100644 --- a/pkg/analysis_server/lib/src/computer/computer_hover.dart +++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart @@ -155,24 +155,46 @@ class DartUnitHoverComputer { // parameter for a field that does not exist. return null; } - // The documentation of the element itself. - if (element.documentationComment != null) { - return dartdocInfo.processDartdoc(element.documentationComment); - } - // Look for documentation comments of overridden members. + + Element documentedElement; + Element documentedGetter; + + // Look for documentation comments of overridden members var overridden = findOverriddenElements(element); - for (var superElement in [ + for (var candidate in [ + element, ...overridden.superElements, ...overridden.interfaceElements ]) { - var rawDoc = superElement.documentationComment; - if (rawDoc != null) { - var interfaceClass = superElement.enclosingElement; - return dartdocInfo.processDartdoc(rawDoc) + - '\n\nCopied from `${interfaceClass.displayName}`.'; + if (candidate.documentationComment != null) { + documentedElement = candidate; + break; + } + if (documentedGetter == null && + candidate is PropertyAccessorElement && + candidate.isSetter) { + var getter = candidate.correspondingGetter; + if (getter != null && getter.documentationComment != null) { + documentedGetter = getter; + } } } - return null; + + // Use documentation of a corresponding getter if setters don't have it + documentedElement ??= documentedGetter; + if (documentedElement == null) { + return null; + } + + var rawDoc = documentedElement.documentationComment; + var result = dartdocInfo.processDartdoc(rawDoc); + + var documentedElementClass = documentedElement.enclosingElement; + if (documentedElementClass != element.enclosingElement) { + result += '\n\nCopied from `${documentedElementClass.displayName}`.'; + } + + return result; } static DartType _getTypeOfDeclarationOrReference(Expression node) { diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart index b31a487deea..edcae438deb 100644 --- a/pkg/analysis_server/test/analysis/get_hover_test.dart +++ b/pkg/analysis_server/test/analysis/get_hover_test.dart @@ -723,4 +723,108 @@ main() { expect(hover.elementKind, 'parameter'); expect(hover.staticType, 'int'); } + + Future test_setter_hasDocumentation() async { + addTestFile(''' +class A { + /// getting + int get foo => 42; + /// setting + set foo(int x) {} +} +main(A a) { + a.foo = 123; +} +'''); + var hover = await prepareHover('foo = '); + expect(hover.containingClassDescription, 'A'); + expect(hover.dartdoc, '''setting'''); + expect(hover.elementDescription, 'void set foo(int x)'); + expect(hover.elementKind, 'setter'); + } + + Future test_setter_noDocumentation() async { + addTestFile(''' +class A { + /// getting + int get foo => 42; + set foo(int x) {} +} +main(A a) { + a.foo = 123; +} +'''); + var hover = await prepareHover('foo = '); + expect(hover.containingClassDescription, 'A'); + expect(hover.dartdoc, '''getting'''); + expect(hover.elementDescription, 'void set foo(int x)'); + expect(hover.elementKind, 'setter'); + } + + Future test_setter_super_hasDocumentation() async { + addTestFile(''' +class A { + /// pgetting + int get foo => 42; + /// psetting + set foo(int x) {} +} +class B extends A { + /// getting + int get foo => 42; + set foo(int x) {} +} +main(B b) { + b.foo = 123; +} +'''); + var hover = await prepareHover('foo = '); + expect(hover.containingClassDescription, 'B'); + expect(hover.dartdoc, '''psetting\n\nCopied from `A`.'''); + expect(hover.elementDescription, 'void set foo(int x)'); + expect(hover.elementKind, 'setter'); + } + + Future test_setter_super_noDocumentation() async { + addTestFile(''' +class A { + /// pgetting + int get foo => 42; + set foo(int x) {} +} +class B extends A { + int get foo => 42; + set foo(int x) {} +} +main(B b) { + b.foo = 123; +} +'''); + var hover = await prepareHover('foo = '); + expect(hover.containingClassDescription, 'B'); + expect(hover.dartdoc, '''pgetting\n\nCopied from `A`.'''); + expect(hover.elementDescription, 'void set foo(int x)'); + expect(hover.elementKind, 'setter'); + } + + @failingTest + Future test_setter_super_noSetter() async { + addTestFile(''' +class A { + /// pgetting + int get foo => 42; +} +class B extends A { + set foo(int x) {} +} +main(B b) { + b.foo = 123; +} +'''); + var hover = await prepareHover('foo = '); + expect(hover.containingClassDescription, 'B'); + expect(hover.dartdoc, '''pgetting'''); + expect(hover.elementDescription, 'void set foo(int x)'); + expect(hover.elementKind, 'setter'); + } }