Update from Google.

--
MOE_MIGRATED_REVID=85702957
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
new file mode 100644
index 0000000..ad5756e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BaseRuleClasses.java
@@ -0,0 +1,265 @@
+// Copyright 2014 Google Inc. 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.devtools.build.lib.packages.Attribute.ConfigurationTransition.DATA;
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.DISTRIBUTIONS;
+import static com.google.devtools.build.lib.packages.Type.INTEGER;
+import static com.google.devtools.build.lib.packages.Type.LABEL;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.LICENSE;
+import static com.google.devtools.build.lib.packages.Type.NODEP_LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.RunUnder;
+import com.google.devtools.build.lib.analysis.constraints.EnvironmentRule;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel;
+import com.google.devtools.build.lib.packages.Attribute.LateBoundLabelList;
+import com.google.devtools.build.lib.packages.AttributeMap;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.packages.TestSize;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.util.FileTypeSet;
+
+import java.util.List;
+
+/**
+ * Rule class definitions used by (almost) every rule.
+ */
+public class BaseRuleClasses {
+  /**
+   * Label of the pseudo-filegroup that contains all the targets that are needed
+   * for running tests in coverage mode.
+   */
+  private static final Label COVERAGE_SUPPORT_LABEL =
+      Label.parseAbsoluteUnchecked("//tools/defaults:coverage");
+
+  private static final Attribute.ComputedDefault obsoleteDefault =
+      new Attribute.ComputedDefault() {
+        @Override
+        public Object getDefault(AttributeMap rule) {
+          return rule.getPackageDefaultObsolete();
+        }
+      };
+
+  private static final Attribute.ComputedDefault testonlyDefault =
+      new Attribute.ComputedDefault() {
+        @Override
+        public Object getDefault(AttributeMap rule) {
+          return rule.getPackageDefaultTestOnly();
+        }
+      };
+
+  private static final Attribute.ComputedDefault deprecationDefault =
+      new Attribute.ComputedDefault() {
+        @Override
+        public Object getDefault(AttributeMap rule) {
+          return rule.getPackageDefaultDeprecation();
+        }
+      };
+
+  /**
+   * Implementation for the :action_listener attribute.
+   */
+  private static final LateBoundLabelList<BuildConfiguration> ACTION_LISTENER =
+      new LateBoundLabelList<BuildConfiguration>() {
+    @Override
+    public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+      // action_listeners are special rules; they tell the build system to add extra_actions to
+      // existing rules. As such they need an edge to every ConfiguredTarget with the limitation
+      // that they only run on the target configuration and should not operate on action_listeners
+      // and extra_actions themselves (to avoid cycles).
+      return configuration.getActionListeners();
+    }
+  };
+
+  private static final LateBoundLabelList<BuildConfiguration> COVERAGE_SUPPORT =
+      new LateBoundLabelList<BuildConfiguration>(ImmutableList.of(COVERAGE_SUPPORT_LABEL)) {
+        @Override
+        public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+          return configuration.isCodeCoverageEnabled()
+              ? ImmutableList.<Label>copyOf(configuration.getCoverageLabels())
+              : ImmutableList.<Label>of();
+        }
+      };
+
+  private static final LateBoundLabelList<BuildConfiguration> COVERAGE_REPORT_GENERATOR =
+      new LateBoundLabelList<BuildConfiguration>(ImmutableList.of(COVERAGE_SUPPORT_LABEL)) {
+        @Override
+        public List<Label> getDefault(Rule rule, BuildConfiguration configuration) {
+          return configuration.isCodeCoverageEnabled()
+              ? ImmutableList.<Label>copyOf(configuration.getCoverageReportGeneratorLabels())
+              : ImmutableList.<Label>of();
+        }
+      };
+
+  /**
+   * Implementation for the :run_under attribute.
+   */
+  private static final LateBoundLabel<BuildConfiguration> RUN_UNDER =
+      new LateBoundLabel<BuildConfiguration>() {
+        @Override
+        public Label getDefault(Rule rule, BuildConfiguration configuration) {
+          RunUnder runUnder = configuration.getRunUnder();
+          return runUnder == null ? null : runUnder.getLabel();
+        }
+      };
+
+  /**
+   * A base rule for all test rules.
+   */
+  @BlazeRule(name = "$test_base_rule",
+      type = RuleClassType.ABSTRACT)
+  public static final class TestBaseRule implements RuleDefinition {
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+      return builder
+          .add(attr("size", STRING).value("medium").taggable()
+              .nonconfigurable("policy decision: should be consistent across configurations"))
+          .add(attr("timeout", STRING).taggable()
+              .nonconfigurable("policy decision: should be consistent across configurations")
+              .value(new Attribute.ComputedDefault() {
+                @Override
+                public Object getDefault(AttributeMap rule) {
+                  TestSize size = TestSize.getTestSize(rule.get("size", Type.STRING));
+                  if (size != null) {
+                    String timeout = size.getDefaultTimeout().toString();
+                    if (timeout != null) {
+                      return timeout;
+                    }
+                  }
+                  return "illegal";
+                }
+              }))
+          .add(attr("flaky", BOOLEAN).value(false).taggable()
+              .nonconfigurable("policy decision: should be consistent across configurations"))
+          .add(attr("shard_count", INTEGER).value(-1))
+          .add(attr("local", BOOLEAN).value(false).taggable()
+              .nonconfigurable("policy decision: should be consistent across configurations"))
+          .add(attr("args", STRING_LIST)
+              .nonconfigurable("policy decision: should be consistent across configurations"))
+          .add(attr("$test_runtime", LABEL_LIST).cfg(HOST).value(ImmutableList.of(
+              env.getLabel("//tools/test:runtime"))))
+
+          // TODO(bazel-team): TestActions may need to be run with coverage, so all tests
+          // implicitly depend on crosstool, which provides gcov.  We could add gcov to
+          // InstrumentedFilesProvider.getInstrumentationMetadataFiles() (or a new method) for
+          // all the test rules that have C++ in their transitive closure. Then this could go.
+          .add(attr(":coverage_support", LABEL_LIST).cfg(HOST).value(COVERAGE_SUPPORT))
+          .add(attr(":coverage_report_generator", LABEL_LIST).cfg(HOST)
+              .value(COVERAGE_REPORT_GENERATOR))
+
+          // The target itself and run_under both run on the same machine. We use the DATA config
+          // here because the run_under acts like a data dependency (e.g. no LIPO optimization).
+          .add(attr(":run_under", LABEL).cfg(DATA).value(RUN_UNDER))
+          .build();
+    }
+  }
+
+  /**
+   * Share common attributes across both base and Skylark base rules.
+   */
+  public static RuleClass.Builder commonCoreAndSkylarkAttributes(RuleClass.Builder builder) {
+    return builder
+        // The visibility attribute is special: it is a nodep label, and loading the
+        // necessary package groups is handled by {@link LabelVisitor#visitTargetVisibility}.
+        // Package groups always have the null configuration so that they are not duplicated
+        // needlessly.
+        .add(attr("visibility", NODEP_LABEL_LIST).orderIndependent().cfg(HOST)
+            .nonconfigurable("special attribute integrated more deeply into Bazel's core logic"))
+        .add(attr("deprecation", STRING).value(deprecationDefault)
+            .nonconfigurable("Used in core loading phase logic with no access to configs"))
+        .add(attr("tags", STRING_LIST).orderIndependent().taggable()
+            .nonconfigurable("low-level attribute, used in TargetUtils without configurations"))
+        .add(attr("generator_name", STRING).undocumented("internal"))
+        .add(attr("generator_function", STRING).undocumented("internal"))
+        .add(attr("testonly", BOOLEAN).value(testonlyDefault)
+            .nonconfigurable("policy decision: rules testability should be consistent"))
+        .add(attr(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, LABEL_LIST)
+            .allowedRuleClasses(EnvironmentRule.RULE_NAME)
+            .cfg(Attribute.ConfigurationTransition.HOST)
+            .allowedFileTypes(FileTypeSet.NO_FILE)
+            .undocumented("not yet released"))
+        .add(attr(RuleClass.RESTRICTED_ENVIRONMENT_ATTR, LABEL_LIST)
+            .allowedRuleClasses(EnvironmentRule.RULE_NAME)
+            .cfg(Attribute.ConfigurationTransition.HOST)
+            .allowedFileTypes(FileTypeSet.NO_FILE)
+            .undocumented("not yet released"));
+  }
+
+  /**
+   * Common parts of rules.
+   */
+  @BlazeRule(name = "$base_rule",
+      type = RuleClassType.ABSTRACT)
+  public static final class BaseRule implements RuleDefinition {
+    @Override
+    public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) {
+      return commonCoreAndSkylarkAttributes(builder)
+          // The name attribute is handled specially, so it does not appear here.
+          //
+          // Aggregates the labels of all {@link ConfigRuleClasses} rules this rule uses (e.g.
+          // keys for configurable attributes). This is specially populated in
+          // {@RuleClass#populateRuleAttributeValues}.
+          //
+          // This attribute is not needed for actual builds. Its main purpose is so query's
+          // proto/XML output includes the labels of config dependencies, so, e.g., depserver
+          // reverse dependency lookups remain accurate. These can't just be added to the
+          // attribute definitions proto/XML queries already output because not all attributes
+          // contain labels.
+          //
+          // Builds and Blaze-interactive queries don't need this because they find dependencies
+          // through direct Rule label visitation, which already factors these in.
+          .add(attr("$config_dependencies", LABEL_LIST)
+              .nonconfigurable("not intended for actual builds"))
+          .add(attr("licenses", LICENSE)
+              .nonconfigurable("Used in core loading phase logic with no access to configs"))
+          .add(attr("distribs", DISTRIBUTIONS)
+              .nonconfigurable("Used in core loading phase logic with no access to configs"))
+          .add(attr("obsolete", BOOLEAN).value(obsoleteDefault)
+              .nonconfigurable("Used in core loading phase logic with no access to configs"))
+          .add(attr(":action_listener", LABEL_LIST).cfg(HOST).value(ACTION_LISTENER))
+          .build();
+    }
+  }
+
+  /**
+   * Common ancestor class for all rules.
+   */
+  @BlazeRule(name = "$rule",
+      type = RuleClassType.ABSTRACT,
+      ancestors = { BaseRule.class })
+  public static final class RuleBase implements RuleDefinition {
+    @Override
+    public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+      return builder
+          .add(attr("deps", LABEL_LIST).legacyAllowAnyFileType())
+          .add(attr("data", LABEL_LIST).cfg(DATA).allowedFileTypes(FileTypeSet.ANY_FILE))
+          .build();
+    }
+  }
+
+}