diff --git a/idea-plugin/build.gradle.kts b/idea-plugin/build.gradle.kts index e70f4c8a52..c46af07c23 100644 --- a/idea-plugin/build.gradle.kts +++ b/idea-plugin/build.gradle.kts @@ -12,6 +12,12 @@ val projectProperties = ProjectProperties(project) group = "org.jetbrains.compose.desktop.ide" version = projectProperties.deployVersion +sourceSets { + main { + java.srcDir("src/main/kotlin") + } +} + repositories { mavenCentral() } @@ -45,7 +51,7 @@ tasks { // Set the compatibility versions to 1.8 withType { sourceCompatibility = "1.8" - targetCompatibility = "1.8" + targetCompatibility = "11" } withType { kotlinOptions.jvmTarget = "11" diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposableAnnotator.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposableAnnotator.kt index 46264a3a86..7a8935778f 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposableAnnotator.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposableAnnotator.kt @@ -16,6 +16,7 @@ package com.android.tools.compose +import com.android.tools.modules.* import com.intellij.lang.annotation.AnnotationHolder import com.intellij.lang.annotation.Annotator import com.intellij.lang.annotation.HighlightSeverity @@ -57,10 +58,11 @@ class ComposableAnnotator : Annotator { // AnnotationHolder.currentAnnotationSession applies to a single file. var canContainComposable = holder.currentAnnotationSession.getUserData(CAN_CONTAIN_COMPOSABLE_KEY) if (canContainComposable == null) { - // isComposeEnabled doesn't work for library sources, we check all kt library sources files. File check only once on opening. - canContainComposable = isComposeEnabled(element) || - (element.containingFile.virtualFile != null && - ProjectFileIndex.getInstance(element.project).isInLibrarySource(element.containingFile.virtualFile)) + // isComposeEnabled doesn't work for library sources, we check all kt library sources files. File check only once on opening. + canContainComposable = element.inComposeModule() || + (element.containingFile.virtualFile != null && + ProjectFileIndex.getInstance(element.project) + .isInLibrarySource(element.containingFile.virtualFile)) holder.currentAnnotationSession.putUserData(CAN_CONTAIN_COMPOSABLE_KEY, canContainComposable) } diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeDiagnosticSuppressor.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeDiagnosticSuppressor.kt index 6742426f3b..185b6f0624 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeDiagnosticSuppressor.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeDiagnosticSuppressor.kt @@ -16,6 +16,7 @@ package com.android.tools.compose +import com.android.tools.modules.* import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.project.Project import org.jetbrains.kotlin.diagnostics.Diagnostic @@ -46,7 +47,7 @@ class ComposeDiagnosticSuppressor : DiagnosticSuppressor { } override fun isSuppressed(diagnostic: Diagnostic, bindingContext: BindingContext?): Boolean { - if (!isComposeEnabled(diagnostic.psiElement)) return false + if (!diagnostic.psiElement.inComposeModule()) return false if (diagnostic.factory == Errors.NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION) { for (entry in ( diagnostic.psiElement.parent as KtAnnotatedExpression diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeFoldingBuilder.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeFoldingBuilder.kt index 9e302894c3..a54362c935 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeFoldingBuilder.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposeFoldingBuilder.kt @@ -15,6 +15,7 @@ */ package com.android.tools.compose +import com.android.tools.modules.* import com.intellij.lang.ASTNode import com.intellij.lang.folding.CustomFoldingBuilder import com.intellij.lang.folding.FoldingDescriptor @@ -33,7 +34,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType */ class ComposeFoldingBuilder : CustomFoldingBuilder() { override fun buildLanguageFoldRegions(descriptors: MutableList, root: PsiElement, document: Document, quick: Boolean) { - if (root !is KtFile || DumbService.isDumb(root.project) || !isComposeEnabled(root)) { + if (root !is KtFile || DumbService.isDumb(root.project) || !root.inComposeModule()) { return } diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginIrGenerationExtension.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginIrGenerationExtension.kt new file mode 100644 index 0000000000..7458bde098 --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginIrGenerationExtension.kt @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.tools.compose + +import androidx.compose.compiler.plugins.kotlin.ComposeIrGenerationExtension +import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment + +@Suppress("INVISIBLE_REFERENCE", "EXPERIMENTAL_IS_NOT_ENABLED") +@OptIn(org.jetbrains.kotlin.extensions.internal.InternalNonStableExtensionPoints::class) +class ComposePluginIrGenerationExtension : IrGenerationExtension { + override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { + try { + ComposeIrGenerationExtension(reportsDestination = null, + metricsDestination = null).generate(moduleFragment, pluginContext); + } catch (t : Throwable) { + t.printStackTrace() + } + } +} \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginUtils.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginUtils.kt index c5bb4e5cb9..0b303524a8 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginUtils.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/ComposePluginUtils.kt @@ -28,8 +28,6 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.supertypes -fun isComposeEnabled(element: PsiElement): Boolean = element.inComposeModule() ?: false - fun isModifierChainLongerThanTwo(element: KtElement): Boolean { if (element.getChildrenOfType().isNotEmpty()) { val fqName = element.resolveToCall(BodyResolveMode.PARTIAL)?.getReturnType()?.fqName?.asString() diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeImplementationsCompletionContributor.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeImplementationsCompletionContributor.kt index 18569a8b23..f5ef9cc356 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeImplementationsCompletionContributor.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeImplementationsCompletionContributor.kt @@ -22,8 +22,8 @@ import com.android.tools.compose.COMPOSE_ARRANGEMENT import com.android.tools.compose.COMPOSE_ARRANGEMENT_HORIZONTAL import com.android.tools.compose.COMPOSE_ARRANGEMENT_VERTICAL import com.android.tools.compose.isClassOrExtendsClass -import com.android.tools.compose.isComposeEnabled import com.android.tools.idea.flags.StudioFlags +import com.android.tools.modules.* import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionParameters import com.intellij.codeInsight.completion.CompletionResultSet @@ -67,7 +67,7 @@ class ComposeImplementationsCompletionContributor : CompletionContributor() { override fun fillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) { val elementToComplete = parameters.position - if (!StudioFlags.COMPOSE_EDITOR_SUPPORT.get() || !isComposeEnabled(elementToComplete) || parameters.originalFile !is KtFile) { + if (!StudioFlags.COMPOSE_EDITOR_SUPPORT.get() || !elementToComplete.inComposeModule() || parameters.originalFile !is KtFile) { return } val elementToCompleteTypeFqName = elementToComplete.argumentTypeFqName ?: elementToComplete.propertyTypeFqName diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeModifierCompletionContributor.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeModifierCompletionContributor.kt index 909df0af08..a71473be6b 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeModifierCompletionContributor.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/code/completion/ComposeModifierCompletionContributor.kt @@ -16,8 +16,8 @@ package com.android.tools.compose.code.completion import com.android.tools.compose.ComposeLibraryNamespace -import com.android.tools.compose.isComposeEnabled import com.android.tools.idea.flags.StudioFlags +import com.android.tools.modules.* import com.intellij.codeInsight.completion.CompletionContributor import com.intellij.codeInsight.completion.CompletionInitializationContext import com.intellij.codeInsight.completion.CompletionParameters @@ -95,7 +95,7 @@ class ComposeModifierCompletionContributor : CompletionContributor() { override fun fillCompletionVariants(parameters: CompletionParameters, resultSet: CompletionResultSet) { val element = parameters.position - if (!StudioFlags.COMPOSE_EDITOR_SUPPORT.get() || !isComposeEnabled(element) || parameters.originalFile !is KtFile) { + if (!StudioFlags.COMPOSE_EDITOR_SUPPORT.get() || !element.inComposeModule() || parameters.originalFile !is KtFile) { return } @@ -241,8 +241,8 @@ class ComposeModifierCompletionContributor : CompletionContributor() { val elementOnWhichMethodCalled: KtExpression = parent.safeAs()?.getReceiverExpression() ?: return false // Case Modifier.align().%this%, modifier.%this% val fqName = elementOnWhichMethodCalled.resolveToCall(BodyResolveMode.PARTIAL)?.getReturnType()?.fqName ?: - // Case Modifier.%this% - elementOnWhichMethodCalled.safeAs()?.resolve().safeAs()?.fqName + // Case Modifier.%this% + elementOnWhichMethodCalled.safeAs()?.resolve().safeAs()?.fqName return fqName?.asString() == modifierFqName } diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/debug/ComposePositionManager.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/debug/ComposePositionManager.kt index 0dbb7c301f..00950be087 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/debug/ComposePositionManager.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/debug/ComposePositionManager.kt @@ -15,22 +15,27 @@ */ package com.android.tools.compose.debug -import com.intellij.debugger.* -import com.intellij.debugger.engine.* -import com.intellij.debugger.engine.evaluation.* -import com.intellij.debugger.jdi.* -import com.intellij.debugger.requests.* -import com.intellij.openapi.application.* -import com.intellij.openapi.fileTypes.* -import com.intellij.util.* -import com.intellij.xdebugger.frame.* -import com.sun.jdi.* -import com.sun.jdi.request.* -import org.jetbrains.kotlin.fileClasses.* -import org.jetbrains.kotlin.idea.* -import org.jetbrains.kotlin.idea.debugger.* -import org.jetbrains.kotlin.load.kotlin.* -import org.jetbrains.kotlin.psi.* +import com.intellij.debugger.MultiRequestPositionManager +import com.intellij.debugger.NoDataException +import com.intellij.debugger.SourcePosition +import com.intellij.debugger.engine.DebugProcess +import com.intellij.debugger.engine.DebugProcessImpl +import com.intellij.debugger.engine.PositionManagerWithMultipleStackFrames +import com.intellij.debugger.engine.evaluation.EvaluationContext +import com.intellij.debugger.jdi.StackFrameProxyImpl +import com.intellij.debugger.requests.ClassPrepareRequestor +import com.intellij.openapi.application.runReadAction +import com.intellij.openapi.fileTypes.FileType +import com.intellij.util.ThreeState +import com.intellij.xdebugger.frame.XStackFrame +import com.sun.jdi.Location +import com.sun.jdi.ReferenceType +import com.sun.jdi.request.ClassPrepareRequest +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil +import org.jetbrains.kotlin.idea.KotlinFileType +import org.jetbrains.kotlin.idea.debugger.KotlinPositionManager +import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils +import org.jetbrains.kotlin.psi.KtFile /** * A PositionManager capable of setting breakpoints inside of ComposableSingleton lambdas. diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/formatting/ComposePostFormatProcessor.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/formatting/ComposePostFormatProcessor.kt index eed507bebe..7cd0813167 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/formatting/ComposePostFormatProcessor.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/formatting/ComposePostFormatProcessor.kt @@ -15,9 +15,9 @@ */ package com.android.tools.compose.formatting -import com.android.tools.compose.isComposeEnabled import com.android.tools.compose.isModifierChainLongerThanTwo import com.android.tools.compose.settings.ComposeCustomCodeStyleSettings +import com.android.tools.modules.* import com.intellij.application.options.CodeStyle import com.intellij.openapi.project.DumbService import com.intellij.openapi.util.TextRange @@ -42,9 +42,9 @@ class ComposePostFormatProcessor : PostFormatProcessor { private fun isAvailable(psiElement: PsiElement, settings: CodeStyleSettings): Boolean { return psiElement.containingFile is KtFile && - isComposeEnabled(psiElement) && - !DumbService.isDumb(psiElement.project) && - settings.getCustomSettings(ComposeCustomCodeStyleSettings::class.java).USE_CUSTOM_FORMATTING_FOR_MODIFIERS + psiElement.inComposeModule() && + !DumbService.isDumb(psiElement.project) && + settings.getCustomSettings(ComposeCustomCodeStyleSettings::class.java).USE_CUSTOM_FORMATTING_FOR_MODIFIERS } override fun processElement(source: PsiElement, settings: CodeStyleSettings): PsiElement { diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/settings/ComposeCustomCodeStyleSettings.java b/idea-plugin/src/main/kotlin/com/android/tools/compose/settings/ComposeCustomCodeStyleSettings.java new file mode 100644 index 0000000000..b0cbfb067e --- /dev/null +++ b/idea-plugin/src/main/kotlin/com/android/tools/compose/settings/ComposeCustomCodeStyleSettings.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tools.compose.settings; + +import com.intellij.psi.codeStyle.CodeStyleSettings; +import com.intellij.psi.codeStyle.CustomCodeStyleSettings; + +// Don't convert to Kotlin due to the serialization implementation for Settings. +public class ComposeCustomCodeStyleSettings extends CustomCodeStyleSettings { + public boolean USE_CUSTOM_FORMATTING_FOR_MODIFIERS = true; + + protected ComposeCustomCodeStyleSettings(CodeStyleSettings container) { + super("ComposeCustomCodeStyleSettings", container); + } + + public static ComposeCustomCodeStyleSettings getInstance(CodeStyleSettings settings) { + return settings.getCustomSettings(ComposeCustomCodeStyleSettings.class); + } +} \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/android/tools/compose/settings/ComposeCustomCodeStyleSettings.kt b/idea-plugin/src/main/kotlin/com/android/tools/compose/settings/ComposeCustomCodeStyleSettings.kt deleted file mode 100644 index e403921fb2..0000000000 --- a/idea-plugin/src/main/kotlin/com/android/tools/compose/settings/ComposeCustomCodeStyleSettings.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.tools.compose.settings - -import com.intellij.configurationStore.* -import com.intellij.psi.codeStyle.* - -class ComposeCustomCodeStyleSettings(settings: CodeStyleSettings) : CustomCodeStyleSettings("ComposeCustomCodeStyleSettings", settings) { - @Property(externalName = "use_custom_formatting_for_modifiers") - @JvmField - var USE_CUSTOM_FORMATTING_FOR_MODIFIERS = true - - companion object { - fun getInstance(settings: CodeStyleSettings): ComposeCustomCodeStyleSettings { - return settings.getCustomSettings(ComposeCustomCodeStyleSettings::class.java) - } - } -} \ No newline at end of file diff --git a/idea-plugin/src/main/kotlin/com/android/tools/modules/Module.kt b/idea-plugin/src/main/kotlin/com/android/tools/modules/Module.kt index a621a98236..efcdf05e55 100644 --- a/idea-plugin/src/main/kotlin/com/android/tools/modules/Module.kt +++ b/idea-plugin/src/main/kotlin/com/android/tools/modules/Module.kt @@ -5,8 +5,23 @@ package com.android.tools.modules -import com.intellij.openapi.module.Module +import com.android.tools.compose.* +import com.intellij.openapi.module.* +import com.intellij.openapi.roots.* import com.intellij.psi.* +import com.intellij.psi.search.* +import com.intellij.psi.util.* +import org.jetbrains.kotlin.idea.util.* -fun PsiElement.inComposeModule() = true -fun Module.isComposeModule() = true \ No newline at end of file +fun PsiElement.inComposeModule() = module?.isComposeModule() ?: false +fun Module.isComposeModule(): Boolean { + return CachedValuesManager.getManager(project).getCachedValue(this) { + val javaPsiFacade = JavaPsiFacade.getInstance(this.project) + val value = COMPOSABLE_FQ_NAMES.any { + javaPsiFacade.findClass(it, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(this)) != null + } + val rootModificationTracker = ProjectRootModificationTracker.getInstance(project) + CachedValueProvider.Result.create(value, rootModificationTracker) + } +} + diff --git a/idea-plugin/src/main/resources/META-INF/plugin.xml b/idea-plugin/src/main/resources/META-INF/plugin.xml index 0745614e12..2906ed56dd 100644 --- a/idea-plugin/src/main/resources/META-INF/plugin.xml +++ b/idea-plugin/src/main/resources/META-INF/plugin.xml @@ -25,6 +25,7 @@ +