Allow analyzer to fallback to getter documentation for setters

The analyzer server firsts looks for the setter's dartdoc, then the first parent setter's dartdoc, then the closest getter's dartdoc.

Fixes #38963

Bug: https://github.com/dart-lang/sdk/issues/38963
Change-Id: I09f7ae0e5aa49d2536ebefd44dcfd3d6101bb0a6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/148566
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Parker Lougheed
2020-05-20 23:00:20 +00:00
committed by commit-bot@chromium.org
parent f0450f3efc
commit bf7e9d13d7
2 changed files with 138 additions and 12 deletions
@@ -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) {
@@ -723,4 +723,108 @@ main() {
expect(hover.elementKind, 'parameter');
expect(hover.staticType, 'int');
}
Future<void> 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<void> 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<void> 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<void> 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<void> 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');
}
}