# 翻译：Kotlin light-classes


# Kotlin light-classes

Note: 随着 JetBrains 对 Kotlin 插件的修改，本文档很有可能会被淘汰。例如，Kotlin 插件 1.3.50 版本默认启用了 Ultra Light Class，这可能会改变这里讨论的一些性能特征。

Kotlin 的轻型类与 "light R classes" 和 Android Studio 的类似功能只有少许的关系(见[android-light-classes.md](./220318-android-plugin.md))。这两种机制都借用了`LightElement`的名字，它是没有实际源代码支持的 PsiElement 的超类型（即不是由`PsiParser`创建的），但以非常不同的方式实现这一想法。

Background
---
当 IDE 使用 Kotlin 编译器解析 Kotlin 文件时，其结果是一堆 KtElements（如 KtClass、KtConstructor 等）。然而，KtElements 并没有真正实现完整的 PSI 接口。例如，KtClass 没有实现 PsiClass，而 KtFunction 也没有实现 PsiMethod。

不过，很多代码还是依赖于解析和使用 PsiClass、PsiMethod 等。因此，为了使其发挥作用，Kotlin 插件用KtLightElements（也称为 Kotlin light-classes）包装了 KtElements。KtLightClass 实现了查询 PsiClass，KtLightMethod 实现了
PsiMethod...

因此 Kotlin light-classes 包名就叫做: `org.jetbrains.kotlin.asJava`

当我们关注一下 KtLightClass，会发现它基本上有两种方式实现对 PsiClass 接口的查询

1. 如果他只需要从底层的 KtElement 中检索信息，那么这是很容易做到的，例如
   KtLightClassForSourceDeclaration.isInterface()
2. 否则，它将委托 Kotlin 编译器为该类创建 Java stub，然后使用该 Java stub 来实现对接口的访问。(记住，在编译一个混合的 Java/Kotlin 项目时，Kotlin 编译器已经能够创建 Java stub，以便 Kotlin 类能被 javac 看到。所以，Kotlin 的 Light Class 可以委托给编译器以获得便利。关于这方面的例子，请看委托到 `clsDelegate` 上的 KtLightClassForSourceDeclaration.getSupers()

Q: Why are light-classes so slow?
---
对于(1)类型的查询，Kotlin light-classes 很快速。然而，当委托给编译器来回答(2)类型的查询时，事情就会变得很慢。例如，当 KtLightClassForSourceDeclaration 委托给它的`clsDelegate`时，Kotlin 编译器必须为该类生成 Java stub。这导致了对 forceResolveAllContents() 和 kotlin.codegen.ClassBodyCodegen.generateBridges() 等的调用。在我的手动测试中，每个类可能需要50毫秒左右。这就是为什么随着时间的推移，JetBrains 试图减少其委托给编译器的次数：

    c00fbb236f7cab7e9a256c8c4c3fa55f105b106b
    don't perform full resolve and stub building for isInheritor() checks
    https://youtrack.jetbrains.com/issue/KT-8656
    
    d74a989d9340e16662bc6b14e7c222d337db115c
    Tweak light classes to avoid computing stubs on certain api calls
    
    3cb38e7f02b3612d9f0741d0e70b3b39a57f86b2
    Implement getLanguageLevel for FakeFileForLightClass
    https://youtrack.jetbrains.com/issue/KT-12006
    
    daef8a0eed08502c0aea5f14e4d1459cf8c74666
    Light classes in IDE: Make light class delegate construction a two step process

不过有时如果有助于避免复杂性的话，他们会回到委托给编译器

    19db4304bd616cbc9b3abfdc60fbead6f04d7826
    Use clsDelegate to calculate hasModifierProperty("final") for light psi
    https://youtrack.jetbrains.com/issue/KT-17857

这个实际上使类搜索其继承的父类的速度降低了不少，这也是我们提出 KT-33250 的原因

Q: How can I identity when light-classes are being slow?
---
如果你在看一份 freeze report，并且它包含一个大的堆栈，其中有`getJavaFileStub`或`getClsDelegate`这样的方法，那么很有可能是 Kotlin Light class 导致了速度变慢

Q: Are Kotlin light-classes cached?
---
是的，但是缓存经常被废止。在过去（在1.3.41中也是如此），每次PSI的变化都会使缓存失效，因为平台废除了代码块外的修改跟踪器。最近，JetBrains 似乎正在为 Kotlin 开发一个代码块外的修改跟踪器；见 KotlinModificationTrackerService

这些缓存失效的一个有趣的影响是，你会经常得到 KtLightElements 的新实例。这意味着任何存储在 PSI 中的用户数据都会丢失。这里有一个非常好的例子，JetBrains试图解决由这个问题引起的性能问题。

    6ac345df516b38b4bf5ee1300626c936079f2672
    Caching `KtLightClassForSourceDeclaration` (to keep user data longer)
    to make their UserData survive for longer, because otherwise a new LightClass with empty UserData comes to Spring every time, but Spring stores a lot of important things in UserData
    https://youtrack.jetbrains.com/issue/KT-21701

因此，当在 PsiElements 中缓存可能来自 Kotlin 的东西时要小心。

Q: What are Kotlin ultra-light classes?
---
Kotlin ultra-light classes 的设计是为了解决 Kotlin light-classes 的缓慢性。它们的功能与 light-classes 一样，但它们的想法是，它们不委托 Kotlin 编译器生成 Java stub。说实话，我不知道为什么它是另一个层次（而不是仅仅改进原来的 light-classes），但可惜了，第一次提交是在：

    ebc998d710ae275d9d91d2e53446612aec33fe86
    add ultra-light classes/members that work without backend in simple cases

如果成功的话，ultra-light classes 可能会大大改善 Kotlin IDE 的支持。这尤其影响到我们从 Android 插件进行的查询，如类的继承者搜索等。例如，在 KT-33250 中，我发现委托给 Kotlin 编译器会使类继承者搜索的速度比它能做到的慢10倍。

目前，ultra-light classes 只为 "不太复杂" 的类生成。
(见UltraLightSupport.isTooComplexForUltraLightGeneration())。随着时间的推移，JetBrains似乎会支持越来越多的类的复杂性。

Kotlin ultra-light classes 在 Kotlin 1.3.50 已经被默认启用:

    1b5f72bd599a3725c8b2bf3b27cd8bd49cde7987
    Enable ultra-light classes by default
    https://youtrack.jetbrains.com/issue/KT-29267

---

原文：[google android idea plugin docs](https://android.googlesource.com/platform/tools/adt/idea/+/HEAD/android/docs/)
