@@ -97,8 +97,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<void> {
97
97
_strictInference =
98
98
(analysisOptions as AnalysisOptionsImpl ).strictInference,
99
99
_inheritanceManager = inheritanceManager,
100
- _invalidAccessVerifier =
101
- _InvalidAccessVerifier ( _errorReporter, _currentLibrary),
100
+ _invalidAccessVerifier = _InvalidAccessVerifier (
101
+ _errorReporter, _currentLibrary, workspacePackage ),
102
102
_workspacePackage = workspacePackage {
103
103
_inDeprecatedMember = _currentLibrary.hasDeprecated;
104
104
@@ -1745,34 +1745,35 @@ class _InvalidAccessVerifier {
1745
1745
1746
1746
final ErrorReporter _errorReporter;
1747
1747
final LibraryElement _library;
1748
+ final WorkspacePackage _workspacePackage;
1748
1749
1749
1750
bool _inTemplateSource;
1750
1751
bool _inTestDirectory;
1751
1752
1752
1753
ClassElement _enclosingClass;
1753
1754
1754
- _InvalidAccessVerifier (this ._errorReporter, this ._library) {
1755
+ _InvalidAccessVerifier (
1756
+ this ._errorReporter, this ._library, this ._workspacePackage) {
1755
1757
var path = _library.source.fullName;
1756
1758
_inTemplateSource = path.contains (_templateExtension);
1757
1759
_inTestDirectory = path.contains (_testDir) ||
1758
1760
path.contains (_testDriverDir) ||
1759
1761
path.contains (_testingDir);
1760
1762
}
1761
1763
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:
1764
1767
///
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.
1776
1777
void verify (SimpleIdentifier identifier) {
1777
1778
if (identifier.inDeclarationContext () || _inCommentReference (identifier)) {
1778
1779
return ;
@@ -1786,24 +1787,42 @@ class _InvalidAccessVerifier {
1786
1787
}
1787
1788
AstNode grandparent = parent? .parent;
1788
1789
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;
1802
1793
1803
1794
if (element == null || _inCurrentLibrary (element)) {
1804
1795
return ;
1805
1796
}
1806
1797
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) {
1807
1826
bool hasProtected = _hasProtected (element);
1808
1827
if (hasProtected) {
1809
1828
ClassElement definingClass = element.enclosingElement;
@@ -1827,8 +1846,22 @@ class _InvalidAccessVerifier {
1827
1846
}
1828
1847
1829
1848
// 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
+
1832
1865
Element definingClass = element.enclosingElement;
1833
1866
if (hasProtected) {
1834
1867
_errorReporter.reportErrorForNode (
@@ -1851,6 +1884,19 @@ class _InvalidAccessVerifier {
1851
1884
}
1852
1885
}
1853
1886
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
+
1854
1900
bool _hasProtected (Element element) {
1855
1901
if (element is PropertyAccessorElement &&
1856
1902
element.enclosingElement is ClassElement &&
@@ -1912,6 +1958,15 @@ class _InvalidAccessVerifier {
1912
1958
bool _inExportDirective (SimpleIdentifier identifier) =>
1913
1959
identifier.parent is Combinator &&
1914
1960
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
+ }
1915
1970
}
1916
1971
1917
1972
/// A visitor that determines, upon visiting a function body and/or a
0 commit comments