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,