Extend Attribute by doc string

While the Starlark API accepts a doc string for attributes, our
implementation of attributes cannot store this string. Extend the
Attribute class accordingly.

This will make it possible to show the doc string of an attribute
for errors clearly related to that attribute.

Related to #7165.

Change-Id: If362058b98f016dde00aceaa9c4f1bcff674af98
PiperOrigin-RevId: 236348448
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 ceb3e9a..3bdfeb3 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
@@ -388,6 +388,7 @@
   @AutoCodec
   public static class ImmutableAttributeFactory {
     private final Type<?> type;
+    private final String doc;
     private final ConfigurationTransition configTransition;
     private final RuleClassNamePredicate allowedRuleClassesForLabels;
     private final RuleClassNamePredicate allowedRuleClassesForLabelsWarning;
@@ -406,6 +407,7 @@
     @AutoCodec.VisibleForSerialization
     ImmutableAttributeFactory(
         Type<?> type,
+        String doc,
         ImmutableSet<PropertyFlag> propertyFlags,
         Object value,
         ConfigurationTransition configTransition,
@@ -421,6 +423,7 @@
         RequiredProviders requiredProviders,
         ImmutableList<RuleAspect<?>> aspects) {
       this.type = type;
+      this.doc = doc;
       this.configTransition = configTransition;
       this.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
       this.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;
@@ -471,6 +474,7 @@
 
       return new Attribute(
           name,
+          doc,
           type,
           propertyFlags,
           value,
@@ -503,6 +507,7 @@
     private FileTypeSet allowedFileTypesForLabels;
     private ValidityPredicate validityPredicate = ANY_EDGE;
     private Object value;
+    private String doc;
     private AttributeValueSource valueSource = AttributeValueSource.DIRECT;
     private boolean valueSet;
     private Predicate<AttributeMap> condition;
@@ -686,6 +691,16 @@
     }
 
     /**
+     * Set the doc string for the attribute.
+     *
+     * @param doc The doc string for this attribute.
+     */
+    public Builder<TYPE> setDoc(String doc) {
+      this.doc = doc;
+      return this;
+    }
+
+    /**
      * Sets the attribute default value. The type of the default value must
      * match the type parameter. (e.g. list=[], integer=0, string="",
      * label=null). The {@code defaultValue} must be immutable.
@@ -1178,6 +1193,7 @@
 
       return new ImmutableAttributeFactory(
           type,
+          doc,
           Sets.immutableEnumSet(propertyFlags),
           valueSet ? value : type.getDefaultValue(),
           configTransition,
@@ -1909,6 +1925,8 @@
 
   private final String name;
 
+  private final String doc;
+
   private final Type<?> type;
 
   private final Set<PropertyFlag> propertyFlags;
@@ -1980,6 +1998,7 @@
   @VisibleForSerialization
   Attribute(
       String name,
+      String doc,
       Type<?> type,
       Set<PropertyFlag> propertyFlags,
       Object defaultValue,
@@ -2011,6 +2030,7 @@
     }
 
     this.name = name;
+    this.doc = doc;
     this.type = type;
     this.propertyFlags = propertyFlags;
     this.defaultValue = defaultValue;
@@ -2024,21 +2044,23 @@
     this.allowedValues = allowedValues;
     this.requiredProviders = requiredProviders;
     this.aspects = aspects;
-    this.hashCode = Objects.hash(
-        name,
-        type,
-        propertyFlags,
-        defaultValue,
-        configTransition,
-        splitTransitionProvider,
-        allowedRuleClassesForLabels,
-        allowedRuleClassesForLabelsWarning,
-        allowedFileTypesForLabels,
-        validityPredicate,
-        condition,
-        allowedValues,
-        requiredProviders,
-        aspects);
+    this.hashCode =
+        Objects.hash(
+            name,
+            doc,
+            type,
+            propertyFlags,
+            defaultValue,
+            configTransition,
+            splitTransitionProvider,
+            allowedRuleClassesForLabels,
+            allowedRuleClassesForLabelsWarning,
+            allowedFileTypesForLabels,
+            validityPredicate,
+            condition,
+            allowedValues,
+            requiredProviders,
+            aspects);
   }
 
   /**
@@ -2048,6 +2070,11 @@
     return name;
   }
 
+  /** Returns the doc string for that attribute, if any. */
+  public String getDoc() {
+    return doc;
+  }
+
   /**
    * Returns the public name of this attribute. This is the name we use in Skylark code
    * and we can use it to display to the end-user.
@@ -2429,6 +2456,7 @@
     Attribute attribute = (Attribute) o;
     return Objects.equals(hashCode, attribute.hashCode)
         && Objects.equals(name, attribute.name)
+        && Objects.equals(doc, attribute.doc)
         && Objects.equals(type, attribute.type)
         && Objects.equals(propertyFlags, attribute.propertyFlags)
         && Objects.equals(defaultValue, attribute.defaultValue)
@@ -2456,6 +2484,7 @@
   public <TYPE> Attribute.Builder<TYPE> cloneBuilder(Type<TYPE> tp) {
     Preconditions.checkArgument(tp == this.type);
     Builder<TYPE> builder = new Builder<>(name, tp);
+    builder.doc = doc;
     builder.allowedFileTypesForLabels = allowedFileTypesForLabels;
     builder.allowedRuleClassesForLabels = allowedRuleClassesForLabels;
     builder.allowedRuleClassesForLabelsWarning = allowedRuleClassesForLabelsWarning;