• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.jar
18 
19 import com.android.tools.metalava.ApiAnalyzer
20 import com.android.tools.metalava.ProgressTracker
21 import com.android.tools.metalava.model.Codebase
22 import com.android.tools.metalava.model.annotation.DefaultAnnotationManager
23 import com.android.tools.metalava.model.source.EnvironmentManager
24 import com.android.tools.metalava.model.source.SourceModelProvider
25 import com.android.tools.metalava.model.source.SourceParser
26 import com.android.tools.metalava.model.visitors.ApiPredicate
27 import com.android.tools.metalava.reporter.Reporter
28 import java.io.Closeable
29 import java.io.File
30 
31 /** Provides support for loading [Codebase]s from jar files. */
32 sealed interface JarCodebaseLoader {
33 
34     /** Load a [Codebase] from a jar file. */
loadFromJarFilenull35     fun loadFromJarFile(
36         apiJar: File,
37         apiAnalyzerConfig: ApiAnalyzer.Config = ApiAnalyzer.Config(),
38         freezeCodebase: Boolean = true,
39         classPath: List<File> = emptyList(),
40     ): Codebase
41 
42     companion object {
43         /** Create an instance fo [JarCodebaseLoader] from an existing [SourceParser]. */
44         fun createForSourceParser(
45             progressTracker: ProgressTracker,
46             reporter: Reporter,
47             sourceParser: SourceParser,
48         ): JarCodebaseLoader {
49             return FromSourceParser(progressTracker, reporter, sourceParser)
50         }
51     }
52 
53     /** A [JarCodebaseLoader] created from an existing [SourceParser]. */
54     private class FromSourceParser(
55         private val progressTracker: ProgressTracker,
56         private val reporter: Reporter,
57         private val sourceParser: SourceParser,
58     ) : JarCodebaseLoader {
loadFromJarFilenull59         override fun loadFromJarFile(
60             apiJar: File,
61             apiAnalyzerConfig: ApiAnalyzer.Config,
62             freezeCodebase: Boolean,
63             classPath: List<File>,
64         ): Codebase {
65             progressTracker.progress("Processing jar file: ")
66 
67             val apiPredicateConfig = apiAnalyzerConfig.apiPredicateConfig
68             val apiEmit =
69                 ApiPredicate(
70                     config = apiPredicateConfig.copy(ignoreShown = true),
71                 )
72             val apiReference = apiEmit
73 
74             val codebase = sourceParser.loadFromJar(apiJar, classPath)
75             val analyzer = ApiAnalyzer(sourceParser, codebase, reporter, apiAnalyzerConfig)
76             analyzer.mergeExternalInclusionAnnotations()
77             analyzer.computeApi()
78             analyzer.mergeExternalQualifierAnnotations()
79             analyzer.generateInheritedStubs(apiEmit, apiReference)
80 
81             if (freezeCodebase) {
82                 // Prevent the codebase from being mutated.
83                 codebase.freezeClasses()
84             }
85 
86             return codebase
87         }
88     }
89 }
90 
91 /**
92  * A [JarCodebaseLoader] that owns its own [EnvironmentManager] and supports releasing its resources
93  * through the [close] method.
94  */
95 class StandaloneJarCodebaseLoader
96 private constructor(
97     /**
98      * The [EnvironmentManager] that created the [SourceParser] that is used to read the jar files.
99      */
100     private val environmentManager: EnvironmentManager,
101 
102     /** The underlying [JarCodebaseLoader] to which this will delegate the [loadFromJarFile]. */
103     private val delegate: JarCodebaseLoader,
104 ) : Closeable, JarCodebaseLoader by delegate {
105 
106     /** Free up any resources held by [environmentManager]. */
closenull107     override fun close() {
108         environmentManager.close()
109     }
110 
111     companion object {
112         /**
113          * Create a [StandaloneJarCodebaseLoader].
114          *
115          * The caller must ensure that the [close] method is called after this has been finished
116          * with to ensure prompt release of resources, e.g. using `...use { jarCodebaseLoader -> }`.
117          */
createnull118         fun create(
119             disableStderrDumping: Boolean,
120             progressTracker: ProgressTracker,
121             reporter: Reporter,
122             sourceModelProvider: SourceModelProvider = SourceModelProvider.getImplementation("psi"),
123         ): StandaloneJarCodebaseLoader {
124 
125             val environmentManager =
126                 sourceModelProvider.createEnvironmentManager(
127                     disableStderrDumping,
128                 )
129 
130             val annotationManager = DefaultAnnotationManager()
131             val codebaseConfig =
132                 Codebase.Config(
133                     annotationManager = annotationManager,
134                     reporter = reporter,
135                 )
136 
137             val sourceParser =
138                 environmentManager.createSourceParser(
139                     codebaseConfig,
140                 )
141 
142             val jarLoader =
143                 JarCodebaseLoader.createForSourceParser(
144                     progressTracker,
145                     reporter,
146                     sourceParser,
147                 )
148 
149             return StandaloneJarCodebaseLoader(environmentManager, jarLoader)
150         }
151     }
152 }
153