Thank you for your interest in contributing to Kotlin!
This guide explains the contribution process established in the Kotlin IntelliJ IDEA plugin, as well as defines requirements for the changes. Please read the document carefully before submitting requests.
Here are links to other related projects you might want to contribute to:
- Kotlin compiler and runtime libraries: JetBrains/kotlin
- IntelliJ IDEA Community: JetBrains/intellij-community
You can contribute to the plugin by sending us a Pull Request to the master
branch.
Because of technical reasons, we can't use the Github UI for accepting PRs. Instead, we pick commits manually. Don't worry: we won't change the commits (except maybe trivial changes such as typos) or its author information.
You will likely need to set up a project locally to modify its code. The detailed setup instructions are available in the README.
To learn how to write plugins for IntelliJ IDEA, please refer to the IntelliJ Platform SDK DevGuide. The portal contains a lot of useful information and explains how the IDE works under-the-hood.
There's also a #kontributors channel in the public Slack. Please feel free to ask questions regarding contributions to the Kotlin IntelliJ IDEA plugin.
An excellent way to contribute would be to fix some of the issues marked with the "up-for-grabs" tag. They usually don't take a lot of time to be fixed, and the fix is often local.
If you plan to work on new functionality (new intentions, inspections and so on) or want to fix something by re-writing a significant part of a subsystem, please contact us beforehand via the #kontributors channel on Slack. Our experience shows that features that seem trivial often require thorough design work, or implementing them might dramatically affect the performance of the whole IDE. So we might not be able to accept the Pull Request, even if it brings significant value to the users.
Surely, this doesn't mean we say no to arbitrary changes. However, the review process might be slightly longer than usual. So sticking to the "up-for-grabs" tag is a safe way to go.
We have several requirements for the Pull Requests:
- A Pull Request must solve some issue. So the issue identifier must be specified.
We use KT and KTIJ projects on YouTrack. If the issue doesn't exist yet, please create it in KTIJ. - Do not submit Pull Requests that solve multiple issues that aren't interconnected. Create several PRs instead.
- The plugin must still work after the change. Please ensure the plugin compiles and runs successfully after the change.
- Each non-trivial change in plugin functionality must come with tests, so add new tests or adapt existing ones. In both cases, please ensure the existing tests don't fail with the PR applied.
- Avoid merge commits. If you want to adapt your PR after changes in
master
, usegit pull --rebase
instead.
This section contains tips that might help you to write a
You can find necessary information about how to write inspections, intentions and quick fixes in the Code Inspections tutorial.
It's essential to know about PSI, the source code model used in IntelliJ IDEA. To inspect PSI, you can use either the built-in Psi Viewer available in the "internal" mode or an external plugin called PsiViewer.
- Intentions and inspections must be registered in
idea/resources/META-INF/inspections.xml
. - There must be a description in English.
Put descriptions for intentions to
idea/resources-en/intentionDescriptions
, descriptions for inspections are inidea/resources-en/inspectionDescriptions
. - All intentions, inspections and quick-fixes should have automatic tests.
Put test data for local inspections with quick fixes to
idea/testData/inspectionsLocal
, inspections without quick fixes toidea/testData/inspections
. - Prefer inspections with
ProblemHighlightType.INFORMATION
and attached quick-fixes over intentions. - In inspection code, use only
ProblemHighlightType.GENERIC_ERROR_OR_WARNING
as it allows users to adjust the inspection level by themselves. - Make the inspection highlighting range as narrow as possible. E.g. highlight only the class name instead of the whole class declaration, and a called function name instead of the whole call.
- Never hard-code strings displayed to the user in code. Use language bundles instead.
See the
KotlinBundle
as an example. - You can test the exception on the kotlin-ide project itself. To do it, clone kotlin-ide to some other directory
(or create a Git worktree), run the "IDEA" run configuration, open the cloned project in it and run your inspection using
the "Run Inspection by Name" action.
Here's a short check list:- Check that you didn't introduce performance issues by monitoring execution time;
- Check if memory consumption is reasonable;
- Check false positives (or maybe false negatives);
- Try to apply quick fixes and check if code is correct.
- Resolution operations (
analyze()
,resolveToCall()
,resolveToDescriptors()
etc.) are expensive. Perform checks that don't depend on resolution first. For instance, if your inspection looks for top-level classes annotated with@Foo
, check if the current declaration is a top-level class before resolving theFoo
reference. - Avoid using
resolveToDesciptor()
unless necessary as it throws an exception if the reference can't be resolved. UseresolveToDescriptorIfAny()
instead. - If you need to resolve several references at once, call
analyze()
on a commonPsiElement
and then fetch results for individual references from the receivedBindingContext
. CallingresolveToDescriptorIfAny()
orresolveToCall()
several times may lead to inconsistent results. - Don't depend too much on applicability checks. Code could have changed since their execution. Check the required pre-conditions once more before code modification.
- Use the
languageVersionSettings
extension property to getLanguageVersionSettings
for a particularPsiElement
.
- Never do anything continuous in the UI thread. Never call
resolve()
from it. - Always start potentially long operations (such as "Usages search") under a
ProgressIndicator
so the user can cancel it if needed. - Access PSI, module and project components only from a read/write action.
- Use
SmartPsiElementPointer
to store references toPsiElement
s across multiple read/write actions. IntelliJ IDEA might dispose or replace aPsiElement
between the actions. - Do not store any references to PSI or a project structure statically or in long-living project components. It will surely lead
to memory leaks. If absolutely necessary, use
SmartPsiElementPointer
(and correspondingcreateSmartPointer()
).