metalava: Avoid eagerly loading the world
Avoids eagerly parsing the world:
- In Java (and Kotlin), import statements can only occur
in the file's import list, so limit the visitor checking import
statements to that.
- Code blocks and doc comments are expensive to parse, but most don't
contain anything of interest to metalava. Don't descend into them
when checking for syntax errors (which for code blocks, javac will
catch anyways, and for doc comments aren't possible in the first
place).
Benchmarks:
- touch $HOST_BIN/metalava && time make droid
- Before: 4m43s
- After: 4m08s (14% speedup)
- module-lib-api-stubs-docs-non-updatable
- Before: 1m40s
- After: 1m27s (15% speedup)
Test: make droid
Test: ./gradlew check
Change-Id: Ia7657ca24f384f4ed365ac06e9eed3bf133f1bf2
diff --git a/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt b/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
index 74b35d4..f782d27 100644
--- a/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
+++ b/src/main/java/com/android/tools/metalava/model/psi/PsiBasedCodebase.kt
@@ -40,6 +40,7 @@
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiClassOwner
import com.intellij.psi.PsiClassType
+import com.intellij.psi.PsiCodeBlock
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.PsiField
@@ -169,7 +170,9 @@
for (psiFile in psiFiles.asSequence().distinct()) {
tick() // show progress
- psiFile.accept(object : JavaRecursiveElementVisitor() {
+ // Visiting psiFile directly would eagerly load the entire file even though we only need
+ // the importList here.
+ (psiFile as? PsiJavaFile)?.importList?.accept(object : JavaRecursiveElementVisitor() {
override fun visitImportStatement(element: PsiImportStatement) {
super.visitImportStatement(element)
if (element.resolve() == null) {
@@ -227,6 +230,15 @@
"Syntax error: `${element.errorDescription}`"
)
}
+
+ override fun visitCodeBlock(block: PsiCodeBlock?) {
+ // Ignore to avoid eagerly parsing all method bodies.
+ }
+
+ override fun visitDocComment(comment: PsiDocComment?) {
+ // Ignore to avoid eagerly parsing all doc comments.
+ // Doc comments cannot contain error elements.
+ }
})
topLevelClassesFromSource += createClass(psiClass)