Implement --incompatible_visibility_private_attributes_at_definition

If enabled, change visibility verification for implict attributes:
For implicit attributes of a rule, i.e., attributes fixed in the
rule definition and not setable by the user of the rule, verify
that the rule definition can see the attribute, rather than the
usage of the rule.

Change-Id: I6fb6e288885c8e0432e94de129882e71064c669b
PiperOrigin-RevId: 277683498
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/VisibilityTest.java b/src/test/java/com/google/devtools/build/lib/analysis/VisibilityTest.java
new file mode 100644
index 0000000..9bf9999
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/analysis/VisibilityTest.java
@@ -0,0 +1,168 @@
+// Copyright 2019 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.analysis;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
+
+import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Test for visibility of targets. */
+@RunWith(JUnit4.class)
+public class VisibilityTest extends AnalysisTestCase {
+
+  void setupArgsScenario() throws Exception {
+    scratch.file("tool/tool.sh", "#!/bin/sh", "echo Hello > $2", "cat $1 >> $2");
+    scratch.file("rule/BUILD");
+    scratch.file(
+        "rule/rule.bzl",
+        "def _impl(ctx):",
+        "  output = ctx.actions.declare_file(ctx.label.name + '.out')",
+        "  ctx.actions.run(",
+        "    inputs = ctx.files._tool + ctx.files.data,",
+        "    executable = ctx.files._tool[0].path,",
+        "    arguments =  [f.path for f in ctx.files.data] + [output.path],",
+        "    outputs = [output],",
+        "  )",
+        "",
+        "greet = rule(",
+        "  implementation = _impl,",
+        "  attrs = {",
+        "    'data' : attr.label(allow_files=True),",
+        "    '_tool' : attr.label(cfg='host', allow_files=True,",
+        "                         default = Label('//tool:tool.sh')),",
+        "  },",
+        "  outputs = {'out' : '%{name}.out'},",
+        ")");
+    scratch.file("data/data.txt", "World");
+    scratch.file(
+        "use/BUILD",
+        "load('//rule:rule.bzl', 'greet')",
+        "",
+        "greet(",
+        "  name = 'world',",
+        "  data = '//data:data.txt',",
+        ")");
+  }
+
+  @Test
+  public void testToolVisibilityRuleCheckAtRule() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:public'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//rule:__pkg__'])");
+    useConfiguration("--incompatible_visibility_private_attributes_at_definition");
+    update("//use:world");
+    assertThat(hasErrors(getConfiguredTarget("//use:world"))).isFalse();
+  }
+
+  @Test
+  public void testToolVisibilityRuleCheckAtUse() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:public'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//rule:__pkg__'])");
+    useConfiguration("--noincompatible_visibility_private_attributes_at_definition");
+
+    reporter.removeHandler(failFastHandler);
+    assertThrows(ViewCreationFailedException.class, () -> update("//use:world"));
+  }
+
+  @Test
+  public void testToolVisibilityUseCheckAtUse() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:public'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//use:__pkg__'])");
+    useConfiguration("--noincompatible_visibility_private_attributes_at_definition");
+    update("//use:world");
+    assertThat(hasErrors(getConfiguredTarget("//use:world"))).isFalse();
+  }
+
+  @Test
+  public void testToolVisibilityUseCheckAtRule() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:public'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//use:__pkg__'])");
+    useConfiguration("--incompatible_visibility_private_attributes_at_definition");
+
+    reporter.removeHandler(failFastHandler);
+    assertThrows(ViewCreationFailedException.class, () -> update("//use:world"));
+  }
+
+  @Test
+  public void testToolVisibilityPrivateCheckAtUse() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:public'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//visibility:private'])");
+    useConfiguration("--noincompatible_visibility_private_attributes_at_definition");
+
+    reporter.removeHandler(failFastHandler);
+    assertThrows(ViewCreationFailedException.class, () -> update("//use:world"));
+  }
+
+  @Test
+  public void testToolVisibilityPrivateCheckAtRule() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:public'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//visibility:private'])");
+    useConfiguration("--incompatible_visibility_private_attributes_at_definition");
+
+    reporter.removeHandler(failFastHandler);
+    assertThrows(ViewCreationFailedException.class, () -> update("//use:world"));
+  }
+
+  @Test
+  public void testDataVisibilityUseCheckPrivateAtUse() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//use:__pkg__'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//visibility:public'])");
+    useConfiguration("--noincompatible_visibility_private_attributes_at_definition");
+    update("//use:world");
+    assertThat(hasErrors(getConfiguredTarget("//use:world"))).isFalse();
+  }
+
+  @Test
+  public void testDataVisibilityUseCheckPrivateAtRule() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//use:__pkg__'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//visibility:public'])");
+    useConfiguration("--incompatible_visibility_private_attributes_at_definition");
+    update("//use:world");
+    assertThat(hasErrors(getConfiguredTarget("//use:world"))).isFalse();
+  }
+
+  @Test
+  public void testDataVisibilityPrivateCheckPrivateAtRule() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:private'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//visibility:public'])");
+    useConfiguration("--incompatible_visibility_private_attributes_at_definition");
+
+    reporter.removeHandler(failFastHandler);
+    assertThrows(ViewCreationFailedException.class, () -> update("//use:world"));
+  }
+
+  @Test
+  public void testDataVisibilityPrivateCheckPrivateAtUse() throws Exception {
+    setupArgsScenario();
+    scratch.file("data/BUILD", "exports_files(['data.txt'], visibility=['//visibility:private'])");
+    scratch.file("tool/BUILD", "exports_files(['tool.sh'], visibility=['//visibility:public'])");
+    useConfiguration("--noincompatible_visibility_private_attributes_at_definition");
+
+    reporter.removeHandler(failFastHandler);
+    assertThrows(ViewCreationFailedException.class, () -> update("//use:world"));
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewForTesting.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewForTesting.java
index 3d99da4..f81268f 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewForTesting.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewForTesting.java
@@ -463,7 +463,7 @@
             targetConfig.extendedSanityChecks(),
             targetConfig.allowAnalysisFailures(),
             eventHandler,
-            /*env=*/ null);
+            skyframeExecutor.getSkyFunctionEnvironmentForTesting(eventHandler));
     return getRuleContextForTesting(eventHandler, target, env, configurations);
   }
 
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 90ff3e8..714a6e6 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
@@ -258,6 +258,8 @@
     getOutputPath().createDirectoryAndParents();
     ImmutableList<PrecomputedValue.Injected> extraPrecomputedValues =
         ImmutableList.of(
+            PrecomputedValue.injected(
+                PrecomputedValue.STARLARK_SEMANTICS, StarlarkSemantics.DEFAULT_SEMANTICS),
             PrecomputedValue.injected(PrecomputedValue.REPO_ENV, ImmutableMap.<String, String>of()),
             PrecomputedValue.injected(
                 RepositoryDelegatorFunction.REPOSITORY_OVERRIDES,
@@ -582,7 +584,7 @@
         /*extendedSanityChecks=*/ false,
         /*allowAnalysisFailures=*/ false,
         reporter,
-        /* env= */ null);
+        skyframeExecutor.getSkyFunctionEnvironmentForTesting(reporter));
   }
 
   /**
@@ -2000,7 +2002,7 @@
 
     @Override
     public StarlarkSemantics getSkylarkSemantics() {
-      throw new UnsupportedOperationException();
+      return starlarkSemanticsOptions.toSkylarkSemantics();
     }
 
     @Override
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
index b88537e..aed9a4f 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
@@ -160,6 +160,7 @@
         "--incompatible_restrict_named_params=" + rand.nextBoolean(),
         "--incompatible_run_shell_command_string=" + rand.nextBoolean(),
         "--incompatible_string_join_requires_strings=" + rand.nextBoolean(),
+        "--incompatible_visibility_private_attributes_at_definition=" + rand.nextBoolean(),
         "--incompatible_restrict_string_escapes=" + rand.nextBoolean(),
         "--incompatible_disallow_dict_lookup_unhashable_keys=" + rand.nextBoolean(),
         "--incompatible_disallow_hashing_frozen_mutables=" + rand.nextBoolean(),
@@ -213,6 +214,7 @@
         .incompatibleRestrictNamedParams(rand.nextBoolean())
         .incompatibleRunShellCommandString(rand.nextBoolean())
         .incompatibleStringJoinRequiresStrings(rand.nextBoolean())
+        .incompatibleVisibilityPrivateAttributesAtDefinition(rand.nextBoolean())
         .incompatibleRestrictStringEscapes(rand.nextBoolean())
         .incompatibleDisallowDictLookupUnhashableKeys(rand.nextBoolean())
         .incompatibleDisallowHashingFrozenMutables(rand.nextBoolean())
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 e1a5d17..d75a86f 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
@@ -241,7 +241,7 @@
             targetConfig.extendedSanityChecks(),
             targetConfig.allowAnalysisFailures(),
             eventHandler,
-            null),
+            skyframeExecutor.getSkyFunctionEnvironmentForTesting(eventHandler)),
         new BuildConfigurationCollection(
             ImmutableList.of(dummy.getConfiguration()), dummy.getHostConfiguration()));
   }