Version 2.14.0-72.0.dev
Merge commit '58413c5d5481e4c4b525582d3bd6152e50d2afef' into 'dev'
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index f40542f..b6850c2 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -102,7 +102,7 @@
}
}
// documentation
- hover.dartdoc = computeDocumentation(_dartdocInfo, element);
+ hover.dartdoc = computeDocumentation(_dartdocInfo, element)?.full;
}
// parameter
hover.parameter = _elementDisplayString(
@@ -141,8 +141,9 @@
withNullability: _unit.isNonNullableByDefault);
}
- static String? computeDocumentation(
- DartdocDirectiveInfo dartdocInfo, Element elementBeingDocumented) {
+ static Documentation? computeDocumentation(
+ DartdocDirectiveInfo dartdocInfo, Element elementBeingDocumented,
+ {bool includeSummary = false}) {
// TODO(dantup) We're reusing this in parameter information - move it
// somewhere shared?
Element? element = elementBeingDocumented;
@@ -192,12 +193,14 @@
if (rawDoc == null) {
return null;
}
- var result = dartdocInfo.processDartdoc(rawDoc);
+ var result =
+ dartdocInfo.processDartdoc(rawDoc, includeSummary: includeSummary);
var documentedElementClass = documentedElement.enclosingElement;
if (documentedElementClass != null &&
documentedElementClass != element.enclosingElement) {
- result += '\n\nCopied from `${documentedElementClass.displayName}`.';
+ var documentedClass = documentedElementClass.displayName;
+ result.full = '${result.full}\n\nCopied from `$documentedClass`.';
}
return result;
diff --git a/pkg/analysis_server/lib/src/computer/computer_signature.dart b/pkg/analysis_server/lib/src/computer/computer_signature.dart
index 9eb563a..55ce1a9 100644
--- a/pkg/analysis_server/lib/src/computer/computer_signature.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_signature.dart
@@ -62,7 +62,8 @@
return AnalysisGetSignatureResult(name, parameters,
dartdoc: DartUnitHoverComputer.computeDocumentation(
- _dartdocInfo, execElement));
+ _dartdocInfo, execElement)
+ ?.full);
}
ParameterInfo _convertParam(ParameterElement param) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
index a7062c3..179e807 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -20,7 +20,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/util/comment.dart';
+import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';
@@ -1111,10 +1111,11 @@
/// documentation fields.
void _setDocumentation(CompletionSuggestion suggestion, Element element) {
var doc = DartUnitHoverComputer.computeDocumentation(
- request.dartdocDirectiveInfo, element);
- if (doc != null) {
- suggestion.docComplete = doc;
- suggestion.docSummary = getDartDocSummary(doc);
+ request.dartdocDirectiveInfo, element,
+ includeSummary: true);
+ if (doc is DocumentationWithSummary) {
+ suggestion.docComplete = doc.full;
+ suggestion.docSummary = doc.summary;
}
}
}
diff --git a/pkg/analyzer/lib/src/dartdoc/dartdoc_directive_info.dart b/pkg/analyzer/lib/src/dartdoc/dartdoc_directive_info.dart
index 85f2e08..540d866 100644
--- a/pkg/analyzer/lib/src/dartdoc/dartdoc_directive_info.dart
+++ b/pkg/analyzer/lib/src/dartdoc/dartdoc_directive_info.dart
@@ -60,82 +60,143 @@
/// Macro directives are replaced with the body of the corresponding template.
///
/// Youtube and animation directives are replaced with markdown hyperlinks.
- String processDartdoc(String comment) {
+ Documentation processDartdoc(String comment, {bool includeSummary = false}) {
List<String> lines = _stripDelimiters(comment);
+ var firstBlankLine = lines.length;
for (int i = lines.length - 1; i >= 0; i--) {
String line = lines[i];
- var match = macroRegExp.firstMatch(line);
- if (match != null) {
- var name = match.group(1)!;
- var value = templateMap[name];
- if (value != null) {
- lines[i] = value;
- }
- continue;
- }
-
- match = videoRegExp.firstMatch(line);
- if (match != null) {
- var uri = match.group(2);
- if (uri != null && uri.isNotEmpty) {
- String label = uri;
- if (label.startsWith('https://')) {
- label = label.substring('https://'.length);
+ if (line.isEmpty) {
+ // Because we're iterating from the last line to the first, the last
+ // blank line we find is the first.
+ firstBlankLine = i;
+ } else {
+ var match = macroRegExp.firstMatch(line);
+ if (match != null) {
+ var name = match.group(1)!;
+ var value = templateMap[name];
+ if (value != null) {
+ lines[i] = value;
}
- lines[i] = '[$label]($uri)';
+ continue;
}
- continue;
+
+ match = videoRegExp.firstMatch(line);
+ if (match != null) {
+ var uri = match.group(2);
+ if (uri != null && uri.isNotEmpty) {
+ String label = uri;
+ if (label.startsWith('https://')) {
+ label = label.substring('https://'.length);
+ }
+ lines[i] = '[$label]($uri)';
+ }
+ continue;
+ }
}
}
- return lines.join('\n');
+ if (includeSummary) {
+ var full = lines.join('\n');
+ var summary = firstBlankLine == lines.length
+ ? full
+ : lines.getRange(0, firstBlankLine).join('\n').trim();
+ return DocumentationWithSummary(full: full, summary: summary);
+ }
+ return Documentation(full: lines.join('\n'));
+ }
+
+ bool _isWhitespace(String comment, int index, bool includeEol) {
+ if (comment.startsWith(' ', index) ||
+ comment.startsWith('\t', index) ||
+ (includeEol && comment.startsWith('\n', index))) {
+ return true;
+ }
+ return false;
+ }
+
+ int _skipWhitespaceBackward(String comment, int start, int end,
+ [bool skipEol = false]) {
+ while (start < end && _isWhitespace(comment, end, skipEol)) {
+ end--;
+ }
+ return end;
+ }
+
+ int _skipWhitespaceForward(String comment, int start, int end,
+ [bool skipEol = false]) {
+ while (start < end && _isWhitespace(comment, start, skipEol)) {
+ start++;
+ }
+ return start;
}
/// Remove the delimiters from the given [comment].
List<String> _stripDelimiters(String comment) {
- //
- // Remove /** */.
- //
+ var start = 0;
+ var end = comment.length;
if (comment.startsWith('/**')) {
- comment = comment.substring(3);
+ start = _skipWhitespaceForward(comment, 3, end, true);
+ if (comment.endsWith('*/')) {
+ end = _skipWhitespaceBackward(comment, start, end - 2, true);
+ }
}
- if (comment.endsWith('*/')) {
- comment = comment.substring(0, comment.length - 2);
- }
- comment = comment.trim();
- //
- // Remove leading '* ' and '/// '.
- //
- List<String> lines = comment.split('\n');
- int firstNonEmpty = lines.length + 1;
- int lastNonEmpty = -1;
- for (var i = 0; i < lines.length; i++) {
- String line = lines[i];
- line = line.trim();
- if (line.startsWith('*')) {
- line = line.substring(1);
- if (line.startsWith(' ')) {
- line = line.substring(1);
+ var line = -1;
+ var firstNonEmpty = -1;
+ var lastNonEmpty = -1;
+ var lines = <String>[];
+ while (start < end) {
+ line++;
+ var eolIndex = comment.indexOf('\n', start);
+ if (eolIndex < 0) {
+ eolIndex = end;
+ }
+ var lineStart = _skipWhitespaceForward(comment, start, eolIndex);
+ if (comment.startsWith('///', lineStart)) {
+ lineStart += 3;
+ if (_isWhitespace(comment, lineStart, false)) {
+ lineStart++;
}
- } else if (line.startsWith('///')) {
- line = line.substring(3);
- if (line.startsWith(' ')) {
- line = line.substring(1);
+ } else if (comment.startsWith('*', lineStart)) {
+ lineStart += 1;
+ if (_isWhitespace(comment, lineStart, false)) {
+ lineStart++;
}
}
- if (line.isNotEmpty) {
- if (i < firstNonEmpty) {
- firstNonEmpty = i;
+ var lineEnd =
+ _skipWhitespaceBackward(comment, lineStart, eolIndex - 1) + 1;
+ if (lineStart < lineEnd) {
+ // If the line is not empty, update the line range.
+ if (firstNonEmpty < 0) {
+ firstNonEmpty = line;
}
- if (i > lastNonEmpty) {
- lastNonEmpty = i;
+ if (line > lastNonEmpty) {
+ lastNonEmpty = line;
}
+ lines.add(comment.substring(lineStart, lineEnd));
+ } else {
+ lines.add('');
}
- lines[i] = line;
+ start = eolIndex + 1;
}
if (lastNonEmpty < firstNonEmpty) {
// All of the lines are empty.
- return <String>[];
+ return const <String>[];
}
return lines.sublist(firstNonEmpty, lastNonEmpty + 1);
}
}
+
+/// A representation of the documentation for an element.
+class Documentation {
+ String full;
+
+ Documentation({required this.full});
+}
+
+/// A representation of the documentation for an element that includes a
+/// summary.
+class DocumentationWithSummary extends Documentation {
+ final String summary;
+
+ DocumentationWithSummary({required String full, required this.summary})
+ : super(full: full);
+}
diff --git a/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart b/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart
index e796527..05f4cfd 100644
--- a/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart
+++ b/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart
@@ -17,11 +17,11 @@
DartdocDirectiveInfo info = DartdocDirectiveInfo();
test_processDartdoc_animation_directive() {
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4}
''');
expect(
- result,
+ result.full,
'[flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4]'
'(https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4)');
}
@@ -34,13 +34,13 @@
* template.
* {@endtemplate}
*/''');
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/**
* Before macro.
* {@macro foo}
* After macro.
*/''');
- expect(result, '''
+ expect(result.full, '''
Before macro.
Body of the
template.
@@ -48,11 +48,11 @@
}
test_processDartdoc_macro_undefined() {
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/**
* {@macro foo}
*/''');
- expect(result, '''
+ expect(result.full, '''
{@macro foo}''');
}
@@ -67,7 +67,7 @@
/// {@template bar}
/// Second template.
/// {@endtemplate}''');
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/**
* Before macro.
* {@macro foo}
@@ -75,7 +75,7 @@
* {@macro bar}
* After macro.
*/''');
- expect(result, '''
+ expect(result.full, '''
Before macro.
First template.
Between macros.
@@ -84,27 +84,51 @@
}
test_processDartdoc_noMacro() {
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/**
* Comment without a macro.
*/''');
- expect(result, '''
+ expect(result.full, '''
+Comment without a macro.''');
+ }
+
+ test_processDartdoc_summary_different() {
+ var result = info.processDartdoc('''
+/// Comment without a macro.
+///
+/// Has content after summary.
+''', includeSummary: true) as DocumentationWithSummary;
+ expect(result.full, '''
+Comment without a macro.
+
+Has content after summary.''');
+ expect(result.summary, '''
+Comment without a macro.''');
+ }
+
+ test_processDartdoc_summary_same() {
+ var result = info.processDartdoc('''
+/// Comment without a macro.
+''', includeSummary: true) as DocumentationWithSummary;
+ expect(result.full, '''
+Comment without a macro.''');
+ expect(result.summary, '''
Comment without a macro.''');
}
test_processDartdoc_youtube_directive() {
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/// {@youtube 560 315 https://www.youtube.com/watch?v=2uaoEDOgk_I}
''');
- expect(result, '''
+ expect(result.full, '''
[www.youtube.com/watch?v=2uaoEDOgk_I](https://www.youtube.com/watch?v=2uaoEDOgk_I)''');
}
test_processDartdoc_youtube_malformed() {
- String result = info.processDartdoc('''
+ var result = info.processDartdoc('''
/// {@youtube 560x315 https://www.youtube.com/watch?v=2uaoEDOgk_I}
''');
- expect(result,
+ expect(result.full,
'{@youtube 560x315 https://www.youtube.com/watch?v=2uaoEDOgk_I}');
}
}
diff --git a/pkg/analyzer/test/src/services/available_declarations_test.dart b/pkg/analyzer/test/src/services/available_declarations_test.dart
index ec8b732..9829096 100644
--- a/pkg/analyzer/test/src/services/available_declarations_test.dart
+++ b/pkg/analyzer/test/src/services/available_declarations_test.dart
@@ -1178,7 +1178,7 @@
/// Before macro.
/// {@macro foo}
/// After macro.''');
- expect(result, '''
+ expect(result.full, '''
Before macro.
Body of the template.
After macro.''');
diff --git a/tools/VERSION b/tools/VERSION
index 62e3603..811a318 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 71
+PRERELEASE 72
PRERELEASE_PATCH 0
\ No newline at end of file