Change skylint to accept UpperCamelCaseWithSuffixInfo identifiers

Closes #5914

Closes #5969.

PiperOrigin-RevId: 211674953
diff --git a/site/docs/skylark/skylint.md b/site/docs/skylark/skylint.md
index 686ad5c..14a282b 100644
--- a/site/docs/skylark/skylint.md
+++ b/site/docs/skylark/skylint.md
@@ -188,9 +188,8 @@
     *   **Constants** that are **immutable**. The variable must not be rebound
         and also its deep contents must not be changed.
 *   Use **`UpperCamelCase`** for:
-    *   **Providers**. Currently, the analyzer only allows assignments of the
-        form `FooBarInfo = provider(...)`. In addition provider names have to
-        end in the **suffix `Info`**.
+    *   **Providers**. In addition, provider names have to end in the
+        **suffix `Info`**.
 *   **Never** use:
     *   **Builtin names** like `print`, `True`. Rebinding these is too
         confusing.
diff --git a/src/tools/skylark/java/com/google/devtools/skylark/skylint/NamingConventionsChecker.java b/src/tools/skylark/java/com/google/devtools/skylark/skylint/NamingConventionsChecker.java
index cca66fc..3531d21 100644
--- a/src/tools/skylark/java/com/google/devtools/skylark/skylint/NamingConventionsChecker.java
+++ b/src/tools/skylark/java/com/google/devtools/skylark/skylint/NamingConventionsChecker.java
@@ -85,15 +85,16 @@
     super.visit(node);
   }
 
-  private void checkSnakeCase(String name, Location location) {
-    if (!isSnakeCase(name)) {
+  private void checkIdentifier(String name, Location location) {
+    if (!isSnakeCase(name) && !(isUpperCamelCase(name) && name.endsWith("Info"))) {
       issues.add(
           Issue.create(
               NAME_WITH_WRONG_CASE_CATEGORY,
               "identifier '"
                   + name
                   + "' should be lower_snake_case (for variables)"
-                  + " or UPPER_SNAKE_CASE (for constants)",
+                  + " or UPPER_SNAKE_CASE (for constants)"
+                  + " or UpperCamelCase and end in \"Info\" (for providers; example: FizzBuzzInfo)",
               location));
     }
   }
@@ -175,7 +176,7 @@
     if (nameInfo.kind == Kind.PARAMETER || nameInfo.kind == Kind.FUNCTION) {
       checkLowerSnakeCase(nameInfo.name, node.getLocation());
     } else {
-      checkSnakeCase(nameInfo.name, node.getLocation());
+      checkIdentifier(nameInfo.name, node.getLocation());
     }
   }
 
diff --git a/src/tools/skylark/javatests/com/google/devtools/skylark/skylint/NamingConventionsCheckerTest.java b/src/tools/skylark/javatests/com/google/devtools/skylark/skylint/NamingConventionsCheckerTest.java
index 325e7ad..cec3a81 100644
--- a/src/tools/skylark/javatests/com/google/devtools/skylark/skylint/NamingConventionsCheckerTest.java
+++ b/src/tools/skylark/javatests/com/google/devtools/skylark/skylint/NamingConventionsCheckerTest.java
@@ -40,13 +40,22 @@
     String errorMessage =
         findIssues(
                 "badGlobalVariableName = 0",
+                "BadProviderWithoutInfoSuffix = _BadProviderWithoutInfoSuffix",
                 "def BAD_FUNCTION_NAME(BadParameterName):",
                 "  badLocalVariableName = 1")
             .toString();
     Truth.assertThat(errorMessage)
         .contains(
             "'badGlobalVariableName' should be lower_snake_case (for variables)"
-                + " or UPPER_SNAKE_CASE (for constants) [name-with-wrong-case]");
+                + " or UPPER_SNAKE_CASE (for constants)"
+                + " or UpperCamelCase and end in \"Info\" (for providers; example: FizzBuzzInfo)"
+                + " [name-with-wrong-case]");
+    Truth.assertThat(errorMessage)
+        .contains(
+            "'BadProviderWithoutInfoSuffix' should be lower_snake_case (for variables)"
+                + " or UPPER_SNAKE_CASE (for constants)"
+                + " or UpperCamelCase and end in \"Info\" (for providers; example: FizzBuzzInfo)"
+                + " [name-with-wrong-case]");
     Truth.assertThat(errorMessage)
         .contains("'BAD_FUNCTION_NAME' should be lower_snake_case [name-with-wrong-case]");
     Truth.assertThat(errorMessage)
@@ -54,7 +63,9 @@
     Truth.assertThat(errorMessage)
         .contains(
             "'badLocalVariableName' should be lower_snake_case (for variables)"
-                + " or UPPER_SNAKE_CASE (for constants) [name-with-wrong-case]");
+                + " or UPPER_SNAKE_CASE (for constants)"
+                + " or UpperCamelCase and end in \"Info\" (for providers; example: FizzBuzzInfo)"
+                + " [name-with-wrong-case]");
   }
 
   @Test
@@ -99,6 +110,7 @@
     Truth.assertThat(
             findIssues(
                 "GOOD_GLOBAL_VARIABLE_NAME = 0",
+                "GoodAliasedProviderInfo = _GoodAliasedProviderInfo",
                 "def good_function_name(good_parameter_name):",
                 "  GOOD_LOCAL_CONSTANT_NAME = 1"))
         .isEmpty();