1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tools.metalava 18 19 import com.android.tools.metalava.cli.common.ExecutionEnvironment 20 import com.android.tools.metalava.model.Codebase 21 import com.android.tools.metalava.model.source.EnvironmentManager 22 import com.android.tools.metalava.model.source.SourceModelProvider 23 import com.android.tools.metalava.model.source.SourceParser 24 import com.android.tools.metalava.reporter.Reporter 25 import java.io.Closeable 26 import java.io.File 27 28 /** Provides support for loading [Codebase]s from jar files. */ 29 sealed interface JarCodebaseLoader { 30 31 /** Load a [Codebase] from a jar file. */ loadFromJarFilenull32 fun loadFromJarFile( 33 apiJar: File, 34 apiAnalyzerConfig: ApiAnalyzer.Config = ApiAnalyzer.Config(), 35 ): Codebase 36 37 companion object { 38 /** Create an instance fo [JarCodebaseLoader] from an existing [SourceParser]. */ 39 fun createForSourceParser( 40 progressTracker: ProgressTracker, 41 reporter: Reporter, 42 sourceParser: SourceParser, 43 ): JarCodebaseLoader { 44 return FromSourceParser(progressTracker, reporter, sourceParser) 45 } 46 } 47 48 /** A [JarCodebaseLoader] created from an existing [SourceParser]. */ 49 private class FromSourceParser( 50 private val progressTracker: ProgressTracker, 51 private val reporter: Reporter, 52 private val sourceParser: SourceParser, 53 ) : JarCodebaseLoader { loadFromJarFilenull54 override fun loadFromJarFile( 55 apiJar: File, 56 apiAnalyzerConfig: ApiAnalyzer.Config, 57 ): Codebase { 58 progressTracker.progress("Processing jar file: ") 59 60 val apiPredicateConfig = apiAnalyzerConfig.apiPredicateConfig 61 val apiEmit = 62 ApiPredicate( 63 config = apiPredicateConfig.copy(ignoreShown = true), 64 ) 65 val apiReference = apiEmit 66 67 val codebase = sourceParser.loadFromJar(apiJar) 68 val analyzer = ApiAnalyzer(sourceParser, codebase, reporter, apiAnalyzerConfig) 69 analyzer.mergeExternalInclusionAnnotations() 70 analyzer.computeApi() 71 analyzer.mergeExternalQualifierAnnotations() 72 analyzer.generateInheritedStubs(apiEmit, apiReference) 73 return codebase 74 } 75 } 76 } 77 78 /** 79 * A [JarCodebaseLoader] that owns its own [EnvironmentManager] and supports releasing its resources 80 * through the [close] method. 81 */ 82 class StandaloneJarCodebaseLoader 83 private constructor( 84 /** 85 * The [EnvironmentManager] that created the [SourceParser] that is used to read the jar files. 86 */ 87 private val environmentManager: EnvironmentManager, 88 89 /** The underlying [JarCodebaseLoader] to which this will delegate the [loadFromJarFile]. */ 90 private val delegate: JarCodebaseLoader, 91 ) : Closeable, JarCodebaseLoader by delegate { 92 93 /** Free up any resources held by [environmentManager]. */ closenull94 override fun close() { 95 environmentManager.close() 96 } 97 98 companion object { 99 /** 100 * Create a [StandaloneJarCodebaseLoader]. 101 * 102 * The caller must ensure that the [close] method is called after this has been finished 103 * with to ensure prompt release of resources, e.g. using `...use { jarCodebaseLoader -> }`. 104 */ createnull105 fun create( 106 executionEnvironment: ExecutionEnvironment, 107 progressTracker: ProgressTracker, 108 reporter: Reporter, 109 ): StandaloneJarCodebaseLoader { 110 val sourceModelProvider = SourceModelProvider.getImplementation("psi") 111 112 val environmentManager = 113 sourceModelProvider.createEnvironmentManager( 114 executionEnvironment.disableStderrDumping() 115 ) 116 117 val annotationManager = DefaultAnnotationManager() 118 119 val sourceParser = 120 environmentManager.createSourceParser( 121 reporter, 122 annotationManager, 123 ) 124 125 val jarLoader = 126 JarCodebaseLoader.createForSourceParser( 127 progressTracker, 128 reporter, 129 sourceParser, 130 ) 131 132 return StandaloneJarCodebaseLoader(environmentManager, jarLoader) 133 } 134 } 135 } 136