Analyzer: add two checks for the @internal annotation.
The meta package does not yet have an `internal` constant;
this CL just adds one to the mock packages for testing.
Two checks are implemented:
* Hint if an @internal annotation is found on an element which is
already part of a package's public API (based on file path).
* Hint if an element annotated with @internal is exported from a
package's public API.
The notion of "public API" is also implemented for each type of Package:
BasicPackage, BazelPackage, GnPackage, PackageBuildPackage,
and PubPackage.
Bug: https://github.com/dart-lang/sdk/issues/28066
Change-Id: Ifc2709028afcd241f59e802f5952539f717704c3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163126
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 71b8251..9e50585 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -534,6 +534,9 @@
/// Return `true` if this element has an annotation of the form `@factory`.
bool get hasFactory;
+ /// Return `true` if this element has an annotation of the form `@internal`.
+ bool get hasInternal;
+
/// Return `true` if this element has an annotation of the form `@isTest`.
bool get hasIsTest;
@@ -717,6 +720,10 @@
/// subclasses as being immutable.
bool get isImmutable;
+ /// Return `true` if this annotation marks the associated element as being
+ /// internal to its package.
+ bool get isInternal;
+
/// Return `true` if this annotation marks the associated member as running
/// a single test.
bool get isIsTest;
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 4f13b90..9312ea8 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -492,10 +492,12 @@
HintCode.INFERENCE_FAILURE_ON_UNINITIALIZED_VARIABLE,
HintCode.INFERENCE_FAILURE_ON_UNTYPED_PARAMETER,
HintCode.INVALID_ANNOTATION_TARGET,
+ HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
HintCode.INVALID_FACTORY_ANNOTATION,
HintCode.INVALID_FACTORY_METHOD_DECL,
HintCode.INVALID_FACTORY_METHOD_IMPL,
HintCode.INVALID_IMMUTABLE_ANNOTATION,
+ HintCode.INVALID_INTERNAL_ANNOTATION,
HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_AT_SIGN,
HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_EQUALS,
HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index ecf68fe..63df85d 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -2313,6 +2313,10 @@
/// as being immutable.
static const String _IMMUTABLE_VARIABLE_NAME = "immutable";
+ /// The name of the top-level variable used to mark an element as being
+ /// internal to its package.
+ static const String _INTERNAL_VARIABLE_NAME = "internal";
+
/// The name of the top-level variable used to mark a constructor as being
/// literal.
static const String _LITERAL_VARIABLE_NAME = "literal";
@@ -2460,6 +2464,12 @@
element.library?.name == _META_LIB_NAME;
@override
+ bool get isInternal =>
+ element is PropertyAccessorElement &&
+ element.name == _INTERNAL_VARIABLE_NAME &&
+ element.library?.name == _META_LIB_NAME;
+
+ @override
bool get isIsTest =>
element is PropertyAccessorElement &&
element.name == _IS_TEST_VARIABLE_NAME &&
@@ -2748,6 +2758,18 @@
}
@override
+ bool get hasInternal {
+ var metadata = this.metadata;
+ for (var i = 0; i < metadata.length; i++) {
+ var annotation = metadata[i];
+ if (annotation.isInternal) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
bool get hasIsTest {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
@@ -5996,6 +6018,9 @@
bool get hasFactory => false;
@override
+ bool get hasInternal => false;
+
+ @override
bool get hasIsTest => false;
@override
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index a37c9d4..5c08ec5 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -460,6 +460,9 @@
bool get hasFactory => _declaration.hasFactory;
@override
+ bool get hasInternal => _declaration.hasInternal;
+
+ @override
bool get hasIsTest => _declaration.hasIsTest;
@override
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 9d9c4eb..9be0aa2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -577,6 +577,19 @@
"The annotation '{0}' can only be used on {1}");
/**
+ * This hint is generated anywhere where an element annotated with `@internal`
+ * is exported as a part of a package's public API.
+ *
+ * Parameters:
+ * 0: the name of the element
+ */
+ static const HintCode INVALID_EXPORT_OF_INTERNAL_ELEMENT = HintCode(
+ 'INVALID_EXPORT_OF_INTERNAL_ELEMENT',
+ "The member '{0}' can't be exported as a part of a package's public "
+ "API.",
+ correction: "Try using a hide clause to hide '{0}'.");
+
+ /**
* This hint is generated anywhere a @factory annotation is associated with
* anything other than a method.
*/
@@ -612,6 +625,15 @@
'INVALID_IMMUTABLE_ANNOTATION',
"Only classes can be annotated as being immutable.");
+ /**
+ * This hint is generated anywhere a @internal annotation is associated with
+ * an element found in a package's public API.
+ */
+ static const HintCode INVALID_INTERNAL_ANNOTATION = HintCode(
+ 'INVALID_INTERNAL_ANNOTATION',
+ "Only public elements in a package's private API can be annotated as "
+ "being internal.");
+
/// Invalid Dart language version comments don't follow the specification [1].
/// If a comment begins with "@dart" or "dart" (letters in any case),
/// followed by optional whitespace, followed by optional non-alphanumeric,
@@ -922,7 +944,7 @@
/**
* This hint is generated anywhere where a member annotated with `@protected`
- * is used outside an instance member of a subclass.
+ * is used outside of an instance member of a subclass.
*
* Parameters:
* 0: the name of the member
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 24c9c85..5d65e55 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -21,6 +21,7 @@
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
import 'package:analyzer/src/dart/resolver/exit_detector.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -113,6 +114,11 @@
);
}
+ bool get _inPublicPackageApi {
+ return _workspacePackage != null &&
+ _workspacePackage.sourceIsInPublicApi(_currentLibrary.source);
+ }
+
@override
void visitAnnotation(Annotation node) {
ElementAnnotation element = node.elementAnnotation;
@@ -132,6 +138,35 @@
_errorReporter.reportErrorForNode(
HintCode.INVALID_IMMUTABLE_ANNOTATION, node, []);
}
+ } else if (element.isInternal) {
+ var parentElement = parent is Declaration ? parent.declaredElement : null;
+ if (parent is TopLevelVariableDeclaration) {
+ for (VariableDeclaration variable in parent.variables.variables) {
+ if (Identifier.isPrivateName(variable.declaredElement.name)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_INTERNAL_ANNOTATION, variable, []);
+ }
+ }
+ } else if (parent is FieldDeclaration) {
+ for (VariableDeclaration variable in parent.fields.variables) {
+ if (Identifier.isPrivateName(variable.declaredElement.name)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_INTERNAL_ANNOTATION, variable, []);
+ }
+ }
+ } else if (parent is ConstructorDeclaration) {
+ var class_ = parent.declaredElement.enclosingElement;
+ if (class_.isPrivate || (parentElement?.isPrivate ?? false)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_INTERNAL_ANNOTATION, node, []);
+ }
+ } else if (parentElement?.isPrivate ?? false) {
+ _errorReporter
+ .reportErrorForNode(HintCode.INVALID_INTERNAL_ANNOTATION, node, []);
+ } else if (_inPublicPackageApi) {
+ _errorReporter
+ .reportErrorForNode(HintCode.INVALID_INTERNAL_ANNOTATION, node, []);
+ }
} else if (element.isLiteral == true) {
if (parent is! ConstructorDeclaration ||
(parent as ConstructorDeclaration).constKeyword == null) {
@@ -319,6 +354,7 @@
@override
void visitExportDirective(ExportDirective node) {
_checkForDeprecatedMemberUse(node.uriElement, node);
+ _checkForInternalExport(node);
super.visitExportDirective(node);
}
@@ -994,6 +1030,31 @@
}
}
+ /// Check that the namespace exported by [node] does not include any elements
+ /// annotated with `@internal`.
+ void _checkForInternalExport(ExportDirective node) {
+ if (!_inPublicPackageApi) return;
+
+ var libraryElement = node.uriElement;
+ if (libraryElement == null) return;
+ if (libraryElement.hasInternal) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+ node,
+ [libraryElement.displayName]);
+ }
+ var exportNamespace =
+ NamespaceBuilder().createExportNamespaceForDirective(node.element);
+ exportNamespace.definedNames.forEach((String name, Element element) {
+ if (element.hasInternal) {
+ _errorReporter.reportErrorForNode(
+ HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT,
+ node,
+ [element.displayName]);
+ }
+ });
+ }
+
void _checkForInvalidFactory(MethodDeclaration decl) {
// Check declaration.
// Note that null return types are expected to be flagged by other analyses.
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
index 2f054b5..9482e66 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_packages.dart
@@ -28,6 +28,7 @@
const _DoNotStore doNotStore = _DoNotStore();
const _Factory factory = const _Factory();
const Immutable immutable = const Immutable();
+const _Internal internal = const Internal();
const _Literal literal = const _Literal();
const _MustCallSuper mustCallSuper = const _MustCallSuper();
const _NonVirtual nonVirtual = const _NonVirtual();
@@ -50,6 +51,9 @@
final String reason;
const Immutable([this.reason]);
}
+class _Internal {
+ const Internal();
+}
class _Literal {
const _Literal();
}
diff --git a/pkg/analyzer/lib/src/workspace/basic.dart b/pkg/analyzer/lib/src/workspace/basic.dart
index fb02a62..5f3be2a 100644
--- a/pkg/analyzer/lib/src/workspace/basic.dart
+++ b/pkg/analyzer/lib/src/workspace/basic.dart
@@ -80,4 +80,12 @@
@override
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
workspace.packageMap;
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ // Since every source file in a BasicPackage is in the same directory, they
+ // are all in the public API of the package. A file in a subdirectory
+ // is in a separate package.
+ return true;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index 0320187..2c474e6 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -260,6 +260,19 @@
WorkspacePackage findPackageFor(String filePath) {
path.Context context = provider.pathContext;
Folder folder = provider.getFolder(context.dirname(filePath));
+ if (!context.isWithin(root, folder.path)) {
+ return null;
+ }
+
+ // Handle files which are given with their location in "bazel-bin", etc.
+ // This does not typically happen during usual analysis, but it still could,
+ // and it can come up in tests.
+ if ([genfiles, ...binPaths]
+ .any((binPath) => context.isWithin(binPath, folder.path))) {
+ var relative = context.relative(filePath, from: root);
+ return findPackageFor(
+ context.joinAll([root, ...context.split(relative).skip(1)]));
+ }
while (true) {
Folder parent = folder.parent;
@@ -300,7 +313,8 @@
// [folder]'s path, relative to [root]. For example, "foo/bar".
String relative = context.relative(folder.path, from: root);
for (String bin in binPaths) {
- Folder binChild = provider.getFolder(context.join(bin, relative));
+ Folder binChild =
+ provider.getFolder(context.normalize(context.join(bin, relative)));
if (binChild.exists &&
binChild.getChildren().any((c) => c.path.endsWith('.packages'))) {
// [folder]'s sister folder within [bin] contains a ".packages" file.
@@ -548,4 +562,41 @@
// lists.
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
<String, List<Folder>>{};
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$root/lib" is public iff it is not in "$root/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+
+ var relativeRoot =
+ workspace.provider.pathContext.relative(root, from: workspace.root);
+ for (var binPath in workspace.binPaths) {
+ libFolder =
+ workspace.provider.pathContext.join(binPath, relativeRoot, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$bin/lib" is public iff it is not in "$bin/lib/src".
+ var libSrcFolder =
+ workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+ }
+
+ libFolder = workspace.provider.pathContext
+ .join(workspace.genfiles, relativeRoot, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$genfiles/lib" is public iff it is not in
+ // "$genfiles/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+
+ return false;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/gn.dart b/pkg/analyzer/lib/src/workspace/gn.dart
index cca441f..fe78cc0 100644
--- a/pkg/analyzer/lib/src/workspace/gn.dart
+++ b/pkg/analyzer/lib/src/workspace/gn.dart
@@ -237,4 +237,17 @@
@override
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
workspace.packageMap;
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ var libSrcFolder =
+ workspace.provider.pathContext.join(root, 'lib', 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+ return false;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/package_build.dart b/pkg/analyzer/lib/src/workspace/package_build.dart
index 60eb742..7240390 100644
--- a/pkg/analyzer/lib/src/workspace/package_build.dart
+++ b/pkg/analyzer/lib/src/workspace/package_build.dart
@@ -137,6 +137,12 @@
/// package:build does it.
static const String _pubspecName = 'pubspec.yaml';
+ static const List<String> _generatedPathParts = [
+ '.dart_tool',
+ 'build',
+ 'generated'
+ ];
+
/// The resource provider used to access the file system.
final ResourceProvider provider;
@@ -286,7 +292,7 @@
final yaml = loadYaml(pubspec.readAsStringSync());
final packageName = yaml['name'] as String;
final generatedRootPath = provider.pathContext
- .join(folder.path, '.dart_tool', 'build', 'generated');
+ .joinAll([folder.path, ..._generatedPathParts]);
final generatedThisPath =
provider.pathContext.join(generatedRootPath, packageName);
return PackageBuildWorkspace._(provider, packageMap, folder.path,
@@ -334,4 +340,26 @@
@override
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
workspace._packageMap;
+
+ @override
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$root/lib" is public iff it is not in "$root/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+
+ libFolder = workspace.provider.pathContext.joinAll(
+ [root, ...PackageBuildWorkspace._generatedPathParts, 'test', 'lib']);
+ if (workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ // A file in "$generated/lib" is public iff it is not in
+ // "$generated/lib/src".
+ var libSrcFolder = workspace.provider.pathContext.join(libFolder, 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
+ return false;
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/pub.dart b/pkg/analyzer/lib/src/workspace/pub.dart
index f47327d..1fed22e 100644
--- a/pkg/analyzer/lib/src/workspace/pub.dart
+++ b/pkg/analyzer/lib/src/workspace/pub.dart
@@ -120,4 +120,20 @@
// [libraryPath] is inside the `lib` directory.
return workspace.packageMap;
}
+
+ @override
+
+ /// A Pub package's public API consists of libraries found in the top-level
+ /// "lib" directory, and any subdirectories, excluding the "src" directory
+ /// just inside the top-level "lib" directory.
+ bool sourceIsInPublicApi(Source source) {
+ var filePath = filePathFromSource(source);
+ if (filePath == null) return false;
+ var libFolder = workspace.provider.pathContext.join(root, 'lib');
+ if (!workspace.provider.pathContext.isWithin(libFolder, filePath)) {
+ return false;
+ }
+ var libSrcFolder = workspace.provider.pathContext.join(root, 'lib', 'src');
+ return !workspace.provider.pathContext.isWithin(libSrcFolder, filePath);
+ }
}
diff --git a/pkg/analyzer/lib/src/workspace/workspace.dart b/pkg/analyzer/lib/src/workspace/workspace.dart
index d9dc17a..0b83b88 100644
--- a/pkg/analyzer/lib/src/workspace/workspace.dart
+++ b/pkg/analyzer/lib/src/workspace/workspace.dart
@@ -67,6 +67,9 @@
/// path of the root of those packages for all of the packages that could
/// validly be imported by the library with the given [libraryPath].
Map<String, List<Folder>> packagesAvailableTo(String libraryPath);
+
+ /// Return whether [source] is located in this package's public API.
+ bool sourceIsInPublicApi(Source source);
}
/// An interface for a workspace that contains a default analysis options file.
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
new file mode 100644
index 0000000..40ce958
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
@@ -0,0 +1,512 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// 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/dart/analysis/analysis_context.dart';
+import 'package:analyzer/dart/analysis/results.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/mock_packages.dart';
+import 'package:analyzer/src/workspace/bazel.dart';
+import 'package:analyzer/src/workspace/package_build.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidExportOfInternalElement_BazelPackageTest);
+ defineReflectiveTests(
+ InvalidExportOfInternalElement_PackageBuildPackageTest);
+ defineReflectiveTests(InvalidExportOfInternalElement_PubPackageTest);
+ });
+}
+
+@reflectiveTest
+class InvalidExportOfInternalElement_BazelPackageTest
+ extends BazelWorkspaceResolutionTest
+ with InvalidExportOfInternalElementTest {
+ /// A cached analysis context for resolving sources via the same [Workspace].
+ AnalysisContext analysisContext;
+
+ String get testPackageBazelBinPath => '$workspaceRootPath/bazel-bin/dart/my';
+
+ String get testPackageGenfilesPath =>
+ '$workspaceRootPath/bazel-genfiles/dart/my';
+
+ @override
+ String get testPackageLibPath => myPackageLibPath;
+
+ @override
+ Future<ResolvedUnitResult> resolveFile(String path) {
+ analysisContext ??= contextFor(path);
+ assert(analysisContext.workspace is BazelWorkspace);
+ return analysisContext.currentSession.getResolvedUnit(path);
+ }
+
+ @override
+ void setUp() async {
+ super.setUp();
+ var metaPath = '$workspaceThirdPartyDartPath/meta';
+ MockPackages.addMetaPackageFiles(
+ getFolder(metaPath),
+ );
+ newFile('$testPackageBazelBinPath/my.packages');
+ newFolder('$workspaceRootPath/bazel-out');
+ }
+
+ void test_exporterIsInBazelBinLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageBazelBinPath/lib/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageBazelBinPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInBazelBinLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageBazelBinPath/lib/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageBazelBinPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInGenfilesLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageGenfilesPath/lib/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageGenfilesPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInGenfilesLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ newFile('$testPackageGenfilesPath/lib/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageGenfilesPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInTest() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$myPackageRootPath/test/foo_test.dart', content: r'''
+export 'package:dart.my/src/foo.dart';
+''');
+ await resolveFile2('$myPackageRootPath/test/foo_test.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_internalIsInBazelBin() async {
+ newFile('$testPackageBazelBinPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:dart.my/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 38),
+ ]);
+ }
+
+ void test_internalIsInGenfiles() async {
+ newFile('$testPackageGenfilesPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:dart.my/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 38),
+ ]);
+ }
+
+ void test_internalIsInLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:dart.my/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 38),
+ ]);
+ }
+}
+
+@reflectiveTest
+class InvalidExportOfInternalElement_PackageBuildPackageTest
+ extends InvalidExportOfInternalElement_PubPackageTest {
+ /// A cached analysis context for resolving sources via the same [Workspace].
+ AnalysisContext analysisContext;
+
+ String get testPackageDartToolPath =>
+ '$testPackageRootPath/.dart_tool/build/generated/test';
+
+ @override
+ Future<ResolvedUnitResult> resolveFile(String path) {
+ analysisContext ??= contextFor(path);
+ assert(analysisContext.workspace is PackageBuildWorkspace);
+ return analysisContext.currentSession.getResolvedUnit(path);
+ }
+
+ @override
+ void setUp() async {
+ analysisContext = null;
+ super.setUp();
+ newFolder(testPackageDartToolPath);
+ }
+
+ void test_exporterInGeneratedLib() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageDartToolPath/lib/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageDartToolPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+
+ void test_exporterInGeneratedLibSrc() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageDartToolPath/lib/src/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageDartToolPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterInLib() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageRootPath/lib/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageRootPath/lib/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+
+ void test_exporterInLibSrc() async {
+ newFile('$testPackageRootPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/foo.dart');
+
+ newFile('$testPackageRootPath/lib/src/bar.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageRootPath/lib/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_internalIsInGeneratedLibSrc() async {
+ newFile('$testPackageDartToolPath/lib/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:test/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+
+ void test_internalIsLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:test/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+}
+
+@reflectiveTest
+class InvalidExportOfInternalElement_PubPackageTest
+ extends PubPackageResolutionTest with InvalidExportOfInternalElementTest {
+ @override
+ void setUp() async {
+ super.setUp();
+ writeTestPackageConfigWithMeta();
+ newFile('$testPackageRootPath/pubspec.yaml', content: r'''
+name: test
+version: 0.0.1
+''');
+ }
+
+ void test_exporterIsInLib() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/bar.dart', content: r'''
+export 'src/foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/bar.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_exporterIsInLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageLibPath/src/bar.dart', content: r'''
+export 'foo.dart';
+''');
+ await resolveFile2('$testPackageLibPath/src/bar.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_exporterIsInTest() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ newFile('$testPackageRootPath/test/foo_test.dart', content: r'''
+export 'package:test/src/foo.dart';
+''');
+ await resolveFile2('$testPackageRootPath/test/foo_test.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_internalIsLibSrc() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'package:test/src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 35),
+ ]);
+ }
+}
+
+mixin InvalidExportOfInternalElementTest on ContextResolutionTest {
+ String get testPackageImplementationFilePath =>
+ '$testPackageLibPath/src/foo.dart';
+
+ String get testPackageLibPath;
+
+ void test_hideCombinator_internalHidden() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart' hide One;
+''');
+ }
+
+ void test_hideCombinator_internalNotHidden() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart' hide Two;
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 31),
+ ]);
+ }
+
+ void test_noCombinators() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_noCombinators_indirectExport() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+export 'bar.dart';
+''');
+
+ newFile('$testPackageLibPath/src/bar.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_noCombinators_library() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+@internal
+library foo;
+
+import 'package:meta/meta.dart';
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart';
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 22),
+ ]);
+ }
+
+ void test_noCombinators_library_notInternal() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+library foo;
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart';
+''');
+ }
+
+ void test_noCombinators_noInternal() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+class One {}
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart';
+''');
+ }
+
+ void test_showCombinator_internalNotShown() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertNoErrorsInCode(r'''
+export 'src/foo.dart' show Two;
+''');
+ }
+
+ void test_showCombinator_internalShown() async {
+ newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+class Two {}
+''');
+
+ await assertErrorsInCode(r'''
+export 'src/foo.dart' show One;
+''', [
+ error(HintCode.INVALID_EXPORT_OF_INTERNAL_ELEMENT, 0, 31),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_internal_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_internal_annotation_test.dart
new file mode 100644
index 0000000..2dee934
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_internal_annotation_test.dart
@@ -0,0 +1,361 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// 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/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(InvalidInternalAnnotationTest);
+ });
+}
+
+@reflectiveTest
+class InvalidInternalAnnotationTest extends PubPackageResolutionTest {
+ String get testPackageImplementationFilePath =>
+ '$testPackageLibPath/src/foo.dart';
+
+ @override
+ void setUp() async {
+ super.setUp();
+ writeTestPackageConfigWithMeta();
+ await newFile('$testPackageRootPath/pubspec.yaml', content: r'''
+name: test
+version: 0.0.1
+''');
+ }
+
+ void test_annotationInLib() async {
+ await newFile('$testPackageLibPath/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_annotationInLib_onLibrary() async {
+ await newFile('$testPackageLibPath/foo.dart', content: r'''
+@internal
+library foo;
+import 'package:meta/meta.dart';
+''');
+ await resolveFile2('$testPackageLibPath/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 0, 9),
+ ]);
+ }
+
+ void test_annotationInLibSrc() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_annotationInLibSrcSubdirectory() async {
+ await newFile('$testPackageLibPath/src/foo/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo/foo.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_annotationInLibSubdirectory() async {
+ await newFile('$testPackageLibPath/foo/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageLibPath/foo/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_annotationInTest() async {
+ await newFile('$testPackageRootPath/test/foo_test.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal class One {}
+''');
+ await resolveFile2('$testPackageRootPath/test/foo_test.dart');
+
+ assertErrorsInResolvedUnit(result, []);
+ }
+
+ void test_privateClass() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal class _One {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 49, 4),
+ ]);
+ }
+
+ void test_privateClassConstructor_named() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal _C.named();
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 46, 9),
+ ]);
+ }
+
+ void test_privateClassConstructor_unnamed() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal _C();
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 46, 9),
+ ]);
+ }
+
+ void test_privateConstructor() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal C._f();
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ ]);
+ }
+
+ void test_privateEnum() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal enum _E {one}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 48, 2),
+ error(HintCode.UNUSED_FIELD, 52, 3),
+ ]);
+ }
+
+ void test_privateEnumValue() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+enum E {@internal _one}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 41, 9),
+ error(HintCode.UNUSED_FIELD, 51, 4),
+ ]);
+ }
+
+ void test_privateExtension() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal extension _One on String {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_privateExtension_unnamed() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+@internal extension on String {}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ ]);
+ }
+
+ void test_privateField_instance() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal int _i = 0;
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_FIELD, 59, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 59, 6),
+ ]);
+ }
+
+ void test_privateField_static() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal static int _i = 0;
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_FIELD, 66, 2),
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 66, 6),
+ ]);
+ }
+
+ void test_privateGetter() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal int get _i => 0;
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ error(HintCode.UNUSED_ELEMENT, 63, 2),
+ ]);
+ }
+
+ void test_privateMethod_instance() async {
+ await newFile(testPackageImplementationFilePath, content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal void _f() {}
+}
+''');
+ await resolveFile2(testPackageImplementationFilePath);
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ error(HintCode.UNUSED_ELEMENT, 60, 2),
+ ]);
+ }
+
+ void test_privateMethod_static() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+class C {
+ @internal static void _f() {}
+}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 45, 9),
+ error(HintCode.UNUSED_ELEMENT, 67, 2),
+ ]);
+ }
+
+ void test_privateMixin() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal mixin _One {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 49, 4),
+ ]);
+ }
+
+ void test_privateTopLevelFunction() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal void _f() {}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 48, 2),
+ ]);
+ }
+
+ void test_privateTopLevelVariable() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal int _i = 1;
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 47, 6),
+ error(HintCode.UNUSED_ELEMENT, 47, 2),
+ ]);
+ }
+
+ void test_privateTypedef() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+@internal typedef _T = void Function();
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.INVALID_INTERNAL_ANNOTATION, 33, 9),
+ error(HintCode.UNUSED_ELEMENT, 51, 2),
+ ]);
+ }
+
+ void test_publicMethod_privateClass() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal void f() {}
+}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ ]);
+ }
+
+ void test_publicMethod_privateClass_static() async {
+ await newFile('$testPackageLibPath/src/foo.dart', content: r'''
+import 'package:meta/meta.dart';
+class _C {
+ @internal static void f() {}
+}
+''');
+ await resolveFile2('$testPackageLibPath/src/foo.dart');
+
+ assertErrorsInResolvedUnit(result, [
+ error(HintCode.UNUSED_ELEMENT, 39, 2),
+ error(HintCode.UNUSED_ELEMENT, 68, 1),
+ ]);
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 55f08d2..08a65a1 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -279,6 +279,8 @@
import 'invalid_constant_test.dart' as invalid_constant;
import 'invalid_constructor_name_test.dart' as invalid_constructor_name;
import 'invalid_exception_value_test.dart' as invalid_exception_value;
+import 'invalid_export_of_internal_element_test.dart'
+ as invalid_export_of_internal_element;
import 'invalid_extension_argument_count_test.dart'
as invalid_extension_argument_count;
import 'invalid_factory_annotation_test.dart' as invalid_factory_annotation;
@@ -287,6 +289,7 @@
as invalid_factory_name_not_a_class;
import 'invalid_field_type_in_struct_test.dart' as invalid_field_type_in_struct;
import 'invalid_immutable_annotation_test.dart' as invalid_immutable_annotation;
+import 'invalid_internal_annotation_test.dart' as invalid_internal_annotation;
import 'invalid_language_override_greater_test.dart'
as invalid_language_override_greater;
import 'invalid_language_override_test.dart' as invalid_language_override;
@@ -828,12 +831,14 @@
invalid_constant.main();
invalid_constructor_name.main();
invalid_exception_value.main();
+ invalid_export_of_internal_element.main();
invalid_extension_argument_count.main();
invalid_factory_annotation.main();
invalid_factory_method_impl.main();
invalid_factory_name_not_a_class.main();
invalid_field_type_in_struct.main();
invalid_immutable_annotation.main();
+ invalid_internal_annotation.main();
invalid_language_override_greater.main();
invalid_language_override.main();
invalid_literal_annotation.main();