@@ -233,6 +233,8 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
233
233
234
234
static String _TO_INT_METHOD_NAME = "toInt" ;
235
235
236
+ static final _templateExtension = '.template' ;
237
+
236
238
static final _testDir = '${path .separator }test${path .separator }' ;
237
239
238
240
static final _testingDir = '${path .separator }testing${path .separator }' ;
@@ -849,9 +851,13 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
849
851
/// getter/setter, method closure or invocation accessed outside a subclass,
850
852
/// or accessed outside the library wherein the identifier is declared, or
851
853
/// * if the given identifier is a closure, field, getter, setter, method
854
+ /// closure or invocation which is annotated with `visibleForTemplate` , and
855
+ /// is accessed outside of the defining library, and the current library
856
+ /// does not have the suffix '.template' in its source path, or
857
+ /// * if the given identifier is a closure, field, getter, setter, method
852
858
/// closure or invocation which is annotated with `visibleForTesting` , and
853
859
/// is accessed outside of the defining library, and the current library
854
- /// does not have the word 'test' in its name .
860
+ /// does not have a directory named 'test' or 'testing' in its path .
855
861
void _checkForInvalidAccess (SimpleIdentifier identifier) {
856
862
if (identifier.inDeclarationContext ()) {
857
863
return ;
@@ -871,6 +877,21 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
871
877
return false ;
872
878
}
873
879
880
+ bool isVisibleForTemplate (Element element) {
881
+ if (element == null ) {
882
+ return false ;
883
+ }
884
+ if (element.hasVisibleForTemplate) {
885
+ return true ;
886
+ }
887
+ if (element is PropertyAccessorElement &&
888
+ element.enclosingElement is ClassElement &&
889
+ element.variable.hasVisibleForTemplate) {
890
+ return true ;
891
+ }
892
+ return false ;
893
+ }
894
+
874
895
bool isVisibleForTesting (Element element) {
875
896
if (element == null ) {
876
897
return false ;
@@ -897,12 +918,19 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
897
918
identifier.parent is Combinator &&
898
919
identifier.parent.parent is ExportDirective ;
899
920
921
+ bool inTemplateSource (LibraryElement library) =>
922
+ library.definingCompilationUnit.source.fullName
923
+ .contains (_templateExtension);
924
+
900
925
bool inTestDirectory (LibraryElement library) =>
901
926
library.definingCompilationUnit.source.fullName.contains (_testDir) ||
902
927
library.definingCompilationUnit.source.fullName.contains (_testingDir);
903
928
904
929
Element element = identifier.staticElement;
905
- if (! isProtected (element) && ! isVisibleForTesting (element)) {
930
+ if (! isProtected (element) &&
931
+ ! isVisibleForTemplate (element) &&
932
+ ! isVisibleForTesting (element)) {
933
+ // Without any of these annotations, the access is valid.
906
934
return ;
907
935
}
908
936
@@ -920,26 +948,43 @@ class BestPracticesVerifier extends RecursiveAstVisitor<Object> {
920
948
return ;
921
949
}
922
950
}
951
+ if (isVisibleForTemplate (element)) {
952
+ if (inCurrentLibrary (element) ||
953
+ inTemplateSource (_currentLibrary) ||
954
+ inExportDirective (identifier) ||
955
+ inCommentReference (identifier)) {
956
+ // The access is valid; even if [element] is also marked `protected`,
957
+ // the "visibilities" are unioned.
958
+ return ;
959
+ }
960
+ }
923
961
if (isVisibleForTesting (element)) {
924
962
if (inCurrentLibrary (element) ||
925
963
inTestDirectory (_currentLibrary) ||
926
964
inExportDirective (identifier) ||
927
965
inCommentReference (identifier)) {
928
- // The access is valid; even if [element] is also marked
929
- // `protected`, the "visibilities" are unioned.
966
+ // The access is valid; even if [element] is also marked `protected`,
967
+ // the "visibilities" are unioned.
930
968
return ;
931
969
}
932
970
}
933
971
934
972
// At this point, [identifier] was not cleared as protected access, nor
935
- // cleared as access for testing. Report the appropriate violation(s).
973
+ // cleared as access for templates or testing. Report the appropriate
974
+ // violation(s).
936
975
Element definingClass = element.enclosingElement;
937
976
if (isProtected (element)) {
938
977
_errorReporter.reportErrorForNode (
939
978
HintCode .INVALID_USE_OF_PROTECTED_MEMBER ,
940
979
identifier,
941
980
[identifier.name.toString (), definingClass.name]);
942
981
}
982
+ if (isVisibleForTemplate (element)) {
983
+ _errorReporter.reportErrorForNode (
984
+ HintCode .INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER ,
985
+ identifier,
986
+ [identifier.name.toString (), definingClass.name]);
987
+ }
943
988
if (isVisibleForTesting (element)) {
944
989
_errorReporter.reportErrorForNode (
945
990
HintCode .INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER ,
0 commit comments