linter: allow dotted usernames in flutter-style-todos

Fixes https://github.com/dart-lang/linter/issues/4348

Change-Id: Ib6394f30db251c9f91c592c22c00ea497b5406cf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/362740
Auto-Submit: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
Commit-Queue: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/linter/lib/src/rules/flutter_style_todos.dart b/pkg/linter/lib/src/rules/flutter_style_todos.dart
index 682abb2..0ccd7f7 100644
--- a/pkg/linter/lib/src/rules/flutter_style_todos.dart
+++ b/pkg/linter/lib/src/rules/flutter_style_todos.dart
@@ -14,9 +14,15 @@
 const _details = r'''
 **DO** use Flutter TODO format.
 
-From the [Flutter docs](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#comments):
+From the [Flutter
+docs](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#comments):
 
-> TODOs should include the string TODO in all caps, followed by the GitHub username of the person with the best context about the problem referenced by the TODO in parenthesis. A TODO is not a commitment that the person referenced will fix the problem, it is intended to be the person with enough context to explain the problem. Thus, when you create a TODO, it is almost always your username that is given.
+> TODOs should include the string TODO in all caps, followed by the GitHub
+username of the person with the best context about the problem referenced by the
+TODO in parenthesis. A TODO is not a commitment that the person referenced will
+fix the problem, it is intended to be the person with enough context to explain
+the problem. Thus, when you create a TODO, it is almost always your username
+that is given.
 
 **GOOD:**
 ```dart
@@ -34,7 +40,7 @@
   static final _todoRegExp = RegExp(r'//+(.* )?TODO\b', caseSensitive: false);
 
   static final RegExp _todoExpectedRegExp =
-      RegExp(r'// TODO\([a-zA-Z0-9][-a-zA-Z0-9]*\): ');
+      RegExp(r'// TODO\([a-zA-Z0-9][-a-zA-Z0-9\.]*\): ');
 
   FlutterStyleTodos()
       : super(
@@ -53,7 +59,7 @@
     registry.addCompilationUnit(this, visitor);
   }
 
-  /// Return `true` if the given [content] is invalid and should trigger a lint.
+  /// Returns whether the given [content] is invalid and should trigger a lint.
   static bool invalidTodo(String content) =>
       content.startsWith(_todoRegExp) &&
       !content.startsWith(_todoExpectedRegExp);
diff --git a/pkg/linter/test/rules/flutter_style_todos_test.dart b/pkg/linter/test/rules/flutter_style_todos_test.dart
index 703888c..e558a38 100644
--- a/pkg/linter/test/rules/flutter_style_todos_test.dart
+++ b/pkg/linter/test/rules/flutter_style_todos_test.dart
@@ -47,16 +47,7 @@
     );
   }
 
-  test_badUsername1() async {
-    await assertDiagnostics(
-      r'// TODO(#12357): bla',
-      [
-        lint(0, 20),
-      ],
-    );
-  }
-
-  test_badUsername2() async {
+  test_badUsername_comma() async {
     await assertDiagnostics(
       r'// TODO(user1,user2): bla',
       [
@@ -65,6 +56,15 @@
     );
   }
 
+  test_badUsername_extraSymbols() async {
+    await assertDiagnostics(
+      r'// TODO(#12357): bla',
+      [
+        lint(0, 20),
+      ],
+    );
+  }
+
   test_docComment() async {
     await assertDiagnostics(
       r'/// TODO(user): bla',
@@ -137,6 +137,10 @@
     );
   }
 
+  test_properFormat_dottedUsername() async {
+    await assertNoDiagnostics(r'// TODO(user.name): bla');
+  }
+
   test_properFormat_hyphenatedUsername() async {
     await assertNoDiagnostics(r'// TODO(user-name): bla');
   }