Skip to content

Commit dbf7798

Browse files
cushonCopybara-Service
authored and
Copybara-Service
committed
Emit SJD errors even if we don't know the label of a dependency
Fixes #4846 PiperOrigin-RevId: 189123353
1 parent a1c2826 commit dbf7798

File tree

3 files changed

+52
-48
lines changed

3 files changed

+52
-48
lines changed

src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JarOwner.java

+13-18
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
package com.google.devtools.build.buildjar;
1616

1717
import com.google.auto.value.AutoValue;
18-
import com.google.common.base.Function;
19-
import javax.annotation.Nullable;
18+
import java.nio.file.Path;
19+
import java.util.Optional;
2020

2121
/**
2222
* Holds information about the Bazel rule that created a certain jar.
@@ -27,26 +27,21 @@
2727
@AutoValue
2828
public abstract class JarOwner {
2929

30-
/** A long way to say 'JarOwner::label'. */
31-
public static final Function<JarOwner, String> LABEL =
32-
new Function<JarOwner, String>() {
33-
@Nullable
34-
@Override
35-
public String apply(@Nullable JarOwner jarOwner) {
36-
return jarOwner == null ? null : jarOwner.label();
37-
}
38-
};
30+
public abstract Path jar();
3931

40-
public abstract String label();
32+
public abstract Optional<String> label();
4133

42-
@Nullable
43-
public abstract String aspect();
34+
public abstract Optional<String> aspect();
4435

45-
public static JarOwner create(String label) {
46-
return new AutoValue_JarOwner(label, null);
36+
public static JarOwner create(Path jar) {
37+
return new AutoValue_JarOwner(jar, Optional.empty(), Optional.empty());
4738
}
4839

49-
public static JarOwner create(String label, String aspect) {
50-
return new AutoValue_JarOwner(label, aspect);
40+
public static JarOwner create(Path jar, String label, Optional<String> aspect) {
41+
return new AutoValue_JarOwner(jar, Optional.of(label), aspect);
42+
}
43+
44+
public JarOwner withLabel(Optional<String> label) {
45+
return new AutoValue_JarOwner(jar(), label, aspect());
5146
}
5247
}

src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/DependencyModule.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
package com.google.devtools.build.buildjar.javac.plugins.dependency;
1616

1717
import static com.google.common.collect.ImmutableList.toImmutableList;
18+
import static java.util.stream.Collectors.joining;
1819

1920
import com.google.common.annotations.VisibleForTesting;
2021
import com.google.common.collect.ImmutableList;
2122
import com.google.common.collect.ImmutableSet;
23+
import com.google.common.collect.Streams;
2224
import com.google.devtools.build.buildjar.JarOwner;
2325
import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
2426
import com.google.devtools.build.lib.view.proto.Deps.Dependencies;
@@ -37,6 +39,7 @@
3739
import java.util.Map;
3840
import java.util.Optional;
3941
import java.util.Set;
42+
import java.util.stream.Stream;
4043
import javax.tools.Diagnostic;
4144
import javax.tools.JavaFileObject;
4245

@@ -340,12 +343,11 @@ public static class Builder {
340343
private static class DefaultFixMessage implements FixMessage {
341344
@Override
342345
public String get(Iterable<JarOwner> missing, String recipient, DependencyModule depModule) {
343-
StringBuilder missingTargetsStr = new StringBuilder();
344-
for (JarOwner owner : missing) {
345-
missingTargetsStr.append(owner.label());
346-
missingTargetsStr.append(" ");
347-
}
348-
346+
// TODO(cushon): remove the extra whitespace at the end, and fix local_repository_test_jdk8
347+
String missingTargetsStr =
348+
Streams.stream(missing)
349+
.flatMap(owner -> owner.label().map(Stream::of).orElse(Stream.empty()))
350+
.collect(joining(" ", "", " "));
349351
return String.format(
350352
"%1$s ** Please add the following dependencies:%2$s \n %3$s to %4$s \n"
351353
+ "%1$s ** You can use the following buildozer command:%2$s "

src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/dependency/StrictJavaDepsPlugin.java

+31-24
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414

1515
package com.google.devtools.build.buildjar.javac.plugins.dependency;
1616

17+
import static com.google.common.collect.ImmutableSet.toImmutableSet;
1718
import static com.google.common.collect.Iterables.getOnlyElement;
1819
import static com.google.devtools.build.buildjar.javac.plugins.dependency.DependencyModule.StrictJavaDeps.ERROR;
1920

2021
import com.google.auto.value.AutoValue;
2122
import com.google.common.annotations.VisibleForTesting;
2223
import com.google.common.collect.ImmutableSet;
23-
import com.google.common.collect.Ordering;
2424
import com.google.devtools.build.buildjar.JarOwner;
2525
import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
2626
import com.google.devtools.build.buildjar.javac.plugins.dependency.DependencyModule.StrictJavaDeps;
@@ -45,12 +45,12 @@
4545
import java.io.PrintWriter;
4646
import java.io.UncheckedIOException;
4747
import java.nio.file.Path;
48-
import java.text.MessageFormat;
4948
import java.util.ArrayList;
49+
import java.util.Comparator;
5050
import java.util.HashSet;
51-
import java.util.LinkedHashSet;
5251
import java.util.List;
5352
import java.util.Map;
53+
import java.util.Optional;
5454
import java.util.Properties;
5555
import java.util.Set;
5656
import java.util.jar.Attributes;
@@ -209,14 +209,18 @@ public void finish() {
209209
? null
210210
// we don't use the target mapping for the target, just the missing deps
211211
: canonicalizeTarget(dependencyModule.getTargetLabel());
212-
LinkedHashSet<JarOwner> canonicalizedMissing = new LinkedHashSet<>();
213-
for (JarOwner owner :
214-
Ordering.natural().onResultOf(JarOwner.LABEL).immutableSortedCopy(missingTargets)) {
215-
// for dependencies that are missing we canonicalize and remap the target so we don't
216-
// suggest private build labels.
217-
String actualTarget = canonicalizeTarget(remapTarget(owner.label()));
218-
canonicalizedMissing.add(JarOwner.create(actualTarget, owner.aspect()));
219-
}
212+
Set<JarOwner> canonicalizedMissing =
213+
missingTargets
214+
.stream()
215+
.filter(owner -> owner.label().isPresent())
216+
.sorted(Comparator.comparing((JarOwner owner) -> owner.label().get()))
217+
// for dependencies that are missing we canonicalize and remap the target so we don't
218+
// suggest private build labels.
219+
.map(
220+
owner ->
221+
owner.withLabel(
222+
owner.label().map(label -> canonicalizeTarget(remapTarget(label)))))
223+
.collect(toImmutableSet());
220224
errWriter.print(
221225
dependencyModule
222226
.getFixMessage()
@@ -231,10 +235,6 @@ public void finish() {
231235
*/
232236
private static class CheckingTreeScanner extends TreeScanner {
233237

234-
private static final String TRANSITIVE_DEP_MESSAGE =
235-
"[strict] Using {0} from an indirect dependency (TOOL_INFO: \"{1}\"). "
236-
+ "See command below **";
237-
238238
private final ImmutableSet<Path> directJars;
239239

240240
/** Strict deps diagnostics. */
@@ -308,20 +308,27 @@ private void collectExplicitDependency(Path jarPath, JCTree node, Symbol sym) {
308308
// IO cost here is fine because we only hit this path for an explicit dependency
309309
// _not_ in the direct jars, i.e. an error
310310
JarOwner owner = readJarOwnerFromManifest(jarPath);
311-
if (owner != null && seenTargets.add(owner)) {
311+
if (seenTargets.add(owner)) {
312312
// owner is of the form "//label/of:rule <Aspect name>" where <Aspect name> is
313313
// optional.
314-
String canonicalTargetName = canonicalizeTarget(remapTarget(owner.label()));
314+
Optional<String> canonicalTargetName =
315+
owner.label().map(label -> canonicalizeTarget(remapTarget(label)));
315316
missingTargets.add(owner);
316317
String toolInfo =
317-
owner.aspect() == null
318-
? canonicalTargetName
319-
: String.format("%s wrapped in %s", canonicalTargetName, owner.aspect());
318+
owner.aspect().isPresent()
319+
? String.format(
320+
"%s wrapped in %s", canonicalTargetName.get(), owner.aspect().get())
321+
: canonicalTargetName.isPresent()
322+
? canonicalTargetName.get()
323+
: owner.jar().toString();
320324
String used =
321325
sym.getSimpleName().contentEquals("package-info")
322326
? "package " + sym.getEnclosingElement()
323327
: "type " + sym;
324-
String message = MessageFormat.format(TRANSITIVE_DEP_MESSAGE, used, toolInfo);
328+
String message =
329+
String.format(
330+
"[strict] Using %s from an indirect dependency (TOOL_INFO: \"%s\").%s",
331+
used, toolInfo, (owner.label().isPresent() ? " See command below **" : ""));
325332
diagnostics.add(SjdDiagnostic.create(node.pos, message, source));
326333
}
327334
}
@@ -346,15 +353,15 @@ private static JarOwner readJarOwnerFromManifest(Path jarPath) {
346353
try (JarFile jarFile = new JarFile(jarPath.toFile())) {
347354
Manifest manifest = jarFile.getManifest();
348355
if (manifest == null) {
349-
return null;
356+
return JarOwner.create(jarPath);
350357
}
351358
Attributes attributes = manifest.getMainAttributes();
352359
String label = (String) attributes.get(TARGET_LABEL);
353360
if (label == null) {
354-
return null;
361+
return JarOwner.create(jarPath);
355362
}
356363
String injectingRuleKind = (String) attributes.get(INJECTING_RULE_KIND);
357-
return JarOwner.create(label, injectingRuleKind);
364+
return JarOwner.create(jarPath, label, Optional.ofNullable(injectingRuleKind));
358365
} catch (IOException e) {
359366
// This jar file pretty much has to exist, we just used it in the compiler. Throw unchecked.
360367
throw new UncheckedIOException(e);

0 commit comments

Comments
 (0)