Expose TargetsBelowDirectory as a visible subclass of TargetPattern: it has too many dedicated methods for it to remain hidden.

PiperOrigin-RevId: 349560782
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
index e6e1122..c04f409 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/TargetPattern.java
@@ -62,7 +62,6 @@
 
   private static final Parser DEFAULT_PARSER = new Parser(PathFragment.EMPTY_FRAGMENT);
 
-  private final Type type;
   private final String originalPattern;
   private final PathFragment offset;
 
@@ -117,9 +116,8 @@
     return SLASH_JOINER.join(pieces);
   }
 
-  private TargetPattern(Type type, String originalPattern, PathFragment offset) {
+  private TargetPattern(String originalPattern, PathFragment offset) {
     // Don't allow inheritance outside this class.
-    this.type = type;
     this.originalPattern = Preconditions.checkNotNull(originalPattern);
     this.offset = Preconditions.checkNotNull(offset);
   }
@@ -128,9 +126,7 @@
    * Return the type of the pattern. Examples include "below directory" like "foo/..." and "single
    * target" like "//x:y".
    */
-  public Type getType() {
-    return type;
-  }
+  public abstract Type getType();
 
   /**
    * Return the string that was parsed into this pattern.
@@ -209,72 +205,6 @@
   }
 
   /**
-   * Returns {@code true} iff this pattern has type {@code Type.TARGETS_BELOW_DIRECTORY} and
-   * {@code directory} is contained by or equals this pattern's directory.
-   *
-   * <p>For example, returns {@code true} for {@code this = TargetPattern ("//...")} and
-   * {@code directory = "foo")}.
-   */
-  public abstract boolean containsAllTransitiveSubdirectoriesForTBD(PackageIdentifier directory);
-
-  /** A tristate return value for {@link #containsTBDForTBD}. */
-  public enum ContainsTBDForTBDResult {
-    /**
-     * Evaluating this TBD pattern with a directory exclusion of the other TBD pattern's directory
-     * would result in exactly the same set of targets as evaluating the subtraction of the other
-     * TBD pattern from this one.
-     */
-    DIRECTORY_EXCLUSION_WOULD_BE_EXACT,
-    /**
-     * A directory exclusion of the other TBD pattern's directory would be too broad because this
-     * TBD pattern is not "rules only" and the other one is, meaning that this TBD pattern
-     * potentially matches more targets underneath the directory in question than the other one
-     * does. Thus, a directory exclusion would incorrectly exclude non-rule targets.
-     */
-    DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD,
-    /**
-     * None of the above. Perhaps the other pattern isn't a TBD pattern or perhaps it's not
-     * contained by this pattern.
-     */
-    OTHER,
-  }
-
-  /**
-   * Determines how, if it all, the evaluation of this TBD pattern with a directory exclusion of the
-   * given TBD {@code containedPattern}'s directory relates to the evaluation of the subtraction of
-   * the given {@code containedPattern} from this one.
-   */
-  public ContainsTBDForTBDResult containsTBDForTBD(TargetPattern containedPattern) {
-    if (containedPattern.getType() != Type.TARGETS_BELOW_DIRECTORY) {
-      return ContainsTBDForTBDResult.OTHER;
-    } else if (containsAllTransitiveSubdirectoriesForTBD(
-        containedPattern.getDirectoryForTargetsUnderDirectory())) {
-      return !getRulesOnly() && containedPattern.getRulesOnly()
-          ? ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD
-          : ContainsTBDForTBDResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT;
-    } else {
-      return ContainsTBDForTBDResult.OTHER;
-    }
-
-  }
-
-  /**
-   * For patterns of type {@link Type#TARGETS_BELOW_DIRECTORY}, returns a {@link PackageIdentifier}
-   * identifying the most specific containing directory of the patterns that could be matched by
-   * this pattern.
-   *
-   * <p>Note that we are using the {@link PackageIdentifier} type as a convenience; there may not
-   * actually be a package corresponding to this directory!
-   *
-   * <p>This returns a {@link PackageIdentifier} that identifies the referred-to directory. For
-   * example, for a {@link Type#TARGETS_BELOW_DIRECTORY} corresponding to "//foo/bar/...", this
-   * method returns a {@link PackageIdentifier} for "foo/bar".
-   */
-  public PackageIdentifier getDirectoryForTargetsUnderDirectory() {
-    throw new IllegalStateException();
-  }
-
-  /**
    * For patterns of type {@link Type#PATH_AS_TARGET}, returns the path in question.
    *
    * <p>The interpretation of this path, of course, depends on the existence of packages.
@@ -318,7 +248,7 @@
         PackageIdentifier directory,
         String originalPattern,
         PathFragment offset) {
-      super(Type.SINGLE_TARGET, originalPattern, offset);
+      super(originalPattern, offset);
       this.targetName = Preconditions.checkNotNull(targetName);
       this.directory = Preconditions.checkNotNull(directory);
     }
@@ -335,11 +265,6 @@
     }
 
     @Override
-    public boolean containsAllTransitiveSubdirectoriesForTBD(PackageIdentifier directory) {
-      return false;
-    }
-
-    @Override
     public PackageIdentifier getDirectoryForTargetOrTargetsInPackage() {
       return directory;
     }
@@ -360,6 +285,11 @@
     }
 
     @Override
+    public Type getType() {
+      return Type.SINGLE_TARGET;
+    }
+
+    @Override
     public boolean equals(Object o) {
       if (this == o) {
         return true;
@@ -378,11 +308,10 @@
   }
 
   private static final class InterpretPathAsTarget extends TargetPattern {
-
     private final String path;
 
     private InterpretPathAsTarget(String path, String originalPattern, PathFragment offset) {
-      super(Type.PATH_AS_TARGET, originalPattern, offset);
+      super(originalPattern, offset);
       this.path = normalize(Preconditions.checkNotNull(path));
     }
 
@@ -422,11 +351,6 @@
     }
 
     @Override
-    public boolean containsAllTransitiveSubdirectoriesForTBD(PackageIdentifier directory) {
-      return false;
-    }
-
-    @Override
     public String getPathForPathAsTarget() {
       return path;
     }
@@ -444,6 +368,11 @@
     }
 
     @Override
+    public Type getType() {
+      return Type.PATH_AS_TARGET;
+    }
+
+    @Override
     public boolean equals(Object o) {
       if (this == o) {
         return true;
@@ -462,7 +391,6 @@
   }
 
   private static final class TargetsInPackage extends TargetPattern {
-
     private final PackageIdentifier packageIdentifier;
     private final String suffix;
     private final boolean wasOriginallyAbsolute;
@@ -477,7 +405,7 @@
         boolean wasOriginallyAbsolute,
         boolean rulesOnly,
         boolean checkWildcardConflict) {
-      super(Type.TARGETS_IN_PACKAGE, originalPattern, offset);
+      super(originalPattern, offset);
       Preconditions.checkArgument(!packageIdentifier.getRepository().isDefault());
       this.packageIdentifier = packageIdentifier;
       this.suffix = Preconditions.checkNotNull(suffix);
@@ -507,11 +435,6 @@
     }
 
     @Override
-    public boolean containsAllTransitiveSubdirectoriesForTBD(PackageIdentifier directory) {
-      return false;
-    }
-
-    @Override
     public PackageIdentifier getDirectoryForTargetOrTargetsInPackage() {
       return packageIdentifier;
     }
@@ -527,6 +450,11 @@
     }
 
     @Override
+    public Type getType() {
+      return Type.TARGETS_IN_PACKAGE;
+    }
+
+    @Override
     public boolean equals(Object o) {
       if (this == o) {
         return true;
@@ -586,8 +514,13 @@
     }
   }
 
-  private static final class TargetsBelowDirectory extends TargetPattern {
-
+  /**
+   * Specialization of {@link TargetPattern} for {@link Type#TARGETS_BELOW_DIRECTORY}. Exposed
+   * because it has a considerable number of specific methods. If {@link TargetPattern#getType}
+   * returns {@link Type#TARGETS_BELOW_DIRECTORY} the instance can safely be cast to {@code
+   * TargetsBelowDirectory}.
+   */
+  public static final class TargetsBelowDirectory extends TargetPattern {
     private final PackageIdentifier directory;
     private final boolean rulesOnly;
 
@@ -596,7 +529,7 @@
         PathFragment offset,
         PackageIdentifier directory,
         boolean rulesOnly) {
-      super(Type.TARGETS_BELOW_DIRECTORY, originalPattern, offset);
+      super(originalPattern, offset);
       Preconditions.checkArgument(!directory.getRepository().isDefault());
       this.directory = Preconditions.checkNotNull(directory);
       this.rulesOnly = rulesOnly;
@@ -641,8 +574,14 @@
           executor);
     }
 
-    @Override
-    public boolean containsAllTransitiveSubdirectoriesForTBD(PackageIdentifier containedDirectory) {
+    /**
+     * Returns true if {@code containedDirectory} is contained by or equals this pattern's
+     * directory.
+     *
+     * <p>For example, returns {@code true} for {@code this = TargetPattern ("//...")} and {@code
+     * directory = "foo")}.
+     */
+    public boolean containsAllTransitiveSubdirectories(PackageIdentifier containedDirectory) {
       // Note that merely checking to see if the directory startsWith the TargetsBelowDirectory's
       // directory is insufficient. "food" begins with "foo", but "//foo/..." does not contain
       // "//food/...".
@@ -650,8 +589,51 @@
           && containedDirectory.getPackageFragment().startsWith(directory.getPackageFragment());
     }
 
-    @Override
-    public PackageIdentifier getDirectoryForTargetsUnderDirectory() {
+    /**
+     * Determines how, if it all, the evaluation of this pattern with a directory exclusion of the
+     * given {@code containedPattern}'s directory relates to the evaluation of the subtraction of
+     * the given {@code containedPattern} from this one.
+     */
+    public ContainsResult contains(TargetsBelowDirectory containedPattern) {
+      if (containsAllTransitiveSubdirectories(containedPattern.getDirectory())) {
+        return !getRulesOnly() && containedPattern.getRulesOnly()
+            ? ContainsResult.DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD
+            : ContainsResult.DIRECTORY_EXCLUSION_WOULD_BE_EXACT;
+      } else {
+        return ContainsResult.NOT_CONTAINED;
+      }
+    }
+
+    /** A tristate return value for {@link #contains}. */
+    public enum ContainsResult {
+      /**
+       * Evaluating this pattern with a directory exclusion of the other pattern's directory would
+       * result in exactly the same set of targets as evaluating the subtraction of the other
+       * pattern from this one.
+       */
+      DIRECTORY_EXCLUSION_WOULD_BE_EXACT,
+      /**
+       * A directory exclusion of the other pattern's directory would be too broad because this
+       * pattern is not "rules only" and the other one is, meaning that this pattern potentially
+       * matches more targets underneath the directory in question than the other one does. Thus, a
+       * directory exclusion would incorrectly exclude non-rule targets.
+       */
+      DIRECTORY_EXCLUSION_WOULD_BE_TOO_BROAD,
+      /** None of the above. The other pattern isn't contained by this pattern. */
+      NOT_CONTAINED,
+    }
+
+    /**
+     * Returns a {@link PackageIdentifier} identifying the most specific containing directory of the
+     * patterns that could be matched by this pattern.
+     *
+     * <p>Note that we are using the {@link PackageIdentifier} type as a convenience; there may not
+     * actually be a package corresponding to this directory!
+     *
+     * <p>This returns a {@link PackageIdentifier} that identifies the referred-to directory. For
+     * example, for "//foo/bar/...", this method returns a {@link PackageIdentifier} for "foo/bar".
+     */
+    public PackageIdentifier getDirectory() {
       return directory;
     }
 
@@ -666,6 +648,11 @@
     }
 
     @Override
+    public Type getType() {
+      return Type.TARGETS_BELOW_DIRECTORY;
+    }
+
+    @Override
     public boolean equals(Object o) {
       if (this == o) {
         return true;