Introduce TreeArtifact and associated code to work with it. No functionality implemented yet.

--
MOS_MIGRATED_REVID=114157140
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index 24bece9..23e2a4c 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -65,6 +65,29 @@
  * during include validation, will also have null generating Actions.
  * </ul>
  *
+ * In the usual case, an Artifact represents a single file. However, an Artifact may
+ * also represent the following:
+ * <ul>
+ * <li>A TreeArtifact, which is a directory containing a tree of unknown {@link ArtifactFile}s.
+ * In the future, Actions will be able to examine these files as inputs and declare them as outputs
+ * at execution time, but this is not yet implemented. This is used for Actions where
+ * the inputs and/or outputs might not be discoverable except during Action execution.
+ * <li>A directory of unknown contents, but not a TreeArtifact.
+ * This is a legacy facility and should not be used by any new rule implementations.
+ * In particular, the file system cache integrity checks fail for directories.
+ * <li>An 'aggregating middleman' special Artifact, which may be expanded using a
+ * {@link MiddlemanExpander} at Action execution time. This is used by a handful of rules to save
+ * memory.
+ * <li>A 'constant metadata' special Artifact. These represent real files, changes to which are
+ * ignored by the build system. They are useful for files which change frequently but do not affect
+ * the result of a build, such as timestamp files.
+ * <li>A 'Fileset' special Artifact. This is a legacy type of Artifact and should not be used
+ * by new rule implementations.
+ * </ul>
+ * <p/>
+ * This class implements {@link ArtifactFile}, and is modeled as an Artifact "containing" itself
+ * as an ArtifactFile.
+ * <p/>
  * <p>This class is "theoretically" final; it should not be subclassed except by
  * {@link SpecialArtifact}.
  */
@@ -72,7 +95,7 @@
 @SkylarkModule(name = "File",
     doc = "This type represents a file used by the build system. It can be "
         + "either a source file or a derived file produced by a rule.")
-public class Artifact implements FileType.HasFilename, ActionInput, SkylarkValue {
+public class Artifact implements FileType.HasFilename, ArtifactFile, SkylarkValue {
 
   /**
    * Compares artifact according to their exec paths. Sorts null values first.
@@ -204,14 +227,23 @@
         root.getExecPath().getRelative(rootRelativePath), ArtifactOwner.NULL_OWNER);
   }
 
-  /**
-   * Returns the location of this Artifact on the filesystem.
-   */
+  @Override
   public final Path getPath() {
     return path;
   }
 
   /**
+   * Returns the Artifact containing this ArtifactFile. Since normal Artifacts correspond
+   * to only one ArtifactFile -- itself -- for normal Artifacts, this method returns {@code this}.
+   * For special artifacts, throws {@link UnsupportedOperationException}.
+   * See also {@link ArtifactFile#getParent()}.
+   */
+  @Override
+  public Artifact getParent() throws UnsupportedOperationException {
+    return this;
+  }
+
+  /**
    * Returns the directory name of this artifact, similar to dirname(1).
    *
    * <p> The directory name is always a relative path to the execution directory.
@@ -271,6 +303,7 @@
    * package-path entries (for source Artifacts), or one of the bin, genfiles or includes dirs
    * (for derived Artifacts). It will always be an ancestor of getPath().
    */
+  @Override
   @SkylarkCallable(name = "root", structField = true,
       doc = "The root beneath which this file resides."
   )
@@ -278,16 +311,23 @@
     return root;
   }
 
-  /**
-   * Returns the exec path of this Artifact. The exec path is a relative path
-   * that is suitable for accessing this artifact relative to the execution
-   * directory for this build.
-   */
+  @Override
   public final PathFragment getExecPath() {
     return execPath;
   }
 
   /**
+   * Returns the path of this ArtifactFile relative to this containing Artifact. Since
+   * ordinary Artifacts correspond to only one ArtifactFile -- itself -- for ordinary Artifacts,
+   * this just returns the empty path. For special Artifacts, throws
+   * {@link UnsupportedOperationException}. See also {@link ArtifactFile#getParentRelativePath()}.
+   */
+  @Override
+  public PathFragment getParentRelativePath() {
+    return PathFragment.EMPTY_FRAGMENT;
+  }
+
+  /**
    * Returns true iff this is a source Artifact as determined by its path and
    * root relationships. Note that this will report all Artifacts in the output
    * tree, including in the include symlink tree, as non-source.
@@ -306,6 +346,13 @@
   }
 
   /**
+   * Returns true iff this is a TreeArtifact representing a directory tree containing ArtifactFiles.
+   */
+  public boolean isTreeArtifact() {
+    return false;
+  }
+
+  /**
    * Returns whether the artifact represents a Fileset.
    */
   public boolean isFileset() {
@@ -325,8 +372,10 @@
    *
    * @see SpecialArtifact
    */
-  static enum SpecialArtifactType {
+  @VisibleForTesting
+  public static enum SpecialArtifactType {
     FILESET,
+    TREE,
     CONSTANT_METADATA,
   }
 
@@ -342,7 +391,8 @@
   public static final class SpecialArtifact extends Artifact {
     private final SpecialArtifactType type;
 
-    SpecialArtifact(Path path, Root root, PathFragment execPath, ArtifactOwner owner,
+    @VisibleForTesting
+    public SpecialArtifact(Path path, Root root, PathFragment execPath, ArtifactOwner owner,
         SpecialArtifactType type) {
       super(path, root, execPath, owner);
       this.type = type;
@@ -357,12 +407,28 @@
     public boolean isConstantMetadata() {
       return type == SpecialArtifactType.CONSTANT_METADATA;
     }
+
+    @Override
+    public boolean isTreeArtifact() {
+      return type == SpecialArtifactType.TREE;
+    }
+
+    @Override
+    public Artifact getParent() {
+      throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PathFragment getParentRelativePath() {
+      throw new UnsupportedOperationException();
+    }
   }
 
   /**
    * Returns the relative path to this artifact relative to its root.  (Useful
    * when deriving output filenames from input files, etc.)
    */
+  @Override
   public final PathFragment getRootRelativePath() {
     return rootRelativePath;
   }
@@ -397,13 +463,7 @@
     return getRootRelativePath().getPathString();
   }
 
-  /**
-   * Returns a pretty string representation of the path denoted by this artifact, suitable for use
-   * in user error messages.  Artifacts beneath a root will be printed relative to that root; other
-   * artifacts will be printed as an absolute path.
-   *
-   * <p>(The toString method is intended for developer messages since its more informative.)
-   */
+  @Override
   public final String prettyPrint() {
     // toDetailString would probably be more useful to users, but lots of tests rely on the
     // current values.
@@ -475,26 +535,26 @@
   /**
    * Formatter for execPath PathFragment output.
    */
-  private static final Function<Artifact, PathFragment> EXEC_PATH_FORMATTER =
-      new Function<Artifact, PathFragment>() {
+  private static final Function<ArtifactFile, PathFragment> EXEC_PATH_FORMATTER =
+      new Function<ArtifactFile, PathFragment>() {
         @Override
-        public PathFragment apply(Artifact input) {
+        public PathFragment apply(ArtifactFile input) {
           return input.getExecPath();
         }
       };
 
-  public static final Function<Artifact, String> ROOT_RELATIVE_PATH_STRING =
-      new Function<Artifact, String>() {
+  public static final Function<ArtifactFile, String> ROOT_RELATIVE_PATH_STRING =
+      new Function<ArtifactFile, String>() {
         @Override
-        public String apply(Artifact artifact) {
+        public String apply(ArtifactFile artifact) {
           return artifact.getRootRelativePath().getPathString();
         }
       };
 
-  public static final Function<Artifact, String> ABSOLUTE_PATH_STRING =
-      new Function<Artifact, String>() {
+  public static final Function<ArtifactFile, String> ABSOLUTE_PATH_STRING =
+      new Function<ArtifactFile, String>() {
         @Override
-        public String apply(Artifact artifact) {
+        public String apply(ArtifactFile artifact) {
           return artifact.getPath().getPathString();
         }
       };
@@ -708,7 +768,7 @@
   /**
    * Converts artifacts into their exec paths. Returns an immutable list.
    */
-  public static List<PathFragment> asPathFragments(Iterable<Artifact> artifacts) {
+  public static List<PathFragment> asPathFragments(Iterable<? extends ArtifactFile> artifacts) {
     return ImmutableList.copyOf(Iterables.transform(artifacts, EXEC_PATH_FORMATTER));
   }