AllOpen: Add IDE integration

This commit is contained in:
Yan Zhulanow
2016-12-01 17:43:00 +03:00
committed by Yan Zhulanow
parent 4d638c2cfd
commit 6abde4223b
53 changed files with 677 additions and 175 deletions
+95 -88
View File
@@ -1,90 +1,97 @@
<component name="ArtifactManager">
<artifact name="KotlinPlugin">
<output-path>$PROJECT_DIR$/out/artifacts/Kotlin</output-path>
<properties id="ant-postprocessing">
<options enabled="true">
<file>file://$PROJECT_DIR$/idea-runner/runner.xml</file>
<target>copy-runtime-for-idea-plugin</target>
</options>
</properties>
<root id="root">
<element id="directory" name="lib">
<element id="archive" name="kotlin-plugin.jar">
<element id="module-output" name="backend" />
<element id="module-output" name="frontend" />
<element id="module-output" name="descriptors" />
<element id="module-output" name="frontend.java" />
<element id="module-output" name="descriptor.loader.java" />
<element id="module-output" name="idea" />
<element id="module-output" name="light-classes" />
<element id="module-output" name="util" />
<element id="module-output" name="util.runtime" />
<element id="module-output" name="j2k" />
<element id="module-output" name="js.frontend" />
<element id="module-output" name="js.parser" />
<element id="module-output" name="cli-common" />
<element id="module-output" name="idea-jps-common" />
<element id="module-output" name="preloader" />
<element id="module-output" name="deserialization" />
<element id="module-output" name="backend-common" />
<element id="library" level="project" name="builtins" />
<element id="module-output" name="js.dart-ast" />
<element id="directory" name="kotlin">
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/native/kotlin" />
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/src/kotlin" />
</element>
<element id="module-output" name="eval4j" />
<element id="module-output" name="idea-analysis" />
<element id="module-output" name="ide-common" />
<element id="file-copy" path="$PROJECT_DIR$/resources/kotlinManifest.properties" />
<element id="module-output" name="idea-android" />
<element id="module-output" name="idea-android-output-parser" />
<element id="module-output" name="js.serializer" />
<element id="module-output" name="serialization" />
<element id="module-output" name="idea-completion" />
<element id="module-output" name="idea-core" />
<element id="module-output" name="container" />
<element id="module-output" name="daemon-common" />
<element id="module-output" name="idea-repl" />
<element id="module-output" name="idea-live-templates" />
<element id="module-output" name="resolution" />
<element id="module-output" name="plugin-api" />
<element id="module-output" name="idea-ultimate" />
<element id="module-output" name="formatter" />
<element id="module-output" name="idea-maven" />
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/protobuf-2.6.1.jar" path-in-jar="/" />
<element id="module-output" name="backend.common" />
<element id="module-output" name="ir.tree" />
<element id="module-output" name="backend.jvm" />
<element id="module-output" name="ir.psi2ir" />
</element>
<element id="library" level="project" name="javax.inject" />
<element id="directory" name="jps">
<element id="artifact" artifact-name="KotlinJpsPlugin" />
</element>
<element id="library" level="project" name="markdown" />
<element id="archive" name="kotlin-android-extensions-plugin.jar">
<element id="module-output" name="android-extensions-idea" />
</element>
<element id="archive" name="kotlin-android-extensions-compiler-plugin.jar">
<element id="module-output" name="android-extensions-compiler" />
</element>
<element id="archive" name="android-lint.jar">
<element id="module-output" name="uast-kotlin" />
<element id="module-output" name="lint-idea" />
<element id="module-output" name="uast-java" />
<element id="module-output" name="uast-common" />
<element id="module-output" name="lint-checks" />
<element id="library" level="project" name="guava" />
<element id="module-output" name="lint-api" />
<element id="module-output" name="uast-android" />
</element>
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-daemon-client.jar" />
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-script-runtime.jar" />
</element>
<element id="directory" name="kotlinc">
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
</element>
</root>
</artifact>
<artifact name="KotlinPlugin">
<output-path>$PROJECT_DIR$/out/artifacts/Kotlin</output-path>
<properties id="ant-postprocessing">
<options enabled="true">
<file>file://$PROJECT_DIR$/idea-runner/runner.xml</file>
<target>copy-runtime-for-idea-plugin</target>
</options>
</properties>
<root id="root">
<element id="directory" name="lib">
<element id="archive" name="kotlin-plugin.jar">
<element id="module-output" name="backend" />
<element id="module-output" name="frontend" />
<element id="module-output" name="descriptors" />
<element id="module-output" name="frontend.java" />
<element id="module-output" name="descriptor.loader.java" />
<element id="module-output" name="idea" />
<element id="module-output" name="light-classes" />
<element id="module-output" name="util" />
<element id="module-output" name="util.runtime" />
<element id="module-output" name="j2k" />
<element id="module-output" name="js.frontend" />
<element id="module-output" name="js.parser" />
<element id="module-output" name="cli-common" />
<element id="module-output" name="idea-jps-common" />
<element id="module-output" name="preloader" />
<element id="module-output" name="deserialization" />
<element id="module-output" name="backend-common" />
<element id="library" level="project" name="builtins" />
<element id="module-output" name="js.dart-ast" />
<element id="directory" name="kotlin">
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/native/kotlin" />
<element id="dir-copy" path="$PROJECT_DIR$/core/builtins/src/kotlin" />
</element>
<element id="module-output" name="eval4j" />
<element id="module-output" name="idea-analysis" />
<element id="module-output" name="ide-common" />
<element id="file-copy" path="$PROJECT_DIR$/resources/kotlinManifest.properties" />
<element id="module-output" name="idea-android" />
<element id="module-output" name="idea-android-output-parser" />
<element id="module-output" name="js.serializer" />
<element id="module-output" name="serialization" />
<element id="module-output" name="idea-completion" />
<element id="module-output" name="idea-core" />
<element id="module-output" name="container" />
<element id="module-output" name="daemon-common" />
<element id="module-output" name="idea-repl" />
<element id="module-output" name="idea-live-templates" />
<element id="module-output" name="resolution" />
<element id="module-output" name="plugin-api" />
<element id="module-output" name="idea-ultimate" />
<element id="module-output" name="formatter" />
<element id="module-output" name="idea-maven" />
<element id="extracted-dir" path="$PROJECT_DIR$/dependencies/protobuf-2.6.1.jar" path-in-jar="/" />
<element id="module-output" name="backend.common" />
<element id="module-output" name="ir.tree" />
<element id="module-output" name="backend.jvm" />
<element id="module-output" name="ir.psi2ir" />
<element id="module-output" name="annotation-based-compiler-plugins-ide-support" />
</element>
<element id="library" level="project" name="javax.inject" />
<element id="directory" name="jps">
<element id="artifact" artifact-name="KotlinJpsPlugin" />
</element>
<element id="library" level="project" name="markdown" />
<element id="archive" name="kotlin-android-extensions-plugin.jar">
<element id="module-output" name="android-extensions-idea" />
</element>
<element id="archive" name="kotlin-android-extensions-compiler-plugin.jar">
<element id="module-output" name="android-extensions-compiler" />
</element>
<element id="archive" name="android-lint.jar">
<element id="module-output" name="uast-kotlin" />
<element id="module-output" name="lint-idea" />
<element id="module-output" name="uast-java" />
<element id="module-output" name="uast-common" />
<element id="module-output" name="lint-checks" />
<element id="library" level="project" name="guava" />
<element id="module-output" name="lint-api" />
<element id="module-output" name="uast-android" />
</element>
<element id="archive" name="allopen-ide-plugin.jar">
<element id="module-output" name="allopen-ide" />
</element>
<element id="archive" name="allopen-compiler-plugin.jar">
<element id="module-output" name="allopen-cli" />
</element>
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-daemon-client.jar" />
<element id="file-copy" path="$PROJECT_DIR$/dist/kotlinc/lib/kotlin-script-runtime.jar" />
</element>
<element id="directory" name="kotlinc">
<element id="dir-copy" path="$PROJECT_DIR$/dist/kotlinc" />
</element>
</root>
</artifact>
</component>
+3 -1
View File
@@ -3,13 +3,15 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Kotlin.iml" filepath="$PROJECT_DIR$/Kotlin.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/allopen/allopen.iml" filepath="$PROJECT_DIR$/plugins/allopen/allopen.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/allopen/allopen-cli/allopen-cli.iml" filepath="$PROJECT_DIR$/plugins/allopen/allopen-cli/allopen-cli.iml" group="plugins/allopen" />
<module fileurl="file://$PROJECT_DIR$/plugins/allopen/allopen-ide/allopen-ide.iml" filepath="$PROJECT_DIR$/plugins/allopen/allopen-ide/allopen-ide.iml" group="plugins/allopen" />
<module fileurl="file://$PROJECT_DIR$/plugins/lint/android-annotations/android-annotations.iml" filepath="$PROJECT_DIR$/plugins/lint/android-annotations/android-annotations.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-compiler/android-extensions-compiler.iml" group="plugins/android-extensions" />
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-idea/android-extensions-idea.iml" group="plugins/android-extensions" />
<module fileurl="file://$PROJECT_DIR$/plugins/android-extensions/android-extensions-jps/android-extensions-jps.iml" filepath="$PROJECT_DIR$/plugins/android-extensions/android-extensions-jps/android-extensions-jps.iml" group="plugins/android-extensions" />
<module fileurl="file://$PROJECT_DIR$/android-studio/android-studio.iml" filepath="$PROJECT_DIR$/android-studio/android-studio.iml" group="ide" />
<module fileurl="file://$PROJECT_DIR$/compiler/android-tests/android-tests.iml" filepath="$PROJECT_DIR$/compiler/android-tests/android-tests.iml" group="compiler" />
<module fileurl="file://$PROJECT_DIR$/plugins/annotation-based-compiler-plugins-ide-support/annotation-based-compiler-plugins-ide-support.iml" filepath="$PROJECT_DIR$/plugins/annotation-based-compiler-plugins-ide-support/annotation-based-compiler-plugins-ide-support.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/annotation-collector/annotation-collector.iml" filepath="$PROJECT_DIR$/plugins/annotation-collector/annotation-collector.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/plugins/annotation-processing/annotation-processing.iml" filepath="$PROJECT_DIR$/plugins/annotation-processing/annotation-processing.iml" group="plugins" />
<module fileurl="file://$PROJECT_DIR$/ant/ant.iml" filepath="$PROJECT_DIR$/ant/ant.iml" />
+2 -2
View File
@@ -828,7 +828,7 @@
</withKotlin>
<skip pattern="kotlin/Metadata"/>
<src>
<pathelement path="plugins/allopen/src"/>
<pathelement path="plugins/allopen/allopen-cli/src"/>
</src>
<classpath>
<pathelement path="${idea.sdk}/core/intellij-core.jar"/>
@@ -839,7 +839,7 @@
<jar destfile="${kotlin-home}/lib/allopen-compiler-plugin.jar">
<fileset dir="${output}/classes/allopen-compiler-plugin"/>
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
<fileset dir="${basedir}/plugins/allopen/src" includes="META-INF/services/**"/>
<fileset dir="${basedir}/plugins/allopen/allopen-cli/src" includes="META-INF/services/**"/>
</jar>
</target>
@@ -48,6 +48,9 @@ public interface KotlinPaths {
@NotNull
File getJsStdLibSrcJarPath();
@NotNull
File getAllOpenPluginJarPath();
@NotNull
File getCompilerPath();
@@ -82,6 +82,12 @@ public class KotlinPathsFromHomeDir implements KotlinPaths {
return getLibraryFile(PathUtil.JS_LIB_SRC_JAR_NAME);
}
@NotNull
@Override
public File getAllOpenPluginJarPath() {
return getLibraryFile(PathUtil.ALLOPEN_PLUGIN_JAR_NAME);
}
@NotNull
@Override
public File getCompilerPath() {
@@ -29,6 +29,7 @@ public class PathUtil {
public static final String JPS_KOTLIN_HOME_PROPERTY = "jps.kotlin.home";
public static final String JS_LIB_JAR_NAME = "kotlin-jslib.jar";
public static final String ALLOPEN_PLUGIN_JAR_NAME = "allopen-compiler-plugin.jar";
public static final String JS_LIB_SRC_JAR_NAME = "kotlin-jslib-sources.jar";
public static final String KOTLIN_JAVA_RUNTIME_JAR = "kotlin-runtime.jar";
public static final String KOTLIN_JAVA_REFLECT_JAR = "kotlin-reflect.jar";
@@ -1159,7 +1159,7 @@ fun main(args: Array<String>) {
}
}
testGroup("plugins/plugins-tests/tests", "plugins/allopen/testData") {
testGroup("plugins/plugins-tests/tests", "plugins/allopen/allopen-cli/testData") {
testClass<AbstractBytecodeListingTestForAllOpen>() {
model("bytecodeListing", extension = "kt")
}
@@ -33,21 +33,31 @@ import org.jetbrains.idea.maven.model.MavenPlugin
import org.jetbrains.idea.maven.project.*
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.facet.configureFacet
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
import org.jetbrains.kotlin.idea.facet.initializeIfNeeded
import org.jetbrains.kotlin.idea.facet.mavenLibraryId
import org.jetbrains.kotlin.idea.maven.configuration.KotlinMavenConfigurator
import java.io.File
import java.util.*
private val KotlinPluginGroupId = "org.jetbrains.kotlin"
private val KotlinPluginArtifactId = "kotlin-maven-plugin"
private val KotlinPluginSourceDirsConfig = "sourceDirs"
interface MavenProjectImportHandler {
companion object : ProjectExtensionDescriptor<MavenProjectImportHandler>(
"org.jetbrains.kotlin.mavenProjectImportHandler",
MavenProjectImportHandler::class.java
)
operator fun invoke(facet: KotlinFacet, mavenProject: MavenProject)
}
class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_ARTIFACT_ID) {
companion object {
val KOTLIN_PLUGIN_GROUP_ID = "org.jetbrains.kotlin"
val KOTLIN_PLUGIN_ARTIFACT_ID = "kotlin-maven-plugin"
val KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG = "sourceDirs"
}
class KotlinMavenImporter : MavenImporter(KotlinPluginGroupId, KotlinPluginArtifactId) {
override fun preProcess(module: Module, mavenProject: MavenProject, changes: MavenProjectChanges, modifiableModelsProvider: IdeModifiableModelsProvider) {
}
@@ -70,7 +80,7 @@ class KotlinMavenImporter : MavenImporter(KotlinPluginGroupId, KotlinPluginArtif
if (changes.dependencies) {
// TODO: here we have to process all kotlin libraries but for now we only handle standard libraries
val artifacts = mavenProject.dependencyArtifactIndex.data[KotlinPluginGroupId]?.values?.flatMap { it.filter { it.isResolved } } ?: emptyList()
val artifacts = mavenProject.dependencyArtifactIndex.data[KOTLIN_PLUGIN_GROUP_ID]?.values?.flatMap { it.filter { it.isResolved } } ?: emptyList()
val librariesWithNoSources = ArrayList<Library>()
OrderEnumerator.orderEntries(module).forEachLibrary { library ->
@@ -93,7 +103,9 @@ class KotlinMavenImporter : MavenImporter(KotlinPluginGroupId, KotlinPluginArtif
private fun configureFacet(mavenProject: MavenProject, modifiableModelsProvider: IdeModifiableModelsProvider, module: Module) {
val compilerVersion = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID)?.version
?: return
module.getOrCreateFacet(modifiableModelsProvider).configureFacet(compilerVersion, modifiableModelsProvider)
val kotlinFacet = module.getOrCreateFacet(modifiableModelsProvider)
kotlinFacet.configureFacet(compilerVersion, modifiableModelsProvider)
MavenProjectImportHandler.getInstances(module.project).forEach { it(kotlinFacet, mavenProject) }
}
// TODO in theory it should work like this but it doesn't as it couldn't unmark source roots that are not roots anymore.
@@ -143,8 +155,8 @@ class KotlinMavenImporter : MavenImporter(KotlinPluginGroupId, KotlinPluginArtif
}.distinct()
}
private fun MavenPlugin.isKotlinPlugin() = groupId == KotlinPluginGroupId && artifactId == KotlinPluginArtifactId
private fun Element?.sourceDirectories(): List<String> = this?.getChildren(KotlinPluginSourceDirsConfig)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim } ?: emptyList()
private fun MavenPlugin.isKotlinPlugin() = groupId == KotlinMavenImporter.KOTLIN_PLUGIN_GROUP_ID && artifactId == KotlinMavenImporter.KOTLIN_PLUGIN_ARTIFACT_ID
private fun Element?.sourceDirectories(): List<String> = this?.getChildren(KotlinMavenImporter.KOTLIN_PLUGIN_SOURCE_DIRS_CONFIG)?.flatMap { it.children ?: emptyList() }?.map { it.textTrim } ?: emptyList()
private fun MavenPlugin.Execution.sourceType() =
goals.map { if (isTestGoalName(it)) SourceType.TEST else SourceType.PROD }
.distinct()
+4
View File
@@ -2,6 +2,10 @@
<extensionPoints>
<extensionPoint name="updater" beanClass="com.intellij.openapi.fileTypes.FileTypeExtensionPoint"/>
<extensionPoint name="projectConfigurator" interface="org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator"/>
<extensionPoint name="declarationAttributeAltererExtension"
interface="org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension"
area="IDEA_PROJECT"/>
</extensionPoints>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
+12 -7
View File
@@ -1,13 +1,14 @@
<idea-plugin>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
<versionInfoProvider implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinVersionInfoProvider"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
</extensions>
<extensionPoints>
<extensionPoint qualifiedName="org.jetbrains.kotlin.gradleProjectImportHandler" area="IDEA_PROJECT"
interface="org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
@@ -19,9 +20,7 @@
language="Groovy"
hasStaticDescription="true"
level="WARNING"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentStdlibGradleVersionInspection"
displayName="Kotlin library and Gradle plugin versions are different"
@@ -34,4 +33,10 @@
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
<versionInfoProvider implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinVersionInfoProvider"/>
</extensions>
</idea-plugin>
+8 -1
View File
@@ -2,9 +2,10 @@
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<projectConfigurator implementation="org.jetbrains.kotlin.idea.maven.configuration.KotlinJavaMavenConfigurator"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.maven.configuration.KotlinJavascriptMavenConfigurator"/>
<versionInfoProvider implementation="org.jetbrains.kotlin.idea.maven.facet.MavenKotlinVersionInfoProvider"/>
<mavenProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenMavenProjectImportHandler"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.idea.maven">
<importer implementation="org.jetbrains.kotlin.idea.maven.KotlinMavenImporter" />
<archetypesProvider implementation="org.jetbrains.kotlin.idea.maven.KotlinMavenArchetypesProvider" />
@@ -21,6 +22,12 @@
<param name="script" language="kotlin" />
</pluginDescriptor>
</extensions>
<extensionPoints>
<extensionPoint qualifiedName="org.jetbrains.kotlin.mavenProjectImportHandler" area="IDEA_PROJECT"
interface="org.jetbrains.kotlin.idea.maven.MavenProjectImportHandler"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<localInspection implementationClass="org.jetbrains.kotlin.idea.maven.inspections.KotlinMavenPluginPhaseInspection"
displayName="Kotlin Maven Plugin misconfigured"
+2
View File
@@ -2014,6 +2014,8 @@
<xi:include href="extensions/kotlin2jvm.xml" xpointer="xpointer(/idea-plugin/extensions/*)"/>
<xi:include href="extensions/kotlin2js.xml" xpointer="xpointer(/idea-plugin/extensions/*)"/>
<quickFixContributor implementation="org.jetbrains.kotlin.idea.quickfix.QuickFixRegistrar"/>
<declarationAttributeAltererExtension implementation="org.jetbrains.kotlin.allopen.ide.IdeAllOpenDeclarationAttributeAltererExtension"/>
</extensions>
</idea-plugin>
@@ -23,6 +23,8 @@ import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsPr
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.facet.configureFacet
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
import org.jetbrains.kotlin.idea.inspections.gradle.findAll
@@ -30,6 +32,15 @@ import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
interface GradleProjectImportHandler {
companion object : ProjectExtensionDescriptor<GradleProjectImportHandler>(
"org.jetbrains.kotlin.gradleProjectImportHandler",
GradleProjectImportHandler::class.java
)
operator fun invoke(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>)
}
class KotlinGradleProjectDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
override fun getTargetDataKey() = GradleSourceSetData.KEY
@@ -47,7 +58,9 @@ class KotlinGradleProjectDataService : AbstractProjectDataService<GradleSourceSe
val compilerVersion = moduleNode?.findAll(BuildScriptClasspathData.KEY)?.firstOrNull()?.data?.let(::findKotlinPluginVersion)
?: continue
ideModule.getOrCreateFacet(modelsProvider).configureFacet(compilerVersion, modelsProvider)
val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider)
kotlinFacet.configureFacet(compilerVersion, modelsProvider)
GradleProjectImportHandler.getInstances(project).forEach { it(kotlinFacet, sourceSetNode) }
}
}
}
@@ -37,7 +37,6 @@ import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase
val KOTLIN_PLUGIN_CLASSPATH_MARKER = "${KotlinWithGradleConfigurator.GROUP_ID}:${KotlinWithGradleConfigurator.GRADLE_PLUGIN_ID}:"
val KOTLIN_PLUGIN_PATH_MARKER = "${KotlinWithGradleConfigurator.GROUP_ID}/${KotlinWithGradleConfigurator.GRADLE_PLUGIN_ID}/"
abstract class KotlinGradleInspectionVisitor : BaseInspectionVisitor() {
override fun visitFile(file: GroovyFileBase?) {
@@ -72,14 +71,27 @@ fun getResolvedKotlinGradleVersion(module: Module): String? {
return null
}
// Gradle path (example): ~/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-runtime/<version>
private val KOTLIN_PLUGIN_PATH_MARKER = "${KotlinWithGradleConfigurator.GROUP_ID}/${KotlinWithGradleConfigurator.GRADLE_PLUGIN_ID}/"
// Maven local repo path (example): ~/.m2/repository/org/jetbrains/kotlin/kotlin-runtime/<version>
private val KOTLIN_PLUGIN_PATH_MARKER_FOR_MAVEN_LOCAL_REPO =
"${KotlinWithGradleConfigurator.GROUP_ID.replace('.', '/')}/${KotlinWithGradleConfigurator.GRADLE_PLUGIN_ID}/"
internal fun findKotlinPluginVersion(classpathData: BuildScriptClasspathData): String? {
for (classPathEntry in classpathData.classpathEntries) {
for (path in classPathEntry.classesFile) {
val uniformedPath = path.replace('\\', '/')
// check / for local maven repo, and '.' for gradle
if (uniformedPath.contains(KOTLIN_PLUGIN_PATH_MARKER)) {
val versionSubstring = uniformedPath.substringAfter(KOTLIN_PLUGIN_PATH_MARKER).substringBefore('/', "<error>")
if (versionSubstring != "<error>") {
return versionSubstring;
return versionSubstring
}
} else if (uniformedPath.contains(KOTLIN_PLUGIN_PATH_MARKER_FOR_MAVEN_LOCAL_REPO)) {
val versionSubstring = uniformedPath.substringAfter(KOTLIN_PLUGIN_PATH_MARKER_FOR_MAVEN_LOCAL_REPO).substringBefore('/', "<error>")
if (versionSubstring != "<error>") {
return versionSubstring
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.version>3.0.4</maven.version>
<allopen.src>${basedir}/../../../plugins/allopen/src</allopen.src>
<allopen.src>${basedir}/../../../plugins/allopen/allopen-cli/src</allopen.src>
<allopen.gradle.plugin.src>${basedir}/src/main/kotlin</allopen.gradle.plugin.src>
<allopen.gradle.plugin.resources>${basedir}/src/main/resources</allopen.gradle.plugin.resources>
<allopen.target-src>${basedir}/target/src/main/kotlin</allopen.target-src>
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.allopen.gradle
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.internal.AbstractTask
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
@@ -32,14 +34,39 @@ class AllOpenGradleSubplugin : Plugin<Project> {
}
}
fun Project.getBuildscriptArtifacts(): Set<ResolvedArtifact> =
buildscript.configurations.findByName("classpath")?.resolvedConfiguration?.resolvedArtifacts ?: emptySet()
override fun apply(project: Project) {
project.extensions.create("allOpen", AllOpenExtension::class.java)
val allOpenExtension = project.extensions.create("allOpen", AllOpenExtension::class.java)
project.afterEvaluate {
val fqNamesAsString = allOpenExtension.myAnnotations.joinToString(",")
project.extensions.extraProperties.set("kotlinAllOpenAnnotations", fqNamesAsString)
val allBuildscriptArtifacts = project.getBuildscriptArtifacts() + project.rootProject.getBuildscriptArtifacts()
val allOpenCompilerPluginFile = allBuildscriptArtifacts.filter {
val id = it.moduleVersion.id
id.group == AllOpenKotlinGradleSubplugin.ALLOPEN_GROUP_NAME
&& id.name == AllOpenKotlinGradleSubplugin.ALLOPEN_ARTIFACT_NAME
}.firstOrNull()?.file?.absolutePath ?: ""
open class TaskForAllOpen : AbstractTask()
project.tasks.add(project.tasks.create("allOpenDataStorageTask", TaskForAllOpen::class.java).apply {
isEnabled = false
description = "Supported annotations: " + fqNamesAsString +
"; Compiler plugin classpath: $allOpenCompilerPluginFile"
})
}
}
}
class AllOpenKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
private companion object {
val ANNOTATIONS_ARG_NAME = "annotation"
companion object {
val ALLOPEN_GROUP_NAME = "org.jetbrains.kotlin"
val ALLOPEN_ARTIFACT_NAME = "kotlin-allopen"
private val ANNOTATIONS_ARG_NAME = "annotation"
}
override fun isApplicable(project: Project, task: AbstractCompile) = AllOpenGradleSubplugin.isEnabled(project)
@@ -64,7 +91,7 @@ class AllOpenKotlinGradleSubplugin : KotlinGradleSubplugin<AbstractCompile> {
return options
}
override fun getArtifactName() = "kotlin-allopen"
override fun getGroupName() = "org.jetbrains.kotlin"
override fun getPluginName() = "org.jetbrains.kotlin.allopen"
override fun getGroupName() = ALLOPEN_GROUP_NAME
override fun getArtifactName() = ALLOPEN_ARTIFACT_NAME
override fun getCompilerPluginId() = "org.jetbrains.kotlin.allopen"
}
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.allopen
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
@@ -28,10 +27,14 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.TypeUtils
class AllOpenDeclarationAttributeAltererExtension(val allOpenAnnotationFqNames: List<String>) : DeclarationAttributeAltererExtension {
private companion object {
private val INHERITED_FQNAME = "java.lang.annotation.Inherited"
}
class CliAllOpenDeclarationAttributeAltererExtension(
private val allOpenAnnotationFqNames: List<String>
) : AbstractAllOpenDeclarationAttributeAltererExtension() {
override fun getAllOpenAnnotationFqNames(modifierListOwner: KtModifierListOwner) = allOpenAnnotationFqNames
}
abstract class AbstractAllOpenDeclarationAttributeAltererExtension : DeclarationAttributeAltererExtension {
abstract fun getAllOpenAnnotationFqNames(modifierListOwner: KtModifierListOwner): List<String>
override fun refineDeclarationModality(
modifierListOwner: KtModifierListOwner,
@@ -40,10 +43,8 @@ class AllOpenDeclarationAttributeAltererExtension(val allOpenAnnotationFqNames:
currentModality: Modality,
bindingContext: BindingContext
): Modality? {
// We alter only 'final' modality
when (currentModality) {
Modality.OPEN, Modality.ABSTRACT, Modality.SEALED -> return null
else -> {}
if (currentModality != Modality.FINAL) {
return null
}
// Explicit final
@@ -52,31 +53,34 @@ class AllOpenDeclarationAttributeAltererExtension(val allOpenAnnotationFqNames:
}
val descriptor = declaration ?: containingDeclaration ?: return null
if (descriptor.hasAllOpenAnnotation()) return Modality.OPEN
if (descriptor.hasAllOpenAnnotation(modifierListOwner)) return Modality.OPEN
return null
}
private fun DeclarationDescriptor.hasAllOpenAnnotation(): Boolean {
if (annotations.any { it.isAllOpenAnnotation() }) return true
private fun DeclarationDescriptor.hasAllOpenAnnotation(modifierListOwner: KtModifierListOwner): Boolean {
if (annotations.any { it.isAllOpenAnnotation(modifierListOwner) }) return true
if (this is ClassDescriptor) {
for (superType in TypeUtils.getAllSupertypes(defaultType)) {
val superTypeDescriptor = superType.constructor.declarationDescriptor as? ClassDescriptor ?: continue
if (superTypeDescriptor.annotations.any { it.isAllOpenAnnotation() }) return true
if (superTypeDescriptor.annotations.any { it.isAllOpenAnnotation(modifierListOwner) }) return true
}
}
return false
}
private fun AnnotationDescriptor.isAllOpenAnnotation(allowMetaAnnotations: Boolean = true): Boolean {
private fun AnnotationDescriptor.isAllOpenAnnotation(
modifierListOwner: KtModifierListOwner,
allowMetaAnnotations: Boolean = true
): Boolean {
val annotationType = type.constructor.declarationDescriptor ?: return false
if (annotationType.fqNameSafe.asString() in allOpenAnnotationFqNames) return true
if (annotationType.fqNameSafe.asString() in getAllOpenAnnotationFqNames(modifierListOwner)) return true
if (allowMetaAnnotations) {
for (metaAnnotation in annotationType.annotations) {
if (metaAnnotation.isAllOpenAnnotation(allowMetaAnnotations = false)) {
if (metaAnnotation.isAllOpenAnnotation(modifierListOwner, allowMetaAnnotations = false)) {
return true
}
}
@@ -34,9 +34,11 @@ class AllOpenCommandLineProcessor : CommandLineProcessor {
companion object {
val ANNOTATION_OPTION = CliOption("annotation", "<fqname>", "Annotation qualified names",
required = false, allowMultipleOccurrences = true)
val PLUGIN_ID = "org.jetbrains.kotlin.allopen"
}
override val pluginId = "org.jetbrains.kotlin.allopen"
override val pluginId = PLUGIN_ID
override val pluginOptions = listOf(ANNOTATION_OPTION)
override fun processOption(option: CliOption, value: String, configuration: CompilerConfiguration) = when (option) {
@@ -54,6 +56,6 @@ class AllOpenComponentRegistrar : ComponentRegistrar {
val annotations = configuration.get(AllOpenConfigurationKeys.ANNOTATION) ?: return
if (annotations.isEmpty()) return
DeclarationAttributeAltererExtension.registerExtension(project, AllOpenDeclarationAttributeAltererExtension(annotations))
DeclarationAttributeAltererExtension.registerExtension(project, CliAllOpenDeclarationAttributeAltererExtension(annotations))
}
}
@@ -0,0 +1,18 @@
annotation class AllOpen
@AllOpen
final class Test1
@AllOpen
class Test2 {
fun method1() {}
val prop1: String = ""
final fun method2() {}
final val prop2: String = ""
final var prop3: String = ""
// Modifier 'final' is not applicable to 'setter'
// var prop4: String = ""
// final set
}
@@ -13,9 +13,12 @@ public final class Test1 {
public class Test2 {
private final @org.jetbrains.annotations.NotNull field prop1: java.lang.String
private final @org.jetbrains.annotations.NotNull field prop2: java.lang.String
private @org.jetbrains.annotations.NotNull field prop3: java.lang.String
public method <init>(): void
public @org.jetbrains.annotations.NotNull method getProp1(): java.lang.String
public @org.jetbrains.annotations.NotNull method getProp2(): java.lang.String
public final @org.jetbrains.annotations.NotNull method getProp2(): java.lang.String
public final @org.jetbrains.annotations.NotNull method getProp3(): java.lang.String
public method method1(): void
public final method method2(): void
public final method setProp3(@org.jetbrains.annotations.NotNull p0: java.lang.String): void
}
@@ -20,9 +20,9 @@ interface Intf {
}
open class IntfImpl : Intf {
fun intfImplMethod_ShouldBeFinal() {}
fun intfImplMethod_ShouldBeOpen() {}
}
class IntfImpl2_ShouldBeFinalBecauseIntfIsAnInterface : IntfImpl() {
fun intfImpl2Method_ShouldBeFinal() {}
class IntfImpl2_ShouldBeOpen : IntfImpl() {
fun intfImpl2Method_ShouldBeOpen() {}
}
@@ -39,12 +39,12 @@ public interface Intf {
@kotlin.Metadata
public class IntfImpl {
public method <init>(): void
public final method intfImplMethod_ShouldBeFinal(): void
public method intfImplMethod_ShouldBeOpen(): void
public method intfMethod(): void
}
@kotlin.Metadata
public final class IntfImpl2_ShouldBeFinalBecauseIntfIsAnInterface {
public class IntfImpl2_ShouldBeOpen {
public method <init>(): void
public final method intfImpl2Method_ShouldBeFinal(): void
public method intfImpl2Method_ShouldBeOpen(): void
}
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="allopen-cli" />
<orderEntry type="library" name="idea-full" level="project" />
<orderEntry type="library" name="gradle-and-groovy-plugin" level="project" />
<orderEntry type="module" module-name="idea" />
<orderEntry type="module" module-name="idea-maven" />
<orderEntry type="library" name="maven" level="project" />
<orderEntry type="module" module-name="cli-common" />
<orderEntry type="module" module-name="idea-jps-common" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="annotation-based-compiler-plugins-ide-support" />
</component>
</module>
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.allopen.ide
import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor
import org.jetbrains.kotlin.annotation.plugin.ide.AbstractGradleImportHandler
import org.jetbrains.kotlin.utils.PathUtil
class AllOpenGradleProjectImportHandler : AbstractGradleImportHandler() {
override val compilerPluginId = AllOpenCommandLineProcessor.PLUGIN_ID
override val pluginName = "allopen"
override val annotationOptionName = AllOpenCommandLineProcessor.ANNOTATION_OPTION.name
override val dataStorageTaskName = "allOpenDataStorageTask"
override val pluginJarFileFromIdea = PathUtil.getKotlinPathsForIdeaPlugin().allOpenPluginJarPath
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.allopen.ide
import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor
import org.jetbrains.kotlin.annotation.plugin.ide.AbstractMavenImportHandler
class AllOpenMavenProjectImportHandler : AbstractMavenImportHandler() {
private companion object {
val ANNOTATION_PARAMETER_PREFIX = "all-open:${AllOpenCommandLineProcessor.ANNOTATION_OPTION.name}="
private val SPRING_ALLOPEN_ANNOTATIONS = listOf(
"org.springframework.stereotype.Component",
"org.springframework.transaction.annotation.Transactional",
"org.springframework.scheduling.annotation.Async",
"org.springframework.cache.annotation.Cacheable"
)
}
override val compilerPluginId = AllOpenCommandLineProcessor.PLUGIN_ID
override val pluginName = "allopen"
override val annotationOptionName = AllOpenCommandLineProcessor.ANNOTATION_OPTION.name
override val mavenPluginArtifactName = "kotlin-maven-allopen"
override fun getAnnotations(enabledCompilerPlugins: List<String>, compilerPluginOptions: List<String>): List<String>? {
if ("all-open" !in enabledCompilerPlugins && "spring" !in enabledCompilerPlugins) {
return null
}
val annotations = mutableListOf<String>()
if ("spring" in enabledCompilerPlugins) {
annotations.addAll(SPRING_ALLOPEN_ANNOTATIONS)
}
annotations.addAll(compilerPluginOptions.mapNotNull { text ->
if (!text.startsWith(ANNOTATION_PARAMETER_PREFIX)) return@mapNotNull null
text.substring(ANNOTATION_PARAMETER_PREFIX.length)
})
return annotations
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.allopen.ide
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.psi.util.CachedValue
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import org.jetbrains.kotlin.allopen.AbstractAllOpenDeclarationAttributeAltererExtension
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor.Companion.PLUGIN_ID
import org.jetbrains.kotlin.allopen.AllOpenCommandLineProcessor.Companion.ANNOTATION_OPTION
import java.util.*
class IdeAllOpenDeclarationAttributeAltererExtension(val project: Project) : AbstractAllOpenDeclarationAttributeAltererExtension() {
private companion object {
val ANNOTATION_OPTION_PREFIX = "plugin:$PLUGIN_ID:${ANNOTATION_OPTION.name}="
}
private val cache: CachedValue<WeakHashMap<Module, List<String>>> = cachedValue(project) {
CachedValueProvider.Result.create(WeakHashMap<Module, List<String>>(), ProjectRootModificationTracker.getInstance(project))
}
override fun getAllOpenAnnotationFqNames(modifierListOwner: KtModifierListOwner): List<String> {
val project = modifierListOwner.project
val virtualFile = modifierListOwner.containingFile?.virtualFile ?: return emptyList()
val module = ProjectRootManager.getInstance(project).fileIndex.getModuleForFile(virtualFile) ?: return emptyList()
return cache.value.getOrPut(module) {
val kotlinFacet = KotlinFacet.get(module) ?: return@getOrPut emptyList()
val commonArgs = kotlinFacet.configuration.settings.compilerInfo.commonCompilerArguments ?: return@getOrPut emptyList()
commonArgs.pluginOptions?.filter { it.startsWith(ANNOTATION_OPTION_PREFIX) }
?.map { it.substring(ANNOTATION_OPTION_PREFIX.length) }
?: emptyList()
}
}
private fun <T> cachedValue(project: Project, result: () -> CachedValueProvider.Result<T>): CachedValue<T> {
return CachedValuesManager.getManager(project).createCachedValue(result, false)
}
}
@@ -1,13 +0,0 @@
annotation class AllOpen
@AllOpen
final class Test1
@AllOpen
class Test2 {
fun method1() {}
val prop1: String = ""
final fun method2() {}
val prop2: String = ""
}
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
<orderEntry type="module" module-name="idea" />
<orderEntry type="module" module-name="idea-maven" />
<orderEntry type="module" module-name="cli-common" />
<orderEntry type="library" name="idea-full" level="project" />
<orderEntry type="library" name="maven" level="project" />
<orderEntry type="library" name="gradle-and-groovy-plugin" level="project" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="idea-jps-common" />
</component>
</module>
@@ -0,0 +1,66 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.annotation.plugin.ide
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.task.TaskData
import org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
import java.io.File
abstract class AbstractGradleImportHandler : GradleProjectImportHandler {
private companion object {
private val TASK_DESCRIPTION_REGEX = "Supported annotations: (.*?); Compiler plugin classpath: (.*)".toRegex()
}
abstract val compilerPluginId: String
abstract val pluginName: String
abstract val annotationOptionName: String
abstract val dataStorageTaskName: String
abstract val pluginJarFileFromIdea: File
override fun invoke(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>) {
modifyCompilerArgumentsForPlugin(facet, getPluginSetup(sourceSetNode),
compilerPluginId = compilerPluginId,
pluginName = pluginName,
annotationOptionName = annotationOptionName)
}
private fun getPluginSetup(
sourceSetNode: DataNode<GradleSourceSetData>
): AnnotationBasedCompilerPluginSetup? {
val moduleNode = sourceSetNode.parent ?: return null
if (moduleNode.data !is ModuleData) return null
val dataStorageTaskData = moduleNode.children.firstOrNull {
val data = it.data as? TaskData ?: return@firstOrNull false
data.name == dataStorageTaskName
}?.data as? TaskData ?: return null
val dataStorageTaskDescription = dataStorageTaskData.description ?: return null
val (annotationFqNamesList, classpathList) = TASK_DESCRIPTION_REGEX.matchEntire(
dataStorageTaskDescription)?.groupValues?.drop(1) ?: return null
val annotationFqNames = annotationFqNamesList.split(',')
// For now we can't use plugins from Gradle cause they're shaded. So we use ones from the IDEA plugin
val classpath = listOf(pluginJarFileFromIdea.absolutePath)
return AnnotationBasedCompilerPluginSetup(annotationFqNames, classpath)
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.annotation.plugin.ide
import org.jdom.Element
import org.jdom.Text
import org.jetbrains.idea.maven.project.MavenProject
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.maven.MavenProjectImportHandler
import org.jetbrains.kotlin.idea.maven.KotlinMavenImporter.Companion.KOTLIN_PLUGIN_GROUP_ID
import org.jetbrains.kotlin.idea.maven.KotlinMavenImporter.Companion.KOTLIN_PLUGIN_ARTIFACT_ID
import java.io.File
abstract class AbstractMavenImportHandler : MavenProjectImportHandler {
abstract val compilerPluginId: String
abstract val pluginName: String
abstract val annotationOptionName: String
abstract val mavenPluginArtifactName: String
override fun invoke(facet: KotlinFacet, mavenProject: MavenProject) {
modifyCompilerArgumentsForPlugin(facet, getPluginSetup(mavenProject),
compilerPluginId = compilerPluginId,
pluginName = pluginName,
annotationOptionName = annotationOptionName)
}
abstract fun getAnnotations(enabledCompilerPlugins: List<String>, compilerPluginOptions: List<String>): List<String>?
private fun getPluginSetup(mavenProject: MavenProject): AnnotationBasedCompilerPluginSetup? {
val kotlinPlugin = mavenProject.plugins.firstOrNull {
it.groupId == KOTLIN_PLUGIN_GROUP_ID && it.artifactId == KOTLIN_PLUGIN_ARTIFACT_ID
} ?: return null
val runtimeJarFile = mavenProject.dependencies
.firstOrNull { it.groupId == KOTLIN_PLUGIN_GROUP_ID &&
(it.artifactId == "kotlin-runtime" || it.artifactId == "kotlin-stdlib") }
?.file ?: return null
val runtimeVersion = runtimeJarFile.parentFile.name
val mavenCompilerPluginJar = File(runtimeJarFile.parentFile.parentFile.parentFile,
"$mavenPluginArtifactName/$runtimeVersion/$mavenPluginArtifactName-$runtimeVersion.jar")
val configuration = kotlinPlugin.configurationElement ?: return null
val enabledCompilerPlugins = configuration.getElement("compilerPlugins")
?.getElements()
?.flatMap { plugin -> plugin.content.mapNotNull { (it as? Text)?.text } }
?: emptyList()
val compilerPluginOptions = configuration.getElement("pluginOptions")
?.getElements()
?.flatMap { it.content }
?.mapTo(mutableListOf()) { (it as Text).text }
?: mutableListOf<String>()
val annotationFqNames = getAnnotations(enabledCompilerPlugins, compilerPluginOptions) ?: return null
return AnnotationBasedCompilerPluginSetup(annotationFqNames, listOf(mavenCompilerPluginJar.absolutePath))
}
private fun Element.getElement(name: String) = content.firstOrNull { it is Element && it.name == name } as? Element
@Suppress("UNCHECKED_CAST")
private fun Element.getElements() = content.filterIsInstance<Element>()
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.annotation.plugin.ide
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.idea.facet.KotlinFacet
internal class AnnotationBasedCompilerPluginSetup(val annotationFqNames: List<String>, val classpath: List<String>)
internal fun modifyCompilerArgumentsForPlugin(
facet: KotlinFacet,
setup: AnnotationBasedCompilerPluginSetup?,
compilerPluginId: String,
pluginName: String,
annotationOptionName: String
) {
val compileInfo = facet.configuration.settings.compilerInfo
// investigate why copyBean() sometimes throws exceptions
val commonArguments = compileInfo.commonCompilerArguments ?: CommonCompilerArguments.DummyImpl()
/** See [CommonCompilerArguments.PLUGIN_OPTION_FORMAT] **/
val annotationOptions = setup?.annotationFqNames?.map { "plugin:$compilerPluginId:$annotationOptionName=$it" } ?: emptyList()
val oldPluginOptions = (commonArguments.pluginOptions ?: emptyArray()).filterTo(mutableListOf()) { !it.startsWith("plugin:$compilerPluginId:") }
val newPluginOptions = oldPluginOptions + annotationOptions
val oldPluginClasspaths = (commonArguments.pluginClasspaths ?: emptyArray()).filterTo(mutableListOf()) {
!it.substringAfterLast('/', missingDelimiterValue = "").matches("(kotlin-)?$pluginName-.*\\.jar".toRegex())
}
val newPluginClasspaths = oldPluginClasspaths + (setup?.classpath ?: emptyList())
commonArguments.pluginOptions = newPluginOptions.toTypedArray()
commonArguments.pluginClasspaths = newPluginClasspaths.toTypedArray()
compileInfo.commonCompilerArguments = commonArguments
}
+1 -1
View File
@@ -37,6 +37,6 @@
<orderEntry type="module" module-name="build-common" scope="TEST" />
<orderEntry type="module" module-name="jps-tests" scope="TEST" />
<orderEntry type="module" module-name="kapt3" scope="TEST" />
<orderEntry type="module" module-name="allopen" scope="TEST" />
<orderEntry type="module" module-name="allopen-cli" scope="TEST" />
</component>
</module>
@@ -25,8 +25,8 @@ abstract class AbstractBytecodeListingTestForAllOpen : AbstractBytecodeListingTe
val ALLOPEN_ANNOTATIONS = listOf("AllOpen", "AllOpen2", "test.AllOpen")
}
override fun setUpEnvironment(environment: KotlinCoreEnvironment) {
override fun setupEnvironment(environment: KotlinCoreEnvironment) {
DeclarationAttributeAltererExtension.registerExtension(
environment.project, AllOpenDeclarationAttributeAltererExtension(ALLOPEN_ANNOTATIONS))
environment.project, CliAllOpenDeclarationAttributeAltererExtension(ALLOPEN_ANNOTATIONS))
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.allopen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
@@ -27,71 +28,71 @@ import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/allopen/testData/bytecodeListing")
@TestMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class BytecodeListingTestForAllOpenGenerated extends AbstractBytecodeListingTestForAllOpen {
public void testAllFilesPresentInBytecodeListing() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/allopen/testData/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), true);
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/allopen/allopen-cli/testData/bytecodeListing"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("allOpenOnNotClasses.kt")
public void testAllOpenOnNotClasses() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/allOpenOnNotClasses.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/allOpenOnNotClasses.kt");
doTest(fileName);
}
@TestMetadata("alreadyOpen.kt")
public void testAlreadyOpen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/alreadyOpen.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/alreadyOpen.kt");
doTest(fileName);
}
@TestMetadata("explicitFinal.kt")
public void testExplicitFinal() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/explicitFinal.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/explicitFinal.kt");
doTest(fileName);
}
@TestMetadata("metaAnnotation.kt")
public void testMetaAnnotation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/metaAnnotation.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/metaAnnotation.kt");
doTest(fileName);
}
@TestMetadata("nestedInner.kt")
public void testNestedInner() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/nestedInner.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/nestedInner.kt");
doTest(fileName);
}
@TestMetadata("noAllOpen.kt")
public void testNoAllOpen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/noAllOpen.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/noAllOpen.kt");
doTest(fileName);
}
@TestMetadata("sealed.kt")
public void testSealed() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/sealed.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/sealed.kt");
doTest(fileName);
}
@TestMetadata("severalAllOpen.kt")
public void testSeveralAllOpen() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/severalAllOpen.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/severalAllOpen.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/simple.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/simple.kt");
doTest(fileName);
}
@TestMetadata("superClassAnnotation.kt")
public void testSuperClassAnnotation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/testData/bytecodeListing/superClassAnnotation.kt");
String fileName = KotlinTestUtils.navigationMetadata("plugins/allopen/allopen-cli/testData/bytecodeListing/superClassAnnotation.kt");
doTest(fileName);
}
}