Completion. Issue 35449. Don't suggest @internal instance members when not available.

Bug: https://github.com/dart-lang/sdk/issues/35449
Change-Id: I9e65a0075a69e0bbc00e814272099a6810b82ed9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/358261
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/cider/completion.dart b/pkg/analysis_server/lib/src/cider/completion.dart
index 2052196..5c4507b 100644
--- a/pkg/analysis_server/lib/src/cider/completion.dart
+++ b/pkg/analysis_server/lib/src/cider/completion.dart
@@ -79,6 +79,7 @@
 
       _dartCompletionRequest = DartCompletionRequest(
         analysisSession: analysisSession,
+        fileState: resolvedUnit.fileState,
         filePath: resolvedUnit.path,
         fileContent: resolvedUnit.content,
         unitElement: resolvedUnit.unitElement,
diff --git a/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart b/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart
index 332d9e2..33f35a2 100644
--- a/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart
+++ b/pkg/analysis_server/lib/src/handler/legacy/completion_get_suggestions2.dart
@@ -191,6 +191,7 @@
 
         var completionRequest = DartCompletionRequest(
           analysisSession: analysisSession,
+          fileState: resolvedUnit.fileState,
           filePath: resolvedUnit.path,
           fileContent: resolvedUnit.content,
           unitElement: resolvedUnit.unitElement,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 0cac73e..75c3eba 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -18,6 +18,7 @@
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_collector.dart';
 import 'package:analysis_server/src/services/completion/dart/uri_contributor.dart';
+import 'package:analysis_server/src/utilities/extensions/object.dart';
 import 'package:analysis_server/src/utilities/selection.dart';
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/results.dart';
@@ -30,12 +31,15 @@
 import 'package:analyzer/source/source.dart';
 import 'package:analyzer/source/source_range.dart';
 import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/results.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
 import 'package:analyzer/src/generated/source.dart' show SourceFactory;
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/performance/operation_performance.dart';
+import 'package:analyzer/src/workspace/pub.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
 import 'package:analyzer_plugin/src/utilities/completion/optype.dart';
@@ -266,6 +270,9 @@
   /// request.
   final OpType opType;
 
+  /// The file where completion is requested.
+  final FileState fileState;
+
   /// The absolute path of the file where completion is requested.
   final String path;
 
@@ -298,6 +305,7 @@
 
   factory DartCompletionRequest({
     required AnalysisSession analysisSession,
+    required FileState fileState,
     required String filePath,
     required String fileContent,
     required CompilationUnitElement unitElement,
@@ -335,6 +343,7 @@
       libraryElement: libraryElement,
       offset: offset,
       opType: opType,
+      fileState: fileState,
       path: filePath,
       replacementRange: target.computeReplacementRange(offset),
       source: unitElement.source,
@@ -349,8 +358,10 @@
     DartdocDirectiveInfo? dartdocDirectiveInfo,
     CompletionPreference completionPreference = CompletionPreference.insert,
   }) {
+    resolvedUnit as ResolvedUnitResultImpl;
     return DartCompletionRequest(
       analysisSession: resolvedUnit.session,
+      fileState: resolvedUnit.fileState,
       filePath: resolvedUnit.path,
       fileContent: resolvedUnit.content,
       unitElement: resolvedUnit.unit.declaredElement!,
@@ -372,6 +383,7 @@
     required this.libraryElement,
     required this.offset,
     required this.opType,
+    required this.fileState,
     required this.path,
     required this.replacementRange,
     required this.source,
@@ -400,6 +412,12 @@
   /// Answer the [DartType] for Object in dart:core
   InterfaceType get objectType => libraryElement.typeProvider.objectType;
 
+  /// Returns the [PubPackage] of the file where completion is requested.
+  /// Or `null` if the package is not [PubPackage].
+  PubPackage? get pubPackage {
+    return fileState.workspacePackage.ifTypeOrNull();
+  }
+
   /// The length of the text to be replaced if the remainder of the identifier
   /// containing the cursor is to be replaced when the suggestion is applied
   /// (that is, the number of characters in the existing identifier).
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
index 7888f2c..683c994 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/declaration_helper.dart
@@ -1029,6 +1029,14 @@
       return false;
     }
 
+    if (element.isInternal) {
+      if (request.pubPackage case var pubPackage?) {
+        if (!pubPackage.contains(element.librarySource)) {
+          return false;
+        }
+      }
+    }
+
     if (element.isProtected) {
       var elementInterface = element.enclosingElement;
       if (elementInterface is! InterfaceElement) {
@@ -1727,7 +1735,20 @@
   }
 }
 
-extension on ExecutableElement {
+extension on Element {
+  bool get isInternal {
+    if (hasInternal) {
+      return true;
+    }
+    if (this case PropertyAccessorElement accessor) {
+      var variable = accessor.variable2;
+      if (variable != null && variable.hasInternal) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   bool get isProtected {
     final self = this;
     if (self is PropertyAccessorElement &&
diff --git a/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart b/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart
index eba4b8b..a34e243 100644
--- a/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/location/property_access_expression_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/src/test_utilities/package_config_file_builder.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../../../../client/completion_driver_test.dart';
@@ -174,6 +175,76 @@
 ''');
   }
 
+  Future<void> test_isInternal_method_otherPackage() async {
+    var otherRoot = getFolder('$packagesRootPath/other');
+    newFile('${otherRoot.path}/lib/src/a.dart', r'''
+import 'package:meta/meta.dart';
+
+class A {
+  void f01() {}
+
+  @internal
+  void f02() {}
+}
+''');
+
+    writeTestPackageConfig(
+      config: PackageConfigFileBuilder()
+        ..add(
+          name: 'other',
+          rootPath: otherRoot.path,
+        ),
+      meta: true,
+    );
+
+    await computeSuggestions('''
+import 'package:other/src/a.dart''
+
+void f() {
+  A().^
+}
+''');
+
+    assertResponse(r'''
+suggestions
+  f01
+    kind: methodInvocation
+''');
+  }
+
+  Future<void> test_isInternal_method_samePackage() async {
+    writeTestPackageConfig(
+      meta: true,
+    );
+
+    newFile('$testPackageLibPath/src/a.dart', r'''
+import 'package:meta/meta.dart';
+
+class A {
+  void f01() {}
+
+  @internal
+  void f02() {}
+}
+''');
+
+    await computeSuggestions('''
+import 'src/a.dart''
+
+void f() {
+  A().^
+}
+''');
+
+    assertResponse(r'''
+suggestions
+  f01
+    kind: methodInvocation
+  f02
+    kind: methodInvocation
+''');
+  }
+
   Future<void> test_isProtected_field_otherLibrary_function() async {
     writeTestPackageConfig(
       meta: true,
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 1bbf854..982f54d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -2069,6 +2069,7 @@
 
       return ResolvedForCompletionResultImpl(
         analysisSession: currentSession,
+        fileState: file,
         path: path,
         uri: file.uri,
         exists: file.exists,
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index f44d325..2e7ef79 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -54,10 +54,12 @@
 import 'package:path/path.dart' as path;
 
 class AnalysisForCompletionResult {
+  final FileState fileState;
   final CompilationUnit parsedUnit;
   final List<AstNode> resolvedNodes;
 
   AnalysisForCompletionResult({
+    required this.fileState,
     required this.parsedUnit,
     required this.resolvedNodes,
   });
@@ -195,6 +197,7 @@
           nodeToResolve.accept(resolverVisitor);
           resolverVisitor.checkIdle();
           return AnalysisForCompletionResult(
+            fileState: file,
             parsedUnit: parsedUnit,
             resolvedNodes: [nodeToResolve],
           );
@@ -204,6 +207,7 @@
       _parseAndResolve();
       var unit = _libraryUnits.values.first.unit;
       return AnalysisForCompletionResult(
+        fileState: file,
         parsedUnit: unit,
         resolvedNodes: [unit],
       );
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index 2aac1c1..4a3c15b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -342,6 +342,7 @@
 
 class ResolvedForCompletionResultImpl {
   final AnalysisSession analysisSession;
+  final FileState fileState;
   final String path;
   final Uri uri;
   final bool exists;
@@ -371,6 +372,7 @@
 
   ResolvedForCompletionResultImpl({
     required this.analysisSession,
+    required this.fileState,
     required this.path,
     required this.uri,
     required this.exists,
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 4602721..7987514f 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -615,6 +615,7 @@
 
         return ResolvedForCompletionResultImpl(
           analysisSession: analysisSession,
+          fileState: analysisResult.fileState,
           path: path,
           uri: file.uri,
           exists: file.exists,