diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java
index 50eb695027b44f..c29c09e99230ad 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Package.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java
@@ -915,7 +915,7 @@ private enum NameConflictCheckingPolicy {
* file having that prefix. Used for error reporting.
*
*
This field is null if name conflict checking is disabled. It is also null after the
- * package is built.
+ * package is built. The content of the map is manipulated only in {@link #checkForConflicts}.
*/
@Nullable private Map outputFilePrefixes = new HashMap<>();
@@ -1472,11 +1472,7 @@ void addPackageGroup(
repoRootMeansCurrentRepo,
eventHandler,
location);
- Target existing = targets.get(group.getName());
- if (existing != null) {
- throw nameConflict(group, existing);
- }
-
+ checkNameConflict(group);
targets.put(group.getName(), group);
if (group.containsErrors()) {
@@ -1526,12 +1522,9 @@ void addEnvironmentGroup(
EnvironmentGroup group =
new EnvironmentGroup(createLabel(name), pkg, environments, defaults, location);
- Target existing = targets.get(group.getName());
- if (existing != null) {
- throw nameConflict(group, existing);
- }
-
+ checkNameConflict(group);
targets.put(group.getName(), group);
+
// Invariant: once group is inserted into targets, it must also:
// (a) be inserted into environmentGroups, or
// (b) have its group.processMemberEnvironments called.
@@ -1587,6 +1580,10 @@ private void ensureNameConflictChecking() {
this.nameConflictCheckingPolicy = NameConflictCheckingPolicy.ENABLED;
}
+ /**
+ * Adds a rule and its outputs to the targets map, and propagates the error bit from the rule to
+ * the package.
+ */
private void addRuleInternal(Rule rule) {
Preconditions.checkArgument(rule.getPackage() == pkg);
for (OutputFile outputFile : rule.getOutputFiles()) {
@@ -1775,40 +1772,49 @@ private InputFile addInputFile(InputFile inputFile) {
}
/**
- * Precondition check for addRule. We must maintain these invariants of the package:
+ * Precondition check for {@link #addRule}. Verifies that:
*
*
- *
Each name refers to at most one target.
- *
No rule with errors is inserted into the package.
- *
The generating rule of every output file in the package must itself be in the package.
+ *
The added rule's name, and the names of its output files, are not the same as the name
+ * of any target already declared in the package.
+ *
The added rule's output files list does not contain the same name twice.
+ *
The added rule does not have an input file and an output file that share the same name.
+ *
For each of the added rule's output files, no directory prefix of that file matches the
+ * name of another output file in the package; and conversely, the file is not itself a
+ * prefix for another output file. (This check statefully mutates the {@code
+ * outputFilePrefixes} field.)
*
*/
+ // TODO(bazel-team): We verify that all prefixes of output files are distinct from other output
+ // file names, but not that they're distinct from other target names in the package. What
+ // happens if you define an input file "abc" and output file "abc/xyz"?
private void checkForConflicts(Rule rule, List