diff options
Diffstat (limited to 'java/com/google/devtools/build/android/desugar/Desugar.java')
-rw-r--r-- | java/com/google/devtools/build/android/desugar/Desugar.java | 89 |
1 files changed, 79 insertions, 10 deletions
diff --git a/java/com/google/devtools/build/android/desugar/Desugar.java b/java/com/google/devtools/build/android/desugar/Desugar.java index 31c362e..87aa0d7 100644 --- a/java/com/google/devtools/build/android/desugar/Desugar.java +++ b/java/com/google/devtools/build/android/desugar/Desugar.java @@ -176,6 +176,26 @@ class Desugar { public int minSdkVersion; @Option( + name = "emit_dependency_metadata_as_needed", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, + effectTags = {OptionEffectTag.UNKNOWN}, + help = "Whether to emit META-INF/desugar_deps as needed for later consistency checking." + ) + public boolean emitDependencyMetadata; + + @Option( + name = "best_effort_tolerate_missing_deps", + defaultValue = "true", + category = "misc", + documentationCategory = OptionDocumentationCategory.UNCATEGORIZED, + effectTags = {OptionEffectTag.UNKNOWN}, + help = "Whether to tolerate missing dependencies on the classpath in some cases. You should " + + "strive to set this flag to false." + ) + public boolean tolerateMissingDependencies; + + @Option( name = "desugar_interface_method_bodies_if_needed", defaultValue = "true", category = "misc", @@ -225,7 +245,6 @@ class Desugar { defaultValue = "false", documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, effectTags = {OptionEffectTag.UNKNOWN}, - implicitRequirements = "--allow_empty_bootclasspath", help = "Enables rewriting to desugar java.* classes." ) public boolean coreLibrary; @@ -316,6 +335,7 @@ class Desugar { try (OutputFileProvider outputFileProvider = toOutputFileProvider(outputPath); InputFileProvider inputFiles = toInputFileProvider(inputPath)) { + DependencyCollector depsCollector = createDepsCollector(); IndexedInputs indexedInputFiles = new IndexedInputs(ImmutableList.of(inputFiles)); // Prepend classpath with input file itself so LambdaDesugaring can load classes with // lambdas. @@ -344,6 +364,7 @@ class Desugar { outputFileProvider, loader, classpathReader, + depsCollector, bootclasspathReader, interfaceLambdaMethodCollector); @@ -351,12 +372,18 @@ class Desugar { outputFileProvider, loader, classpathReader, + depsCollector, bootclasspathReader, interfaceLambdaMethodCollector.build(), bridgeMethodReader); - desugarAndWriteGeneratedClasses(outputFileProvider); + desugarAndWriteGeneratedClasses(outputFileProvider, bootclasspathReader); copyThrowableExtensionClass(outputFileProvider); + + byte[] depsInfo = depsCollector.toByteArray(); + if (depsInfo != null) { + outputFileProvider.write(OutputFileProvider.DESUGAR_DEPS_FILENAME, depsInfo); + } } ImmutableMap<Path, LambdaInfo> lambdasLeftBehind = lambdas.drain(); @@ -365,6 +392,32 @@ class Desugar { checkState(generatedLeftBehind.isEmpty(), "Didn't process %s", generatedLeftBehind.keySet()); } + /** + * Returns a dependency collector for use with a single input Jar. If + * {@link DesugarOptions#emitDependencyMetadata} is set, this method instantiates the collector + * reflectively to allow compiling and using the desugar tool without this mechanism. + */ + private DependencyCollector createDepsCollector() { + if (options.emitDependencyMetadata) { + try { + return (DependencyCollector) + Thread.currentThread() + .getContextClassLoader() + .loadClass( + "com.google.devtools.build.android.desugar.dependencies.MetadataCollector") + .getConstructor(Boolean.TYPE) + .newInstance(options.tolerateMissingDependencies); + } catch (ReflectiveOperationException + | SecurityException e) { + throw new IllegalStateException("Can't emit desugaring metadata as requested"); + } + } else if (options.tolerateMissingDependencies) { + return DependencyCollector.NoWriteCollectors.NOOP; + } else { + return DependencyCollector.NoWriteCollectors.FAIL_ON_MISSING; + } + } + private void copyThrowableExtensionClass(OutputFileProvider outputFileProvider) { if (allowTryWithResources || options.desugarTryWithResourcesOmitRuntimeClasses) { // try-with-resources statements are okay in the output jar. @@ -390,10 +443,15 @@ class Desugar { OutputFileProvider outputFileProvider, ClassLoader loader, @Nullable ClassReaderFactory classpathReader, + DependencyCollector depsCollector, ClassReaderFactory bootclasspathReader, Builder<String> interfaceLambdaMethodCollector) throws IOException { for (String filename : inputFiles) { + if (OutputFileProvider.DESUGAR_DEPS_FILENAME.equals(filename)) { + // TODO(kmb): rule out that this happens or merge input file with what's in depsCollector + continue; // skip as we're writing a new file like this at the end or don't want it + } try (InputStream content = inputFiles.getInputStream(filename)) { // We can write classes uncompressed since they need to be converted to .dex format // for Android anyways. Resources are written as they were in the input jar to avoid @@ -405,6 +463,7 @@ class Desugar { createClassVisitorsForClassesInInputs( loader, classpathReader, + depsCollector, bootclasspathReader, interfaceLambdaMethodCollector, writer, @@ -431,6 +490,7 @@ class Desugar { OutputFileProvider outputFileProvider, ClassLoader loader, @Nullable ClassReaderFactory classpathReader, + DependencyCollector depsCollector, ClassReaderFactory bootclasspathReader, ImmutableSet<String> interfaceLambdaMethods, @Nullable ClassReaderFactory bridgeMethodReader) @@ -460,6 +520,7 @@ class Desugar { createClassVisitorsForDumpedLambdaClasses( loader, classpathReader, + depsCollector, bootclasspathReader, interfaceLambdaMethods, bridgeMethodReader, @@ -473,7 +534,8 @@ class Desugar { } } - private void desugarAndWriteGeneratedClasses(OutputFileProvider outputFileProvider) + private void desugarAndWriteGeneratedClasses( + OutputFileProvider outputFileProvider, ClassReaderFactory bootclasspathReader) throws IOException { // Write out any classes we generated along the way ImmutableMap<String, ClassNode> generatedClasses = store.drain(); @@ -485,7 +547,8 @@ class Desugar { UnprefixingClassWriter writer = rewriter.writer(ClassWriter.COMPUTE_MAXS); // checkState above implies that we want Java 7 .class files, so send through that visitor. // Don't need a ClassReaderFactory b/c static interface methods should've been moved. - ClassVisitor visitor = new Java7Compatibility(writer, (ClassReaderFactory) null); + ClassVisitor visitor = + new Java7Compatibility(writer, (ClassReaderFactory) null, bootclasspathReader); generated.getValue().accept(visitor); String filename = rewriter.unprefix(generated.getKey()) + ".class"; outputFileProvider.write(filename, writer.toByteArray()); @@ -499,6 +562,7 @@ class Desugar { private ClassVisitor createClassVisitorsForDumpedLambdaClasses( ClassLoader loader, @Nullable ClassReaderFactory classpathReader, + DependencyCollector depsCollector, ClassReaderFactory bootclasspathReader, ImmutableSet<String> interfaceLambdaMethods, @Nullable ClassReaderFactory bridgeMethodReader, @@ -520,12 +584,14 @@ class Desugar { } if (outputJava7) { // null ClassReaderFactory b/c we don't expect to need it for lambda classes - visitor = new Java7Compatibility(visitor, (ClassReaderFactory) null); + visitor = new Java7Compatibility(visitor, (ClassReaderFactory) null, bootclasspathReader); if (options.desugarInterfaceMethodBodiesIfNeeded) { visitor = - new DefaultMethodClassFixer(visitor, classpathReader, bootclasspathReader, loader); + new DefaultMethodClassFixer( + visitor, classpathReader, depsCollector, bootclasspathReader, loader); visitor = - new InterfaceDesugaring(visitor, bootclasspathReader, store, options.legacyJacocoFix); + new InterfaceDesugaring( + visitor, depsCollector, bootclasspathReader, store, options.legacyJacocoFix); } } visitor = @@ -553,6 +619,7 @@ class Desugar { private ClassVisitor createClassVisitorsForClassesInInputs( ClassLoader loader, @Nullable ClassReaderFactory classpathReader, + DependencyCollector depsCollector, ClassReaderFactory bootclasspathReader, Builder<String> interfaceLambdaMethodCollector, UnprefixingClassWriter writer, @@ -571,12 +638,14 @@ class Desugar { } if (!options.onlyDesugarJavac9ForLint) { if (outputJava7) { - visitor = new Java7Compatibility(visitor, classpathReader); + visitor = new Java7Compatibility(visitor, classpathReader, bootclasspathReader); if (options.desugarInterfaceMethodBodiesIfNeeded) { visitor = - new DefaultMethodClassFixer(visitor, classpathReader, bootclasspathReader, loader); + new DefaultMethodClassFixer( + visitor, classpathReader, depsCollector, bootclasspathReader, loader); visitor = - new InterfaceDesugaring(visitor, bootclasspathReader, store, options.legacyJacocoFix); + new InterfaceDesugaring( + visitor, depsCollector, bootclasspathReader, store, options.legacyJacocoFix); } } // LambdaDesugaring is relatively expensive, so check first whether we need it. Additionally, |