Fix missing print statements in output functions

PiperOrigin-RevId: 177708823
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 3223ae8..eef1771 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
@@ -1211,7 +1211,9 @@
       throws InterruptedException {
     Iterable<String> result;
     try {
-      result = function.getImplicitOutputs(RawAttributeMapper.of(rule));
+      result =
+          function.getImplicitOutputs(
+              getAnalysisEnvironment().getEventHandler(), RawAttributeMapper.of(rule));
     } catch (EvalException e) {
       // It's ok as long as we don't use this method from Skylark.
       throw new IllegalStateException(e);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkAttr.java
index 7ba8bf6..1dea86c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkAttr.java
@@ -189,7 +189,8 @@
       if (defaultValue instanceof UserDefinedFunction) {
         // Computed attribute. Non label type attributes already caused a type check error.
         SkylarkCallbackFunction callback =
-            new SkylarkCallbackFunction((UserDefinedFunction) defaultValue, ast, env);
+            new SkylarkCallbackFunction(
+                (UserDefinedFunction) defaultValue, ast, env.getSemantics());
         // SkylarkComputedDefaultTemplate needs to know the names of all attributes that it depends
         // on. However, this method does not know anything about other attributes.
         // We solve this problem by asking the SkylarkCallbackFunction for the parameter names used
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
index a697721..baee697 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
@@ -522,7 +522,8 @@
           if (implicitOutputs != Runtime.NONE) {
             if (implicitOutputs instanceof BaseFunction) {
               BaseFunction func = (BaseFunction) implicitOutputs;
-              SkylarkCallbackFunction callback = new SkylarkCallbackFunction(func, ast, funcallEnv);
+              SkylarkCallbackFunction callback =
+                  new SkylarkCallbackFunction(func, ast, funcallEnv.getSemantics());
               builder.setImplicitOutputsFunction(
                   new SkylarkImplicitOutputsFunctionWithCallback(callback, ast.getLocation()));
             } else {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java
index 7ed1211..a979f2b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleContext.java
@@ -232,7 +232,10 @@
         SkylarkImplicitOutputsFunction func =
             (SkylarkImplicitOutputsFunction) implicitOutputsFunction;
         for (Map.Entry<String, String> entry :
-            func.calculateOutputs(RawAttributeMapper.of(ruleContext.getRule())).entrySet()) {
+            func.calculateOutputs(
+                    ruleContext.getAnalysisEnvironment().getEventHandler(),
+                    RawAttributeMapper.of(ruleContext.getRule()))
+                .entrySet()) {
           outputs.addOutput(
               entry.getKey(),
               ruleContext.getImplicitOutputArtifact(entry.getValue()));
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index 03f56dc..6d96a92 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -1410,7 +1410,7 @@
             @Override
             public Object compute(AttributeMap map) throws InterruptedException {
               try {
-                return owner.computeValue(map);
+                return owner.computeValue(eventHandler, map);
               } catch (EvalException ex) {
                 caughtEvalExceptionIfAny.compareAndSet(null, ex);
                 return null;
@@ -1445,7 +1445,8 @@
       return new SkylarkComputedDefault(dependencies, dependencyTypesBuilder.build(), lookupTable);
     }
 
-    private Object computeValue(AttributeMap rule) throws EvalException, InterruptedException {
+    private Object computeValue(EventHandler eventHandler, AttributeMap rule)
+        throws EvalException, InterruptedException {
       Map<String, Object> attrValues = new HashMap<>();
       for (String attrName : rule.getAttributeNames()) {
         Attribute attr = rule.getAttributeDefinition(attrName);
@@ -1456,15 +1457,15 @@
           }
         }
       }
-      return invokeCallback(attrValues);
+      return invokeCallback(eventHandler, attrValues);
     }
 
-    private Object invokeCallback(Map<String, Object> attrValues)
+    private Object invokeCallback(EventHandler eventHandler, Map<String, Object> attrValues)
         throws EvalException, InterruptedException {
       ClassObject attrs =
           NativeProvider.STRUCT.create(
               attrValues, "No such regular (non computed) attribute '%s'.");
-      Object result = callback.call(attrs);
+      Object result = callback.call(eventHandler, attrs);
       try {
         return type.cast((result == Runtime.NONE) ? type.getDefaultValue() : result);
       } catch (ClassCastException ex) {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java b/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java
index e8e9102..5fa3a0c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/ImplicitOutputsFunction.java
@@ -27,6 +27,7 @@
 import com.google.common.escape.Escaper;
 import com.google.common.escape.Escapers;
 import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.syntax.ClassObject;
 import com.google.devtools.build.lib.syntax.EvalException;
@@ -64,13 +65,13 @@
    */
   public abstract static class SkylarkImplicitOutputsFunction extends ImplicitOutputsFunction {
 
-    public abstract ImmutableMap<String, String> calculateOutputs(AttributeMap map)
-        throws EvalException, InterruptedException;
+    public abstract ImmutableMap<String, String> calculateOutputs(
+        EventHandler eventHandler, AttributeMap map) throws EvalException, InterruptedException;
 
     @Override
-    public Iterable<String> getImplicitOutputs(AttributeMap map)
+    public Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap map)
         throws EvalException, InterruptedException {
-      return calculateOutputs(map).values();
+      return calculateOutputs(eventHandler, map).values();
     }
   }
 
@@ -90,8 +91,8 @@
     }
 
     @Override
-    public ImmutableMap<String, String> calculateOutputs(AttributeMap map)
-        throws EvalException, InterruptedException {
+    public ImmutableMap<String, String> calculateOutputs(
+        EventHandler eventHandler, AttributeMap map) throws EvalException, InterruptedException {
       Map<String, Object> attrValues = new HashMap<>();
       for (String attrName : map.getAttributeNames()) {
         Type<?> attrType = map.getAttributeType(attrName);
@@ -109,11 +110,17 @@
                   + "or uses a select() (i.e. could have multiple values)");
       try {
         ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
-        for (Map.Entry<String, String> entry : castMap(callback.call(attrs),
-            String.class, String.class, "implicit outputs function return value").entrySet()) {
+        for (Map.Entry<String, String> entry :
+            castMap(
+                    callback.call(eventHandler, attrs),
+                    String.class,
+                    String.class,
+                    "implicit outputs function return value")
+                .entrySet()) {
 
           // Returns empty string only in case of invalid templates
-          Iterable<String> substitutions = fromTemplates(entry.getValue()).getImplicitOutputs(map);
+          Iterable<String> substitutions =
+              fromTemplates(entry.getValue()).getImplicitOutputs(eventHandler, map);
           if (Iterables.isEmpty(substitutions)) {
             throw new EvalException(
                 loc,
@@ -144,15 +151,15 @@
     }
 
     @Override
-    public ImmutableMap<String, String> calculateOutputs(AttributeMap map)
-        throws EvalException, InterruptedException {
+    public ImmutableMap<String, String> calculateOutputs(
+        EventHandler eventHandler, AttributeMap map) throws EvalException, InterruptedException {
 
       ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
       for (Map.Entry<String, String> entry : outputMap.entrySet()) {
         // Empty iff invalid placeholders present.
         ImplicitOutputsFunction outputsFunction =
             fromUnsafeTemplates(ImmutableList.of(entry.getValue()));
-        Iterable<String> substitutions = outputsFunction.getImplicitOutputs(map);
+        Iterable<String> substitutions = outputsFunction.getImplicitOutputs(eventHandler, map);
         if (Iterables.isEmpty(substitutions)) {
           throw new EvalException(
               null,
@@ -173,7 +180,8 @@
    */
   public abstract static class SafeImplicitOutputsFunction extends ImplicitOutputsFunction {
     @Override
-    public abstract Iterable<String> getImplicitOutputs(AttributeMap map);
+    public abstract Iterable<String> getImplicitOutputs(
+        EventHandler eventHandler, AttributeMap map);
   }
 
   /**
@@ -203,20 +211,20 @@
   private static final Escaper PERCENT_ESCAPER = Escapers.builder().addEscape('%', "%%").build();
 
   /**
-   * Given a newly-constructed Rule instance (with attributes populated),
-   * returns the list of output files that this rule produces implicitly.
+   * Given a newly-constructed Rule instance (with attributes populated), returns the list of output
+   * files that this rule produces implicitly.
    */
-  public abstract Iterable<String> getImplicitOutputs(AttributeMap rule)
+  public abstract Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap rule)
       throws EvalException, InterruptedException;
 
-  /**
-   * The implicit output function that returns no files.
-   */
-  public static final SafeImplicitOutputsFunction NONE = new SafeImplicitOutputsFunction() {
-      @Override public Iterable<String> getImplicitOutputs(AttributeMap rule) {
-        return Collections.emptyList();
-      }
-    };
+  /** The implicit output function that returns no files. */
+  public static final SafeImplicitOutputsFunction NONE =
+      new SafeImplicitOutputsFunction() {
+        @Override
+        public Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap rule) {
+          return Collections.emptyList();
+        }
+      };
 
   /**
    * A convenience wrapper for {@link #fromTemplates(Iterable)}.
@@ -240,7 +248,7 @@
     return new SafeImplicitOutputsFunction() {
       // TODO(bazel-team): parse the templates already here
       @Override
-      public Iterable<String> getImplicitOutputs(AttributeMap rule) {
+      public Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap rule) {
         ImmutableSet.Builder<String> result = new ImmutableSet.Builder<>();
         for (String template : templates) {
           List<String> substitutions = substitutePlaceholderIntoTemplate(template, rule);
@@ -277,7 +285,8 @@
     return new ImplicitOutputsFunction() {
       // TODO(bazel-team): parse the templates already here
       @Override
-      public Iterable<String> getImplicitOutputs(AttributeMap rule) throws EvalException {
+      public Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap rule)
+          throws EvalException {
         ImmutableSet.Builder<String> result = new ImmutableSet.Builder<>();
         for (String template : templates) {
           List<String> substitutions =
@@ -319,13 +328,14 @@
       final Iterable<SafeImplicitOutputsFunction> functions) {
     return new SafeImplicitOutputsFunction() {
       @Override
-      public Iterable<String> getImplicitOutputs(AttributeMap rule) {
+      public Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap rule) {
         Collection<String> result = new LinkedHashSet<>();
         for (SafeImplicitOutputsFunction function : functions) {
-          Iterables.addAll(result, function.getImplicitOutputs(rule));
+          Iterables.addAll(result, function.getImplicitOutputs(eventHandler, rule));
         }
         return result;
       }
+
       @Override
       public String toString() {
         return StringUtil.joinEnglishList(functions);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Rule.java b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
index 2dcc89b..6615fe6 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Rule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
@@ -549,7 +549,7 @@
       throws InterruptedException {
     try {
       RawAttributeMapper attributeMap = RawAttributeMapper.of(this);
-      for (String out : implicitOutputsFunction.getImplicitOutputs(attributeMap)) {
+      for (String out : implicitOutputsFunction.getImplicitOutputs(eventHandler, attributeMap)) {
         Label label;
         if (performChecks) {
           try {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index bc28f84..5dcef25 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -38,6 +38,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
 import com.google.devtools.build.lib.packages.Attribute.LateBoundDefault;
@@ -339,7 +340,7 @@
       new SafeImplicitOutputsFunction() {
 
         @Override
-        public Iterable<String> getImplicitOutputs(AttributeMap rule) {
+        public Iterable<String> getImplicitOutputs(EventHandler eventHandler, AttributeMap rule) {
           List<SafeImplicitOutputsFunction> functions = Lists.newArrayList();
           functions.add(AndroidRuleClasses.ANDROID_BINARY_APK);
           functions.add(AndroidRuleClasses.ANDROID_BINARY_UNSIGNED_APK);
@@ -352,14 +353,15 @@
               functions.add(JavaSemantics.JAVA_BINARY_PROGUARD_MAP);
             }
           }
-          return fromFunctions(functions).getImplicitOutputs(rule);
+          return fromFunctions(functions).getImplicitOutputs(eventHandler, rule);
         }
       };
 
   public static final SafeImplicitOutputsFunction ANDROID_LIBRARY_IMPLICIT_OUTPUTS =
       new SafeImplicitOutputsFunction() {
         @Override
-        public Iterable<String> getImplicitOutputs(AttributeMap attributes) {
+        public Iterable<String> getImplicitOutputs(
+            EventHandler eventHandler, AttributeMap attributes) {
 
           ImmutableList.Builder<SafeImplicitOutputsFunction> implicitOutputs =
               ImmutableList.builder();
@@ -376,7 +378,8 @@
                 AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR);
           }
 
-          return fromFunctions(implicitOutputs.build()).getImplicitOutputs(attributes);
+          return fromFunctions(implicitOutputs.build())
+              .getImplicitOutputs(eventHandler, attributes);
         }
       };
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
index ed79584..719c94b 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkCallbackFunction.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableList.Builder;
+import com.google.devtools.build.lib.events.EventHandler;
 
 /**
  * A helper class for calling Skylark functions from Java.
@@ -23,26 +24,27 @@
 
   private final BaseFunction callback;
   private final FuncallExpression ast;
-  private final Environment funcallEnv;
+  private final SkylarkSemantics skylarkSemantics;
 
   public SkylarkCallbackFunction(
-      BaseFunction callback, FuncallExpression ast, Environment funcallEnv) {
+      BaseFunction callback, FuncallExpression ast, SkylarkSemantics skylarkSemantics) {
     this.callback = callback;
     this.ast = ast;
-    this.funcallEnv = funcallEnv;
+    this.skylarkSemantics = skylarkSemantics;
   }
 
   public ImmutableList<String> getParameterNames() {
     return callback.signature.getSignature().getNames();
   }
 
-  public Object call(ClassObject ctx, Object... arguments)
+  public Object call(EventHandler eventHandler, ClassObject ctx, Object... arguments)
       throws EvalException, InterruptedException {
     try (Mutability mutability = Mutability.create("callback %s", callback)) {
-      Environment env = Environment.builder(mutability)
-          .setSemantics(funcallEnv.getSemantics())
-          .setEventHandler(funcallEnv.getEventHandler())
-          .build();
+      Environment env =
+          Environment.builder(mutability)
+              .setSemantics(skylarkSemantics)
+              .setEventHandler(eventHandler)
+              .build();
       return callback.call(buildArgumentList(ctx, arguments), null, ast, env);
     } catch (ClassCastException | IllegalArgumentException e) {
       throw new EvalException(ast.getLocation(), e.getMessage());
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
index 571fe23..efdd13d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java
@@ -1917,7 +1917,7 @@
 
     RawAttributeMapper attr = RawAttributeMapper.of(associatedRule);
 
-    String path = Iterables.getOnlyElement(outputFunction.getImplicitOutputs(attr));
+    String path = Iterables.getOnlyElement(outputFunction.getImplicitOutputs(eventCollector, attr));
 
     return view.getArtifactFactory()
         .getDerivedArtifact(
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
index 8b2770a..8039563 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
@@ -915,6 +915,35 @@
   }
 
   @Test
+  public void testRuleClassImplicitOutputFunctionPrints() throws Exception {
+    scratch.file(
+        "test/skylark/extension.bzl",
+        "def custom_rule_impl(ctx):",
+        "  print('implementation', ctx.label)",
+        "  files = [ctx.outputs.o]",
+        "  ctx.actions.run_shell(",
+        "    outputs = files,",
+        "    command = 'echo')",
+        "",
+        "def output_func(name):",
+        "  print('output function', name)",
+        "  return {'o': name + '.txt'}",
+        "",
+        "custom_rule = rule(implementation = custom_rule_impl,",
+        "  outputs = output_func)");
+
+    scratch.file(
+        "test/skylark/BUILD",
+        "load('/test/skylark/extension', 'custom_rule')",
+        "",
+        "custom_rule(name = 'cr')");
+
+    getConfiguredTarget("//test/skylark:cr");
+    assertContainsEvent("output function cr");
+    assertContainsEvent("implementation //test/skylark:cr");
+  }
+
+  @Test
   public void testRuleClassNonMandatoryEmptyOutputs() throws Exception {
     scratch.file(
         "test/skylark/extension.bzl",
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
index 0371315..d947562 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -701,7 +701,7 @@
         "r1 = rule(impl, outputs = {'a': 'a.txt'})");
     RuleClass c = ((SkylarkRuleFunction) lookup("r1")).getRuleClass();
     ImplicitOutputsFunction function = c.getDefaultImplicitOutputsFunction();
-    assertThat(function.getImplicitOutputs(null)).containsExactly("a.txt");
+    assertThat(function.getImplicitOutputs(ev.getEventHandler(), null)).containsExactly("a.txt");
   }
 
   @Test