Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dokka K2 analysis #3094

Merged
merged 30 commits into from Aug 28, 2023
Merged

Dokka K2 analysis #3094

merged 30 commits into from Aug 28, 2023

Conversation

vmishenev
Copy link
Member

@vmishenev vmishenev commented Jul 26, 2023

Compiler: Kotlin 1.9.0

The PR stems from #2995, but it's using a recent refactoring #3034.


The PR description is WIP.

Dokka has its own documentable model to represent analyzed code, The analysis is performed by a compiler frontend.

In K1 the compiler frontend has descriptors that use the underlying Binding Context (global shared stateful structure). Dokka just maps descriptors to Documentable by DefaultDescriptorToDocumentableTranslator.

K2 compiler has FIR tree, which means “Frontend Intermediate Representation”, instead of Binding Context. But we do not use FIR in Dokka directly, since it is too low-level for analysis. The Kotlin compiler provides high-level Analysis API for this case. The API is used by KSP too. Analysis API represent elements of FIR (declarations, parameters and so on) as Symbols. For more details see KtSymbolByFirBuilder, KtSymbol.
For Dokka symbol is the replacement of descriptors in K2.

The general data pipeline is:

flowchart LR

a(Source file)  --> b(Parse tree)  --> c(Raw FIR) --> d(Resolved FIR) -->  e(Symbols)  --> f(Documentable Model)

In code:

flowchart LR
a1(.kt files)  --> b2(KtElement)   -->  c2(FirElement)  -->   d2(FirElement)   --> |KtSymbolByFirBuilder|e2(KtSymbol)  --> |DefaultSymbolToDocumentableTranslator|f2(Documentable)

Also, to set up the environment of project analysis in K1 we use idea dependencies (or copy-past from there). In K2 for these aims there is Standalone Analysis API from Analysis API.

Overview

Main principles

  • Do not use FIR directly, only via Analysis API.
  • Keep compatibility with the Documentable model from K1. It does not break our and user plugins,
  • Do not do double-checking. Dokka supposes that the output from the analysis API is correct. For example, we do not check the correctness of the annotation target.
  • Do not keep symbols or KtAnalysisSession. Symbols are bounded by KtAnalysisSession (although KtAlwaysAccessibleLifetimeToken does not check their lifetime; a session caches them, and a session is cached by KtAnalysisSessionProvider). The documentable model keeps almost full information from symbols. Also, there are analysis principles, but Dokka does not have ReadAction unlike IDE.

Entry point

The main entry point is DefaultSymbolToDocumentableTranslator (this is an extension for the extension point ), that used by the Dokka core to build Documentable model by source set.

Across running Dokka we keep StandaloneAnalysisAPISession and KtSourceModule instances into AnalysisContex per source set. (See createAnalysisContext).
AnalysisContex is used in 'DefaultSymbolToDocumentableTranslator' and other services, that need additional analysis. (see classes in services package)

Differences from K1 in documentable model

  • We do not put empty extra properties anymore (e.g. AdditionalModifiers, Annotations).
  • KotlinModifier.Empty is used only for constructors
  • If while translating an exception is thrown, Dokka rethrows it with TranslatorError that contains a file path where it has happened. In this case, It fails to generate documentation. (Or should Dokka skip a declaration with exception and only emit a warning in the logger?)

Current state

  • Analysis API does not support MPP.
  • Standalone API is a prototype. For now, it does not support libraries and JDK. See KT-60884 Currently, it supports only modular JDK.

Testing

Currently, K2 translator is tested on unit tests of base plugin. To run it, you can use symbolsTest task.
Some tests (currently, 37 from 843) in K2 analysis are muted by a special annotation (@OnlyDescriptors or @OnlyDescriptorsMPP):

  • In K1 Documentable Java field does not have modality modifiers. In K2 they have open.
  • Order of constructors and inheritors is different in K1 and K2.
  • ... Todo

Plans

  • Fix muted unit tests (fix in K1/fix in K2/have 2 sets of tests)
  • Migrate to new Standalone
    • Update the compiler to 1.9.20
    • Use expect/actual from Symbols
  • Add integration tests for only JVM project
  • Support kotlin-as-java and javadoc plugins in K2
  • Use K2 analysis on only JVM projects by default

@vmishenev vmishenev linked an issue Jul 26, 2023 that may be closed by this pull request
4 tasks
@vmishenev vmishenev marked this pull request as ready for review July 27, 2023 14:33
@vmishenev vmishenev force-pushed the 2888-k2-analysis branch 3 times, most recently from 05a213e to ab5f311 Compare July 28, 2023 12:52
Copy link
Contributor

@darthorimar darthorimar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only reviewed the Analysis API usage; I did not look at logic or Dokka-specific code

* Map [KtAnnotationApplication] to Dokka [Annotations.Annotation]
*/
internal class AnnotationTranslator {
private fun KtAnalysisSession.getFileLevelAnnotationsFrom(symbol: KtSymbol) =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KtAnalysisSession is supposed to be used as a context receiver, this way you can always use your extension receiver :

context(KtAnalysisSession)
private fun KtSymbol.getFileLevelAnnotationsFrom() = ...

plugins/all-modules-page/build.gradle.kts Outdated Show resolved Hide resolved
Comment on lines 15 to 16
runtimeOnly(project(path = ":subprojects:analysis-kotlin-descriptors", configuration = "shadow"))
//runtimeOnly(project(path = ":subprojects:analysis-kotlin-symbols", configuration = "shadow"))
//runtimeOnly(project(path = ":subprojects:analysis-kotlin-descriptors", configuration = "shadow"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe removing this line will break 3rd party plugins, even for K1, as their tests will have no analysis implementation. It's worth checking or reverting it to play it safe.

val expectedMessage = "Wrong AST Tree. Header does not contain expected content in Test.kt/example.Test, element starts from offset 0 and ends 3: ###"
assert(
exception?.message == expectedMessage
|| /* for K2 */ exception?.cause?.cause?.message == expectedMessage
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this exception throw from the markdown module? Why is the depth different with K2? Maybe we need to re-wrap it somewhere to remove excessive layers?

Copy link
Member Author

@vmishenev vmishenev Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this exception throw from the markdown module?

Yes

In K2 it is wrapped TranslatorError

subprojects/analysis-kotlin-symbols/build.gradle.kts Outdated Show resolved Hide resolved



// ----------- copy-paste from IDE ----------------------------------------------------------------------------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two questions:

  1. Is this the only copy-pasted code from IDE?
  2. Is this the only copy-pasted code in general, from anywhere? Maybe something was copy-pasted from the compiler or something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Yes
  2. No, there is some code in KotlinAnalysis, but it is related to the Standalone prototype.

@vmishenev vmishenev force-pushed the 2888-k2-analysis branch 2 times, most recently from 7ec03e6 to 565be8f Compare August 18, 2023 20:17
@vmishenev vmishenev merged commit 0e00edc into master Aug 28, 2023
29 of 30 checks passed
@vmishenev vmishenev deleted the 2888-k2-analysis branch August 28, 2023 16:42
@IgnatBeresnev IgnatBeresnev added the topic: K2 Issues / PRs that are related to the K2 migration. See #2888 label Oct 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: K2 Issues / PRs that are related to the K2 migration. See #2888
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Migrate Dokka's analysis to the K2 compiler API
3 participants