Precompute FileState.uri properties.

Working with Uri, in form of _SimpleUri, was taking about 11%.
Now it _PubFilter is about 1%.

Change-Id: I35cd426d9c79e57cf85dcfe751ac57556f1a8b42
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/219849
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
index 912c845..53550d8 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/not_imported_contributor.dart
@@ -145,14 +145,15 @@
 
   @override
   bool shouldInclude(FileState file) {
-    var uri = file.uri;
-    if (uri.isScheme('dart')) {
+    var uri = file.uriProperties;
+    if (uri.isDart) {
       return true;
     }
 
     // Normally only package URIs are available.
     // But outside of lib/ we allow any files of this package.
-    if (!uri.isScheme('package')) {
+    var packageName = uri.packageName;
+    if (packageName == null) {
       if (targetInLib) {
         return false;
       } else {
@@ -162,20 +163,13 @@
       }
     }
 
-    // Sanity check.
-    var uriPathSegments = uri.pathSegments;
-    if (uriPathSegments.length < 2) {
-      return false;
-    }
-
     // Any `package:` library from the same package.
-    var packageName = uriPathSegments[0];
     if (packageName == targetPackageName) {
       return true;
     }
 
     // If not the same package, must be public.
-    if (uriPathSegments[1] == 'src') {
+    if (uri.isSrc) {
       return false;
     }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index f0f35eb..b728d00 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -94,6 +94,9 @@
   /// The absolute URI of the file.
   final Uri uri;
 
+  /// Properties of the [uri].
+  final FileUriProperties uriProperties;
+
   /// The [Source] of the file with the [uri].
   final Source source;
 
@@ -148,7 +151,7 @@
     this.workspacePackage,
     this._contextFeatureSet,
     this.packageLanguageVersion,
-  );
+  ) : uriProperties = FileUriProperties(uri);
 
   /// The unlinked API signature of the file.
   Uint8List get apiSignature => _apiSignature!;
@@ -971,3 +974,46 @@
         .toSet();
   }
 }
+
+/// Precomputed properties of a file URI, used because [Uri] is relatively
+/// expensive to work with, if we do this thousand times.
+class FileUriProperties {
+  static const int _isDart = 1 << 0;
+  static const int _isSrc = 1 << 1;
+
+  final int _flags;
+  final String? packageName;
+
+  factory FileUriProperties(Uri uri) {
+    if (uri.isScheme('dart')) {
+      return const FileUriProperties._dart();
+    } else if (uri.isScheme('package')) {
+      var segments = uri.pathSegments;
+      if (segments.length >= 2) {
+        return FileUriProperties._package(
+          packageName: segments[0],
+          isSrc: segments[1] == 'src',
+        );
+      }
+    }
+    return const FileUriProperties._unknown();
+  }
+
+  const FileUriProperties._dart()
+      : _flags = _isDart,
+        packageName = null;
+
+  FileUriProperties._package({
+    required String packageName,
+    required bool isSrc,
+  })  : _flags = isSrc ? _isSrc : 0,
+        packageName = packageName;
+
+  const FileUriProperties._unknown()
+      : _flags = 0,
+        packageName = null;
+
+  bool get isDart => (_flags & _isDart) != 0;
+
+  bool get isSrc => (_flags & _isSrc) != 0;
+}