[analysis_server] Add documentation to editable arguments that represent fields
If an argument is for a field parameter, this includes the documentation from that field, so that the property editor can show the same content you'd see by hovering over the argument name in the editor. See https://github.com/flutter/devtools/issues/8938 Change-Id: Iebee757dd42fe9da2c8938c95febc99c0c96b609 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/411684 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Elliott Brooks <elliottbrooks@google.com>
This commit is contained in:
committed by
Commit Queue
parent
ef71100e1f
commit
af68c2d5ea
+10
-10
@@ -28,6 +28,14 @@ typedef EditableInvocationInfo =
|
||||
mixin EditableArgumentsMixin {
|
||||
DartdocDirectiveInfo getDartdocDirectiveInfoFor(ResolvedUnitResult result);
|
||||
|
||||
String? getDocumentation(ResolvedUnitResult result, Element2 element) {
|
||||
var dartDocInfo = getDartdocDirectiveInfoFor(result);
|
||||
var dartDocComputer = DartDocumentationComputer(dartDocInfo);
|
||||
var dartDoc = dartDocComputer.compute(element);
|
||||
|
||||
return dartDoc?.full;
|
||||
}
|
||||
|
||||
/// Gets the argument list at [offset] that can be edited.
|
||||
EditableInvocationInfo? getInvocationInfo(
|
||||
ResolvedUnitResult result,
|
||||
@@ -48,19 +56,11 @@ mixin EditableArgumentsMixin {
|
||||
widgetName = invocation.constructorName.type.name2.lexeme;
|
||||
|
||||
if (invocation.constructorName.element case var element?) {
|
||||
var dartDocInfo = getDartdocDirectiveInfoFor(result);
|
||||
var dartDocComputer = DartDocumentationComputer(dartDocInfo);
|
||||
var dartDoc = dartDocComputer.compute(element);
|
||||
|
||||
widgetDocumentation = dartDoc?.full;
|
||||
widgetDocumentation = getDocumentation(result, element);
|
||||
}
|
||||
} else if (invocation is InvocationExpression) {
|
||||
if (invocation.function case Identifier(:var element?)) {
|
||||
var dartDocInfo = getDartdocDirectiveInfoFor(result);
|
||||
var dartDocComputer = DartDocumentationComputer(dartDocInfo);
|
||||
var dartDoc = dartDocComputer.compute(element);
|
||||
|
||||
widgetDocumentation = dartDoc?.full;
|
||||
widgetDocumentation = getDocumentation(result, element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -117,6 +117,7 @@ class EditableArgumentsHandler
|
||||
var editableArguments = [
|
||||
for (var parameter in parameters)
|
||||
_toEditableArgument(
|
||||
result,
|
||||
parameter,
|
||||
parameterArguments[parameter],
|
||||
positionalIndex: positionalParameterIndexes[parameter],
|
||||
@@ -148,6 +149,7 @@ class EditableArgumentsHandler
|
||||
/// Converts a [parameter]/[argument] pair into an [EditableArgument] if it
|
||||
/// is an argument that can be edited.
|
||||
EditableArgument? _toEditableArgument(
|
||||
ResolvedUnitResult result,
|
||||
FormalParameterElement parameter,
|
||||
Expression? argument, {
|
||||
int? positionalIndex,
|
||||
@@ -223,8 +225,11 @@ class EditableArgumentsHandler
|
||||
displayValue = null;
|
||||
}
|
||||
|
||||
var documentation = getDocumentation(result, parameter);
|
||||
|
||||
return EditableArgument(
|
||||
name: parameter.displayName,
|
||||
documentation: documentation,
|
||||
type: type,
|
||||
value: value,
|
||||
displayValue: displayValue,
|
||||
|
||||
@@ -40,7 +40,7 @@ $content
|
||||
return hasArgs(contains(matcher));
|
||||
}
|
||||
|
||||
Matcher hasArgNamed(String argumentName) {
|
||||
Matcher hasArgNamed(String argumentName, {String? doc}) {
|
||||
return hasArg(isArg(argumentName));
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ $content
|
||||
|
||||
Matcher isArg(
|
||||
String name, {
|
||||
Object? documentation = anything,
|
||||
Object? type = anything,
|
||||
Object? value = anything,
|
||||
Object? displayValue = anything,
|
||||
@@ -83,6 +84,7 @@ $content
|
||||
}) {
|
||||
return isA<EditableArgument>()
|
||||
.having((arg) => arg.name, 'name', name)
|
||||
.having((arg) => arg.documentation, 'documentation', documentation)
|
||||
.having((arg) => arg.type, 'type', type)
|
||||
.having((arg) => arg.value, 'value', value)
|
||||
.having((arg) => arg.displayValue, 'displayValue', displayValue)
|
||||
@@ -223,6 +225,41 @@ class MyWidget extends StatelessWidget {
|
||||
expect(result, hasArg(isArg('a', defaultValue: null)));
|
||||
}
|
||||
|
||||
test_documentation_fieldParameter_literal() async {
|
||||
var result = await getEditableArgumentsFor('''
|
||||
class MyWidget extends StatelessWidget {
|
||||
/// Documentation for x.
|
||||
final int x;
|
||||
|
||||
/// Creates a MyWidget.
|
||||
const MyWidget(this.x);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => MyW^idget(1);
|
||||
}
|
||||
''');
|
||||
expect(result, hasArg(isArg('x', documentation: 'Documentation for x.')));
|
||||
}
|
||||
|
||||
test_documentation_fieldParameter_macro() async {
|
||||
var result = await getEditableArgumentsFor('''
|
||||
/// {@template shared_docs}
|
||||
/// Shared docs.
|
||||
/// {@endtemplate}
|
||||
class MyWidget extends StatelessWidget {
|
||||
/// {@macro shared_docs}
|
||||
final int x;
|
||||
|
||||
/// Creates a MyWidget.
|
||||
const MyWidget(this.x);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => MyW^idget(1);
|
||||
}
|
||||
''');
|
||||
expect(result, hasArg(isArg('x', documentation: 'Shared docs.')));
|
||||
}
|
||||
|
||||
test_documentation_literal() async {
|
||||
var result = await getEditableArgumentsFor('''
|
||||
class MyWidget extends StatelessWidget {
|
||||
|
||||
@@ -432,6 +432,7 @@ List<LspEntity> getCustomClasses() {
|
||||
type: 'string',
|
||||
comment: 'The name of the corresponding parameter.',
|
||||
),
|
||||
field('documentation', type: 'string', canBeUndefined: true),
|
||||
field(
|
||||
'type',
|
||||
type: 'string',
|
||||
|
||||
@@ -1449,6 +1449,8 @@ class EditableArgument implements ToJsonable {
|
||||
/// same as the value field, for example an expression or named constant.
|
||||
final String? displayValue;
|
||||
|
||||
final String? documentation;
|
||||
|
||||
/// Whether an explicit argument exists for this parameter in the code.
|
||||
///
|
||||
/// This will be true even if the explicit argument is the same value as the
|
||||
@@ -1499,6 +1501,7 @@ class EditableArgument implements ToJsonable {
|
||||
EditableArgument({
|
||||
this.defaultValue,
|
||||
this.displayValue,
|
||||
this.documentation,
|
||||
required this.hasArgument,
|
||||
required this.isEditable,
|
||||
required this.isNullable,
|
||||
@@ -1513,6 +1516,7 @@ class EditableArgument implements ToJsonable {
|
||||
int get hashCode => Object.hash(
|
||||
defaultValue,
|
||||
displayValue,
|
||||
documentation,
|
||||
hasArgument,
|
||||
isEditable,
|
||||
isNullable,
|
||||
@@ -1530,6 +1534,7 @@ class EditableArgument implements ToJsonable {
|
||||
other.runtimeType == EditableArgument &&
|
||||
defaultValue == other.defaultValue &&
|
||||
displayValue == other.displayValue &&
|
||||
documentation == other.documentation &&
|
||||
hasArgument == other.hasArgument &&
|
||||
isEditable == other.isEditable &&
|
||||
isNullable == other.isNullable &&
|
||||
@@ -1550,6 +1555,9 @@ class EditableArgument implements ToJsonable {
|
||||
if (displayValue != null) {
|
||||
result['displayValue'] = displayValue;
|
||||
}
|
||||
if (documentation != null) {
|
||||
result['documentation'] = documentation;
|
||||
}
|
||||
result['hasArgument'] = hasArgument;
|
||||
result['isEditable'] = isEditable;
|
||||
result['isNullable'] = isNullable;
|
||||
@@ -1577,6 +1585,10 @@ class EditableArgument implements ToJsonable {
|
||||
allowsUndefined: true, allowsNull: false)) {
|
||||
return false;
|
||||
}
|
||||
if (!_canParseString(obj, reporter, 'documentation',
|
||||
allowsUndefined: true, allowsNull: false)) {
|
||||
return false;
|
||||
}
|
||||
if (!_canParseBool(obj, reporter, 'hasArgument',
|
||||
allowsUndefined: false, allowsNull: false)) {
|
||||
return false;
|
||||
@@ -1618,6 +1630,8 @@ class EditableArgument implements ToJsonable {
|
||||
final defaultValue = defaultValueJson;
|
||||
final displayValueJson = json['displayValue'];
|
||||
final displayValue = displayValueJson as String?;
|
||||
final documentationJson = json['documentation'];
|
||||
final documentation = documentationJson as String?;
|
||||
final hasArgumentJson = json['hasArgument'];
|
||||
final hasArgument = hasArgumentJson as bool;
|
||||
final isEditableJson = json['isEditable'];
|
||||
@@ -1640,6 +1654,7 @@ class EditableArgument implements ToJsonable {
|
||||
return EditableArgument(
|
||||
defaultValue: defaultValue,
|
||||
displayValue: displayValue,
|
||||
documentation: documentation,
|
||||
hasArgument: hasArgument,
|
||||
isEditable: isEditable,
|
||||
isNullable: isNullable,
|
||||
|
||||
Reference in New Issue
Block a user