[linter] Add tests and make regex static for unintended_html lint.
Follow up to https://dart-review.googlesource.com/c/sdk/+/379519
Adding a few more tests and making sure the regex isn't instantiated every time
we check.
Added some tests from https://github.com/dart-lang/sdk/issues/56450 as well.
Change-Id: Ief895cdfb5fa1049ce4599e2241577e91bc5701a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/380320
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
diff --git a/pkg/linter/lib/src/rules/unintended_html_in_doc_comment.dart b/pkg/linter/lib/src/rules/unintended_html_in_doc_comment.dart
index 768f844..7b5fda3 100644
--- a/pkg/linter/lib/src/rules/unintended_html_in_doc_comment.dart
+++ b/pkg/linter/lib/src/rules/unintended_html_in_doc_comment.dart
@@ -208,6 +208,46 @@
}
class _Visitor extends SimpleAstVisitor<void> {
+ static final _markdownTokenPattern = RegExp(
+ // Escaped Markdown character.
+ r'\\.'
+
+ // Or code span, from "`"*N to "`"*N or just the start if it's
+ // unterminated, to avoid "```a``" matching the "``a``".
+ // The ```-sequence is atomic.
+ r'|(?<cq>`+)(?:[^]*?\k<cq>)?'
+
+ // Or autolink, start with scheme + `:`.
+ r'|<[a-z][a-z\d\-+.]+:[^\x00-\x20\x7f<>]*>'
+
+ // Or HTML comments.
+ r'|<!--(?:-?>|[^]*?-->)'
+
+ // Or HTML declarations.
+ r'|<![a-z][^]*?!>'
+
+ // Or HTML processing instructions.
+ r'|<\?[^]*?\?>'
+
+ // Or HTML CDATA sections sections.
+ r'|<\[CDATA[^]*\]>'
+
+ // Or valid HTML tag.
+ // Matches `<validTag>`, `<validTag ...>`, `<validTag/>`, `</validTag>`
+ // and `</validTag ...>.
+ r'|<(?<et>/?)(?:'
+ '${_validHtmlTags.join('|')}'
+ r')'
+ r'(?:/(?=\k<et>)>|>|[\x20\r\n\t][^]*?>)'
+
+ // Or any of the following matches which are considered invalid tags.
+ // If the "nh" capture group is participating, one of these matched.
+ r'|(?<nh>)(?:'
+
+ // Any other `</?tag ...>` sequence.
+ r'</?[a-z][^]*?>'
+ r')', caseSensitive: false);
+
final LintRule rule;
_Visitor(this.rule);
@@ -236,48 +276,8 @@
/// Finds tags that are not valid HTML tags, not contained in a code span, and
/// are not autolinks.
List<_UnintendedTag> _findUnintendedHtmlTags(String text) {
- var markdownTokenPattern = RegExp(
- // Escaped Markdown character.
- r'\\.'
-
- // Or code span, from "`"*N to "`"*N or just the start if it's
- // unterminated, to avoid "```a``" matching the "``a``".
- // The ```-sequence is atomic.
- r'|(?<cq>`+)(?:[^]*?\k<cq>)?'
-
- // Or autolink, start with scheme + `:`.
- r'|<[a-z][a-z\d\-+.]+:[^\x00-\x20\x7f<>]*>'
-
- // Or HTML comments.
- r'|<!--(?:-?>|[^]*?-->)'
-
- // Or HTML declarations.
- r'|<![a-z][^]*?!>'
-
- // Or HTML processing instructions.
- r'|<\?[^]*?\?>'
-
- // Or HTML CDATA sections sections.
- r'|<\[CDATA[^]*\]>'
-
- // Or valid HTML tag.
- // Matches `<validTag>`, `<validTag ...>`, `<validTag/>`, `</validTag>`
- // and `</validTag ...>.
- r'|<(?<et>/?)(?:'
- '${_validHtmlTags.join('|')}'
- r')'
- r'(?:/(?=\k<et>)>|>|[\x20\r\n\t][^]*?>)'
-
- // Or any of the following matches which are considered invalid tags.
- // If the "nh" capture group is participating, one of these matched.
- r'|(?<nh>)(?:'
-
- // Any other `</?tag ...>` sequence.
- r'</?[a-z][^]*?>'
- r')', caseSensitive: false);
-
var matches = <_UnintendedTag>[];
- for (var match in markdownTokenPattern.allMatches(text)) {
+ for (var match in _markdownTokenPattern.allMatches(text)) {
if (match.namedGroup('nh') != null) {
matches.add(_UnintendedTag(match.start, match.end - match.start));
}
diff --git a/pkg/linter/test/rules/unintended_html_in_doc_comment_test.dart b/pkg/linter/test/rules/unintended_html_in_doc_comment_test.dart
index 09bb8c9..3c7eae1 100644
--- a/pkg/linter/test/rules/unintended_html_in_doc_comment_test.dart
+++ b/pkg/linter/test/rules/unintended_html_in_doc_comment_test.dart
@@ -90,6 +90,13 @@
''');
}
+ test_html_cData_nested() async {
+ await assertNoDiagnostics(r'''
+/// <[CDATA[<bad>]]>
+class C {}
+''');
+ }
+
test_html_comment() async {
await assertNoDiagnostics(r'''
/// <!--comment-->
@@ -97,6 +104,13 @@
''');
}
+ test_html_comment_nested() async {
+ await assertNoDiagnostics(r'''
+/// <!--<bad>-->
+class C {}
+''');
+ }
+
test_html_declaration() async {
await assertNoDiagnostics(r'''
/// <!DOCTYPE html>
@@ -111,6 +125,23 @@
''');
}
+ test_html_processingInstruction_nested() async {
+ await assertNoDiagnostics(r'''
+/// <?<bad>?>
+class C {}
+''');
+ }
+
+ test_html_tags_valid() async {
+ await assertNoDiagnostics(r'''
+/// <table class="properties">
+/// <th scope="row">
+/// <br />
+/// <h1> Test. </h1>
+class C {}
+''');
+ }
+
test_notDocComment() async {
await assertNoDiagnostics(r'''
// List<int> <tag>
@@ -183,17 +214,6 @@
]);
}
- test_unintendedHtml_multipleTags() async {
- await assertDiagnostics(r'''
-/// <assignment> -> <variable> = <expression>
-class C {}
-''', [
- lint(4, 12), // <assignment>
- lint(20, 10), // <variable>
- lint(33, 12), // <expression>
- ]);
- }
-
test_unintendedHtml_nested() async {
await assertDiagnostics(r'''
/// Text List<List<int>>.
@@ -223,10 +243,24 @@
]);
}
- test_validHtmlTag() async {
- await assertNoDiagnostics(r'''
-/// <h1> Test. </h1>
+ test_unintendedHtml_tags_multiple() async {
+ await assertDiagnostics(r'''
+/// <assignment> -> <variable> = <expression>
class C {}
-''');
+''', [
+ lint(4, 12), // <assignment>
+ lint(20, 10), // <variable>
+ lint(33, 12), // <expression>
+ ]);
+ }
+
+ test_unintendedHtml_tags_slash() async {
+ await assertDiagnostics(r'''
+/// </bad> <bad/>
+class C {}
+''', [
+ lint(4, 6), // </bad>
+ lint(11, 6), // <bad/>
+ ]);
}
}