Extract more RuleContext error-related methods into RuleErrorConsumer

This will make it easier to pass only error-handling functionality into support classes.

RELNOTES: None.
PiperOrigin-RevId: 172148072
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index f94ac86..e948dd3 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -311,18 +311,12 @@
     return attributes;
   }
 
-  /**
-   * Returns whether this instance is known to have errors at this point during analysis. Do not
-   * call this method after the initializationHook has returned.
-   */
+  @Override
   public boolean hasErrors() {
     return getAnalysisEnvironment().hasErrors();
   }
 
-  /**
-   * No-op if {@link #hasErrors} is false, throws {@link RuleErrorException} if it is true.
-   * This provides a convenience to early-exit of configured target creation if there are errors.
-   */
+  @Override
   public void assertNoErrors() throws RuleErrorException {
     if (hasErrors()) {
       throw new RuleErrorException();
@@ -452,13 +446,8 @@
     reporter.ruleError(message);
   }
 
-  /**
-   * Convenience function to report non-attribute-specific errors in the current rule and then
-   * throw a {@link RuleErrorException}, immediately exiting the build invocation. Alternatively,
-   * invoke {@link #ruleError} instead to collect additional error information before ending the
-   * invocation.
-   */
-  public void throwWithRuleError(String message) throws RuleErrorException {
+  @Override
+  public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
     reporter.ruleError(message);
     throw new RuleErrorException();
   }
@@ -484,15 +473,7 @@
     reporter.attributeError(attrName, message);
   }
 
-  /**
-   * Convenience function to report attribute-specific errors in the current rule, and then throw a
-   * {@link RuleErrorException}, immediately exiting the build invocation. Alternatively, invoke
-   * {@link #attributeError} instead to collect additional error information before ending the
-   * invocation.
-   *
-   * <p>If the name of the attribute starts with <code>$</code>
-   * it is replaced with a string <code>(an implicit dependency)</code>.
-   */
+  @Override
   public RuleErrorException throwWithAttributeError(String attrName, String message)
       throws RuleErrorException {
     reporter.attributeError(attrName, message);
@@ -1598,6 +1579,27 @@
       reporter.attributeWarning(attrName, message);
     }
 
+    @Override
+    public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
+      throw reporter.throwWithRuleError(message);
+    }
+
+    @Override
+    public RuleErrorException throwWithAttributeError(String attrName, String message)
+        throws RuleErrorException {
+      throw reporter.throwWithAttributeError(attrName, message);
+    }
+
+    @Override
+    public boolean hasErrors() {
+      return reporter.hasErrors();
+    }
+
+    @Override
+    public void assertNoErrors() throws RuleErrorException {
+      reporter.assertNoErrors();
+    }
+
     private String badPrerequisiteMessage(String targetKind, ConfiguredTarget prerequisite,
         String reason, boolean isWarning) {
       String msgPrefix = targetKind != null ? targetKind + " " : "";
@@ -1879,6 +1881,31 @@
       reportError(rule.getAttributeLocation(attrName), completeAttributeMessage(attrName, message));
     }
 
+    @Override
+    public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
+      ruleError(message);
+      throw new RuleErrorException();
+    }
+
+    @Override
+    public RuleErrorException throwWithAttributeError(String attrName, String message)
+        throws RuleErrorException {
+      attributeError(attrName, message);
+      throw new RuleErrorException();
+    }
+
+    @Override
+    public boolean hasErrors() {
+      return env.hasErrors();
+    }
+
+    @Override
+    public void assertNoErrors() throws RuleErrorException {
+      if (hasErrors()) {
+        throw new RuleErrorException();
+      }
+    }
+
     public void reportWarning(Location location, String message) {
       env.getEventHandler().handle(Event.warn(location, message));
     }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleErrorConsumer.java b/src/main/java/com/google/devtools/build/lib/packages/RuleErrorConsumer.java
index c5b8a79..9e1683e 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleErrorConsumer.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleErrorConsumer.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.packages;
 
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+
 /**
  * A thin interface exposing only the warning and error reporting functionality
  * of a rule.
@@ -24,6 +26,7 @@
  * <p>This interface should only be implemented by {@code RuleContext}.
  */
 public interface RuleErrorConsumer {
+
   /**
    * Consume a non-attribute-specific warning in a rule.
    */
@@ -43,4 +46,36 @@
    * Consume an attribute-specific error in a rule.
    */
   void attributeError(String attrName, String message);
+
+  /**
+   * Convenience function to report non-attribute-specific errors in the current rule and then
+   * throw a {@link RuleErrorException}, immediately exiting the build invocation. Alternatively,
+   * invoke {@link #ruleError} instead to collect additional error information before ending the
+   * invocation.
+   */
+  RuleErrorException throwWithRuleError(String message) throws RuleErrorException;
+
+  /**
+   * Convenience function to report attribute-specific errors in the current rule, and then throw a
+   * {@link RuleErrorException}, immediately exiting the build invocation. Alternatively, invoke
+   * {@link #attributeError} instead to collect additional error information before ending the
+   * invocation.
+   *
+   * <p>If the name of the attribute starts with <code>$</code>
+   * it is replaced with a string <code>(an implicit dependency)</code>.
+   */
+  RuleErrorException throwWithAttributeError(String attrName, String message)
+      throws RuleErrorException;
+
+  /**
+   * Returns whether this instance is known to have errors at this point during analysis. Do not
+   * call this method after the initializationHook has returned.
+   */
+  boolean hasErrors();
+
+  /**
+   * No-op if {@link #hasErrors} is false, throws {@link RuleErrorException} if it is true.
+   * This provides a convenience to early-exit of configured target creation if there are errors.
+   */
+  void assertNoErrors() throws RuleErrorException;
 }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/LocationExpanderTest.java b/src/test/java/com/google/devtools/build/lib/analysis/LocationExpanderTest.java
index ae23f50..a60cd7c 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/LocationExpanderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/LocationExpanderTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
 import java.util.ArrayList;
 import java.util.List;
@@ -48,6 +49,31 @@
     public void attributeError(String attrName, String message) {
       warnsOrErrors.add("ERROR-" + attrName + ": " + message);
     }
+
+    @Override
+    public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
+      ruleError(message);
+      throw new RuleErrorException();
+    }
+
+    @Override
+    public RuleErrorException throwWithAttributeError(String attrName, String message)
+        throws RuleErrorException {
+      attributeError(attrName, message);
+      throw new RuleErrorException();
+    }
+
+    @Override
+    public boolean hasErrors() {
+      return !warnsOrErrors.isEmpty();
+    }
+
+    @Override
+    public void assertNoErrors() throws RuleErrorException {
+      if (hasErrors()) {
+        throw new RuleErrorException();
+      }
+    }
   }
 
   private LocationExpander makeExpander(RuleErrorConsumer ruleErrorConsumer) throws Exception {
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java
index 27ca351..cd1992d 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.lib.actions.Root;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
@@ -80,6 +81,31 @@
       attributeErrorMessage = message;
     }
 
+    @Override
+    public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
+      ruleError(message);
+      throw new RuleErrorException();
+    }
+
+    @Override
+    public RuleErrorException throwWithAttributeError(String attrName, String message)
+        throws RuleErrorException {
+      attributeError(attrName, message);
+      throw new RuleErrorException();
+    }
+
+    @Override
+    public boolean hasErrors() {
+      return ruleErrorMessage != null || attributeErrorMessage != null;
+    }
+
+    @Override
+    public void assertNoErrors() throws RuleErrorException {
+      if (hasErrors()) {
+        throw new RuleErrorException();
+      }
+    }
+
     public Collection<String> getAndClearRuleWarnings() {
       Collection<String> warnings = ImmutableList.copyOf(ruleWarnings);
       ruleWarnings.clear();