Skip to content

Commit 8638214

Browse files
srawlinscommit-bot@chromium.org
authored andcommitted
Analyzer: Report invalid use of internal members
Bug: #28066 Change-Id: Iee39fee48340fb9311a8f7a07d1ae7aa474a22f4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163961 Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 04e2482 commit 8638214

File tree

5 files changed

+639
-31
lines changed

5 files changed

+639
-31
lines changed

pkg/analyzer/lib/error/error.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ const List<ErrorCode> errorCodeValues = [
514514
HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
515515
HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
516516
HintCode.INVALID_SEALED_ANNOTATION,
517+
HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
517518
HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
518519
HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
519520
HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,

pkg/analyzer/lib/src/dart/error/hint_codes.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,17 @@ class HintCode extends AnalyzerErrorCode {
942942
"annotated with it.",
943943
correction: "Remove @sealed.");
944944

945+
/**
946+
* This hint is generated anywhere where a member annotated with `@internal`
947+
* is used outside of the package in which it is declared.
948+
*
949+
* Parameters:
950+
* 0: the name of the member
951+
*/
952+
static const HintCode INVALID_USE_OF_INTERNAL_MEMBER = HintCode(
953+
'INVALID_USE_OF_INTERNAL_MEMBER',
954+
"The member '{0}' can only be used within its package.");
955+
945956
/**
946957
* This hint is generated anywhere where a member annotated with `@protected`
947958
* is used outside of an instance member of a subclass.

pkg/analyzer/lib/src/error/best_practices_verifier.dart

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
9797
_strictInference =
9898
(analysisOptions as AnalysisOptionsImpl).strictInference,
9999
_inheritanceManager = inheritanceManager,
100-
_invalidAccessVerifier =
101-
_InvalidAccessVerifier(_errorReporter, _currentLibrary),
100+
_invalidAccessVerifier = _InvalidAccessVerifier(
101+
_errorReporter, _currentLibrary, workspacePackage),
102102
_workspacePackage = workspacePackage {
103103
_inDeprecatedMember = _currentLibrary.hasDeprecated;
104104

@@ -1745,34 +1745,35 @@ class _InvalidAccessVerifier {
17451745

17461746
final ErrorReporter _errorReporter;
17471747
final LibraryElement _library;
1748+
final WorkspacePackage _workspacePackage;
17481749

17491750
bool _inTemplateSource;
17501751
bool _inTestDirectory;
17511752

17521753
ClassElement _enclosingClass;
17531754

1754-
_InvalidAccessVerifier(this._errorReporter, this._library) {
1755+
_InvalidAccessVerifier(
1756+
this._errorReporter, this._library, this._workspacePackage) {
17551757
var path = _library.source.fullName;
17561758
_inTemplateSource = path.contains(_templateExtension);
17571759
_inTestDirectory = path.contains(_testDir) ||
17581760
path.contains(_testDriverDir) ||
17591761
path.contains(_testingDir);
17601762
}
17611763

1762-
/// Produces a hint if [identifier] is accessed from an invalid location. In
1763-
/// particular:
1764+
/// Produces a hint if [identifier] is accessed from an invalid location.
1765+
///
1766+
/// In particular, a hint is produced in either of the two following cases:
17641767
///
1765-
/// * if the given identifier is a protected closure, field or
1766-
/// getter/setter, method closure or invocation accessed outside a subclass,
1767-
/// or accessed outside the library wherein the identifier is declared, or
1768-
/// * if the given identifier is a closure, field, getter, setter, method
1769-
/// closure or invocation which is annotated with `visibleForTemplate`, and
1770-
/// is accessed outside of the defining library, and the current library
1771-
/// does not have the suffix '.template' in its source path, or
1772-
/// * if the given identifier is a closure, field, getter, setter, method
1773-
/// closure or invocation which is annotated with `visibleForTesting`, and
1774-
/// is accessed outside of the defining library, and the current library
1775-
/// does not have a directory named 'test' or 'testing' in its path.
1768+
/// * The element associated with [identifier] is annotated with [internal],
1769+
/// and is accessed from outside the package in which the element is
1770+
/// declared.
1771+
/// * The element associated with [identifier] is annotated with [protected],
1772+
/// [visibleForTesting], and/or [visibleForTemplate], and is accessed from a
1773+
/// location which is invalid as per the rules of each such annotation.
1774+
/// Conversely, if the element is annotated with more than one of these
1775+
/// annotations, the access is valid (and no hint will be produced) if it
1776+
/// conforms to the rules of at least one of the annotations.
17761777
void verify(SimpleIdentifier identifier) {
17771778
if (identifier.inDeclarationContext() || _inCommentReference(identifier)) {
17781779
return;
@@ -1786,24 +1787,42 @@ class _InvalidAccessVerifier {
17861787
}
17871788
AstNode grandparent = parent?.parent;
17881789

1789-
Element element;
1790-
String name;
1791-
AstNode node;
1792-
1793-
if (grandparent is ConstructorName) {
1794-
element = grandparent.staticElement;
1795-
name = grandparent.toSource();
1796-
node = grandparent;
1797-
} else {
1798-
element = identifier.staticElement;
1799-
name = identifier.name;
1800-
node = identifier;
1801-
}
1790+
var element = grandparent is ConstructorName
1791+
? grandparent.staticElement
1792+
: identifier.staticElement;
18021793

18031794
if (element == null || _inCurrentLibrary(element)) {
18041795
return;
18051796
}
18061797

1798+
_checkForInvalidInternalAccess(identifier, element);
1799+
_checkForOtherInvalidAccess(identifier, element);
1800+
}
1801+
1802+
void _checkForInvalidInternalAccess(
1803+
SimpleIdentifier identifier, Element element) {
1804+
if (_hasInternal(element) &&
1805+
!_isLibraryInWorkspacePackage(element.library)) {
1806+
String name;
1807+
AstNode node;
1808+
1809+
var grandparent = identifier.parent?.parent;
1810+
1811+
if (grandparent is ConstructorName) {
1812+
name = grandparent.toSource();
1813+
node = grandparent;
1814+
} else {
1815+
name = identifier.name;
1816+
node = identifier;
1817+
}
1818+
1819+
_errorReporter.reportErrorForNode(
1820+
HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [name]);
1821+
}
1822+
}
1823+
1824+
void _checkForOtherInvalidAccess(
1825+
SimpleIdentifier identifier, Element element) {
18071826
bool hasProtected = _hasProtected(element);
18081827
if (hasProtected) {
18091828
ClassElement definingClass = element.enclosingElement;
@@ -1827,8 +1846,22 @@ class _InvalidAccessVerifier {
18271846
}
18281847

18291848
// At this point, [identifier] was not cleared as protected access, nor
1830-
// cleared as access for templates or testing. Report the appropriate
1831-
// violation(s).
1849+
// cleared as access for templates or testing. Report a violation for each
1850+
// annotation present.
1851+
1852+
String name;
1853+
AstNode node;
1854+
1855+
var grandparent = identifier.parent?.parent;
1856+
1857+
if (grandparent is ConstructorName) {
1858+
name = grandparent.toSource();
1859+
node = grandparent;
1860+
} else {
1861+
name = identifier.name;
1862+
node = identifier;
1863+
}
1864+
18321865
Element definingClass = element.enclosingElement;
18331866
if (hasProtected) {
18341867
_errorReporter.reportErrorForNode(
@@ -1851,6 +1884,19 @@ class _InvalidAccessVerifier {
18511884
}
18521885
}
18531886

1887+
bool _hasInternal(Element element) {
1888+
if (element == null) {
1889+
return false;
1890+
}
1891+
if (element.hasInternal) {
1892+
return true;
1893+
}
1894+
if (element is PropertyAccessorElement && element.variable.hasInternal) {
1895+
return true;
1896+
}
1897+
return false;
1898+
}
1899+
18541900
bool _hasProtected(Element element) {
18551901
if (element is PropertyAccessorElement &&
18561902
element.enclosingElement is ClassElement &&
@@ -1912,6 +1958,15 @@ class _InvalidAccessVerifier {
19121958
bool _inExportDirective(SimpleIdentifier identifier) =>
19131959
identifier.parent is Combinator &&
19141960
identifier.parent.parent is ExportDirective;
1961+
1962+
bool _isLibraryInWorkspacePackage(LibraryElement library) {
1963+
if (_workspacePackage == null || library == null) {
1964+
// Better to not make a big claim that they _are_ in the same package,
1965+
// if we were unable to determine what package [_currentLibrary] is in.
1966+
return false;
1967+
}
1968+
return _workspacePackage.contains(library.source);
1969+
}
19151970
}
19161971

19171972
/// A visitor that determines, upon visiting a function body and/or a

0 commit comments

Comments
 (0)