Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 3cc6cda

Browse files
author
Dart CI
committed
Version 2.14.0-72.0.dev
Merge commit '58413c5d5481e4c4b525582d3bd6152e50d2afef' into 'dev'
2 parents 0288f79 + 58413c5 commit 3cc6cda

File tree

7 files changed

+168
-78
lines changed

7 files changed

+168
-78
lines changed

pkg/analysis_server/lib/src/computer/computer_hover.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class DartUnitHoverComputer {
102102
}
103103
}
104104
// documentation
105-
hover.dartdoc = computeDocumentation(_dartdocInfo, element);
105+
hover.dartdoc = computeDocumentation(_dartdocInfo, element)?.full;
106106
}
107107
// parameter
108108
hover.parameter = _elementDisplayString(
@@ -141,8 +141,9 @@ class DartUnitHoverComputer {
141141
withNullability: _unit.isNonNullableByDefault);
142142
}
143143

144-
static String? computeDocumentation(
145-
DartdocDirectiveInfo dartdocInfo, Element elementBeingDocumented) {
144+
static Documentation? computeDocumentation(
145+
DartdocDirectiveInfo dartdocInfo, Element elementBeingDocumented,
146+
{bool includeSummary = false}) {
146147
// TODO(dantup) We're reusing this in parameter information - move it
147148
// somewhere shared?
148149
Element? element = elementBeingDocumented;
@@ -192,12 +193,14 @@ class DartUnitHoverComputer {
192193
if (rawDoc == null) {
193194
return null;
194195
}
195-
var result = dartdocInfo.processDartdoc(rawDoc);
196+
var result =
197+
dartdocInfo.processDartdoc(rawDoc, includeSummary: includeSummary);
196198

197199
var documentedElementClass = documentedElement.enclosingElement;
198200
if (documentedElementClass != null &&
199201
documentedElementClass != element.enclosingElement) {
200-
result += '\n\nCopied from `${documentedElementClass.displayName}`.';
202+
var documentedClass = documentedElementClass.displayName;
203+
result.full = '${result.full}\n\nCopied from `$documentedClass`.';
201204
}
202205

203206
return result;

pkg/analysis_server/lib/src/computer/computer_signature.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ class DartUnitSignatureComputer {
6262

6363
return AnalysisGetSignatureResult(name, parameters,
6464
dartdoc: DartUnitHoverComputer.computeDocumentation(
65-
_dartdocInfo, execElement));
65+
_dartdocInfo, execElement)
66+
?.full);
6667
}
6768

6869
ParameterInfo _convertParam(ParameterElement param) {

pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import 'package:analyzer/dart/ast/ast.dart';
2020
import 'package:analyzer/dart/element/element.dart';
2121
import 'package:analyzer/dart/element/nullability_suffix.dart';
2222
import 'package:analyzer/dart/element/type.dart';
23-
import 'package:analyzer/src/util/comment.dart';
23+
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
2424
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
2525
import 'package:analyzer_plugin/utilities/range_factory.dart';
2626

@@ -1111,10 +1111,11 @@ class SuggestionBuilder {
11111111
/// documentation fields.
11121112
void _setDocumentation(CompletionSuggestion suggestion, Element element) {
11131113
var doc = DartUnitHoverComputer.computeDocumentation(
1114-
request.dartdocDirectiveInfo, element);
1115-
if (doc != null) {
1116-
suggestion.docComplete = doc;
1117-
suggestion.docSummary = getDartDocSummary(doc);
1114+
request.dartdocDirectiveInfo, element,
1115+
includeSummary: true);
1116+
if (doc is DocumentationWithSummary) {
1117+
suggestion.docComplete = doc.full;
1118+
suggestion.docSummary = doc.summary;
11181119
}
11191120
}
11201121
}

pkg/analyzer/lib/src/dartdoc/dartdoc_directive_info.dart

Lines changed: 112 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -60,82 +60,143 @@ class DartdocDirectiveInfo {
6060
/// Macro directives are replaced with the body of the corresponding template.
6161
///
6262
/// Youtube and animation directives are replaced with markdown hyperlinks.
63-
String processDartdoc(String comment) {
63+
Documentation processDartdoc(String comment, {bool includeSummary = false}) {
6464
List<String> lines = _stripDelimiters(comment);
65+
var firstBlankLine = lines.length;
6566
for (int i = lines.length - 1; i >= 0; i--) {
6667
String line = lines[i];
67-
var match = macroRegExp.firstMatch(line);
68-
if (match != null) {
69-
var name = match.group(1)!;
70-
var value = templateMap[name];
71-
if (value != null) {
72-
lines[i] = value;
68+
if (line.isEmpty) {
69+
// Because we're iterating from the last line to the first, the last
70+
// blank line we find is the first.
71+
firstBlankLine = i;
72+
} else {
73+
var match = macroRegExp.firstMatch(line);
74+
if (match != null) {
75+
var name = match.group(1)!;
76+
var value = templateMap[name];
77+
if (value != null) {
78+
lines[i] = value;
79+
}
80+
continue;
7381
}
74-
continue;
75-
}
7682

77-
match = videoRegExp.firstMatch(line);
78-
if (match != null) {
79-
var uri = match.group(2);
80-
if (uri != null && uri.isNotEmpty) {
81-
String label = uri;
82-
if (label.startsWith('https://')) {
83-
label = label.substring('https://'.length);
83+
match = videoRegExp.firstMatch(line);
84+
if (match != null) {
85+
var uri = match.group(2);
86+
if (uri != null && uri.isNotEmpty) {
87+
String label = uri;
88+
if (label.startsWith('https://')) {
89+
label = label.substring('https://'.length);
90+
}
91+
lines[i] = '[$label]($uri)';
8492
}
85-
lines[i] = '[$label]($uri)';
93+
continue;
8694
}
87-
continue;
8895
}
8996
}
90-
return lines.join('\n');
97+
if (includeSummary) {
98+
var full = lines.join('\n');
99+
var summary = firstBlankLine == lines.length
100+
? full
101+
: lines.getRange(0, firstBlankLine).join('\n').trim();
102+
return DocumentationWithSummary(full: full, summary: summary);
103+
}
104+
return Documentation(full: lines.join('\n'));
105+
}
106+
107+
bool _isWhitespace(String comment, int index, bool includeEol) {
108+
if (comment.startsWith(' ', index) ||
109+
comment.startsWith('\t', index) ||
110+
(includeEol && comment.startsWith('\n', index))) {
111+
return true;
112+
}
113+
return false;
114+
}
115+
116+
int _skipWhitespaceBackward(String comment, int start, int end,
117+
[bool skipEol = false]) {
118+
while (start < end && _isWhitespace(comment, end, skipEol)) {
119+
end--;
120+
}
121+
return end;
122+
}
123+
124+
int _skipWhitespaceForward(String comment, int start, int end,
125+
[bool skipEol = false]) {
126+
while (start < end && _isWhitespace(comment, start, skipEol)) {
127+
start++;
128+
}
129+
return start;
91130
}
92131

93132
/// Remove the delimiters from the given [comment].
94133
List<String> _stripDelimiters(String comment) {
95-
//
96-
// Remove /** */.
97-
//
134+
var start = 0;
135+
var end = comment.length;
98136
if (comment.startsWith('/**')) {
99-
comment = comment.substring(3);
100-
}
101-
if (comment.endsWith('*/')) {
102-
comment = comment.substring(0, comment.length - 2);
137+
start = _skipWhitespaceForward(comment, 3, end, true);
138+
if (comment.endsWith('*/')) {
139+
end = _skipWhitespaceBackward(comment, start, end - 2, true);
140+
}
103141
}
104-
comment = comment.trim();
105-
//
106-
// Remove leading '* ' and '/// '.
107-
//
108-
List<String> lines = comment.split('\n');
109-
int firstNonEmpty = lines.length + 1;
110-
int lastNonEmpty = -1;
111-
for (var i = 0; i < lines.length; i++) {
112-
String line = lines[i];
113-
line = line.trim();
114-
if (line.startsWith('*')) {
115-
line = line.substring(1);
116-
if (line.startsWith(' ')) {
117-
line = line.substring(1);
142+
var line = -1;
143+
var firstNonEmpty = -1;
144+
var lastNonEmpty = -1;
145+
var lines = <String>[];
146+
while (start < end) {
147+
line++;
148+
var eolIndex = comment.indexOf('\n', start);
149+
if (eolIndex < 0) {
150+
eolIndex = end;
151+
}
152+
var lineStart = _skipWhitespaceForward(comment, start, eolIndex);
153+
if (comment.startsWith('///', lineStart)) {
154+
lineStart += 3;
155+
if (_isWhitespace(comment, lineStart, false)) {
156+
lineStart++;
118157
}
119-
} else if (line.startsWith('///')) {
120-
line = line.substring(3);
121-
if (line.startsWith(' ')) {
122-
line = line.substring(1);
158+
} else if (comment.startsWith('*', lineStart)) {
159+
lineStart += 1;
160+
if (_isWhitespace(comment, lineStart, false)) {
161+
lineStart++;
123162
}
124163
}
125-
if (line.isNotEmpty) {
126-
if (i < firstNonEmpty) {
127-
firstNonEmpty = i;
164+
var lineEnd =
165+
_skipWhitespaceBackward(comment, lineStart, eolIndex - 1) + 1;
166+
if (lineStart < lineEnd) {
167+
// If the line is not empty, update the line range.
168+
if (firstNonEmpty < 0) {
169+
firstNonEmpty = line;
128170
}
129-
if (i > lastNonEmpty) {
130-
lastNonEmpty = i;
171+
if (line > lastNonEmpty) {
172+
lastNonEmpty = line;
131173
}
174+
lines.add(comment.substring(lineStart, lineEnd));
175+
} else {
176+
lines.add('');
132177
}
133-
lines[i] = line;
178+
start = eolIndex + 1;
134179
}
135180
if (lastNonEmpty < firstNonEmpty) {
136181
// All of the lines are empty.
137-
return <String>[];
182+
return const <String>[];
138183
}
139184
return lines.sublist(firstNonEmpty, lastNonEmpty + 1);
140185
}
141186
}
187+
188+
/// A representation of the documentation for an element.
189+
class Documentation {
190+
String full;
191+
192+
Documentation({required this.full});
193+
}
194+
195+
/// A representation of the documentation for an element that includes a
196+
/// summary.
197+
class DocumentationWithSummary extends Documentation {
198+
final String summary;
199+
200+
DocumentationWithSummary({required String full, required this.summary})
201+
: super(full: full);
202+
}

pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ class DartdocDirectiveInfoTest {
1717
DartdocDirectiveInfo info = DartdocDirectiveInfo();
1818

1919
test_processDartdoc_animation_directive() {
20-
String result = info.processDartdoc('''
20+
var result = info.processDartdoc('''
2121
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4}
2222
''');
2323
expect(
24-
result,
24+
result.full,
2525
'[flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4]'
2626
'(https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4)');
2727
}
@@ -34,25 +34,25 @@ class DartdocDirectiveInfoTest {
3434
* template.
3535
* {@endtemplate}
3636
*/''');
37-
String result = info.processDartdoc('''
37+
var result = info.processDartdoc('''
3838
/**
3939
* Before macro.
4040
* {@macro foo}
4141
* After macro.
4242
*/''');
43-
expect(result, '''
43+
expect(result.full, '''
4444
Before macro.
4545
Body of the
4646
template.
4747
After macro.''');
4848
}
4949

5050
test_processDartdoc_macro_undefined() {
51-
String result = info.processDartdoc('''
51+
var result = info.processDartdoc('''
5252
/**
5353
* {@macro foo}
5454
*/''');
55-
expect(result, '''
55+
expect(result.full, '''
5656
{@macro foo}''');
5757
}
5858

@@ -67,15 +67,15 @@ After macro.''');
6767
/// {@template bar}
6868
/// Second template.
6969
/// {@endtemplate}''');
70-
String result = info.processDartdoc('''
70+
var result = info.processDartdoc('''
7171
/**
7272
* Before macro.
7373
* {@macro foo}
7474
* Between macros.
7575
* {@macro bar}
7676
* After macro.
7777
*/''');
78-
expect(result, '''
78+
expect(result.full, '''
7979
Before macro.
8080
First template.
8181
Between macros.
@@ -84,27 +84,51 @@ After macro.''');
8484
}
8585

8686
test_processDartdoc_noMacro() {
87-
String result = info.processDartdoc('''
87+
var result = info.processDartdoc('''
8888
/**
8989
* Comment without a macro.
9090
*/''');
91-
expect(result, '''
91+
expect(result.full, '''
92+
Comment without a macro.''');
93+
}
94+
95+
test_processDartdoc_summary_different() {
96+
var result = info.processDartdoc('''
97+
/// Comment without a macro.
98+
///
99+
/// Has content after summary.
100+
''', includeSummary: true) as DocumentationWithSummary;
101+
expect(result.full, '''
102+
Comment without a macro.
103+
104+
Has content after summary.''');
105+
expect(result.summary, '''
106+
Comment without a macro.''');
107+
}
108+
109+
test_processDartdoc_summary_same() {
110+
var result = info.processDartdoc('''
111+
/// Comment without a macro.
112+
''', includeSummary: true) as DocumentationWithSummary;
113+
expect(result.full, '''
114+
Comment without a macro.''');
115+
expect(result.summary, '''
92116
Comment without a macro.''');
93117
}
94118

95119
test_processDartdoc_youtube_directive() {
96-
String result = info.processDartdoc('''
120+
var result = info.processDartdoc('''
97121
/// {@youtube 560 315 https://www.youtube.com/watch?v=2uaoEDOgk_I}
98122
''');
99-
expect(result, '''
123+
expect(result.full, '''
100124
[www.youtube.com/watch?v=2uaoEDOgk_I](https://www.youtube.com/watch?v=2uaoEDOgk_I)''');
101125
}
102126

103127
test_processDartdoc_youtube_malformed() {
104-
String result = info.processDartdoc('''
128+
var result = info.processDartdoc('''
105129
/// {@youtube 560x315 https://www.youtube.com/watch?v=2uaoEDOgk_I}
106130
''');
107-
expect(result,
131+
expect(result.full,
108132
'{@youtube 560x315 https://www.youtube.com/watch?v=2uaoEDOgk_I}');
109133
}
110134
}

pkg/analyzer/test/src/services/available_declarations_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ class A {}
11781178
/// Before macro.
11791179
/// {@macro foo}
11801180
/// After macro.''');
1181-
expect(result, '''
1181+
expect(result.full, '''
11821182
Before macro.
11831183
Body of the template.
11841184
After macro.''');

0 commit comments

Comments
 (0)