1*115816f9SAndroid Build Coastguard Worker# Metalava 2*115816f9SAndroid Build Coastguard Worker 3*115816f9SAndroid Build Coastguard WorkerMetalava is a metadata generator intended for JVM type projects. The main 4*115816f9SAndroid Build Coastguard Workerusers of this tool are Android Platform and AndroidX libraries, however this 5*115816f9SAndroid Build Coastguard Workertool also works on non-Android libraries. 6*115816f9SAndroid Build Coastguard Worker 7*115816f9SAndroid Build Coastguard WorkerMetalava has many features related to API management. Some examples of the most 8*115816f9SAndroid Build Coastguard Workercommonly used ones are: 9*115816f9SAndroid Build Coastguard Worker 10*115816f9SAndroid Build Coastguard Worker* Allows extracting the API (into signature text files, into stub API files 11*115816f9SAndroid Build Coastguard Worker which in turn get compiled into android.jar, the Android SDK library) and 12*115816f9SAndroid Build Coastguard Worker more importantly to hide code intended to be implementation only, driven by 13*115816f9SAndroid Build Coastguard Worker javadoc comments like @hide, @doconly, @removed, etc, as well as various 14*115816f9SAndroid Build Coastguard Worker annotations. 15*115816f9SAndroid Build Coastguard Worker 16*115816f9SAndroid Build Coastguard Worker* Extracting source level annotations into external annotations file (such as 17*115816f9SAndroid Build Coastguard Worker the typedef annotations, which cannot be stored in the SDK as .class level 18*115816f9SAndroid Build Coastguard Worker annotations) to ship alongside the Android SDK and used by Android Lint. 19*115816f9SAndroid Build Coastguard Worker 20*115816f9SAndroid Build Coastguard Worker* Diffing versions of the API and determining whether a newer version is 21*115816f9SAndroid Build Coastguard Worker compatible with the older version. (See [COMPATIBILITY.md](COMPATIBILITY.md)) 22*115816f9SAndroid Build Coastguard Worker 23*115816f9SAndroid Build Coastguard Worker## Building and running 24*115816f9SAndroid Build Coastguard Worker 25*115816f9SAndroid Build Coastguard WorkerTo download the code and any dependencies required for building, see [DOWNLOADING.md](DOWNLOADING.md) 26*115816f9SAndroid Build Coastguard Worker 27*115816f9SAndroid Build Coastguard WorkerTo build: 28*115816f9SAndroid Build Coastguard Worker 29*115816f9SAndroid Build Coastguard Worker $ cd tools/metalava 30*115816f9SAndroid Build Coastguard Worker $ ./gradlew 31*115816f9SAndroid Build Coastguard Worker 32*115816f9SAndroid Build Coastguard WorkerIt puts build artifacts in `../../out/metalava/`. 33*115816f9SAndroid Build Coastguard Worker 34*115816f9SAndroid Build Coastguard WorkerTo run the metalava executable: 35*115816f9SAndroid Build Coastguard Worker 36*115816f9SAndroid Build Coastguard Worker### Through Gradle 37*115816f9SAndroid Build Coastguard Worker 38*115816f9SAndroid Build Coastguard WorkerTo list all the options: 39*115816f9SAndroid Build Coastguard Worker 40*115816f9SAndroid Build Coastguard Worker $ ./gradlew run 41*115816f9SAndroid Build Coastguard Worker 42*115816f9SAndroid Build Coastguard WorkerTo run it with specific arguments: 43*115816f9SAndroid Build Coastguard Worker 44*115816f9SAndroid Build Coastguard Worker $ ./gradlew run --args="--api path/to/api.txt" 45*115816f9SAndroid Build Coastguard Worker 46*115816f9SAndroid Build Coastguard Worker### Through distribution artifact 47*115816f9SAndroid Build Coastguard Worker 48*115816f9SAndroid Build Coastguard WorkerFirst build it with: 49*115816f9SAndroid Build Coastguard Worker 50*115816f9SAndroid Build Coastguard Worker $ ./gradlew installDist 51*115816f9SAndroid Build Coastguard Worker 52*115816f9SAndroid Build Coastguard WorkerThen run it with: 53*115816f9SAndroid Build Coastguard Worker 54*115816f9SAndroid Build Coastguard Worker $ ../../out/metalava/metalava/build/install/metalava/bin/metalava 55*115816f9SAndroid Build Coastguard Worker _ _ 56*115816f9SAndroid Build Coastguard Worker _ __ ___ ___| |_ __ _| | __ ___ ____ _ 57*115816f9SAndroid Build Coastguard Worker | '_ ` _ \ / _ \ __/ _` | |/ _` \ \ / / _` | 58*115816f9SAndroid Build Coastguard Worker | | | | | | __/ || (_| | | (_| |\ V / (_| | 59*115816f9SAndroid Build Coastguard Worker |_| |_| |_|\___|\__\__,_|_|\__,_| \_/ \__,_| 60*115816f9SAndroid Build Coastguard Worker 61*115816f9SAndroid Build Coastguard Worker metalava extracts metadata from source code to generate artifacts such as the 62*115816f9SAndroid Build Coastguard Worker signature files, the SDK stub files, external annotations etc. 63*115816f9SAndroid Build Coastguard Worker 64*115816f9SAndroid Build Coastguard Worker Usage: metalava <flags> 65*115816f9SAndroid Build Coastguard Worker 66*115816f9SAndroid Build Coastguard Worker Flags: 67*115816f9SAndroid Build Coastguard Worker 68*115816f9SAndroid Build Coastguard Worker --help This message. 69*115816f9SAndroid Build Coastguard Worker --quiet Only include vital output 70*115816f9SAndroid Build Coastguard Worker --verbose Include extra diagnostic output 71*115816f9SAndroid Build Coastguard Worker 72*115816f9SAndroid Build Coastguard Worker ... 73*115816f9SAndroid Build Coastguard Worker 74*115816f9SAndroid Build Coastguard Worker(*output truncated*) 75*115816f9SAndroid Build Coastguard Worker 76*115816f9SAndroid Build Coastguard Worker### Maven artifacts 77*115816f9SAndroid Build Coastguard Worker 78*115816f9SAndroid Build Coastguard WorkerTo build Metalava's Maven artifacts including `.pom` and `.module` metadata, run: 79*115816f9SAndroid Build Coastguard Worker 80*115816f9SAndroid Build Coastguard Worker $ ./gradlew createArchive 81*115816f9SAndroid Build Coastguard Worker 82*115816f9SAndroid Build Coastguard WorkerThen locate the artifacts under `../../out/dist/repo/m2repository`. 83*115816f9SAndroid Build Coastguard Worker 84*115816f9SAndroid Build Coastguard Worker### Integration testing 85*115816f9SAndroid Build Coastguard Worker 86*115816f9SAndroid Build Coastguard WorkerTo build and run Metalava against a pinned version of an AndroidX library you can 87*115816f9SAndroid Build Coastguard Workerrun the following: 88*115816f9SAndroid Build Coastguard Worker 89*115816f9SAndroid Build Coastguard Worker $ INTEGRATION=true ./gradlew integration:run 90*115816f9SAndroid Build Coastguard Worker 91*115816f9SAndroid Build Coastguard WorkerDetails on what runs are in `integration/build.gradle.kts`. 92*115816f9SAndroid Build Coastguard Worker 93*115816f9SAndroid Build Coastguard WorkerIt can also be run for repeated measurement using [gradle-profiler](https://github.com/gradle/gradle-profiler) with 94*115816f9SAndroid Build Coastguard Worker 95*115816f9SAndroid Build Coastguard Worker $ INTEGRATION=true /path/to/gradle-profiler --benchmark --project-dir . --scenario-file integration/integration.scenarios 96*115816f9SAndroid Build Coastguard Worker 97*115816f9SAndroid Build Coastguard Worker## Features 98*115816f9SAndroid Build Coastguard Worker 99*115816f9SAndroid Build Coastguard Worker* Ability to read in an existing android.jar file instead of from source, which 100*115816f9SAndroid Build Coastguard Worker means we can regenerate signature files etc for older versions according to 101*115816f9SAndroid Build Coastguard Worker new formats (e.g. to fix past errors in doclava, such as annotation instance 102*115816f9SAndroid Build Coastguard Worker methods which were accidentally not included.) 103*115816f9SAndroid Build Coastguard Worker 104*115816f9SAndroid Build Coastguard Worker* Ability to merge in data (annotations etc) from external sources, such as 105*115816f9SAndroid Build Coastguard Worker IntelliJ external annotations data as well as signature files containing 106*115816f9SAndroid Build Coastguard Worker annotations. This isn't just merged at export time, it's merged at codebase 107*115816f9SAndroid Build Coastguard Worker load time such that it can be part of the API analysis. 108*115816f9SAndroid Build Coastguard Worker 109*115816f9SAndroid Build Coastguard Worker* Support for an updated signature file format (which is described in [FORMAT.md](FORMAT.md)) 110*115816f9SAndroid Build Coastguard Worker 111*115816f9SAndroid Build Coastguard Worker * Address errors in the doclava1 format which for example was missing 112*115816f9SAndroid Build Coastguard Worker annotation class instance methods 113*115816f9SAndroid Build Coastguard Worker 114*115816f9SAndroid Build Coastguard Worker * Improve the signature format such that it for example labels enums "enum" 115*115816f9SAndroid Build Coastguard Worker instead of "abstract class extends java.lang.Enum", annotations as 116*115816f9SAndroid Build Coastguard Worker "@interface" instead of "abstract class extends java.lang.Annotation", sorts 117*115816f9SAndroid Build Coastguard Worker modifiers in the canonical modifier order, using "extends" instead of 118*115816f9SAndroid Build Coastguard Worker "implements" for the superclass of an interface, and many other similar 119*115816f9SAndroid Build Coastguard Worker tweaks outlined in the `Compatibility` class. (Metalava also allows (and 120*115816f9SAndroid Build Coastguard Worker ignores) block comments in the signature files.) 121*115816f9SAndroid Build Coastguard Worker 122*115816f9SAndroid Build Coastguard Worker * Add support for writing (and reading) annotations into the signature 123*115816f9SAndroid Build Coastguard Worker files. This is vital now that some of these annotations become part of the 124*115816f9SAndroid Build Coastguard Worker API contract (in particular nullness contracts, as well as parameter names 125*115816f9SAndroid Build Coastguard Worker and default values.) 126*115816f9SAndroid Build Coastguard Worker 127*115816f9SAndroid Build Coastguard Worker * Support for a "compact" nullness format -- one based on Kotlin's 128*115816f9SAndroid Build Coastguard Worker syntax. Since the goal is to have **all** API elements explicitly state 129*115816f9SAndroid Build Coastguard Worker their nullness contract, the signature files would very quickly become 130*115816f9SAndroid Build Coastguard Worker bloated with @NonNull and @Nullable annotations everywhere. So instead, the 131*115816f9SAndroid Build Coastguard Worker signature format now uses a suffix of `?` for nullable, `!` for not yet 132*115816f9SAndroid Build Coastguard Worker annotated, and nothing for non-null. 133*115816f9SAndroid Build Coastguard Worker 134*115816f9SAndroid Build Coastguard Worker Instead of 135*115816f9SAndroid Build Coastguard Worker 136*115816f9SAndroid Build Coastguard Worker method public java.lang.Double convert0(java.lang.Float); 137*115816f9SAndroid Build Coastguard Worker method @Nullable public java.lang.Double convert1(@NonNull java.lang.Float); 138*115816f9SAndroid Build Coastguard Worker 139*115816f9SAndroid Build Coastguard Worker we have 140*115816f9SAndroid Build Coastguard Worker 141*115816f9SAndroid Build Coastguard Worker method public java.lang.Double! convert0(java.lang.Float!); 142*115816f9SAndroid Build Coastguard Worker method public java.lang.Double? convert1(java.lang.Float); 143*115816f9SAndroid Build Coastguard Worker 144*115816f9SAndroid Build Coastguard Worker * Other compactness improvements: Skip packages in some cases both for export 145*115816f9SAndroid Build Coastguard Worker and reinsert during import. Specifically, drop "java.lang." from package 146*115816f9SAndroid Build Coastguard Worker names such that you have 147*115816f9SAndroid Build Coastguard Worker 148*115816f9SAndroid Build Coastguard Worker method public void onUpdate(int, String); 149*115816f9SAndroid Build Coastguard Worker 150*115816f9SAndroid Build Coastguard Worker instead of 151*115816f9SAndroid Build Coastguard Worker 152*115816f9SAndroid Build Coastguard Worker method public void onUpdate(int, java.lang.String); 153*115816f9SAndroid Build Coastguard Worker 154*115816f9SAndroid Build Coastguard Worker Similarly, annotations (the ones considered part of the API; unknown 155*115816f9SAndroid Build Coastguard Worker annotations are not included in signature files) use just the simple name 156*115816f9SAndroid Build Coastguard Worker instead of the full package name, e.g. `@UiThread` instead of 157*115816f9SAndroid Build Coastguard Worker `@android.annotation.UiThread`. 158*115816f9SAndroid Build Coastguard Worker 159*115816f9SAndroid Build Coastguard Worker * Misc documentation handling; for example, it attempts to fix sentences that 160*115816f9SAndroid Build Coastguard Worker javadoc will mistreat, such as sentences that "end" with "e.g. ". It also 161*115816f9SAndroid Build Coastguard Worker looks for various common typos and fixes those; here's a sample error 162*115816f9SAndroid Build Coastguard Worker message running metalava on master: Enhancing docs: 163*115816f9SAndroid Build Coastguard Worker 164*115816f9SAndroid Build Coastguard Worker frameworks/base/core/java/android/content/res/AssetManager.java:166: error: Replaced Kitkat with KitKat in documentation for Method android.content.res.AssetManager.getLocales() [Typo] 165*115816f9SAndroid Build Coastguard Worker frameworks/base/core/java/android/print/PrinterCapabilitiesInfo.java:122: error: Replaced Kitkat with KitKat in documentation for Method android.print.PrinterCapabilitiesInfo.Builder.setColorModes(int, int) [Typo] 166*115816f9SAndroid Build Coastguard Worker 167*115816f9SAndroid Build Coastguard Worker* Built-in support for injecting new annotations for use by the Kotlin compiler, 168*115816f9SAndroid Build Coastguard Worker not just nullness annotations found in the source code and annotations merged 169*115816f9SAndroid Build Coastguard Worker in from external sources, but also inferring whether nullness annotations have 170*115816f9SAndroid Build Coastguard Worker recently changed and if so marking them as @Migrate (which lets the Kotlin 171*115816f9SAndroid Build Coastguard Worker compiler treat errors in the user code as warnings instead of errors.) 172*115816f9SAndroid Build Coastguard Worker 173*115816f9SAndroid Build Coastguard Worker* Support for generating documentation into the stubs files (so we can run 174*115816f9SAndroid Build Coastguard Worker javadoc or [Dokka](https://github.com/Kotlin/dokka) on the stubs files instead 175*115816f9SAndroid Build Coastguard Worker of the source code). This means that the documentation tool itself does not 176*115816f9SAndroid Build Coastguard Worker need to be able to figure out which parts of the source code is included in 177*115816f9SAndroid Build Coastguard Worker the API and which one is implementation; it is simply handed the filtered API 178*115816f9SAndroid Build Coastguard Worker stub sources that include documentation. 179*115816f9SAndroid Build Coastguard Worker 180*115816f9SAndroid Build Coastguard Worker* Support for parsing Kotlin files. API files can now be implemented in Kotlin 181*115816f9SAndroid Build Coastguard Worker as well and metalava will parse and extract API information from them just as 182*115816f9SAndroid Build Coastguard Worker is done for Java files. 183*115816f9SAndroid Build Coastguard Worker 184*115816f9SAndroid Build Coastguard Worker* Like doclava1, metalava can diff two APIs and warn about API compatibility 185*115816f9SAndroid Build Coastguard Worker problems such as removing API elements. Metalava adds new warnings around 186*115816f9SAndroid Build Coastguard Worker nullness, such as attempting to change a nullness contract incompatibly 187*115816f9SAndroid Build Coastguard Worker (e.g. you can change a parameter from non null to nullable for final classes, 188*115816f9SAndroid Build Coastguard Worker but not versa). It also lets you diff directly on a source tree; it does not 189*115816f9SAndroid Build Coastguard Worker require you to create two signature files to diff. 190*115816f9SAndroid Build Coastguard Worker 191*115816f9SAndroid Build Coastguard Worker* Consistent stubs: In doclava1, the code which iterated over the API and 192*115816f9SAndroid Build Coastguard Worker generated the signature files and generated the stubs had diverged, so there 193*115816f9SAndroid Build Coastguard Worker was some inconsistency. In metalava the stub files contain **exactly** the 194*115816f9SAndroid Build Coastguard Worker same signatures as in the signature files. 195*115816f9SAndroid Build Coastguard Worker 196*115816f9SAndroid Build Coastguard Worker (This turned out to be incredibly important; this revealed for example that 197*115816f9SAndroid Build Coastguard Worker StringBuilder.setLength(int) was missing from the API signatures since it is a 198*115816f9SAndroid Build Coastguard Worker public method inherited from a package protected super class, which the API 199*115816f9SAndroid Build Coastguard Worker extraction code in doclava1 missed, but accidentally included in the SDK 200*115816f9SAndroid Build Coastguard Worker anyway since it packages package private classes. Metalava strictly applies 201*115816f9SAndroid Build Coastguard Worker the exact same API as is listed in the signature files, and once this was 202*115816f9SAndroid Build Coastguard Worker hooked up to the build it immediately became apparent that it was missing 203*115816f9SAndroid Build Coastguard Worker important methods that should really be part of the API.) 204*115816f9SAndroid Build Coastguard Worker 205*115816f9SAndroid Build Coastguard Worker* API Lint: Metalava can optionally (with --api-lint) run a series of additional 206*115816f9SAndroid Build Coastguard Worker checks on the public API in the codebase and flag issues that are discouraged 207*115816f9SAndroid Build Coastguard Worker or forbidden by the Android API Council; there are currently around 80 checks. 208*115816f9SAndroid Build Coastguard Worker Some of these take advantage of looking at the source code which wasn't 209*115816f9SAndroid Build Coastguard Worker possible with the signature-file based Python version; for example, it looks 210*115816f9SAndroid Build Coastguard Worker inside method bodies to see if you're synchronizing on this or the current 211*115816f9SAndroid Build Coastguard Worker class, which is forbidden. 212*115816f9SAndroid Build Coastguard Worker 213*115816f9SAndroid Build Coastguard Worker* Baselines: Metalava can report all of its issues into a "baseline" file, which 214*115816f9SAndroid Build Coastguard Worker records the current set of issues. From that point forward, when metalava 215*115816f9SAndroid Build Coastguard Worker finds a problem, it will only be reported if it is not already in the 216*115816f9SAndroid Build Coastguard Worker baseline. This lets you enforce new issues going forward without having to 217*115816f9SAndroid Build Coastguard Worker fix all existing violations. Periodically, as older issues are fixed, you can 218*115816f9SAndroid Build Coastguard Worker regenerate the baseline. For issues with some false positives, such as API 219*115816f9SAndroid Build Coastguard Worker Lint, being able to check in the set of accepted or verified false positives 220*115816f9SAndroid Build Coastguard Worker is quite important. 221*115816f9SAndroid Build Coastguard Worker 222*115816f9SAndroid Build Coastguard Worker* Metalava can generate reports about nullness annotation coverage (which helps 223*115816f9SAndroid Build Coastguard Worker target efforts since we plan to annotate the entire API). First, it can 224*115816f9SAndroid Build Coastguard Worker generate a raw count: 225*115816f9SAndroid Build Coastguard Worker 226*115816f9SAndroid Build Coastguard Worker Nullness Annotation Coverage Statistics: 227*115816f9SAndroid Build Coastguard Worker 1279 out of 46900 methods were annotated (2%) 228*115816f9SAndroid Build Coastguard Worker 2 out of 21683 fields were annotated (0%) 229*115816f9SAndroid Build Coastguard Worker 2770 out of 47492 parameters were annotated (5%) 230*115816f9SAndroid Build Coastguard Worker 231*115816f9SAndroid Build Coastguard Worker More importantly, you can also point it to some existing compiled applications 232*115816f9SAndroid Build Coastguard Worker (.class or .jar files) and it will then measure the annotation coverage of the 233*115816f9SAndroid Build Coastguard Worker APIs used by those applications. This lets us target the most important APIs 234*115816f9SAndroid Build Coastguard Worker that are currently used by a corpus of apps and target our annotation efforts 235*115816f9SAndroid Build Coastguard Worker in a targeted way. For example, running the analysis on the current version of 236*115816f9SAndroid Build Coastguard Worker framework, and pointing it to the 237*115816f9SAndroid Build Coastguard Worker [Plaid](https://github.com/nickbutcher/plaid) app's compiled output with 238*115816f9SAndroid Build Coastguard Worker 239*115816f9SAndroid Build Coastguard Worker ... --annotation-coverage-of ~/plaid/app/build/intermediates/classes/debug 240*115816f9SAndroid Build Coastguard Worker 241*115816f9SAndroid Build Coastguard Worker This produces the following output: 242*115816f9SAndroid Build Coastguard Worker 243*115816f9SAndroid Build Coastguard Worker 324 methods and fields were missing nullness annotations out of 650 total 244*115816f9SAndroid Build Coastguard Worker API references. API nullness coverage is 50% 245*115816f9SAndroid Build Coastguard Worker 246*115816f9SAndroid Build Coastguard Worker ``` 247*115816f9SAndroid Build Coastguard Worker | Qualified Class Name | Usage Count | 248*115816f9SAndroid Build Coastguard Worker |--------------------------------------------------------------|-----------------:| 249*115816f9SAndroid Build Coastguard Worker | android.os.Parcel | 146 | 250*115816f9SAndroid Build Coastguard Worker | android.view.View | 119 | 251*115816f9SAndroid Build Coastguard Worker | android.view.ViewPropertyAnimator | 114 | 252*115816f9SAndroid Build Coastguard Worker | android.content.Intent | 104 | 253*115816f9SAndroid Build Coastguard Worker | android.graphics.Rect | 79 | 254*115816f9SAndroid Build Coastguard Worker | android.content.Context | 61 | 255*115816f9SAndroid Build Coastguard Worker | android.widget.TextView | 53 | 256*115816f9SAndroid Build Coastguard Worker | android.transition.TransitionValues | 49 | 257*115816f9SAndroid Build Coastguard Worker | android.animation.Animator | 34 | 258*115816f9SAndroid Build Coastguard Worker | android.app.ActivityOptions | 34 | 259*115816f9SAndroid Build Coastguard Worker | android.view.LayoutInflater | 31 | 260*115816f9SAndroid Build Coastguard Worker | android.app.Activity | 28 | 261*115816f9SAndroid Build Coastguard Worker | android.content.SharedPreferences | 26 | 262*115816f9SAndroid Build Coastguard Worker | android.content.SharedPreferences.Editor | 26 | 263*115816f9SAndroid Build Coastguard Worker | android.text.SpannableStringBuilder | 23 | 264*115816f9SAndroid Build Coastguard Worker | android.view.ViewGroup.MarginLayoutParams | 21 | 265*115816f9SAndroid Build Coastguard Worker | ... (99 more items | | 266*115816f9SAndroid Build Coastguard Worker ``` 267*115816f9SAndroid Build Coastguard Worker 268*115816f9SAndroid Build Coastguard WorkerTop referenced un-annotated members: 269*115816f9SAndroid Build Coastguard Worker 270*115816f9SAndroid Build Coastguard Worker ``` 271*115816f9SAndroid Build Coastguard Worker | Member | Usage Count | 272*115816f9SAndroid Build Coastguard Worker |--------------------------------------------------------------|-----------------:| 273*115816f9SAndroid Build Coastguard Worker | Parcel.readString() | 62 | 274*115816f9SAndroid Build Coastguard Worker | Parcel.writeString(String) | 62 | 275*115816f9SAndroid Build Coastguard Worker | TextView.setText(CharSequence) | 34 | 276*115816f9SAndroid Build Coastguard Worker | TransitionValues.values | 28 | 277*115816f9SAndroid Build Coastguard Worker | View.getContext() | 28 | 278*115816f9SAndroid Build Coastguard Worker | ViewPropertyAnimator.setDuration(long) | 26 | 279*115816f9SAndroid Build Coastguard Worker | ViewPropertyAnimator.setInterpolator(android.animation.Ti... | 26 | 280*115816f9SAndroid Build Coastguard Worker | LayoutInflater.inflate(int, android.view.ViewGroup, boole... | 23 | 281*115816f9SAndroid Build Coastguard Worker | Rect.left | 22 | 282*115816f9SAndroid Build Coastguard Worker | Rect.top | 22 | 283*115816f9SAndroid Build Coastguard Worker | Intent.Intent(android.content.Context, Class<?>) | 21 | 284*115816f9SAndroid Build Coastguard Worker | Rect.bottom | 21 | 285*115816f9SAndroid Build Coastguard Worker | TransitionValues.view | 21 | 286*115816f9SAndroid Build Coastguard Worker | VERSION.SDK_INT | 18 | 287*115816f9SAndroid Build Coastguard Worker | Context.getResources() | 18 | 288*115816f9SAndroid Build Coastguard Worker | EditText.getText() | 18 | 289*115816f9SAndroid Build Coastguard Worker | ... (309 more items | | 290*115816f9SAndroid Build Coastguard Worker ``` 291*115816f9SAndroid Build Coastguard Worker 292*115816f9SAndroid Build Coastguard Worker From this it's clear that it would be useful to start annotating 293*115816f9SAndroid Build Coastguard Worker android.os.Parcel and android.view.View for example where there are 294*115816f9SAndroid Build Coastguard Worker unannotated APIs that are frequently used, at least by this app. 295*115816f9SAndroid Build Coastguard Worker 296*115816f9SAndroid Build Coastguard Worker* Built on top of a full, type-resolved AST. Doclava1 was integrated with 297*115816f9SAndroid Build Coastguard Worker javadoc, which meant that most of the source tree was opaque. Therefore, as 298*115816f9SAndroid Build Coastguard Worker just one example, the code which generated documentation for typedef constants 299*115816f9SAndroid Build Coastguard Worker had to require the constants to all share a single prefix it could look 300*115816f9SAndroid Build Coastguard Worker for. However, in metalava, annotation references are available at the AST 301*115816f9SAndroid Build Coastguard Worker level, so it can resolve references and map them back to the original field 302*115816f9SAndroid Build Coastguard Worker references and include those directly. 303*115816f9SAndroid Build Coastguard Worker 304*115816f9SAndroid Build Coastguard Worker* Support for extracting annotations. Metalava can also generate the external 305*115816f9SAndroid Build Coastguard Worker annotation files needed by Studio and lint in Gradle, which captures the 306*115816f9SAndroid Build Coastguard Worker typedefs (@IntDef and @StringDef classes) in the source code. Prior to this 307*115816f9SAndroid Build Coastguard Worker this was generated manually via the development/tools/extract code. This also 308*115816f9SAndroid Build Coastguard Worker merges in manually curated data; some of this is in the manual/ folder in this 309*115816f9SAndroid Build Coastguard Worker project. 310*115816f9SAndroid Build Coastguard Worker 311*115816f9SAndroid Build Coastguard Worker* Support for extracting API levels (api-versions.xml). This was generated by 312*115816f9SAndroid Build Coastguard Worker separate code (tools/base/misc/api-generator), invoked during the build. This 313*115816f9SAndroid Build Coastguard Worker functionality is now rolled into metalava, which has one very important 314*115816f9SAndroid Build Coastguard Worker attribute: metalava will use this information when recording API levels for 315*115816f9SAndroid Build Coastguard Worker API usage. (Prior to this, this was based on signature file parsing in 316*115816f9SAndroid Build Coastguard Worker doclava, which sometimes generated incorrect results. Metalava uses the 317*115816f9SAndroid Build Coastguard Worker android.jar files themselves to ensure that it computes the exact available 318*115816f9SAndroid Build Coastguard Worker SDK data for each API level.) 319*115816f9SAndroid Build Coastguard Worker 320*115816f9SAndroid Build Coastguard Worker* Misc other features. For example, if you use the @VisibleForTesting annotation 321*115816f9SAndroid Build Coastguard Worker from the support library, where you can express the intended visibility if the 322*115816f9SAndroid Build Coastguard Worker method had not required visibility for testing, then metalava will treat that 323*115816f9SAndroid Build Coastguard Worker method using the intended visibility instead when generating signature files 324*115816f9SAndroid Build Coastguard Worker and stubs. 325*115816f9SAndroid Build Coastguard Worker 326*115816f9SAndroid Build Coastguard Worker## Architecture & Implementation 327*115816f9SAndroid Build Coastguard Worker 328*115816f9SAndroid Build Coastguard WorkerMetalava is implemented on top of IntelliJ parsing APIs (PSI and UAST). However, 329*115816f9SAndroid Build Coastguard Workerthese are hidden behind a "model": an abstraction layer which only exposes high 330*115816f9SAndroid Build Coastguard Workerlevel concepts like packages, classes and inner classes, methods, fields, and 331*115816f9SAndroid Build Coastguard Workermodifier lists (including annotations). 332*115816f9SAndroid Build Coastguard Worker 333*115816f9SAndroid Build Coastguard WorkerThis is done for multiple reasons: 334*115816f9SAndroid Build Coastguard Worker 335*115816f9SAndroid Build Coastguard Worker(1) It allows us to have multiple "back-ends": for example, metalava can read in 336*115816f9SAndroid Build Coastguard Worker a model not just from parsing source code, but from reading older SDK 337*115816f9SAndroid Build Coastguard Worker android.jar files (e.g. backed by bytecode) or reading previous signature 338*115816f9SAndroid Build Coastguard Worker files. Reading in multiple versions of an API lets doclava perform 339*115816f9SAndroid Build Coastguard Worker "diffing", such as warning if an API is changing in an incompatible way. It 340*115816f9SAndroid Build Coastguard Worker can also generate signature files in the new format (including data that was 341*115816f9SAndroid Build Coastguard Worker missing in older signature files, such as annotation methods) without having 342*115816f9SAndroid Build Coastguard Worker to parse older source code which may no longer be easy to parse. 343*115816f9SAndroid Build Coastguard Worker 344*115816f9SAndroid Build Coastguard Worker(2) There's a lot of logic for deciding whether code found in the source tree 345*115816f9SAndroid Build Coastguard Worker should be included in the API. With the model approach we can build up an 346*115816f9SAndroid Build Coastguard Worker API and for example mark a subset of its methods as included. By having a 347*115816f9SAndroid Build Coastguard Worker separate hierarchy we can easily perform this work once and pass around our 348*115816f9SAndroid Build Coastguard Worker filtered model instead of passing around PsiClass and PsiMethod instances 349*115816f9SAndroid Build Coastguard Worker and having to keep the filtered data separately and remembering to always 350*115816f9SAndroid Build Coastguard Worker consult the filter, not the PSI elements directly. 351*115816f9SAndroid Build Coastguard Worker 352*115816f9SAndroid Build Coastguard WorkerThe basic API element class is "Item". (In doclava1 this was called a 353*115816f9SAndroid Build Coastguard Worker"DocInfo".) There are several sub interfaces of Item: PackageItem, ClassItem, 354*115816f9SAndroid Build Coastguard WorkerMemberItem, MethodItem, FieldItem, ParameterItem, etc. And then there are 355*115816f9SAndroid Build Coastguard Workerseveral implementation hierarchies: One is PSI based, where you point metalava 356*115816f9SAndroid Build Coastguard Workerto a source tree or a .jar file, and it constructs Items built on top of PSI: 357*115816f9SAndroid Build Coastguard WorkerPsiPackageItem, PsiClassItem, PsiMethodItem, etc. Another is textual, based on 358*115816f9SAndroid Build Coastguard Workersignature files: TextPackageItem, TextClassItem, and so on. 359*115816f9SAndroid Build Coastguard Worker 360*115816f9SAndroid Build Coastguard WorkerThe "Codebase" class captures a complete API snapshot (including classes that 361*115816f9SAndroid Build Coastguard Workerare hidden, which is why it's called a "Codebase" rather than an "API"). 362*115816f9SAndroid Build Coastguard Worker 363*115816f9SAndroid Build Coastguard WorkerThere are methods to load codebases - from source folders, from a .jar file, 364*115816f9SAndroid Build Coastguard Workerfrom a signature file. That's how API diffing is performed: you load two 365*115816f9SAndroid Build Coastguard Workercodebases (from whatever source you want, typically a previous API signature 366*115816f9SAndroid Build Coastguard Workerfile and the current set of source folders), and then you "diff" the two. 367*115816f9SAndroid Build Coastguard Worker 368*115816f9SAndroid Build Coastguard WorkerThere are several key helpers that help with the implementation, detailed next. 369*115816f9SAndroid Build Coastguard Worker 370*115816f9SAndroid Build Coastguard Worker### Visiting Items 371*115816f9SAndroid Build Coastguard Worker 372*115816f9SAndroid Build Coastguard WorkerFirst, metalava provides an ItemVisitor. This lets you visit the API easily. 373*115816f9SAndroid Build Coastguard WorkerFor example, here's how you can visit every class: 374*115816f9SAndroid Build Coastguard Worker 375*115816f9SAndroid Build Coastguard Worker codebase.accept(object : ItemVisitor() { 376*115816f9SAndroid Build Coastguard Worker override fun visitClass(cls: ClassItem) { 377*115816f9SAndroid Build Coastguard Worker // code operating on the class here 378*115816f9SAndroid Build Coastguard Worker } 379*115816f9SAndroid Build Coastguard Worker }) 380*115816f9SAndroid Build Coastguard Worker 381*115816f9SAndroid Build Coastguard WorkerSimilarly you can visit all items (regardless of type) by overriding 382*115816f9SAndroid Build Coastguard Worker`visitItem`, or to specifically visit methods, fields and so on overriding 383*115816f9SAndroid Build Coastguard Worker`visitPackage`, `visitClass`, `visitMethod`, etc. 384*115816f9SAndroid Build Coastguard Worker 385*115816f9SAndroid Build Coastguard WorkerThere is also an `ApiVisitor`. This is a subclass of the `ItemVisitor`, but 386*115816f9SAndroid Build Coastguard Workerwhich limits itself to visiting code elements that are part of the API. 387*115816f9SAndroid Build Coastguard Worker 388*115816f9SAndroid Build Coastguard WorkerThis is how for example the SignatureWriter and the StubWriter are both 389*115816f9SAndroid Build Coastguard Workerimplemented: they simply extend `ApiVisitor`, which means they'll only export 390*115816f9SAndroid Build Coastguard Workerthe API items in the codebase, and then in each relevant method they emit the 391*115816f9SAndroid Build Coastguard Workersignature or stub data: 392*115816f9SAndroid Build Coastguard Worker 393*115816f9SAndroid Build Coastguard Worker class SignatureWriter( 394*115816f9SAndroid Build Coastguard Worker private val writer: PrintWriter, 395*115816f9SAndroid Build Coastguard Worker private val generateDefaultConstructors: Boolean, 396*115816f9SAndroid Build Coastguard Worker private val filter: (Item) -> Boolean) : ApiVisitor() { 397*115816f9SAndroid Build Coastguard Worker 398*115816f9SAndroid Build Coastguard Worker .... 399*115816f9SAndroid Build Coastguard Worker 400*115816f9SAndroid Build Coastguard Worker override fun visitConstructor(constructor: ConstructorItem) { 401*115816f9SAndroid Build Coastguard Worker writer.print(" ctor ") 402*115816f9SAndroid Build Coastguard Worker writeModifiers(constructor) 403*115816f9SAndroid Build Coastguard Worker writer.print(constructor.containingClass().fullName()) 404*115816f9SAndroid Build Coastguard Worker writeParameterList(constructor) 405*115816f9SAndroid Build Coastguard Worker writeThrowsList(constructor) 406*115816f9SAndroid Build Coastguard Worker writer.print(";\n") 407*115816f9SAndroid Build Coastguard Worker } 408*115816f9SAndroid Build Coastguard Worker 409*115816f9SAndroid Build Coastguard Worker .... 410*115816f9SAndroid Build Coastguard Worker 411*115816f9SAndroid Build Coastguard Worker### Visiting Types 412*115816f9SAndroid Build Coastguard Worker 413*115816f9SAndroid Build Coastguard WorkerThere is a `TypeVisitor` similar to `ItemVisitor` which you can use to visit all 414*115816f9SAndroid Build Coastguard Workertypes in the codebase. 415*115816f9SAndroid Build Coastguard Worker 416*115816f9SAndroid Build Coastguard WorkerWhen computing the API, all types that are included in the API should be 417*115816f9SAndroid Build Coastguard Workerincluded (e.g. if `List<Foo>` is part of the API then `Foo` must be too). This 418*115816f9SAndroid Build Coastguard Workeris easy to do with the `TypeVisitor`. 419*115816f9SAndroid Build Coastguard Worker 420*115816f9SAndroid Build Coastguard Worker### Diffing Codebases 421*115816f9SAndroid Build Coastguard Worker 422*115816f9SAndroid Build Coastguard WorkerAnother visitor which helps with implementation is the ComparisonVisitor: 423*115816f9SAndroid Build Coastguard Worker 424*115816f9SAndroid Build Coastguard Worker open class ComparisonVisitor { 425*115816f9SAndroid Build Coastguard Worker open fun compare(old: Item, new: Item) {} 426*115816f9SAndroid Build Coastguard Worker open fun added(item: Item) {} 427*115816f9SAndroid Build Coastguard Worker open fun removed(item: Item) {} 428*115816f9SAndroid Build Coastguard Worker 429*115816f9SAndroid Build Coastguard Worker open fun compare(old: PackageItem, new: PackageItem) { } 430*115816f9SAndroid Build Coastguard Worker open fun compare(old: ClassItem, new: ClassItem) { } 431*115816f9SAndroid Build Coastguard Worker open fun compare(old: MethodItem, new: MethodItem) { } 432*115816f9SAndroid Build Coastguard Worker open fun compare(old: FieldItem, new: FieldItem) { } 433*115816f9SAndroid Build Coastguard Worker open fun compare(old: ParameterItem, new: ParameterItem) { } 434*115816f9SAndroid Build Coastguard Worker 435*115816f9SAndroid Build Coastguard Worker open fun added(item: PackageItem) { } 436*115816f9SAndroid Build Coastguard Worker open fun added(item: ClassItem) { } 437*115816f9SAndroid Build Coastguard Worker open fun added(item: MethodItem) { } 438*115816f9SAndroid Build Coastguard Worker open fun added(item: FieldItem) { } 439*115816f9SAndroid Build Coastguard Worker open fun added(item: ParameterItem) { } 440*115816f9SAndroid Build Coastguard Worker 441*115816f9SAndroid Build Coastguard Worker open fun removed(item: PackageItem) { } 442*115816f9SAndroid Build Coastguard Worker open fun removed(item: ClassItem) { } 443*115816f9SAndroid Build Coastguard Worker open fun removed(item: MethodItem) { } 444*115816f9SAndroid Build Coastguard Worker open fun removed(item: FieldItem) { } 445*115816f9SAndroid Build Coastguard Worker open fun removed(item: ParameterItem) { } 446*115816f9SAndroid Build Coastguard Worker } 447*115816f9SAndroid Build Coastguard Worker 448*115816f9SAndroid Build Coastguard WorkerThis makes it easy to perform API comparison operations. 449*115816f9SAndroid Build Coastguard Worker 450*115816f9SAndroid Build Coastguard WorkerFor example, metalava has a feature to mark "newly annotated" nullness 451*115816f9SAndroid Build Coastguard Workerannotations as migrated. To do this, it just extends `ComparisonVisitor`, 452*115816f9SAndroid Build Coastguard Workeroverrides the `compare(old: Item, new: Item)` method, and checks whether the old 453*115816f9SAndroid Build Coastguard Workeritem has no nullness annotations and the new one does, and if so, also marks the 454*115816f9SAndroid Build Coastguard Workernew annotations as @Migrate. 455*115816f9SAndroid Build Coastguard Worker 456*115816f9SAndroid Build Coastguard WorkerSimilarly, the API Check can simply override 457*115816f9SAndroid Build Coastguard Worker 458*115816f9SAndroid Build Coastguard Worker open fun removed(item: Item) { 459*115816f9SAndroid Build Coastguard Worker reporter.report(error, item, "Removing ${Item.describe(item)} is not allowed") 460*115816f9SAndroid Build Coastguard Worker } 461*115816f9SAndroid Build Coastguard Worker 462*115816f9SAndroid Build Coastguard Workerto flag all API elements that have been removed as invalid (since you cannot 463*115816f9SAndroid Build Coastguard Workerremove API. (The real check is slightly more complicated; it looks into the 464*115816f9SAndroid Build Coastguard Workerhierarchy to see if there still is an inherited method with the same signature, 465*115816f9SAndroid Build Coastguard Workerin which case the deletion is allowed.)) 466*115816f9SAndroid Build Coastguard Worker 467*115816f9SAndroid Build Coastguard Worker### Documentation Generation 468*115816f9SAndroid Build Coastguard Worker 469*115816f9SAndroid Build Coastguard WorkerAs mentioned above, metalava generates documentation directly into the stubs 470*115816f9SAndroid Build Coastguard Workerfiles, which can then be processed by Dokka and Javadoc to generate the same 471*115816f9SAndroid Build Coastguard Workerdocs as before. 472*115816f9SAndroid Build Coastguard Worker 473*115816f9SAndroid Build Coastguard WorkerDoclava1 was integrated with javadoc directly, so the way it generated metadata 474*115816f9SAndroid Build Coastguard Workerdocs (such as documenting permissions, ranges and typedefs from annotations) was 475*115816f9SAndroid Build Coastguard Workerto insert auxiliary tags (`@range`, `@permission`, etc) and then this would get 476*115816f9SAndroid Build Coastguard Workerconverted into English docs later via `macros_override.cs`. 477*115816f9SAndroid Build Coastguard Worker 478*115816f9SAndroid Build Coastguard WorkerThis it not how metalava does it; it generates the English documentation 479*115816f9SAndroid Build Coastguard Workerdirectly. This was not just convenient for the implementation (since metalava 480*115816f9SAndroid Build Coastguard Workerdoes not use javadoc data structures to pass maps like the arguments for the 481*115816f9SAndroid Build Coastguard Workertypedef macro), but should also help Dokka -- and arguably the Kotlin code which 482*115816f9SAndroid Build Coastguard Workergenerates the documentation is easier to reason about and to update when it's 483*115816f9SAndroid Build Coastguard Workerhandling loop conditionals. (As a result I for example improved some of the 484*115816f9SAndroid Build Coastguard Workergrammar, e.g. when it's listing a number of possible constants the conjunction 485*115816f9SAndroid Build Coastguard Workeris usually "or", but if it's a flag, the sentence begins with "a combination of 486*115816f9SAndroid Build Coastguard Worker" and then the conjunction at the end should be "and"). 487