Enhance the skip test parsing the analyzer script. (#88894)
diff --git a/dev/bots/analyze.dart b/dev/bots/analyze.dart
index 7323a5b..2876b8c 100644
--- a/dev/bots/analyze.dart
+++ b/dev/bots/analyze.dart
@@ -8,6 +8,11 @@
import 'dart:io' hide exit;
import 'dart:typed_data';
+import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/dart/analysis/utilities.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
import 'package:crypto/crypto.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
@@ -283,25 +288,66 @@
}
}
-final RegExp _skipTestCommentPattern = RegExp(r'\bskip:.*?//(.*)');
+class _TestSkip {
+ _TestSkip(this.line, this.content);
+
+ final int line;
+ final String content;
+}
+
+Iterable<_TestSkip> _getTestSkips(File file) {
+ final ParseStringResult parseResult = parseFile(
+ featureSet: FeatureSet.latestLanguageVersion(),
+ path: file.absolute.path,
+ );
+ final _TestSkipLinesVisitor<CompilationUnit> visitor = _TestSkipLinesVisitor<CompilationUnit>(parseResult);
+ visitor.visitCompilationUnit(parseResult.unit);
+ return visitor.skips;
+}
+
+class _TestSkipLinesVisitor<T> extends RecursiveAstVisitor<T> {
+ _TestSkipLinesVisitor(this.parseResult) : skips = <_TestSkip>{};
+
+ final ParseStringResult parseResult;
+ final Set<_TestSkip> skips;
+
+ static bool isTestMethod(String name) {
+ return name.startsWith('test') || name == 'group' || name == 'expect';
+ }
+
+ @override
+ T? visitMethodInvocation(MethodInvocation node) {
+ if (isTestMethod(node.methodName.toString())) {
+ for (final Expression argument in node.argumentList.arguments) {
+ if (argument is NamedExpression && argument.name.label.name == 'skip') {
+ final int lineNumber = parseResult.lineInfo.getLocation(argument.beginToken.charOffset).lineNumber;
+ final String content = parseResult.content.substring(parseResult.lineInfo.getOffsetOfLine(lineNumber - 1),
+ parseResult.lineInfo.getOffsetOfLine(lineNumber) - 1);
+ skips.add(_TestSkip(lineNumber, content));
+ }
+ }
+ }
+ return super.visitMethodInvocation(node);
+ }
+}
+
+final RegExp _skipTestCommentPattern = RegExp(r'//(.*)$');
const Pattern _skipTestIntentionalPattern = '[intended]';
final Pattern _skipTestTrackingBugPattern = RegExp(r'https+?://github.com/.*/issues/[0-9]+');
Future<void> verifySkipTestComments(String workingDirectory) async {
final List<String> errors = <String>[];
- final Stream<File> testFiles = _allFiles(workingDirectory, 'dart', minimumMatches: 1500)
+ final Stream<File> testFiles =_allFiles(workingDirectory, 'dart', minimumMatches: 1500)
.where((File f) => f.path.endsWith('_test.dart'));
await for (final File file in testFiles) {
- final List<String> lines = file.readAsLinesSync();
- for (int index = 0; index < lines.length; index++) {
- final Match? match = _skipTestCommentPattern.firstMatch(lines[index]);
+ for (final _TestSkip skip in _getTestSkips(file)) {
+ final Match? match = _skipTestCommentPattern.firstMatch(skip.content);
final String? skipComment = match?.group(1);
- if (skipComment != null
- && !skipComment.contains(_skipTestIntentionalPattern)
- && !skipComment.contains(_skipTestTrackingBugPattern)) {
- final int sourceLine = index + 1;
- errors.add('${file.path}:$sourceLine}: skip test without a justification comment.');
+ if (skipComment == null ||
+ !(skipComment.contains(_skipTestIntentionalPattern) ||
+ skipComment.contains(_skipTestTrackingBugPattern))) {
+ errors.add('${file.path}:${skip.line}: skip test without a justification comment.');
}
}
}