mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
analyzer: Parse '@nodoc' in a doc comment
Work towards https://github.com/dart-lang/sdk/issues/52705 Change-Id: Icaa0bcb0e58ca07250d135372dc88985b5f1f68c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/323423 Commit-Queue: Samuel Rawlins <srawlins@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
224a5c7d32
commit
4a9a0dcfdb
4 changed files with 102 additions and 12 deletions
|
@ -3226,6 +3226,11 @@ abstract final class Comment implements AstNode {
|
|||
@experimental
|
||||
List<DocImport> get docImports;
|
||||
|
||||
/// Whether this comment has a line beginning with '@nodoc', indicating its
|
||||
/// contents are not intended for publishing.
|
||||
@experimental
|
||||
bool get hasNodoc;
|
||||
|
||||
/// Return `true` if this is a block comment.
|
||||
bool get isBlock;
|
||||
|
||||
|
@ -3277,6 +3282,9 @@ final class CommentImpl extends AstNodeImpl implements Comment {
|
|||
@override
|
||||
final List<DocImport> docImports;
|
||||
|
||||
@override
|
||||
final bool hasNodoc;
|
||||
|
||||
/// Initialize a newly created comment. The list of [tokens] must contain at
|
||||
/// least one token. The [_type] is the type of the comment. The list of
|
||||
/// [references] can be empty if the comment does not contain any embedded
|
||||
|
@ -3287,6 +3295,7 @@ final class CommentImpl extends AstNodeImpl implements Comment {
|
|||
required List<CommentReferenceImpl> references,
|
||||
required this.codeBlocks,
|
||||
required this.docImports,
|
||||
required this.hasNodoc,
|
||||
}) : _type = type {
|
||||
_references._initialize(this, references);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ class DocCommentBuilder {
|
|||
final List<CommentReferenceImpl> references = [];
|
||||
final List<MdCodeBlock> codeBlocks = [];
|
||||
final List<DocImport> docImports = [];
|
||||
bool hasNodoc = false;
|
||||
final Token startToken;
|
||||
final _CharacterSequence characterSequence;
|
||||
|
||||
|
@ -117,6 +118,7 @@ class DocCommentBuilder {
|
|||
references: references,
|
||||
codeBlocks: codeBlocks,
|
||||
docImports: docImports,
|
||||
hasNodoc: hasNodoc,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -139,14 +141,16 @@ class DocCommentBuilder {
|
|||
continue;
|
||||
}
|
||||
|
||||
var fencedCodeBlockIndex = _fencedCodeBlockDelimiter(content);
|
||||
if (fencedCodeBlockIndex > -1) {
|
||||
_parseFencedCodeBlock(index: fencedCodeBlockIndex, content: content);
|
||||
} else if (!_parseDocImport(
|
||||
index: whitespaceEndIndex, content: content)) {
|
||||
if (_parseFencedCodeBlock(content: content)) {
|
||||
isPreviousLineEmpty = false;
|
||||
} else if (_parseDocImport(index: whitespaceEndIndex, content: content)) {
|
||||
isPreviousLineEmpty = false;
|
||||
} else if (_parseNodoc(index: whitespaceEndIndex, content: content)) {
|
||||
isPreviousLineEmpty = false;
|
||||
} else {
|
||||
_parseDocCommentLine(offset, content);
|
||||
isPreviousLineEmpty = content.isEmpty;
|
||||
}
|
||||
isPreviousLineEmpty = content.isEmpty;
|
||||
lineInfo = characterSequence.next();
|
||||
}
|
||||
}
|
||||
|
@ -287,10 +291,13 @@ class DocCommentBuilder {
|
|||
///
|
||||
/// When this method returns, [characterSequence] is postioned at the closing
|
||||
/// delimiter line (`.next()` must be called to move to the next line).
|
||||
void _parseFencedCodeBlock({
|
||||
required int index,
|
||||
bool _parseFencedCodeBlock({
|
||||
required String content,
|
||||
}) {
|
||||
var index = _fencedCodeBlockDelimiter(content);
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
var tickCount = 0;
|
||||
var length = content.length;
|
||||
while (content.codeUnitAt(index) == 0x60 /* '`' */) {
|
||||
|
@ -313,25 +320,22 @@ class DocCommentBuilder {
|
|||
var lineInfo = characterSequence.next();
|
||||
while (lineInfo != null) {
|
||||
var (:offset, :content) = lineInfo;
|
||||
|
||||
fencedCodeBlockLines.add(
|
||||
MdCodeBlockLine(offset: offset, length: content.length),
|
||||
);
|
||||
|
||||
var fencedCodeBlockIndex =
|
||||
_fencedCodeBlockDelimiter(content, minimumTickCount: tickCount);
|
||||
if (fencedCodeBlockIndex > -1) {
|
||||
// End the fenced code block.
|
||||
break;
|
||||
}
|
||||
|
||||
lineInfo = characterSequence.next();
|
||||
}
|
||||
|
||||
// Non-terminating fenced code block.
|
||||
codeBlocks.add(
|
||||
MdCodeBlock(infoString: infoString, lines: fencedCodeBlockLines),
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
({int offset, String content})? _parseIndentedCodeBlock(String content) {
|
||||
|
@ -368,6 +372,21 @@ class DocCommentBuilder {
|
|||
return lineInfo;
|
||||
}
|
||||
|
||||
/// Tries to parse a `@nodoc` doc directive at the beginning of a line of a
|
||||
/// doc comment, returning whether this was successful.
|
||||
bool _parseNodoc({required int index, required String content}) {
|
||||
const nodocLength = '@nodoc'.length;
|
||||
if (!content.startsWith('@nodoc', index)) {
|
||||
return false;
|
||||
}
|
||||
if (content.length == index + nodocLength ||
|
||||
content.codeUnitAt(index + nodocLength) == 0x20 /* ' ' */) {
|
||||
hasNodoc = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Parses the [source] text, found at [offset] in a single comment reference.
|
||||
///
|
||||
/// Returns `null` if the text could not be parsed as a comment reference.
|
||||
|
|
|
@ -1168,6 +1168,65 @@ Comment
|
|||
''');
|
||||
}
|
||||
|
||||
test_nodoc_eol() {
|
||||
final parseResult = parseStringWithErrors(r'''
|
||||
/// Text.
|
||||
///
|
||||
/// @nodoc
|
||||
class A {}
|
||||
''');
|
||||
parseResult.assertNoErrors();
|
||||
|
||||
final node = parseResult.findNode.comment('Text.');
|
||||
assertParsedNodeText(node, r'''
|
||||
Comment
|
||||
tokens
|
||||
/// Text.
|
||||
///
|
||||
/// @nodoc
|
||||
hasNodoc: true
|
||||
''');
|
||||
}
|
||||
|
||||
test_nodoc_more() {
|
||||
final parseResult = parseStringWithErrors(r'''
|
||||
/// Text.
|
||||
///
|
||||
/// @nodocxx
|
||||
class A {}
|
||||
''');
|
||||
parseResult.assertNoErrors();
|
||||
|
||||
final node = parseResult.findNode.comment('Text.');
|
||||
assertParsedNodeText(node, r'''
|
||||
Comment
|
||||
tokens
|
||||
/// Text.
|
||||
///
|
||||
/// @nodocxx
|
||||
''');
|
||||
}
|
||||
|
||||
test_nodoc_space() {
|
||||
final parseResult = parseStringWithErrors(r'''
|
||||
/// Text.
|
||||
///
|
||||
/// @nodoc This is not super public.
|
||||
class A {}
|
||||
''');
|
||||
parseResult.assertNoErrors();
|
||||
|
||||
final node = parseResult.findNode.comment('Text.');
|
||||
assertParsedNodeText(node, r'''
|
||||
Comment
|
||||
tokens
|
||||
/// Text.
|
||||
///
|
||||
/// @nodoc This is not super public.
|
||||
hasNodoc: true
|
||||
''');
|
||||
}
|
||||
|
||||
test_onlyWhitespace() {
|
||||
final parseResult = parseStringWithErrors('''
|
||||
///${" "}
|
||||
|
|
|
@ -269,6 +269,9 @@ class ResolvedAstPrinter extends ThrowingAstVisitor<void> {
|
|||
}
|
||||
});
|
||||
}
|
||||
if (node.hasNodoc) {
|
||||
_sink.writelnWithIndent('hasNodoc: true');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue