mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-11 00:21:31 +00:00
Compare commits
82 Commits
rr/pdn_byt
...
master_172
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdcbf49610 | ||
|
|
82ae6b4f05 | ||
|
|
b9148948da | ||
|
|
55247d6944 | ||
|
|
c9b510ce4b | ||
|
|
a1fe66c819 | ||
|
|
2d598ea639 | ||
|
|
924f24b189 | ||
|
|
f81cc4bb72 | ||
|
|
9eccb4d9d2 | ||
|
|
9b724f31b9 | ||
|
|
aa346aa77d | ||
|
|
de664c234e | ||
|
|
04b9e4be4d | ||
|
|
4f4f1c3b3c | ||
|
|
af52dd19c5 | ||
|
|
f35bd41c88 | ||
|
|
ca03f13c5c | ||
|
|
25ead7e78d | ||
|
|
7f9c7bc8d5 | ||
|
|
061a484790 | ||
|
|
c06f150187 | ||
|
|
d0a15721b3 | ||
|
|
eb66af98f0 | ||
|
|
e1c4a62365 | ||
|
|
ad78c11432 | ||
|
|
e959429408 | ||
|
|
5f2e8a4d4a | ||
|
|
4667836852 | ||
|
|
8da5ae155e | ||
|
|
2134c4d207 | ||
|
|
3551d537a0 | ||
|
|
56b40b9725 | ||
|
|
5266db3767 | ||
|
|
cf130b0648 | ||
|
|
fb14e3996c | ||
|
|
c8aaae29d8 | ||
|
|
94ab177ef6 | ||
|
|
14a6863848 | ||
|
|
39d2ca6ad5 | ||
|
|
43fbcd22e6 | ||
|
|
03b92adefe | ||
|
|
f17603acc3 | ||
|
|
cc0cabfb39 | ||
|
|
3f57f182e0 | ||
|
|
37527679c2 | ||
|
|
10f4bbb940 | ||
|
|
5083f4264e | ||
|
|
5e593e8226 | ||
|
|
f92fdb73a8 | ||
|
|
1bca6a9926 | ||
|
|
273310e40a | ||
|
|
018991a69b | ||
|
|
39e86434d4 | ||
|
|
7bbb777fa0 | ||
|
|
55f2283890 | ||
|
|
eab5d7aa74 | ||
|
|
a0a5febc90 | ||
|
|
bfeee946cb | ||
|
|
dd38c1a8a2 | ||
|
|
6b7094b8ea | ||
|
|
32329500e2 | ||
|
|
0d51edcc02 | ||
|
|
4140934233 | ||
|
|
b584bde45d | ||
|
|
b5338c9f40 | ||
|
|
cc42d924ee | ||
|
|
de060dbc81 | ||
|
|
4627b5e412 | ||
|
|
f946fc481e | ||
|
|
0555700daa | ||
|
|
118dee51a5 | ||
|
|
86cc48f509 | ||
|
|
39d23198ab | ||
|
|
58b2f09cf6 | ||
|
|
c18ead17b6 | ||
|
|
7c3a34c0cf | ||
|
|
8a8f01c4ad | ||
|
|
5cb27c9fbf | ||
|
|
190bae16e3 | ||
|
|
53a58ed013 | ||
|
|
d5425608a1 |
@@ -28,7 +28,6 @@ import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.lang.MetaLanguage
|
||||
import com.intellij.lang.java.JavaParserDefinition
|
||||
import com.intellij.lang.jvm.facade.JvmElementProvider
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.TransactionGuard
|
||||
import com.intellij.openapi.application.TransactionGuardImpl
|
||||
@@ -44,7 +43,6 @@ import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.openapi.vfs.impl.ZipHandler
|
||||
import com.intellij.psi.FileContextProvider
|
||||
import com.intellij.psi.JavaModuleSystem
|
||||
import com.intellij.psi.PsiElementFinder
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.augment.PsiAugmentProvider
|
||||
@@ -395,7 +393,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val ideaCompatibleBuildNumber = "173.1"
|
||||
private val ideaCompatibleBuildNumber = "172.9999"
|
||||
|
||||
init {
|
||||
setCompatibleBuild()
|
||||
@@ -518,8 +516,6 @@ class KotlinCoreEnvironment private constructor(
|
||||
//
|
||||
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), TypeAnnotationModifier.EP_NAME, TypeAnnotationModifier::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), MetaLanguage.EP_NAME, MetaLanguage::class.java)
|
||||
//
|
||||
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), JavaModuleSystem.EP_NAME, JavaModuleSystem::class.java)
|
||||
}
|
||||
|
||||
private fun registerApplicationExtensionPointsAndExtensionsFrom(configuration: CompilerConfiguration, configFilePath: String) {
|
||||
@@ -570,7 +566,6 @@ class KotlinCoreEnvironment private constructor(
|
||||
private fun registerProjectExtensionPoints(area: ExtensionsArea) {
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, PsiTreeChangePreprocessor.EP_NAME, PsiTreeChangePreprocessor::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, PsiElementFinder.EP_NAME, PsiElementFinder::class.java)
|
||||
CoreApplicationEnvironment.registerExtensionPoint(area, JvmElementProvider.EP_NAME, JvmElementProvider::class.java)
|
||||
}
|
||||
|
||||
// made public for Upsource
|
||||
|
||||
@@ -50,7 +50,6 @@ messages/**)
|
||||
-dontwarn net.jpountz.lz4.LZ4Factory
|
||||
-dontwarn org.jetbrains.annotations.ReadOnly
|
||||
-dontwarn org.jetbrains.annotations.Mutable
|
||||
-dontwarn com.intellij.util.io.TarUtil
|
||||
|
||||
#-libraryjars '<rtjar>'
|
||||
#-libraryjars '<jssejar>'
|
||||
|
||||
@@ -28,8 +28,8 @@ enum class JvmTarget(override val description: String) : TargetPlatformVersion {
|
||||
JVM_1_6 -> Opcodes.V1_6
|
||||
JVM_1_8 ->
|
||||
when {
|
||||
java.lang.Boolean.valueOf(System.getProperty("kotlin.test.substitute.bytecode.1.8.to.10")) -> Opcodes.V9 + 1
|
||||
java.lang.Boolean.valueOf(System.getProperty("kotlin.test.substitute.bytecode.1.8.to.1.9")) -> Opcodes.V9
|
||||
java.lang.Boolean.valueOf(System.getProperty("kotlin.test.substitute.bytecode.1.8.to.10")) -> Opcodes.V1_9 + 1
|
||||
java.lang.Boolean.valueOf(System.getProperty("kotlin.test.substitute.bytecode.1.8.to.1.9")) -> Opcodes.V1_9
|
||||
else -> Opcodes.V1_8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.ErrorValue
|
||||
|
||||
val JVM_STATIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmStatic")
|
||||
private val JVM_STATIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmStatic")
|
||||
|
||||
val JVM_FIELD_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmField")
|
||||
|
||||
|
||||
@@ -55,12 +55,6 @@ abstract class KtLightAbstractAnnotation(parent: PsiElement, computeDelegate: ()
|
||||
|
||||
override fun getParameterList() = clsDelegate.parameterList
|
||||
|
||||
override fun canNavigate(): Boolean = super<KtLightElementBase>.canNavigate()
|
||||
|
||||
override fun canNavigateToSource(): Boolean = super<KtLightElementBase>.canNavigateToSource()
|
||||
|
||||
override fun navigate(requestFocus: Boolean) = super<KtLightElementBase>.navigate(requestFocus)
|
||||
|
||||
open fun fqNameMatches(fqName: String): Boolean = qualifiedName == fqName
|
||||
}
|
||||
|
||||
@@ -319,12 +313,6 @@ class KtLightNonExistentAnnotation(parent: KtLightElement<*, *>) : KtLightElemen
|
||||
override fun findDeclaredAttributeValue(attributeName: String?) = null
|
||||
override fun getMetaData() = null
|
||||
override fun getParameterList() = KtLightEmptyAnnotationParameterList(this)
|
||||
|
||||
override fun canNavigate(): Boolean = super<KtLightElementBase>.canNavigate()
|
||||
|
||||
override fun canNavigateToSource(): Boolean = super<KtLightElementBase>.canNavigateToSource()
|
||||
|
||||
override fun navigate(requestFocus: Boolean) = super<KtLightElementBase>.navigate(requestFocus)
|
||||
}
|
||||
|
||||
class KtLightEmptyAnnotationParameterList(parent: PsiElement) : KtLightElementBase(parent), PsiAnnotationParameterList {
|
||||
|
||||
@@ -325,8 +325,6 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
return createProperty(text + " val x").modifierList!!
|
||||
}
|
||||
|
||||
fun createEmptyModifierList() = createModifierList(KtTokens.PRIVATE_KEYWORD).apply { firstChild.delete() }
|
||||
|
||||
fun createModifier(modifier: KtModifierKeywordToken): PsiElement {
|
||||
return createModifierList(modifier.value).getModifier(modifier)!!
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// FILE: a/a.java
|
||||
package a;
|
||||
|
||||
public class a {}
|
||||
|
||||
// FILE: a/b.java
|
||||
package a;
|
||||
|
||||
public class b {
|
||||
public void a_b() {}
|
||||
}
|
||||
|
||||
// FILE: test/a.java
|
||||
package test;
|
||||
|
||||
public class a {}
|
||||
|
||||
// FILE: test/d.java
|
||||
package test;
|
||||
|
||||
public class d {
|
||||
public a.b getB() { return null; }
|
||||
}
|
||||
|
||||
// FILE: b.kt
|
||||
package test
|
||||
|
||||
val x = d().getB()
|
||||
|
||||
// FILE: test/c.java
|
||||
package test;
|
||||
|
||||
import a.a;
|
||||
|
||||
public class c {
|
||||
public static a getA() { return null; }
|
||||
}
|
||||
|
||||
// FILE: c.kt
|
||||
package test
|
||||
|
||||
fun foo() {
|
||||
val a = c.getA()
|
||||
a.<!UNRESOLVED_REFERENCE!>a<!>
|
||||
a.<!UNRESOLVED_REFERENCE!>a<!>()
|
||||
}
|
||||
@@ -139,8 +139,18 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
||||
}
|
||||
|
||||
var exceptionFromDescriptorValidation: Throwable? = null
|
||||
val originalTestFile = testDataFile.readText()
|
||||
try {
|
||||
val expectedFile = getExpectedDescriptorFile(testDataFile, files)
|
||||
val postfix = when {
|
||||
InTextDirectivesUtils.isDirectiveDefined(originalTestFile, "// JAVAC_EXPECTED_FILE") &&
|
||||
environment.configuration.getBoolean(JVMConfigurationKeys.USE_JAVAC) -> ".javac.txt"
|
||||
|
||||
InTextDirectivesUtils.isDirectiveDefined(originalTestFile, "// NI_EXPECTED_FILE") &&
|
||||
files.any { it.newInferenceEnabled } && !USE_OLD_INFERENCE_DIAGNOSTICS_FOR_NI -> ".ni.txt"
|
||||
|
||||
else -> ".txt"
|
||||
}
|
||||
val expectedFile = File(FileUtil.getNameWithoutExtension(testDataFile.absolutePath) + postfix)
|
||||
validateAndCompareDescriptorWithFile(expectedFile, files, modules)
|
||||
} catch (e: Throwable) {
|
||||
exceptionFromDescriptorValidation = e
|
||||
@@ -175,7 +185,7 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
||||
exceptionFromDynamicCallDescriptorsValidation = e
|
||||
}
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(getExpectedDiagnosticsFile(testDataFile), actualText.toString())
|
||||
KotlinTestUtils.assertEqualsToFile(testDataFile, actualText.toString())
|
||||
|
||||
assertTrue("Diagnostics mismatch. See the output above", ok)
|
||||
|
||||
@@ -187,26 +197,6 @@ abstract class AbstractDiagnosticsTest : BaseDiagnosticsTest() {
|
||||
performAdditionalChecksAfterDiagnostics(testDataFile, files, groupedByModule, modules, moduleBindings)
|
||||
}
|
||||
|
||||
protected open fun getExpectedDiagnosticsFile(testDataFile: File): File {
|
||||
return testDataFile
|
||||
}
|
||||
|
||||
protected open fun getExpectedDescriptorFile(testDataFile: File, files: List<TestFile>): File {
|
||||
val originalTestFileText = testDataFile.readText()
|
||||
|
||||
val postfix = when {
|
||||
InTextDirectivesUtils.isDirectiveDefined(originalTestFileText, "// JAVAC_EXPECTED_FILE") &&
|
||||
environment.configuration.getBoolean(JVMConfigurationKeys.USE_JAVAC) -> ".javac.txt"
|
||||
|
||||
InTextDirectivesUtils.isDirectiveDefined(originalTestFileText, "// NI_EXPECTED_FILE") &&
|
||||
files.any { it.newInferenceEnabled } && !USE_OLD_INFERENCE_DIAGNOSTICS_FOR_NI -> ".ni.txt"
|
||||
|
||||
else -> ".txt"
|
||||
}
|
||||
|
||||
return File(FileUtil.getNameWithoutExtension(testDataFile.absolutePath) + postfix)
|
||||
}
|
||||
|
||||
protected open fun performAdditionalChecksAfterDiagnostics(
|
||||
testDataFile: File,
|
||||
testFiles: List<TestFile>,
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.checkers.javac
|
||||
|
||||
import org.jetbrains.kotlin.checkers.AbstractDiagnosticsTest
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractJavacDiagnosticsTest : AbstractDiagnosticsTest() {
|
||||
@@ -40,19 +39,5 @@ abstract class AbstractJavacDiagnosticsTest : AbstractDiagnosticsTest() {
|
||||
super.doTest(path)
|
||||
}
|
||||
|
||||
override fun getExpectedDiagnosticsFile(testDataFile: File): File {
|
||||
val suffix = if (useJavac) ".WithJavac.txt" else ".WithoutJavac.txt"
|
||||
val specialFile = File(testDataFile.parent, testDataFile.name + suffix)
|
||||
return specialFile.takeIf { it.exists() } ?: super.getExpectedDiagnosticsFile(testDataFile)
|
||||
}
|
||||
|
||||
override fun createTestFiles(file: File, expectedText: String, modules: MutableMap<String, ModuleAndDependencies>?): List<TestFile> {
|
||||
val specialFile = getExpectedDiagnosticsFile(file)
|
||||
if (file.path == specialFile.path) {
|
||||
return super.createTestFiles(file, expectedText, modules)
|
||||
}
|
||||
|
||||
return super.createTestFiles(specialFile, KotlinTestUtils.doLoadFile(specialFile), modules)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.testFramework
|
||||
|
||||
import com.intellij.mock.MockApplication
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import javax.swing.SwingUtilities
|
||||
@@ -41,12 +39,7 @@ fun runInEdtAndWait(runnable: () -> Unit) {
|
||||
}
|
||||
else {
|
||||
try {
|
||||
val application = ApplicationManager.getApplication()
|
||||
.takeIf { it !is MockApplication } // because MockApplication do nothing instead of `invokeAndWait`
|
||||
if (application != null)
|
||||
application.invokeAndWait(runnable)
|
||||
else
|
||||
SwingUtilities.invokeAndWait(runnable)
|
||||
SwingUtilities.invokeAndWait(runnable)
|
||||
}
|
||||
catch (e: InvocationTargetException) {
|
||||
throw e.cause ?: e
|
||||
|
||||
@@ -52,7 +52,6 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public abstract class KtUsefulTestCase extends TestCase {
|
||||
@@ -218,11 +217,9 @@ public abstract class KtUsefulTestCase extends TestCase {
|
||||
protected void runTest() throws Throwable {
|
||||
Throwable[] throwables = new Throwable[1];
|
||||
|
||||
AtomicBoolean completed = new AtomicBoolean(false);
|
||||
Runnable runnable = () -> {
|
||||
try {
|
||||
super.runTest();
|
||||
completed.set(true);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
e.fillInStackTrace();
|
||||
@@ -242,9 +239,6 @@ public abstract class KtUsefulTestCase extends TestCase {
|
||||
if (throwables[0] != null) {
|
||||
throw throwables[0];
|
||||
}
|
||||
if (!completed.get()) {
|
||||
throw new IllegalStateException("test didn't start");
|
||||
}
|
||||
}
|
||||
|
||||
private static void invokeTestRunnable(@NotNull Runnable runnable) throws Exception {
|
||||
|
||||
@@ -30,15 +30,14 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class MockFileManager implements FileManager {
|
||||
private final PsiManagerEx myManager;
|
||||
// in mock tests it's LightVirtualFile, they're only alive when they're referenced,
|
||||
// and there can not be several instances representing the same file
|
||||
private final ConcurrentMap<VirtualFile, FileViewProvider> myViewProviders = new ConcurrentWeakFactoryMap<VirtualFile, FileViewProvider>() {
|
||||
private final FactoryMap<VirtualFile, FileViewProvider> myViewProviders = new ConcurrentWeakFactoryMap<VirtualFile, FileViewProvider>() {
|
||||
@Override
|
||||
protected ConcurrentMap<VirtualFile, FileViewProvider> createMap() {
|
||||
protected Map<VirtualFile, FileViewProvider> createMap() {
|
||||
return ContainerUtil.createConcurrentWeakKeyWeakValueMap();
|
||||
}
|
||||
|
||||
|
||||
@@ -135,9 +135,7 @@ import org.jetbrains.kotlin.idea.scratch.AbstractScratchRunActionTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationCompletionTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationHighlightingTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationNavigationTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerLeafGroupingTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerNullnessGroupingTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerTreeTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerTest
|
||||
import org.jetbrains.kotlin.idea.structureView.AbstractKotlinFileStructureTest
|
||||
import org.jetbrains.kotlin.idea.stubs.AbstractMultiFileHighlightingTest
|
||||
import org.jetbrains.kotlin.idea.stubs.AbstractResolveByStubTest
|
||||
@@ -749,18 +747,10 @@ fun main(args: Array<String>) {
|
||||
model("refactoring/nameSuggestionProvider")
|
||||
}
|
||||
|
||||
testClass<AbstractSlicerTreeTest> {
|
||||
testClass<AbstractSlicerTest> {
|
||||
model("slicer", singleClass = true)
|
||||
}
|
||||
|
||||
testClass<AbstractSlicerLeafGroupingTest> {
|
||||
model("slicer/inflow", singleClass = true)
|
||||
}
|
||||
|
||||
testClass<AbstractSlicerNullnessGroupingTest> {
|
||||
model("slicer/inflow", singleClass = true)
|
||||
}
|
||||
|
||||
testClass<AbstractScratchRunActionTest> {
|
||||
model("scratch", extension = "kts", testMethod = "doCompilingTest", testClassName = "Compiling", recursive = false)
|
||||
model("scratch", extension = "kts", testMethod = "doReplTest", testClassName = "Repl", recursive = false)
|
||||
|
||||
@@ -85,13 +85,12 @@ public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
|
||||
private void writeExternalBase(Element element, CommonCodeStyleSettings defaultSettings) throws WriteExternalException {
|
||||
Set<String> supportedFields = getSupportedFields();
|
||||
if (supportedFields != null) {
|
||||
supportedFields.add("PARENT_SETTINGS_INSTALLED");
|
||||
supportedFields.add("FORCE_REARRANGE_MODE");
|
||||
supportedFields.add("CODE_STYLE_DEFAULTS");
|
||||
}
|
||||
//noinspection deprecation
|
||||
DefaultJDOMExternalizer.writeExternal(this, element, new SupportedFieldsDiffFilter(this, supportedFields, defaultSettings));
|
||||
List<Integer> softMargins = getSoftMargins();
|
||||
serializeInto(softMargins, element);
|
||||
|
||||
IndentOptions myIndentOptions = getIndentOptions();
|
||||
if (myIndentOptions != null) {
|
||||
@@ -140,21 +139,6 @@ public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
|
||||
commonSettings.setArrangementSettings(arrangementSettings.clone());
|
||||
}
|
||||
|
||||
try {
|
||||
Method setRootSettingsMethod = ArraysKt.singleOrNull(
|
||||
CommonCodeStyleSettings.class.getDeclaredMethods(),
|
||||
method -> "setSoftMargins".equals(method.getName()));
|
||||
|
||||
if (setRootSettingsMethod != null) {
|
||||
// Method was introduced in 173
|
||||
setRootSettingsMethod.setAccessible(true);
|
||||
setRootSettingsMethod.invoke(commonSettings, getSoftMargins());
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
return commonSettings;
|
||||
}
|
||||
|
||||
@@ -169,9 +153,6 @@ public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
|
||||
}
|
||||
|
||||
CommonCodeStyleSettings other = (CommonCodeStyleSettings) obj;
|
||||
if (!getSoftMargins().equals(other.getSoftMargins())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IndentOptions options = getIndentOptions();
|
||||
if ((options == null && other.getIndentOptions() != null) ||
|
||||
@@ -181,13 +162,6 @@ public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
|
||||
|
||||
return arrangementSettingsEqual(other);
|
||||
}
|
||||
|
||||
// SoftMargins.serializeInfo
|
||||
private void serializeInto(@NotNull List<Integer> softMargins, @NotNull Element element) {
|
||||
if (softMargins.size() > 0) {
|
||||
XmlSerializer.serializeInto(this, element);
|
||||
}
|
||||
}
|
||||
//</editor-fold>
|
||||
|
||||
//<editor-fold desc="Copied from CommonCodeStyleSettings">
|
||||
|
||||
@@ -33,7 +33,7 @@ class KtLightClassForDecompiledDeclaration(
|
||||
override val kotlinOrigin: KtClassOrObject?,
|
||||
private val file: KtClsFile
|
||||
) : KtLightClassBase(clsDelegate.manager) {
|
||||
val fqName = kotlinOrigin?.fqName ?: FqName(clsDelegate.qualifiedName.orEmpty())
|
||||
val fqName = kotlinOrigin?.fqName ?: FqName(clsDelegate.qualifiedName)
|
||||
|
||||
override fun copy() = this
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.addRemoveModifier.MODIFIERS_ORDER
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.psi.typeRefHelpers.setReceiverTypeReference
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
@@ -44,7 +43,6 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <reified T : PsiElement> PsiElement.replaced(newElement: T): T {
|
||||
@@ -449,30 +447,6 @@ fun KtParameter.setDefaultValue(newDefaultValue: KtExpression): PsiElement? {
|
||||
return addAfter(newDefaultValue, eq) as KtExpression
|
||||
}
|
||||
|
||||
fun KtModifierList.appendModifier(modifier: KtModifierKeywordToken) {
|
||||
add(KtPsiFactory(this).createModifier(modifier))
|
||||
}
|
||||
|
||||
fun KtModifierList.normalize(): KtModifierList {
|
||||
val psiFactory = KtPsiFactory(this)
|
||||
return psiFactory.createEmptyModifierList().also { newList ->
|
||||
val modifiers = SmartList<PsiElement>()
|
||||
allChildren.forEach {
|
||||
val elementType = it.node.elementType
|
||||
when {
|
||||
it is KtAnnotation || it is KtAnnotationEntry -> newList.add(it)
|
||||
elementType is KtModifierKeywordToken -> {
|
||||
if (elementType == KtTokens.DEFAULT_VISIBILITY_KEYWORD) return@forEach
|
||||
if (elementType == KtTokens.FINALLY_KEYWORD && !hasModifier(KtTokens.OVERRIDE_KEYWORD)) return@forEach
|
||||
modifiers.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
modifiers.sortBy { MODIFIERS_ORDER.indexOf(it.node.elementType) }
|
||||
modifiers.forEach { newList.add(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun KtBlockStringTemplateEntry.canDropBraces() =
|
||||
expression is KtNameReferenceExpression && canPlaceAfterSimpleNameEntry(nextSibling)
|
||||
|
||||
|
||||
@@ -14,14 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.slicer
|
||||
@file:JvmName("GradleKotlinDSLConstants")
|
||||
|
||||
import com.intellij.slicer.SliceRootNode
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
package org.jetbrains.kotlin.gradle.kdsl
|
||||
|
||||
abstract class AbstractSlicerTreeTest : AbstractSlicerTest() {
|
||||
override fun doTest(path: String, sliceProvider: KotlinSliceProvider, rootNode: SliceRootNode) {
|
||||
KotlinTestUtils.assertEqualsToFile(File(path.replace(".kt", ".results.txt")), buildTreeRepresentation(rootNode))
|
||||
}
|
||||
}
|
||||
const val DEFAULT_SCRIPT_NAME = "build.gradle.kts"
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.gradle.kdsl.GradleFrameworksWizardStep">
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="22e59" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="ad16" binding="myOptionsPanel" layout-manager="CardLayout" hgap="0" vgap="0">
|
||||
<constraints border-constraint="Center"/>
|
||||
<properties/>
|
||||
<clientProperties>
|
||||
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithoutIndent"/>
|
||||
</clientProperties>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="27a92" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<card name="templates card"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<grid id="b50ee" binding="myFrameworksPanelPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<card name="frameworks card"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="916d9" class="com.intellij.ui.components.JBLabel" binding="myFrameworksLabel">
|
||||
<constraints border-constraint="North"/>
|
||||
<properties>
|
||||
<text value="Additional Libraries and &Frameworks:"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.gradle.kdsl;
|
||||
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider;
|
||||
import com.intellij.ide.util.newProjectWizard.AddSupportForFrameworksPanel;
|
||||
import com.intellij.ide.util.newProjectWizard.impl.FrameworkSupportModelBase;
|
||||
import com.intellij.ide.util.projectWizard.ModuleBuilder;
|
||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
|
||||
import com.intellij.ide.util.projectWizard.WizardContext;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer;
|
||||
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.components.JBLabel;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleFrameworkSupportProvider;
|
||||
import org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleJavaFrameworkSupportProvider;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class GradleFrameworksWizardStep extends ModuleWizardStep implements Disposable {
|
||||
|
||||
private JPanel myPanel;
|
||||
private final AddSupportForFrameworksPanel myFrameworksPanel;
|
||||
private JPanel myFrameworksPanelPlaceholder;
|
||||
private JPanel myOptionsPanel;
|
||||
@SuppressWarnings("unused") private JBLabel myFrameworksLabel;
|
||||
|
||||
public GradleFrameworksWizardStep(WizardContext context, final ModuleBuilder builder) {
|
||||
|
||||
Project project = context.getProject();
|
||||
final LibrariesContainer container = LibrariesContainerFactory.createContainer(context.getProject());
|
||||
FrameworkSupportModelBase model = new FrameworkSupportModelBase(project, null, container) {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getBaseDirectoryForLibrariesPath() {
|
||||
return StringUtil.notNullize(builder.getContentEntryPath());
|
||||
}
|
||||
};
|
||||
|
||||
myFrameworksPanel =
|
||||
new AddSupportForFrameworksPanel(Collections.emptyList(), model, true, null);
|
||||
|
||||
List<FrameworkSupportInModuleProvider> providers = ContainerUtil.newArrayList();
|
||||
Collections.addAll(providers, GradleFrameworkSupportProvider.EP_NAME.getExtensions());
|
||||
|
||||
myFrameworksPanel.setProviders(providers, Collections.emptySet(), Collections.singleton(GradleJavaFrameworkSupportProvider.ID));
|
||||
Disposer.register(this, myFrameworksPanel);
|
||||
myFrameworksPanelPlaceholder.add(myFrameworksPanel.getMainPanel());
|
||||
|
||||
ModuleBuilder.ModuleConfigurationUpdater configurationUpdater = new ModuleBuilder.ModuleConfigurationUpdater() {
|
||||
@Override
|
||||
public void update(@NotNull Module module, @NotNull ModifiableRootModel rootModel) {
|
||||
myFrameworksPanel.addSupport(module, rootModel);
|
||||
}
|
||||
};
|
||||
builder.addModuleConfigurationUpdater(configurationUpdater);
|
||||
|
||||
((CardLayout)myOptionsPanel.getLayout()).show(myOptionsPanel, "frameworks card");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getComponent() {
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDataModel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
Disposer.dispose(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.gradle.kdsl;
|
||||
|
||||
import com.intellij.ide.fileTemplates.FileTemplate;
|
||||
import com.intellij.ide.fileTemplates.FileTemplateManager;
|
||||
import com.intellij.ide.highlighter.ModuleFileType;
|
||||
import com.intellij.ide.projectWizard.ProjectSettingsStep;
|
||||
import com.intellij.ide.util.EditorHelper;
|
||||
import com.intellij.ide.util.projectWizard.JavaModuleBuilder;
|
||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
|
||||
import com.intellij.ide.util.projectWizard.SettingsStep;
|
||||
import com.intellij.ide.util.projectWizard.WizardContext;
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.components.StorageScheme;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.externalSystem.importing.ImportSpec;
|
||||
import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder;
|
||||
import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectId;
|
||||
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode;
|
||||
import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl;
|
||||
import com.intellij.openapi.externalSystem.service.project.wizard.AbstractExternalModuleBuilder;
|
||||
import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep;
|
||||
import com.intellij.openapi.externalSystem.settings.AbstractExternalSystemSettings;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
|
||||
import com.intellij.openapi.module.*;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkType;
|
||||
import com.intellij.openapi.projectRoots.SdkTypeId;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.gradle.util.GradleVersion;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.BuildScriptDataBuilder;
|
||||
import org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.KotlinBuildScriptDataBuilder;
|
||||
import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl;
|
||||
import org.jetbrains.plugins.gradle.settings.DistributionType;
|
||||
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings;
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.kotlin.gradle.kdsl.GradleKotlinDSLConstants.DEFAULT_SCRIPT_NAME;
|
||||
|
||||
public class GradleModuleBuilder extends AbstractExternalModuleBuilder<GradleProjectSettings> {
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(GradleModuleBuilder.class);
|
||||
|
||||
private static final String TEMPLATE_GRADLE_SETTINGS = "Gradle Kotlin DSL Settings.gradle";
|
||||
private static final String TEMPLATE_GRADLE_SETTINGS_MERGE = "Gradle Settings merge.gradle";
|
||||
private static final String TEMPLATE_GRADLE_BUILD_WITH_WRAPPER = "Gradle Build Script with wrapper.gradle";
|
||||
private static final String DEFAULT_TEMPLATE_GRADLE_BUILD = "Gradle Kotlin DSL Build Script.gradle";
|
||||
|
||||
private static final String TEMPLATE_ATTRIBUTE_PROJECT_NAME = "PROJECT_NAME";
|
||||
private static final String TEMPLATE_ATTRIBUTE_MODULE_PATH = "MODULE_PATH";
|
||||
private static final String TEMPLATE_ATTRIBUTE_MODULE_FLAT_DIR = "MODULE_FLAT_DIR";
|
||||
private static final String TEMPLATE_ATTRIBUTE_MODULE_NAME = "MODULE_NAME";
|
||||
private static final String TEMPLATE_ATTRIBUTE_MODULE_GROUP = "MODULE_GROUP";
|
||||
private static final String TEMPLATE_ATTRIBUTE_MODULE_VERSION = "MODULE_VERSION";
|
||||
private static final String TEMPLATE_ATTRIBUTE_GRADLE_VERSION = "GRADLE_VERSION";
|
||||
private static final String TEMPLATE_ATTRIBUTE_BUILD_FILE_NAME = "BUILD_FILE_NAME";
|
||||
private static final Key<KotlinBuildScriptDataBuilder> BUILD_SCRIPT_DATA =
|
||||
Key.create("gradle.module.kotlinBuildScriptData");
|
||||
|
||||
private WizardContext myWizardContext;
|
||||
|
||||
@Nullable
|
||||
private ProjectData myParentProject;
|
||||
private boolean myInheritGroupId;
|
||||
private boolean myInheritVersion;
|
||||
private ProjectId myProjectId;
|
||||
private String rootProjectPath;
|
||||
|
||||
public GradleModuleBuilder() {
|
||||
super(GradleConstants.SYSTEM_ID, new GradleProjectSettings());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
return "Gradle (Kotlin DSL)";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Module createModule(@NotNull ModifiableModuleModel moduleModel)
|
||||
throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException {
|
||||
LOG.assertTrue(getName() != null);
|
||||
final String originModuleFilePath = getModuleFilePath();
|
||||
LOG.assertTrue(originModuleFilePath != null);
|
||||
|
||||
String moduleName;
|
||||
if (myProjectId == null) {
|
||||
moduleName = getName();
|
||||
}
|
||||
else {
|
||||
moduleName = ModuleGrouperKt.isQualifiedModuleNamesEnabled() && StringUtil.isNotEmpty(myProjectId.getGroupId())
|
||||
? (myProjectId.getGroupId() + '.' + myProjectId.getArtifactId())
|
||||
: myProjectId.getArtifactId();
|
||||
}
|
||||
Project contextProject = myWizardContext.getProject();
|
||||
String projectFileDirectory = null;
|
||||
if (myWizardContext.isCreatingNewProject() || contextProject == null || contextProject.getBasePath() == null) {
|
||||
projectFileDirectory = myWizardContext.getProjectFileDirectory();
|
||||
}
|
||||
else if (myWizardContext.getProjectStorageFormat() == StorageScheme.DEFAULT) {
|
||||
String moduleFileDirectory = getModuleFileDirectory();
|
||||
if (moduleFileDirectory != null) {
|
||||
projectFileDirectory = moduleFileDirectory;
|
||||
}
|
||||
}
|
||||
if (projectFileDirectory == null) {
|
||||
projectFileDirectory = contextProject.getBasePath();
|
||||
}
|
||||
if (myWizardContext.getProjectStorageFormat() == StorageScheme.DIRECTORY_BASED) {
|
||||
projectFileDirectory += "/.idea/modules";
|
||||
}
|
||||
String moduleFilePath = projectFileDirectory + "/" + moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION;
|
||||
deleteModuleFile(moduleFilePath);
|
||||
final ModuleType moduleType = getModuleType();
|
||||
final Module module = moduleModel.newModule(moduleFilePath, moduleType.getId());
|
||||
setupModule(module);
|
||||
return module;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupRootModel(final ModifiableRootModel modifiableRootModel) throws ConfigurationException {
|
||||
String contentEntryPath = getContentEntryPath();
|
||||
if (StringUtil.isEmpty(contentEntryPath)) {
|
||||
return;
|
||||
}
|
||||
File contentRootDir = new File(contentEntryPath);
|
||||
FileUtilRt.createDirectory(contentRootDir);
|
||||
LocalFileSystem fileSystem = LocalFileSystem.getInstance();
|
||||
VirtualFile modelContentRootDir = fileSystem.refreshAndFindFileByIoFile(contentRootDir);
|
||||
if (modelContentRootDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
modifiableRootModel.addContentEntry(modelContentRootDir);
|
||||
// todo this should be moved to generic ModuleBuilder
|
||||
if (myJdk != null) {
|
||||
modifiableRootModel.setSdk(myJdk);
|
||||
}
|
||||
else {
|
||||
modifiableRootModel.inheritSdk();
|
||||
}
|
||||
|
||||
final Project project = modifiableRootModel.getProject();
|
||||
if (myParentProject != null) {
|
||||
rootProjectPath = myParentProject.getLinkedExternalProjectPath();
|
||||
}
|
||||
else {
|
||||
rootProjectPath =
|
||||
FileUtil.toCanonicalPath(myWizardContext.isCreatingNewProject() ? project.getBasePath() : modelContentRootDir.getPath());
|
||||
}
|
||||
assert rootProjectPath != null;
|
||||
|
||||
final VirtualFile gradleBuildFile = setupGradleBuildFile(modelContentRootDir);
|
||||
setupGradleSettingsFile(
|
||||
rootProjectPath, modelContentRootDir, modifiableRootModel.getProject().getName(),
|
||||
myProjectId == null ? modifiableRootModel.getModule().getName() : myProjectId.getArtifactId(),
|
||||
myWizardContext.isCreatingNewProject() || myParentProject == null
|
||||
);
|
||||
|
||||
if (gradleBuildFile != null) {
|
||||
modifiableRootModel.getModule().putUserData(
|
||||
BUILD_SCRIPT_DATA, new KotlinBuildScriptDataBuilder(gradleBuildFile));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupModule(Module module) throws ConfigurationException {
|
||||
super.setupModule(module);
|
||||
assert rootProjectPath != null;
|
||||
|
||||
VirtualFile buildScriptFile = null;
|
||||
final BuildScriptDataBuilder buildScriptDataBuilder = getBuildScriptData(module);
|
||||
try {
|
||||
if (buildScriptDataBuilder != null) {
|
||||
buildScriptFile = buildScriptDataBuilder.getBuildScriptFile();
|
||||
String lineSeparator = lineSeparator(buildScriptFile);
|
||||
String configurationPart = StringUtil.convertLineSeparators(buildScriptDataBuilder.buildConfigurationPart(), lineSeparator);
|
||||
String existingText = StringUtil.trimTrailing(VfsUtilCore.loadText(buildScriptFile));
|
||||
String content = (!configurationPart.isEmpty() ? configurationPart + lineSeparator : "") +
|
||||
(!existingText.isEmpty() ? existingText + lineSeparator : "") +
|
||||
lineSeparator +
|
||||
StringUtil.convertLineSeparators(buildScriptDataBuilder.buildMainPart(), lineSeparator);
|
||||
VfsUtil.saveText(buildScriptFile, content);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn("Unexpected exception on applying frameworks templates", e);
|
||||
}
|
||||
|
||||
final Project project = module.getProject();
|
||||
if (myWizardContext.isCreatingNewProject()) {
|
||||
getExternalProjectSettings().setExternalProjectPath(rootProjectPath);
|
||||
AbstractExternalSystemSettings settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID);
|
||||
project.putUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT, Boolean.TRUE);
|
||||
//noinspection unchecked
|
||||
settings.linkProject(getExternalProjectSettings());
|
||||
}
|
||||
else {
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
final GradleProjectSettings gradleProjectSettings = getExternalProjectSettings();
|
||||
final VirtualFile finalBuildScriptFile = buildScriptFile;
|
||||
Runnable runnable = () -> {
|
||||
if (myParentProject == null) {
|
||||
gradleProjectSettings.setExternalProjectPath(rootProjectPath);
|
||||
AbstractExternalSystemSettings settings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID);
|
||||
//noinspection unchecked
|
||||
settings.linkProject(gradleProjectSettings);
|
||||
}
|
||||
|
||||
ImportSpec importSpec = new ImportSpecBuilder(project, GradleConstants.SYSTEM_ID)
|
||||
.use(ProgressExecutionMode.IN_BACKGROUND_ASYNC)
|
||||
.createDirectoriesForEmptyContentRoots()
|
||||
.useDefaultCallback()
|
||||
.build();
|
||||
ExternalSystemUtil.refreshProject(rootProjectPath, importSpec);
|
||||
|
||||
final PsiFile psiFile;
|
||||
if (finalBuildScriptFile != null) {
|
||||
psiFile = PsiManager.getInstance(project).findFile(finalBuildScriptFile);
|
||||
if (psiFile != null) {
|
||||
EditorHelper.openInEditor(psiFile);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// execute when current dialog is closed
|
||||
ExternalSystemUtil.invokeLater(project, ModalityState.NON_MODAL, runnable);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider) {
|
||||
myWizardContext = wizardContext;
|
||||
return new ModuleWizardStep[]{
|
||||
new GradleModuleWizardStep(this, wizardContext),
|
||||
new ExternalModuleSettingsStep<>(
|
||||
wizardContext, this, new GradleProjectSettingsControl(getExternalProjectSettings()))
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
|
||||
final GradleFrameworksWizardStep step = new GradleFrameworksWizardStep(context, this);
|
||||
Disposer.register(parentDisposable, step);
|
||||
return step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuitableSdkType(SdkTypeId sdk) {
|
||||
return sdk instanceof JavaSdkType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentGroup() {
|
||||
return JavaModuleType.BUILD_TOOLS_GROUP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeight() {
|
||||
return JavaModuleBuilder.BUILD_SYSTEM_WEIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModuleType getModuleType() {
|
||||
return StdModuleTypes.JAVA;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VirtualFile setupGradleBuildFile(@NotNull VirtualFile modelContentRootDir)
|
||||
throws ConfigurationException {
|
||||
final VirtualFile file = getOrCreateExternalProjectConfigFile(modelContentRootDir.getPath(), GradleKotlinDSLConstants.DEFAULT_SCRIPT_NAME);
|
||||
|
||||
if (file != null) {
|
||||
final String templateName = getExternalProjectSettings().getDistributionType() == DistributionType.WRAPPED
|
||||
? TEMPLATE_GRADLE_BUILD_WITH_WRAPPER
|
||||
: DEFAULT_TEMPLATE_GRADLE_BUILD;
|
||||
Map<String, String> attributes = ContainerUtil.newHashMap();
|
||||
if (myProjectId != null) {
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_VERSION, myProjectId.getVersion());
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_GROUP, myProjectId.getGroupId());
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_GRADLE_VERSION, GradleVersion.current().getVersion());
|
||||
}
|
||||
saveFile(file, templateName, attributes);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static VirtualFile setupGradleSettingsFile(@NotNull String rootProjectPath,
|
||||
@NotNull VirtualFile modelContentRootDir,
|
||||
String projectName,
|
||||
String moduleName,
|
||||
boolean renderNewFile)
|
||||
throws ConfigurationException {
|
||||
final VirtualFile file = getOrCreateExternalProjectConfigFile(rootProjectPath, GradleConstants.SETTINGS_FILE_NAME);
|
||||
if (file == null) return null;
|
||||
|
||||
if (renderNewFile) {
|
||||
final String moduleDirName = VfsUtilCore.getRelativePath(modelContentRootDir, file.getParent(), '/');
|
||||
|
||||
Map<String, String> attributes = ContainerUtil.newHashMap();
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_PROJECT_NAME, projectName);
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_PATH, moduleDirName);
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_NAME, moduleName);
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_BUILD_FILE_NAME, DEFAULT_SCRIPT_NAME); // TODO: gradle > 4.0 doesn't need this
|
||||
saveFile(file, TEMPLATE_GRADLE_SETTINGS, attributes);
|
||||
}
|
||||
else {
|
||||
char separatorChar = file.getParent() == null || !VfsUtilCore.isAncestor(file.getParent(), modelContentRootDir, true) ? '/' : ':';
|
||||
String modulePath = VfsUtil.getPath(file, modelContentRootDir, separatorChar);
|
||||
|
||||
Map<String, String> attributes = ContainerUtil.newHashMap();
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_NAME, moduleName);
|
||||
// check for flat structure
|
||||
final String flatStructureModulePath =
|
||||
modulePath != null && StringUtil.startsWith(modulePath, "../") ? StringUtil.trimStart(modulePath, "../") : null;
|
||||
if (StringUtil.equals(flatStructureModulePath, modelContentRootDir.getName())) {
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_FLAT_DIR, "true");
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_PATH, flatStructureModulePath);
|
||||
}
|
||||
else {
|
||||
attributes.put(TEMPLATE_ATTRIBUTE_MODULE_PATH, modulePath);
|
||||
}
|
||||
|
||||
appendToFile(file, TEMPLATE_GRADLE_SETTINGS_MERGE, attributes);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void saveFile(@NotNull VirtualFile file, @NotNull String templateName, @Nullable Map templateAttributes)
|
||||
throws ConfigurationException {
|
||||
FileTemplateManager manager = FileTemplateManager.getDefaultInstance();
|
||||
FileTemplate template = manager.getInternalTemplate(templateName);
|
||||
try {
|
||||
appendToFile(file, templateAttributes != null ? template.getText(templateAttributes) : template.getText());
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn(String.format("Unexpected exception on applying template %s config", GradleConstants.SYSTEM_ID.getReadableName()), e);
|
||||
throw new ConfigurationException(
|
||||
e.getMessage(), String.format("Can't apply %s template config text", GradleConstants.SYSTEM_ID.getReadableName())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendToFile(@NotNull VirtualFile file, @NotNull String templateName, @Nullable Map templateAttributes)
|
||||
throws ConfigurationException {
|
||||
FileTemplateManager manager = FileTemplateManager.getDefaultInstance();
|
||||
FileTemplate template = manager.getInternalTemplate(templateName);
|
||||
try {
|
||||
appendToFile(file, templateAttributes != null ? template.getText(templateAttributes) : template.getText());
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.warn(String.format("Unexpected exception on appending template %s config", GradleConstants.SYSTEM_ID.getReadableName()), e);
|
||||
throw new ConfigurationException(
|
||||
e.getMessage(), String.format("Can't append %s template config text", GradleConstants.SYSTEM_ID.getReadableName())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
private static VirtualFile getOrCreateExternalProjectConfigFile(@NotNull String parent, @NotNull String fileName) {
|
||||
File file = new File(parent, fileName);
|
||||
FileUtilRt.createIfNotExists(file);
|
||||
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
|
||||
}
|
||||
|
||||
public void setParentProject(@Nullable ProjectData parentProject) {
|
||||
myParentProject = parentProject;
|
||||
}
|
||||
|
||||
public boolean isInheritGroupId() {
|
||||
return myInheritGroupId;
|
||||
}
|
||||
|
||||
public void setInheritGroupId(boolean inheritGroupId) {
|
||||
myInheritGroupId = inheritGroupId;
|
||||
}
|
||||
|
||||
public boolean isInheritVersion() {
|
||||
return myInheritVersion;
|
||||
}
|
||||
|
||||
public void setInheritVersion(boolean inheritVersion) {
|
||||
myInheritVersion = inheritVersion;
|
||||
}
|
||||
|
||||
public ProjectId getProjectId() {
|
||||
return myProjectId;
|
||||
}
|
||||
|
||||
public void setProjectId(@NotNull ProjectId projectId) {
|
||||
myProjectId = projectId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
|
||||
if (settingsStep instanceof ProjectSettingsStep) {
|
||||
final ProjectSettingsStep projectSettingsStep = (ProjectSettingsStep)settingsStep;
|
||||
if (myProjectId != null) {
|
||||
final JTextField moduleNameField = settingsStep.getModuleNameField();
|
||||
if (moduleNameField != null) {
|
||||
moduleNameField.setText(myProjectId.getArtifactId());
|
||||
}
|
||||
projectSettingsStep.setModuleName(myProjectId.getArtifactId());
|
||||
}
|
||||
projectSettingsStep.bindModuleSettings();
|
||||
}
|
||||
return super.modifySettingsStep(settingsStep);
|
||||
}
|
||||
|
||||
public static void appendToFile(@NotNull VirtualFile file, @NotNull String text) throws IOException {
|
||||
String lineSeparator = lineSeparator(file);
|
||||
final String existingText = StringUtil.trimTrailing(VfsUtilCore.loadText(file));
|
||||
String content = (StringUtil.isNotEmpty(existingText) ? existingText + lineSeparator : "") +
|
||||
StringUtil.convertLineSeparators(text, lineSeparator);
|
||||
VfsUtil.saveText(file, content);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String lineSeparator(@NotNull VirtualFile file) {
|
||||
String lineSeparator = LoadTextUtil.detectLineSeparator(file, true);
|
||||
if (lineSeparator == null) {
|
||||
lineSeparator = CodeStyleSettingsManager.getSettings(ProjectManagerEx.getInstanceEx().getDefaultProject()).getLineSeparator();
|
||||
}
|
||||
return lineSeparator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BuildScriptDataBuilder getBuildScriptData(@Nullable Module module) {
|
||||
return module == null ? null : module.getUserData(BUILD_SCRIPT_DATA);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Project createProject(String name, String path) {
|
||||
Project project = super.createProject(name, path);
|
||||
if (project != null) {
|
||||
GradleProjectSettings settings = getExternalProjectSettings();
|
||||
ExternalProjectsManagerImpl.getInstance(project).setStoreExternally(settings.isStoreProjectFilesExternally());
|
||||
}
|
||||
return project;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.kotlin.gradle.kdsl.GradleModuleWizardStep">
|
||||
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="529" height="386"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="ddae6" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="d7d25"/>
|
||||
<text value="GroupId"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="bbb74" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="efb5e"/>
|
||||
<text value="ArtifactId"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="4eb56" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="b1344"/>
|
||||
<text value="Version"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="d7d25" class="javax.swing.JTextField" binding="myGroupIdField">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="efb5e" class="javax.swing.JTextField" binding="myArtifactIdField">
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="b1344" class="javax.swing.JTextField" binding="myVersionField">
|
||||
<constraints>
|
||||
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="d0095" class="javax.swing.JCheckBox" binding="myInheritGroupIdCheckBox">
|
||||
<constraints>
|
||||
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Inherit"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="897ff" class="javax.swing.JCheckBox" binding="myInheritVersionCheckBox">
|
||||
<constraints>
|
||||
<grid row="3" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Inherit"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="102d8" binding="myAddToPanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="true"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children/>
|
||||
</grid>
|
||||
<grid id="90185" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="true"/>
|
||||
</properties>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<vspacer id="f04b8">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.gradle.kdsl;
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep;
|
||||
import com.intellij.ide.util.projectWizard.WizardContext;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData;
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectId;
|
||||
import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep;
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.options.ConfigurationException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.service.project.wizard.GradleParentProjectForm;
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
public class GradleModuleWizardStep extends ModuleWizardStep {
|
||||
private static final Icon WIZARD_ICON = null;
|
||||
|
||||
private static final String INHERIT_GROUP_ID_KEY = "GradleModuleWizard.inheritGroupId";
|
||||
private static final String INHERIT_VERSION_KEY = "GradleModuleWizard.inheritVersion";
|
||||
private static final String DEFAULT_VERSION = "1.0-SNAPSHOT";
|
||||
|
||||
@Nullable
|
||||
private final Project myProjectOrNull;
|
||||
@NotNull
|
||||
private final GradleModuleBuilder myBuilder;
|
||||
@NotNull
|
||||
private final WizardContext myContext;
|
||||
@NotNull
|
||||
private final GradleParentProjectForm myParentProjectForm;
|
||||
|
||||
private String myInheritedGroupId;
|
||||
private String myInheritedVersion;
|
||||
|
||||
private JPanel myMainPanel;
|
||||
|
||||
private JTextField myGroupIdField;
|
||||
private JCheckBox myInheritGroupIdCheckBox;
|
||||
private JTextField myArtifactIdField;
|
||||
private JTextField myVersionField;
|
||||
private JCheckBox myInheritVersionCheckBox;
|
||||
private JPanel myAddToPanel;
|
||||
|
||||
public GradleModuleWizardStep(@NotNull GradleModuleBuilder builder, @NotNull WizardContext context) {
|
||||
myProjectOrNull = context.getProject();
|
||||
myBuilder = builder;
|
||||
myContext = context;
|
||||
myParentProjectForm = new GradleParentProjectForm(context, parentProject -> updateComponents());
|
||||
initComponents();
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
myAddToPanel.add(myParentProjectForm.getComponent());
|
||||
ActionListener updatingListener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
updateComponents();
|
||||
}
|
||||
};
|
||||
myInheritGroupIdCheckBox.addActionListener(updatingListener);
|
||||
myInheritVersionCheckBox.addActionListener(updatingListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myGroupIdField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStepLeaving() {
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
myBuilder.setInheritGroupId(getSavedValue(INHERIT_GROUP_ID_KEY, true));
|
||||
myBuilder.setInheritVersion(getSavedValue(INHERIT_VERSION_KEY, true));
|
||||
}
|
||||
|
||||
private void saveSettings() {
|
||||
saveValue(INHERIT_GROUP_ID_KEY, myInheritGroupIdCheckBox.isSelected());
|
||||
saveValue(INHERIT_VERSION_KEY, myInheritVersionCheckBox.isSelected());
|
||||
}
|
||||
|
||||
private static boolean getSavedValue(String key, boolean defaultValue) {
|
||||
return getSavedValue(key, String.valueOf(defaultValue)).equals(String.valueOf(true));
|
||||
}
|
||||
|
||||
private static String getSavedValue(String key, String defaultValue) {
|
||||
String value = PropertiesComponent.getInstance().getValue(key);
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
private static void saveValue(String key, boolean value) {
|
||||
saveValue(key, String.valueOf(value));
|
||||
}
|
||||
|
||||
private static void saveValue(String key, String value) {
|
||||
PropertiesComponent.getInstance().setValue(key, value);
|
||||
}
|
||||
|
||||
public JComponent getComponent() {
|
||||
return myMainPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate() throws ConfigurationException {
|
||||
if (StringUtil.isEmptyOrSpaces(myArtifactIdField.getText())) {
|
||||
ApplicationManager.getApplication().invokeLater(
|
||||
() -> IdeFocusManager.getInstance(myProjectOrNull).requestFocus(myArtifactIdField, true));
|
||||
throw new ConfigurationException("Please, specify artifactId");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateStep() {
|
||||
ProjectData parentProject = myParentProjectForm.getParentProject();
|
||||
ProjectId projectId = myBuilder.getProjectId();
|
||||
|
||||
if (projectId == null) {
|
||||
setTestIfEmpty(myArtifactIdField, myBuilder.getName());
|
||||
setTestIfEmpty(myGroupIdField, parentProject == null ? myBuilder.getName() : parentProject.getGroup());
|
||||
setTestIfEmpty(myVersionField, parentProject == null ? DEFAULT_VERSION : parentProject.getVersion());
|
||||
}
|
||||
else {
|
||||
setTestIfEmpty(myArtifactIdField, projectId.getArtifactId());
|
||||
setTestIfEmpty(myGroupIdField, projectId.getGroupId());
|
||||
setTestIfEmpty(myVersionField, projectId.getVersion());
|
||||
}
|
||||
|
||||
myInheritGroupIdCheckBox.setSelected(myBuilder.isInheritGroupId());
|
||||
myInheritVersionCheckBox.setSelected(myBuilder.isInheritVersion());
|
||||
|
||||
updateComponents();
|
||||
}
|
||||
|
||||
|
||||
private void updateComponents() {
|
||||
final boolean isAddToVisible = myParentProjectForm.isVisible();
|
||||
|
||||
myInheritGroupIdCheckBox.setVisible(isAddToVisible);
|
||||
myInheritVersionCheckBox.setVisible(isAddToVisible);
|
||||
|
||||
myParentProjectForm.updateComponents();
|
||||
ProjectData parentProject = myParentProjectForm.getParentProject();
|
||||
if (parentProject == null) {
|
||||
myContext.putUserData(ExternalModuleSettingsStep.SKIP_STEP_KEY, Boolean.FALSE);
|
||||
myGroupIdField.setEnabled(true);
|
||||
myVersionField.setEnabled(true);
|
||||
myInheritGroupIdCheckBox.setEnabled(false);
|
||||
myInheritVersionCheckBox.setEnabled(false);
|
||||
|
||||
setTestIfEmpty(myArtifactIdField, myBuilder.getName());
|
||||
setTestIfEmpty(myGroupIdField, "");
|
||||
setTestIfEmpty(myVersionField, DEFAULT_VERSION);
|
||||
}
|
||||
else {
|
||||
myContext.putUserData(ExternalModuleSettingsStep.SKIP_STEP_KEY, Boolean.TRUE);
|
||||
myGroupIdField.setEnabled(!myInheritGroupIdCheckBox.isSelected());
|
||||
myVersionField.setEnabled(!myInheritVersionCheckBox.isSelected());
|
||||
|
||||
if (myInheritGroupIdCheckBox.isSelected()
|
||||
|| myGroupIdField.getText().equals(myInheritedGroupId)) {
|
||||
myGroupIdField.setText(parentProject.getGroup());
|
||||
}
|
||||
if (myInheritVersionCheckBox.isSelected()
|
||||
|| myVersionField.getText().equals(myInheritedVersion)) {
|
||||
myVersionField.setText(parentProject.getVersion());
|
||||
}
|
||||
myInheritedGroupId = myGroupIdField.getText();
|
||||
myInheritedVersion = myVersionField.getText();
|
||||
|
||||
myInheritGroupIdCheckBox.setEnabled(true);
|
||||
myInheritVersionCheckBox.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isGradleModuleExist(WizardContext myContext) {
|
||||
for (Module module : myContext.getModulesProvider().getModules()) {
|
||||
if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDataModel() {
|
||||
myContext.setProjectBuilder(myBuilder);
|
||||
ProjectData parentProject = myParentProjectForm.getParentProject();
|
||||
myBuilder.setParentProject(parentProject);
|
||||
|
||||
myBuilder.setProjectId(new ProjectId(myGroupIdField.getText(),
|
||||
myArtifactIdField.getText(),
|
||||
myVersionField.getText()));
|
||||
myBuilder.setInheritGroupId(myInheritGroupIdCheckBox.isSelected());
|
||||
myBuilder.setInheritVersion(myInheritVersionCheckBox.isSelected());
|
||||
|
||||
if (StringUtil.isNotEmpty(myBuilder.getProjectId().getArtifactId())) {
|
||||
myContext.setProjectName(myBuilder.getProjectId().getArtifactId());
|
||||
}
|
||||
if (parentProject != null) {
|
||||
myContext.setProjectFileDirectory(parentProject.getLinkedExternalProjectPath() + '/' + myContext.getProjectName());
|
||||
}
|
||||
else {
|
||||
if (myProjectOrNull != null) {
|
||||
myContext.setProjectFileDirectory(myProjectOrNull.getBaseDir().getPath() + '/' + myContext.getProjectName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return WIZARD_ICON;
|
||||
}
|
||||
|
||||
private static void setTestIfEmpty(@NotNull JTextField field, @Nullable String text) {
|
||||
if (StringUtil.isEmpty(field.getText())) {
|
||||
field.setText(StringUtil.notNullize(text));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpId() {
|
||||
return "Gradle_Archetype_Dialog";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disposeUIResources() {
|
||||
Disposer.dispose(myParentProjectForm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.gradle.kdsl.frameworkSupport;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class BuildScriptDataBuilder {
|
||||
@NotNull private final VirtualFile myBuildScriptFile;
|
||||
private final Set<String> plugins = ContainerUtil.newTreeSet();
|
||||
private final Set<String> pluginsInGroup = ContainerUtil.newTreeSet();
|
||||
private final Set<String> repositories = ContainerUtil.newTreeSet();
|
||||
private final Set<String> dependencies = ContainerUtil.newTreeSet();
|
||||
private final Set<String> properties = ContainerUtil.newTreeSet();
|
||||
private final Set<String> buildScriptProperties = ContainerUtil.newTreeSet();
|
||||
private final Set<String> buildScriptRepositories = ContainerUtil.newTreeSet();
|
||||
private final Set<String> buildScriptDependencies = ContainerUtil.newTreeSet();
|
||||
private final Set<String> other = ContainerUtil.newTreeSet();
|
||||
|
||||
public BuildScriptDataBuilder(@NotNull VirtualFile buildScriptFile) {
|
||||
myBuildScriptFile = buildScriptFile;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public VirtualFile getBuildScriptFile() {
|
||||
return myBuildScriptFile;
|
||||
}
|
||||
|
||||
public String buildConfigurationPart() {
|
||||
List<String> lines = ContainerUtil.newArrayList();
|
||||
addBuildscriptLines(lines, BuildScriptDataBuilder::padding);
|
||||
if (!pluginsInGroup.isEmpty()) {
|
||||
lines.add("plugins {");
|
||||
lines.addAll(ContainerUtil.map(pluginsInGroup, BuildScriptDataBuilder::padding));
|
||||
lines.add("}");
|
||||
lines.add("");
|
||||
}
|
||||
return StringUtil.join(lines, "\n");
|
||||
}
|
||||
|
||||
public String buildMainPart() {
|
||||
List<String> lines = ContainerUtil.newArrayList();
|
||||
if (!plugins.isEmpty()) {
|
||||
lines.addAll(plugins);
|
||||
lines.add("");
|
||||
}
|
||||
if (!properties.isEmpty()) {
|
||||
lines.addAll(properties);
|
||||
lines.add("");
|
||||
}
|
||||
if (!repositories.isEmpty()) {
|
||||
lines.add("repositories {");
|
||||
lines.addAll(ContainerUtil.map(repositories, BuildScriptDataBuilder::padding));
|
||||
lines.add("}");
|
||||
lines.add("");
|
||||
}
|
||||
if (!dependencies.isEmpty()) {
|
||||
lines.add("dependencies {");
|
||||
lines.addAll(ContainerUtil.map(dependencies, BuildScriptDataBuilder::padding));
|
||||
lines.add("}");
|
||||
lines.add("");
|
||||
}
|
||||
if (!other.isEmpty()) {
|
||||
lines.addAll(other);
|
||||
}
|
||||
return StringUtil.join(lines, "\n");
|
||||
}
|
||||
|
||||
private void addBuildscriptLines(@NotNull List<String> lines, @NotNull Function<String, String> padding) {
|
||||
if (!buildScriptRepositories.isEmpty() || !buildScriptDependencies.isEmpty() || !buildScriptProperties.isEmpty()) {
|
||||
lines.add("buildscript {");
|
||||
final List<String> buildScriptLines = ContainerUtil.newSmartList();
|
||||
if (!buildScriptProperties.isEmpty()) {
|
||||
buildScriptLines.addAll(buildScriptProperties);
|
||||
buildScriptLines.add("");
|
||||
}
|
||||
if (!buildScriptRepositories.isEmpty()) {
|
||||
buildScriptLines.add("repositories {");
|
||||
buildScriptLines.addAll(ContainerUtil.map(buildScriptRepositories, padding));
|
||||
buildScriptLines.add("}");
|
||||
}
|
||||
if (!buildScriptDependencies.isEmpty()) {
|
||||
buildScriptLines.add("dependencies {");
|
||||
buildScriptLines.addAll(ContainerUtil.map(buildScriptDependencies, padding));
|
||||
buildScriptLines.add("}");
|
||||
}
|
||||
lines.addAll(ContainerUtil.map(buildScriptLines, padding));
|
||||
lines.add("}");
|
||||
lines.add("");
|
||||
}
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addBuildscriptPropertyDefinition(@NotNull String definition) {
|
||||
buildScriptProperties.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addBuildscriptRepositoriesDefinition(@NotNull String definition) {
|
||||
buildScriptRepositories.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addBuildscriptDependencyNotation(@NotNull String notation) {
|
||||
buildScriptDependencies.add(notation.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addPluginDefinitionInPluginsGroup(@NotNull String definition) {
|
||||
pluginsInGroup.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addPluginDefinition(@NotNull String definition) {
|
||||
plugins.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addRepositoriesDefinition(@NotNull String definition) {
|
||||
repositories.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addDependencyNotation(@NotNull String notation) {
|
||||
dependencies.add(notation.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addPropertyDefinition(@NotNull String definition) {
|
||||
properties.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
public BuildScriptDataBuilder addOther(@NotNull String definition) {
|
||||
other.add(definition.trim());
|
||||
return this;
|
||||
}
|
||||
|
||||
private static String padding(String s) {return StringUtil.isNotEmpty(s) ? " " + s : "";}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.gradle.kdsl.frameworkSupport;
|
||||
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleConfigurable;
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider;
|
||||
import com.intellij.ide.util.frameworkSupport.FrameworkSupportModel;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
import com.intellij.openapi.roots.ModifiableModelsProvider;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import static org.jetbrains.kotlin.gradle.kdsl.GradleModuleBuilder.getBuildScriptData;
|
||||
|
||||
public abstract class GradleFrameworkSupportProvider extends FrameworkSupportInModuleProvider {
|
||||
|
||||
public static final ExtensionPointName<GradleFrameworkSupportProvider> EP_NAME =
|
||||
ExtensionPointName.create("org.jetbrains.kotlin.gradleFrameworkSupport");
|
||||
|
||||
public abstract void addSupport(@NotNull Module module, @NotNull ModifiableRootModel rootModel,
|
||||
@NotNull ModifiableModelsProvider modifiableModelsProvider,
|
||||
@NotNull BuildScriptDataBuilder buildScriptData);
|
||||
|
||||
public JComponent createComponent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FrameworkSupportInModuleConfigurable createConfigurable(@NotNull FrameworkSupportModel model) {
|
||||
return new FrameworkSupportInModuleConfigurable() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createComponent() {
|
||||
return GradleFrameworkSupportProvider.this.createComponent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSupport(@NotNull Module module,
|
||||
@NotNull ModifiableRootModel rootModel,
|
||||
@NotNull ModifiableModelsProvider modifiableModelsProvider) {
|
||||
final BuildScriptDataBuilder buildScriptData = getBuildScriptData(module);
|
||||
if (buildScriptData != null) {
|
||||
GradleFrameworkSupportProvider.this.addSupport(module, rootModel, modifiableModelsProvider, buildScriptData);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabledForModuleType(@NotNull ModuleType moduleType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.gradle.kdsl.frameworkSupport;
|
||||
|
||||
import com.intellij.framework.FrameworkTypeEx;
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ModifiableModelsProvider;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import icons.JetgroovyIcons;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class GradleGroovyFrameworkSupportProvider extends GradleFrameworkSupportProvider {
|
||||
|
||||
public static final String ID = "groovy";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FrameworkTypeEx getFrameworkType() {
|
||||
return new FrameworkTypeEx(ID) {
|
||||
@NotNull
|
||||
@Override
|
||||
public FrameworkSupportInModuleProvider createProvider() {
|
||||
return GradleGroovyFrameworkSupportProvider.this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
return "Groovy";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return JetgroovyIcons.Groovy.Groovy_16x16;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSupport(@NotNull Module module,
|
||||
@NotNull ModifiableRootModel rootModel,
|
||||
@NotNull ModifiableModelsProvider modifiableModelsProvider,
|
||||
@NotNull BuildScriptDataBuilder buildScriptData) {
|
||||
buildScriptData
|
||||
.addPluginDefinition("plugin(\"groovy\")")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
.addDependencyNotation("compile(\"org.codehaus.groovy:groovy-all:2.3.11\")")
|
||||
.addDependencyNotation("testCompile(\"junit\", \"junit\", \"4.12\")");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2000-2015 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.gradle.kdsl.frameworkSupport;
|
||||
|
||||
import com.intellij.framework.FrameworkTypeEx;
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ModifiableModelsProvider;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class GradleJavaFrameworkSupportProvider extends GradleFrameworkSupportProvider {
|
||||
|
||||
public static final String ID = "java";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FrameworkTypeEx getFrameworkType() {
|
||||
return new FrameworkTypeEx(ID) {
|
||||
@NotNull
|
||||
@Override
|
||||
public FrameworkSupportInModuleProvider createProvider() {
|
||||
return GradleJavaFrameworkSupportProvider.this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getPresentableName() {
|
||||
return "Java";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return AllIcons.Nodes.Module;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSupport(@NotNull Module module,
|
||||
@NotNull ModifiableRootModel rootModel,
|
||||
@NotNull ModifiableModelsProvider modifiableModelsProvider,
|
||||
@NotNull BuildScriptDataBuilder buildScriptData) {
|
||||
buildScriptData
|
||||
.addPluginDefinition("plugin(\"java\")")
|
||||
// TODO: in gradle > 4.0 it is just 'java { ... }'
|
||||
.addOther("configure<JavaPluginConvention> {\n sourceCompatibility = JavaVersion.VERSION_1_8\n}")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
.addDependencyNotation("testCompile(\"junit\", \"junit\", \"4.12\")");
|
||||
}
|
||||
}
|
||||
@@ -14,36 +14,34 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
package org.jetbrains.kotlin.gradle.kdsl.frameworkSupport
|
||||
|
||||
import com.intellij.framework.FrameworkTypeEx
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectId
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ModifiableModelsProvider
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.configuration.*
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.GSK_KOTLIN_VERSION_PROPERTY_NAME
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.getCompileDependencySnippet
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.getKotlinGradlePluginClassPathSnippet
|
||||
import org.jetbrains.kotlin.idea.versions.*
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.KotlinDslGradleFrameworkSupportProvider
|
||||
import javax.swing.Icon
|
||||
|
||||
abstract class KotlinDslGradleKotlinFrameworkSupportProvider(
|
||||
abstract class GradleKotlinDSLKotlinFrameworkSupportProvider(
|
||||
val frameworkTypeId: String,
|
||||
val displayName: String,
|
||||
val frameworkIcon: Icon
|
||||
) : KotlinDslGradleFrameworkSupportProvider() {
|
||||
) : GradleFrameworkSupportProvider() {
|
||||
override fun getFrameworkType(): FrameworkTypeEx = object : FrameworkTypeEx(frameworkTypeId) {
|
||||
override fun getIcon(): Icon = frameworkIcon
|
||||
override fun getPresentableName(): String = displayName
|
||||
override fun createProvider(): FrameworkSupportInModuleProvider = this@KotlinDslGradleKotlinFrameworkSupportProvider
|
||||
override fun createProvider(): FrameworkSupportInModuleProvider = this@GradleKotlinDSLKotlinFrameworkSupportProvider
|
||||
}
|
||||
|
||||
override fun addSupport(
|
||||
projectId: ProjectId,
|
||||
module: Module,
|
||||
rootModel: ModifiableRootModel,
|
||||
modifiableModelsProvider: ModifiableModelsProvider,
|
||||
@@ -68,20 +66,18 @@ abstract class KotlinDslGradleKotlinFrameworkSupportProvider(
|
||||
.addBuildscriptRepositoriesDefinition("mavenCentral()")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
// TODO: in gradle > 4.1 this could be single declaration e.g. 'val kotlin_version: String by extra { "1.1.11" }'
|
||||
.addBuildscriptPropertyDefinition("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra\n $GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$kotlinVersion\"")
|
||||
.addBuildscriptPropertyDefinition("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra\n$GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$kotlinVersion\"")
|
||||
.addDependencyNotation(getRuntimeLibrary(rootModel))
|
||||
.addBuildscriptDependencyNotation(getKotlinGradlePluginClassPathSnippet())
|
||||
}
|
||||
|
||||
private fun RepositoryDescription.toKotlinRepositorySnippet() = "maven { setUrl(\"$url\") }"
|
||||
|
||||
protected abstract fun getRuntimeLibrary(rootModel: ModifiableRootModel): String
|
||||
|
||||
protected abstract fun getPluginDefinition(): String
|
||||
}
|
||||
|
||||
class KotlinDslGradleKotlinJavaFrameworkSupportProvider :
|
||||
KotlinDslGradleKotlinFrameworkSupportProvider("KOTLIN", "Kotlin (Java)", KotlinIcons.SMALL_LOGO) {
|
||||
class GradleKotlinDSLKotlinJavaFrameworkSupportProvider :
|
||||
GradleKotlinDSLKotlinFrameworkSupportProvider("KOTLIN", "Kotlin (Java)", KotlinIcons.SMALL_LOGO) {
|
||||
|
||||
override fun getPluginDefinition() = "plugin(\"${KotlinGradleModuleConfigurator.KOTLIN}\")"
|
||||
|
||||
@@ -89,24 +85,28 @@ class KotlinDslGradleKotlinJavaFrameworkSupportProvider :
|
||||
getCompileDependencySnippet(KOTLIN_GROUP_ID, getStdlibArtifactId(rootModel.sdk, bundledRuntimeVersion()))
|
||||
|
||||
override fun addSupport(
|
||||
projectId: ProjectId,
|
||||
module: Module,
|
||||
rootModel: ModifiableRootModel,
|
||||
modifiableModelsProvider: ModifiableModelsProvider,
|
||||
buildScriptData: BuildScriptDataBuilder
|
||||
) {
|
||||
super.addSupport(projectId, module, rootModel, modifiableModelsProvider, buildScriptData)
|
||||
super.addSupport(module, rootModel, modifiableModelsProvider, buildScriptData)
|
||||
val jvmTarget = getDefaultJvmTarget(rootModel.sdk, bundledRuntimeVersion())
|
||||
if (jvmTarget != null) {
|
||||
buildScriptData
|
||||
.addImport("import org.jetbrains.kotlin.gradle.tasks.KotlinCompile")
|
||||
.addImports("import org.jetbrains.kotlin.gradle.tasks.KotlinCompile")
|
||||
.addOther("tasks.withType<KotlinCompile> {\n kotlinOptions.jvmTarget = \"1.8\"\n}\n")
|
||||
}
|
||||
}
|
||||
|
||||
private fun BuildScriptDataBuilder.addImports(vararg import: String): BuildScriptDataBuilder = apply {
|
||||
val text = VfsUtil.loadText(buildScriptFile)
|
||||
VfsUtil.saveText(buildScriptFile, import.joinToString(separator = "\n") + "\n\n" + text)
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinDslGradleKotlinJSFrameworkSupportProvider :
|
||||
KotlinDslGradleKotlinFrameworkSupportProvider("KOTLIN_JS", "Kotlin (JavaScript)", KotlinIcons.JS) {
|
||||
class GradleKotlinDSLKotlinJSFrameworkSupportProvider :
|
||||
GradleKotlinDSLKotlinFrameworkSupportProvider("KOTLIN_JS", "Kotlin (JavaScript)", KotlinIcons.JS) {
|
||||
|
||||
override fun getPluginDefinition(): String = "plugin(\"${KotlinJsGradleModuleConfigurator.KOTLIN_JS}\")"
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.gradle.kdsl.frameworkSupport
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
|
||||
class KotlinBuildScriptDataBuilder(buildScriptFile: VirtualFile) : BuildScriptDataBuilder(buildScriptFile) {
|
||||
private val plugins: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
private val properties: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
private val repositories: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
private val dependencies: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
|
||||
private val buildScriptProperties: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
private val buildScriptRepositories: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
private val buildScriptDependencies: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
private val other: MutableSet<String> = ContainerUtil.newTreeSet<String>()
|
||||
|
||||
override fun addPluginDefinition(definition: String): BuildScriptDataBuilder = apply { plugins.add(definition) }
|
||||
|
||||
override fun addRepositoriesDefinition(definition: String): BuildScriptDataBuilder = apply { repositories.add(definition) }
|
||||
|
||||
override fun addPropertyDefinition(definition: String): BuildScriptDataBuilder = apply { properties.add(definition) }
|
||||
|
||||
override fun addDependencyNotation(notation: String): BuildScriptDataBuilder = apply { dependencies.add(notation) }
|
||||
|
||||
override fun addBuildscriptPropertyDefinition(definition: String): BuildScriptDataBuilder = apply { buildScriptProperties.add(definition) }
|
||||
|
||||
override fun addBuildscriptRepositoriesDefinition(definition: String): BuildScriptDataBuilder = apply { buildScriptRepositories.add(definition) }
|
||||
|
||||
override fun addBuildscriptDependencyNotation(notation: String): BuildScriptDataBuilder = apply { buildScriptDependencies.add(notation) }
|
||||
|
||||
override fun addOther(definition: String): BuildScriptDataBuilder = apply { other.add(definition) }
|
||||
|
||||
override fun buildMainPart(): String = buildString {
|
||||
|
||||
appendlnIfNotNull(buildBuildScriptBlock())
|
||||
|
||||
appendlnIfNotNull(buildBlock("apply", plugins))
|
||||
|
||||
if (properties.isNotEmpty()) {
|
||||
properties.forEach { appendln(it) }
|
||||
appendln()
|
||||
}
|
||||
|
||||
appendlnIfNotNull(buildBlock("repositories", repositories))
|
||||
|
||||
appendlnIfNotNull(buildBlock("dependencies", dependencies))
|
||||
|
||||
other.forEach { appendln(it) }
|
||||
}
|
||||
|
||||
private fun buildBuildScriptBlock(): String? = buildString {
|
||||
if (buildScriptProperties.isEmpty() || buildScriptRepositories.isEmpty() || buildScriptDependencies.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
appendln("buildscript {")
|
||||
buildScriptProperties.forEach { appendln(it.withMargin) }
|
||||
appendln()
|
||||
appendlnIfNotNull(buildBlock("repositories", buildScriptRepositories)?.withMargin)
|
||||
appendlnIfNotNull(buildBlock("dependencies", buildScriptDependencies)?.withMargin)
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
private fun buildBlock(name: String, lines: Set<String>): String? = buildString {
|
||||
if (lines.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
appendln("$name {")
|
||||
lines.forEach { appendln(it.withMargin) }
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
private val String.withMargin: String
|
||||
get() = lines().joinToString(separator = "\n") { " " + it }
|
||||
|
||||
private fun StringBuilder.appendlnIfNotNull(text: String?) = text?.let { appendln(it) }
|
||||
}
|
||||
@@ -103,7 +103,7 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
|
||||
val buildGradle = moduleDir.createChildData(null, "build.gradle")
|
||||
val buildScriptData = BuildScriptDataBuilder(buildGradle)
|
||||
extendScript(buildScriptData, sdk ?: rootModule.rootManager.sdk)
|
||||
VfsUtil.saveText(buildGradle, buildScriptData.buildConfigurationPart() + buildScriptData.buildMainPart())
|
||||
VfsUtil.saveText(buildGradle, buildScriptData.build())
|
||||
}
|
||||
|
||||
private fun setupCommonModule(
|
||||
|
||||
@@ -236,10 +236,10 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD
|
||||
override val dependencyResolver: DependenciesResolver = ErrorScriptDependenciesResolver(message)
|
||||
|
||||
override fun getScriptName(script: KtScript) =
|
||||
Name.identifier(script.containingKtFile.name.removeSuffix(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION))
|
||||
Name.identifier(script.containingKtFile.name.removeSuffix(".gradle.kts"))
|
||||
|
||||
override fun isScript(fileName: String): Boolean =
|
||||
fileName.endsWith(GradleConstants.KOTLIN_DSL_SCRIPT_EXTENSION)
|
||||
fileName.endsWith(".gradle.kts")
|
||||
}
|
||||
|
||||
private class ErrorScriptDependenciesResolver(private val message: String? = null) : DependenciesResolver {
|
||||
|
||||
@@ -350,6 +350,7 @@ class GradleInspectionTest : GradleImportingTestCase() {
|
||||
|
||||
val foundProblems = presentation.problemElements
|
||||
.values
|
||||
.flatMap { it.toList() }
|
||||
.mapNotNull { it as? ProblemDescriptorBase }
|
||||
.map { it.descriptionTemplate }
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
fun isInlineFunctionLineNumber(file: VirtualFile, lineNumber: Int, project: Project): Boolean {
|
||||
if (ProjectRootsUtil.isProjectSourceFile(project, file)) {
|
||||
@@ -119,7 +118,7 @@ class WeakBytecodeDebugInfoStorage : ConcurrentWeakFactoryMap<BinaryCacheKey, By
|
||||
|
||||
return BytecodeDebugInfo(smapData, lineNumberMapping)
|
||||
}
|
||||
override fun createMap(): ConcurrentMap<BinaryCacheKey, BytecodeDebugInfo?> {
|
||||
override fun createMap(): Map<BinaryCacheKey, BytecodeDebugInfo?> {
|
||||
return ContainerUtil.createConcurrentWeakKeyWeakValueMap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,30 +23,20 @@ import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.patterns.PatternCondition
|
||||
import com.intellij.patterns.PatternConditionPlus
|
||||
import com.intellij.patterns.PsiClassNamePatternCondition
|
||||
import com.intellij.patterns.ValuePatternCondition
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.intellij.plugins.intelliLang.Configuration
|
||||
import org.intellij.plugins.intelliLang.inject.InjectorUtils
|
||||
import org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport
|
||||
import org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry
|
||||
import org.intellij.plugins.intelliLang.inject.config.BaseInjection
|
||||
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace
|
||||
import org.intellij.plugins.intelliLang.inject.java.JavaLanguageInjectionSupport
|
||||
import org.intellij.plugins.intelliLang.util.AnnotationUtilEx
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.patterns.KotlinFunctionPattern
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
|
||||
@@ -56,31 +46,30 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.annotations.argumentValue
|
||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import org.jetbrains.kotlin.util.aliasImportMap
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinLanguageInjector(
|
||||
private val configuration: Configuration,
|
||||
private val project: Project,
|
||||
private val temporaryPlacesRegistry: TemporaryPlacesRegistry
|
||||
val configuration: Configuration,
|
||||
val project: Project,
|
||||
val temporaryPlacesRegistry: TemporaryPlacesRegistry
|
||||
) : MultiHostInjector {
|
||||
companion object {
|
||||
private val STRING_LITERALS_REGEXP = "\"([^\"]*)\"".toRegex()
|
||||
private val ABSENT_KOTLIN_INJECTION = BaseInjection("ABSENT_KOTLIN_BASE_INJECTION")
|
||||
}
|
||||
|
||||
var annotationInjectionsEnabled = Registry.`is`("kotlin.annotation.injection.enabled", false)
|
||||
|
||||
private val kotlinSupport: KotlinLanguageInjectionSupport? by lazy {
|
||||
val kotlinSupport: KotlinLanguageInjectionSupport? by lazy {
|
||||
ArrayList(InjectorUtils.getActiveInjectionSupports()).filterIsInstance(KotlinLanguageInjectionSupport::class.java).firstOrNull()
|
||||
}
|
||||
|
||||
private data class KotlinCachedInjection(val modificationCount: Long, val baseInjection: BaseInjection)
|
||||
|
||||
private var KtStringTemplateExpression.cachedInjectionWithModification: KotlinCachedInjection? by UserDataProperty(
|
||||
Key.create<KotlinCachedInjection>("CACHED_INJECTION_WITH_MODIFICATION"))
|
||||
Key.create<KotlinCachedInjection>("CACHED_INJECTION_WITH_MODIFICATION"))
|
||||
|
||||
override fun getLanguagesToInject(registrar: MultiHostRegistrar, context: PsiElement) {
|
||||
val ktHost: KtStringTemplateExpression = context as? KtStringTemplateExpression ?: return
|
||||
@@ -88,7 +77,7 @@ class KotlinLanguageInjector(
|
||||
|
||||
val support = kotlinSupport ?: return
|
||||
|
||||
if (!ProjectRootsUtil.isInProjectOrLibSource(ktHost.containingFile.originalFile)) return
|
||||
if (!ProjectRootsUtil.isInProjectOrLibSource(ktHost)) return
|
||||
|
||||
val needImmediateAnswer = with(ApplicationManager.getApplication()) { isDispatchThread && !isUnitTestMode }
|
||||
val kotlinCachedInjection = ktHost.cachedInjectionWithModification
|
||||
@@ -144,9 +133,9 @@ class KotlinLanguageInjector(
|
||||
|
||||
@Suppress("FoldInitializerAndIfToElvis")
|
||||
private fun computeBaseInjection(
|
||||
ktHost: KtStringTemplateExpression,
|
||||
support: KotlinLanguageInjectionSupport,
|
||||
registrar: MultiHostRegistrar): BaseInjection? {
|
||||
ktHost: KtStringTemplateExpression,
|
||||
support: KotlinLanguageInjectionSupport,
|
||||
registrar: MultiHostRegistrar): BaseInjection? {
|
||||
val containingFile = ktHost.containingFile
|
||||
|
||||
val tempInjectedLanguage = temporaryPlacesRegistry.getLanguageFor(ktHost, containingFile)
|
||||
@@ -168,10 +157,10 @@ class KotlinLanguageInjector(
|
||||
|
||||
private fun findInjectionInfo(place: KtElement, originalHost: Boolean = true): InjectionInfo? {
|
||||
return injectWithExplicitCodeInstruction(place)
|
||||
?: injectWithCall(place)
|
||||
?: injectInAnnotationCall(place)
|
||||
?: injectWithReceiver(place)
|
||||
?: injectWithVariableUsage(place, originalHost)
|
||||
?: injectWithCall(place)
|
||||
?: injectWithReceiver(place)
|
||||
?: injectWithVariableUsage(place, originalHost)
|
||||
?: injectWithAnnotationEntry(place)
|
||||
}
|
||||
|
||||
private fun injectWithExplicitCodeInstruction(host: KtElement): InjectionInfo? {
|
||||
@@ -186,9 +175,9 @@ class KotlinLanguageInjector(
|
||||
val callExpression = qualifiedExpression.selectorExpression as? KtCallExpression ?: return null
|
||||
val callee = callExpression.calleeExpression ?: return null
|
||||
|
||||
if (isAnalyzeOff()) return null
|
||||
if (isAnalyzeOff(qualifiedExpression.project)) return null
|
||||
|
||||
val kotlinInjections = configuration.getInjections(KOTLIN_SUPPORT_ID)
|
||||
val kotlinInjections = Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID)
|
||||
|
||||
val calleeName = callee.text
|
||||
val possibleNames = collectPossibleNames(kotlinInjections)
|
||||
@@ -231,10 +220,11 @@ class KotlinLanguageInjector(
|
||||
// Given place is not original host of the injection so we stop to prevent stepping through indirect references
|
||||
if (!originalHost) return null
|
||||
|
||||
val ktHost: KtElement = host
|
||||
val ktProperty = host.parent as? KtProperty ?: return null
|
||||
if (ktProperty.initializer != host) return null
|
||||
|
||||
if (isAnalyzeOff()) return null
|
||||
if (isAnalyzeOff(ktHost.project)) return null
|
||||
|
||||
val searchScope = LocalSearchScope(arrayOf(ktProperty.containingFile), "", true)
|
||||
return ReferencesSearch.search(ktProperty, searchScope).asSequence().mapNotNull { psiReference ->
|
||||
@@ -247,10 +237,10 @@ class KotlinLanguageInjector(
|
||||
val ktHost: KtElement = host
|
||||
val argument = ktHost.parent as? KtValueArgument ?: return null
|
||||
|
||||
val callExpression = PsiTreeUtil.getParentOfType(ktHost, KtCallElement::class.java) ?: return null
|
||||
val callee = getNameReference(callExpression.calleeExpression) ?: return null
|
||||
val callExpression = PsiTreeUtil.getParentOfType(ktHost, KtCallExpression::class.java) ?: return null
|
||||
val callee = callExpression.calleeExpression ?: return null
|
||||
|
||||
if (isAnalyzeOff()) return null
|
||||
if (isAnalyzeOff(ktHost.project)) return null
|
||||
|
||||
for (reference in callee.references) {
|
||||
ProgressManager.checkCanceled()
|
||||
@@ -273,44 +263,19 @@ class KotlinLanguageInjector(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getNameReference(callee: KtExpression?): KtNameReferenceExpression? {
|
||||
if (callee is KtConstructorCalleeExpression)
|
||||
return callee.constructorReferenceExpression as? KtNameReferenceExpression
|
||||
return callee as? KtNameReferenceExpression
|
||||
}
|
||||
|
||||
private fun injectInAnnotationCall(host: KtElement): InjectionInfo? {
|
||||
if (!annotationInjectionsEnabled) return null
|
||||
val argument = host.parent as? KtValueArgument ?: return null
|
||||
val annotationEntry = argument.parent.parent as? KtCallElement ?: return null
|
||||
if (!fastCheckInjectionsExists(annotationEntry)) return null
|
||||
val calleeExpression = annotationEntry.calleeExpression ?: return null
|
||||
val callee = getNameReference(calleeExpression)?.mainReference?.resolve()
|
||||
when (callee) {
|
||||
is PsiClass -> {
|
||||
val psiClass = callee as? PsiClass ?: return null
|
||||
val argumentName = argument.getArgumentName()?.asName?.identifier ?: "value"
|
||||
val method = psiClass.findMethodsByName(argumentName, false).singleOrNull() ?: return null
|
||||
return findInjection(method, configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
|
||||
}
|
||||
else -> return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun injectionForJavaMethod(argument: KtValueArgument, javaMethod: PsiMethod): InjectionInfo? {
|
||||
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
|
||||
val psiParameter = javaMethod.parameterList.parameters.getOrNull(argumentIndex) ?: return null
|
||||
|
||||
val injectionInfo = findInjection(psiParameter, configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
|
||||
val injectionInfo = findInjection(psiParameter, Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID))
|
||||
if (injectionInfo != null) {
|
||||
return injectionInfo
|
||||
}
|
||||
|
||||
val annotations = AnnotationUtilEx.getAnnotationFrom(
|
||||
psiParameter,
|
||||
configuration.advancedConfiguration.languageAnnotationPair,
|
||||
true)
|
||||
psiParameter,
|
||||
Configuration.getProjectInstance(psiParameter.project).advancedConfiguration.languageAnnotationPair,
|
||||
true)
|
||||
|
||||
if (annotations.isNotEmpty()) {
|
||||
return processAnnotationInjectionInner(annotations)
|
||||
@@ -323,7 +288,7 @@ class KotlinLanguageInjector(
|
||||
val argumentIndex = (argument.parent as KtValueArgumentList).arguments.indexOf(argument)
|
||||
val ktParameter = ktFunction.valueParameters.getOrNull(argumentIndex) ?: return null
|
||||
|
||||
val patternInjection = findInjection(ktParameter, configuration.getInjections(KOTLIN_SUPPORT_ID))
|
||||
val patternInjection = findInjection(ktParameter, Configuration.getInstance().getInjections(KOTLIN_SUPPORT_ID))
|
||||
if (patternInjection != null) {
|
||||
return patternInjection
|
||||
}
|
||||
@@ -341,6 +306,29 @@ class KotlinLanguageInjector(
|
||||
return InjectionInfo(languageId, null, null)
|
||||
}
|
||||
|
||||
private fun injectWithAnnotationEntry(host: KtElement): InjectionInfo? {
|
||||
val argument = host.parent as? KtValueArgument ?: return null
|
||||
val annotationEntry = PsiTreeUtil.getParentOfType(host, KtAnnotationEntry::class.java) ?: return null
|
||||
if (isAnalyzeOff(host.project)) return null
|
||||
|
||||
val calleeReference = annotationEntry.calleeExpression?.constructorReferenceExpression?.mainReference
|
||||
val callee = calleeReference?.resolve()
|
||||
return when (callee) {
|
||||
is KtFunction -> injectionForKotlinCall(argument, callee, calleeReference)
|
||||
is PsiClass -> {
|
||||
// Look for java injections for the PsiAnnotationMethod.
|
||||
(argument.reference ?: argument.getArgumentName()?.referenceExpression?.mainReference)
|
||||
?.let { it.resolve() as? PsiMethod }
|
||||
?.let { findInjection(it, Configuration.getInstance().getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID)) }
|
||||
?.takeIf { injectionInfo ->
|
||||
// Temporary forbid injection for SpEL because of inspections that gives warnings when host language is not Java.
|
||||
injectionInfo.languageId != "SpEL"
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun findInjection(element: PsiElement?, injections: List<BaseInjection>): InjectionInfo? {
|
||||
for (injection in injections) {
|
||||
if (injection.acceptsPsiElement(element)) {
|
||||
@@ -351,8 +339,8 @@ class KotlinLanguageInjector(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isAnalyzeOff(): Boolean {
|
||||
return configuration.advancedConfiguration.dfaOption == Configuration.DfaOption.OFF
|
||||
private fun isAnalyzeOff(project: Project): Boolean {
|
||||
return Configuration.getProjectInstance(project).advancedConfiguration.dfaOption == Configuration.DfaOption.OFF
|
||||
}
|
||||
|
||||
private fun processAnnotationInjectionInner(annotations: Array<PsiAnnotation>): InjectionInfo? {
|
||||
@@ -362,52 +350,4 @@ class KotlinLanguageInjector(
|
||||
|
||||
return InjectionInfo(id, prefix, suffix)
|
||||
}
|
||||
|
||||
private val injectableTargetClassShortNames = CachedValuesManager.getManager(project)
|
||||
.createCachedValue({
|
||||
CachedValueProvider.Result.create(HashSet<String>().apply {
|
||||
for (injection in configuration.getInjections(JavaLanguageInjectionSupport.JAVA_SUPPORT_ID)) {
|
||||
for (injectionPlace in injection.injectionPlaces) {
|
||||
for (targetClassFQN in retrieveJavaPlaceTargetClassesFQNs(injectionPlace)) {
|
||||
add(StringUtilRt.getShortName(targetClassFQN))
|
||||
}
|
||||
}
|
||||
}
|
||||
for (injection in configuration.getInjections(org.jetbrains.kotlin.idea.injection.KOTLIN_SUPPORT_ID)) {
|
||||
for (injectionPlace in injection.injectionPlaces) {
|
||||
for (targetClassFQN in retrieveKotlinPlaceTargetClassesFQNs(injectionPlace)) {
|
||||
add(StringUtilRt.getShortName(targetClassFQN))
|
||||
}
|
||||
}
|
||||
}
|
||||
}, configuration)
|
||||
}, false)
|
||||
|
||||
private fun fastCheckInjectionsExists(annotationEntry: KtCallElement): Boolean {
|
||||
val referencedName = getNameReference(annotationEntry.calleeExpression)?.getReferencedName() ?: return false
|
||||
val annotationShortName = annotationEntry.containingKtFile.aliasImportMap()[referencedName].singleOrNull() ?: referencedName
|
||||
return annotationShortName in injectableTargetClassShortNames.value
|
||||
}
|
||||
|
||||
private fun retrieveJavaPlaceTargetClassesFQNs(place: InjectionPlace): Collection<String> {
|
||||
val classCondition = place.elementPattern.condition.conditions.firstOrNull { it.debugMethodName == "definedInClass" }
|
||||
as? PatternConditionPlus<*, *> ?: return emptyList()
|
||||
val psiClassNamePatternCondition = classCondition.valuePattern.condition.conditions.
|
||||
firstIsInstanceOrNull<PsiClassNamePatternCondition>() ?: return emptyList()
|
||||
val valuePatternCondition = psiClassNamePatternCondition.namePattern.condition.conditions.firstIsInstanceOrNull<ValuePatternCondition<String>>() ?: return emptyList()
|
||||
return valuePatternCondition.values
|
||||
}
|
||||
|
||||
private fun retrieveKotlinPlaceTargetClassesFQNs(place: InjectionPlace): Collection<String> {
|
||||
val classNames = SmartList<String>()
|
||||
fun collect(condition: PatternCondition<*>) {
|
||||
when (condition) {
|
||||
is PatternConditionPlus<*, *> -> condition.valuePattern.condition.conditions.forEach { collect(it) }
|
||||
is KotlinFunctionPattern.DefinedInClassCondition -> classNames.add(condition.fqName)
|
||||
}
|
||||
}
|
||||
place.elementPattern.condition.conditions.forEach { collect(it) }
|
||||
return classNames
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ object InlayScratchOutputHandler : ScratchOutputHandler {
|
||||
return fontInfo.fontMetrics().stringWidth(text)
|
||||
}
|
||||
|
||||
override fun paint(editor: Editor, g: Graphics, r: Rectangle, textAttributes: TextAttributes) {
|
||||
override fun paint(editor: Editor, g: Graphics, r: Rectangle) {
|
||||
val attributes = getAttributes()
|
||||
val fgColor = attributes.foregroundColor ?: return
|
||||
g.color = fgColor
|
||||
|
||||
@@ -71,11 +71,10 @@ abstract class AbstractKotlinMavenInspectionTest : MavenImportingTestCase() {
|
||||
|
||||
val problemElements = runInspection(inspectionClass, myProject).problemElements
|
||||
val actualProblems = problemElements
|
||||
.keys()
|
||||
.filter { it.name == "pom.xml" }
|
||||
.map { problemElements.get(it) }
|
||||
.flatMap { it.toList() }
|
||||
.mapNotNull { it as? ProblemDescriptorBase }
|
||||
.filter { it.key.name == "pom.xml" }
|
||||
.values
|
||||
.flatMap { it.toList() }
|
||||
.mapNotNull { it as? ProblemDescriptorBase }
|
||||
|
||||
val actual = actualProblems
|
||||
.map { SimplifiedProblemDescription(it.descriptionTemplate, it.psiElement.text.replace("\\s+".toRegex(), "")) to it }
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.intellij.execution.process.ProcessOutputTypes
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.annotations.NotNull
|
||||
import org.jetbrains.kotlin.console.actions.logError
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.utils.repl.ReplEscapeType
|
||||
@@ -50,7 +49,7 @@ class ReplOutputHandler(
|
||||
|
||||
override fun isSilentlyDestroyOnClose() = true
|
||||
|
||||
override fun notifyTextAvailable(text: String, key: Key<*>) {
|
||||
override fun notifyTextAvailable(text: String, key: Key<*>?) {
|
||||
// hide warning about adding test folder to classpath
|
||||
if (text.startsWith("warning: classpath entry points to a non-existent location")) return
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<idea-plugin>
|
||||
<id>org.jetbrains.kotlin</id>
|
||||
<version>1.2</version>
|
||||
|
||||
<extensionPoints>
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.diagnosticSuppressor"
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSFrameworkSupportProvider"/>
|
||||
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
|
||||
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPCommonFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPJavaFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPJSFrameworkSupportProvider"/>
|
||||
@@ -61,6 +59,8 @@
|
||||
|
||||
<projectTaskRunner implementation="org.jetbrains.kotlin.idea.run.MultiplatformGradleProjectTaskRunner" order="first,before gradle"/>
|
||||
<orderEnumerationHandlerFactory implementation="org.jetbrains.kotlin.idea.run.MultiplatformGradleOrderEnumeratorHandler$FactoryImpl" order="first"/>
|
||||
|
||||
<moduleBuilder builderClass="org.jetbrains.kotlin.gradle.kdsl.GradleModuleBuilder" />
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
@@ -77,6 +77,10 @@
|
||||
|
||||
<moduleBuilder implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleMultiplatformModuleBuilder"/>
|
||||
|
||||
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleJavaFrameworkSupportProvider" />
|
||||
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleKotlinDSLKotlinJavaFrameworkSupportProvider" />
|
||||
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleKotlinDSLKotlinJSFrameworkSupportProvider" />
|
||||
<gradleFrameworkSupport implementation="org.jetbrains.kotlin.gradle.kdsl.frameworkSupport.GradleGroovyFrameworkSupportProvider" />
|
||||
<buildSystemTypeDetector implementation="org.jetbrains.kotlin.idea.configuration.GradleDetector"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<version>@snapshot@</version>
|
||||
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
|
||||
|
||||
<idea-version since-build="173.1" until-build="173.*"/>
|
||||
<idea-version since-build="172.1" until-build="172.*"/>
|
||||
|
||||
<depends>com.intellij.modules.platform</depends>
|
||||
<depends>com.intellij.modules.remoteServers</depends>
|
||||
@@ -2786,6 +2786,8 @@
|
||||
<resolveScopeProvider implementation="org.jetbrains.kotlin.idea.core.script.dependencies.KotlinScriptResolveScopeProvider"/>
|
||||
<resolveScopeProvider implementation="org.jetbrains.kotlin.idea.core.script.dependencies.ScriptDependenciesResolveScopeProvider"/>
|
||||
|
||||
<codeInsight.intention.jvmCommonIntentionActionsFactory language="kotlin" implementationClass="org.jetbrains.kotlin.idea.intentions.KotlinCommonIntentionActionsFactory"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.uast.kotlin.KotlinUastBindingContextProviderService"
|
||||
serviceImplementation="org.jetbrains.uast.kotlin.internal.IdeaKotlinUastBindingContextProviderService"/>
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.formatter
|
||||
|
||||
import com.intellij.internal.statistic.AbstractProjectsUsagesCollector
|
||||
import com.intellij.internal.statistic.beans.GroupDescriptor
|
||||
import com.intellij.internal.statistic.beans.UsageDescriptor
|
||||
import com.intellij.internal.statistic.utils.getEnumUsage
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||
import org.jetbrains.kotlin.idea.util.compat.statistic.AbstractProjectsUsagesCollector
|
||||
import org.jetbrains.kotlin.idea.util.compat.statistic.getEnumUsage
|
||||
|
||||
class KotlinFormatterUsageCollector : AbstractProjectsUsagesCollector() {
|
||||
override fun getGroupId(): GroupDescriptor = GroupDescriptor.create(GROUP_ID)
|
||||
|
||||
@@ -53,7 +53,7 @@ class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||
val lineNumber = element.getLineNumber()
|
||||
if (lineNumber !in markedLineNumbers && isRecursiveCall(element)) {
|
||||
markedLineNumbers.add(lineNumber)
|
||||
result.add(RecursiveMethodCallMarkerInfo(getElementForLineMark(element)))
|
||||
result.add(RecursiveMethodCallMarkerInfo(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,8 +113,8 @@ class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||
return true
|
||||
}
|
||||
|
||||
private class RecursiveMethodCallMarkerInfo(callElement: PsiElement)
|
||||
: LineMarkerInfo<PsiElement>(
|
||||
private class RecursiveMethodCallMarkerInfo(callElement: KtElement)
|
||||
: LineMarkerInfo<KtElement>(
|
||||
callElement,
|
||||
callElement.textRange,
|
||||
AllIcons.Gutter.RecursiveMethod,
|
||||
@@ -125,7 +125,7 @@ class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||
) {
|
||||
|
||||
override fun createGutterRenderer(): GutterIconRenderer? {
|
||||
return object : LineMarkerInfo.LineMarkerGutterIconRenderer<PsiElement>(this) {
|
||||
return object : LineMarkerInfo.LineMarkerGutterIconRenderer<KtElement>(this) {
|
||||
override fun getClickAction() = null // to place breakpoint on mouse click
|
||||
}
|
||||
}
|
||||
@@ -133,15 +133,6 @@ class KotlinRecursiveCallLineMarkerProvider : LineMarkerProvider {
|
||||
|
||||
}
|
||||
|
||||
internal fun getElementForLineMark(callElement: PsiElement): PsiElement =
|
||||
when (callElement) {
|
||||
is KtSimpleNameExpression -> callElement.getReferencedNameElement()
|
||||
else ->
|
||||
// a fallback,
|
||||
//but who knows what to reference in KtArrayAccessExpression ?
|
||||
generateSequence(callElement, { it.firstChild }).last()
|
||||
}
|
||||
|
||||
private fun PsiElement.getLineNumber(): Int {
|
||||
return PsiDocumentManager.getInstance(project).getDocument(containingFile)!!.getLineNumber(textOffset)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.calls.checkers.isBuiltInCoroutineContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
|
||||
private class SuspendCallMarkerInfo(callElement: PsiElement, message: String) : LineMarkerInfo<PsiElement>(
|
||||
private class SuspendCallMarkerInfo(callElement: KtElement, message: String) : LineMarkerInfo<KtElement>(
|
||||
callElement,
|
||||
callElement.textRange,
|
||||
KotlinIcons.SUSPEND_CALL,
|
||||
@@ -37,7 +37,7 @@ class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
|
||||
GutterIconRenderer.Alignment.RIGHT
|
||||
) {
|
||||
override fun createGutterRenderer(): GutterIconRenderer? {
|
||||
return object : LineMarkerInfo.LineMarkerGutterIconRenderer<PsiElement>(this) {
|
||||
return object : LineMarkerInfo.LineMarkerGutterIconRenderer<KtElement>(this) {
|
||||
override fun getClickAction(): AnAction? = null
|
||||
}
|
||||
}
|
||||
@@ -61,9 +61,9 @@ class KotlinSuspendCallLineMarkerProvider : LineMarkerProvider {
|
||||
|
||||
markedLineNumbers += lineNumber
|
||||
result += if (element is KtForExpression) {
|
||||
SuspendCallMarkerInfo(getElementForLineMark(element.loopRange!!), "Suspending iteration")
|
||||
SuspendCallMarkerInfo(element.loopRange!!, "Suspending iteration")
|
||||
} else {
|
||||
SuspendCallMarkerInfo(getElementForLineMark(element), "Suspend function call")
|
||||
SuspendCallMarkerInfo(element, "Suspend function call")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import com.intellij.codeInsight.daemon.impl.MarkerType
|
||||
import com.intellij.codeInsight.daemon.impl.PsiElementListNavigator
|
||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.util.PsiClassOrFunctionalExpressionListCellRenderer
|
||||
import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.editor.colors.CodeInsightColors
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager
|
||||
@@ -151,20 +150,12 @@ interface TestableLineMarkerNavigator {
|
||||
fun getTargetsPopupDescriptor(element: PsiElement?): NavigationPopupDescriptor?
|
||||
}
|
||||
|
||||
private class SubclassRenderer: PsiClassOrFunctionalExpressionListCellRenderer() {
|
||||
override fun getComparingObject(element: NavigatablePsiElement?): Comparable<Nothing> {
|
||||
val baseText = super.getComparingObject(element)
|
||||
val moduleName = element?.module?.name ?: return baseText
|
||||
return "$baseText [$moduleName]"
|
||||
}
|
||||
}
|
||||
|
||||
private val SUBCLASSED_CLASS = MarkerType(
|
||||
"SUBCLASSED_CLASS",
|
||||
{ getPsiClass(it)?.let { MarkerType.getSubclassedClassTooltip(it) } },
|
||||
object : LineMarkerNavigator() {
|
||||
override fun browse(e: MouseEvent?, element: PsiElement?) {
|
||||
getPsiClass(element)?.let { MarkerType.navigateToSubclassedClass(e, it, SubclassRenderer()) }
|
||||
getPsiClass(element)?.let { MarkerType.navigateToSubclassedClass(e, it) }
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.idea.intentions
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.JvmCommonIntentionActionsFactory
|
||||
import com.intellij.codeInsight.intention.MethodInsertionInfo
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory
|
||||
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
|
||||
import org.jetbrains.kotlin.asJava.LightClassUtil
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.insertMembersAfter
|
||||
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory.CallableBuilder
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory.CallableBuilder.Target.CONSTRUCTOR
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory.CallableBuilder.Target.FUNCTION
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.uast.UClass
|
||||
import org.jetbrains.uast.UDeclaration
|
||||
import org.jetbrains.uast.UElement
|
||||
|
||||
class KotlinCommonIntentionActionsFactory : JvmCommonIntentionActionsFactory() {
|
||||
override fun createChangeModifierAction(declaration: UDeclaration, modifier: String, shouldPresent: Boolean): IntentionAction? {
|
||||
val kModifierOwner = declaration.asKtElement<KtModifierListOwner>()
|
||||
?: throw IllegalArgumentException("$declaration is expected to contain KtLightElement with KtModifierListOwner")
|
||||
|
||||
val (kToken, shouldPresentMapped) = if (PsiModifier.FINAL == modifier)
|
||||
KtTokens.OPEN_KEYWORD to !shouldPresent
|
||||
else
|
||||
javaPsiModifiersMapping[modifier] to shouldPresent
|
||||
|
||||
if (kToken == null) return null
|
||||
return if (shouldPresentMapped)
|
||||
AddModifierFix.createIfApplicable(kModifierOwner, kToken)
|
||||
else
|
||||
RemoveModifierFix(kModifierOwner, kToken, false)
|
||||
}
|
||||
|
||||
override fun createAddBeanPropertyActions(uClass: UClass,
|
||||
propertyName: String,
|
||||
visibilityModifier: String,
|
||||
propertyType: PsiType,
|
||||
setterRequired: Boolean,
|
||||
getterRequired: Boolean): List<IntentionAction> {
|
||||
|
||||
fun addPropertyFix(lateinit: Boolean = false) =
|
||||
Fix(uClass,
|
||||
"Add property",
|
||||
"Add '${if (lateinit) "lateinit " else ""}" +
|
||||
"${if (setterRequired) "var" else "val"}' property '$propertyName' to '${uClass.name}'")
|
||||
{ uClass ->
|
||||
val visibilityStr = javaVisibilityMapping.getValue(visibilityModifier)
|
||||
val psiFactory = KtPsiFactory(uClass)
|
||||
val modifiersString = if (lateinit) "lateinit $visibilityStr" else visibilityStr
|
||||
val function = psiFactory.createProperty(
|
||||
modifiersString,
|
||||
propertyName,
|
||||
typeString(propertyType),
|
||||
setterRequired,
|
||||
if (lateinit) null else "TODO(\"initialize me\")")
|
||||
val ktClassOrObject = uClass.asKtElement<KtClassOrObject>()!!
|
||||
insertMembersAfter(null, ktClassOrObject, listOf(function), null)
|
||||
}
|
||||
|
||||
if (setterRequired)
|
||||
return listOf(addPropertyFix(), addPropertyFix(lateinit = true))
|
||||
else
|
||||
return listOf(addPropertyFix())
|
||||
}
|
||||
|
||||
override fun createAddCallableMemberActions(info: MethodInsertionInfo): List<IntentionAction> =
|
||||
when (info) {
|
||||
is MethodInsertionInfo.Method ->
|
||||
createAddMethodAction(info)?.let { listOf(it) } ?: emptyList()
|
||||
|
||||
is MethodInsertionInfo.Constructor ->
|
||||
createAddConstructorActions(info)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val javaPsiModifiersMapping = mapOf(
|
||||
PsiModifier.PRIVATE to KtTokens.PRIVATE_KEYWORD,
|
||||
PsiModifier.PUBLIC to KtTokens.PUBLIC_KEYWORD,
|
||||
PsiModifier.PROTECTED to KtTokens.PUBLIC_KEYWORD,
|
||||
PsiModifier.ABSTRACT to KtTokens.ABSTRACT_KEYWORD
|
||||
)
|
||||
|
||||
val javaVisibilityMapping: Map<String, String> = mapOf(
|
||||
PsiModifier.PRIVATE to Visibilities.PRIVATE.displayName,
|
||||
PsiModifier.PUBLIC to "",
|
||||
PsiModifier.PROTECTED to Visibilities.PROTECTED.displayName,
|
||||
PsiModifier.PACKAGE_LOCAL to Visibilities.INTERNAL.displayName
|
||||
).withDefault { Visibilities.DEFAULT_VISIBILITY.displayName }
|
||||
|
||||
fun typeString(str: PsiType): String {
|
||||
var typeName: String? = when (str) {
|
||||
PsiType.VOID -> ""
|
||||
PsiType.INT -> "kotlin.Int"
|
||||
PsiType.LONG -> "kotlin.Long"
|
||||
PsiType.SHORT -> "kotlin.Short"
|
||||
PsiType.BOOLEAN -> "kotlin.Boolean"
|
||||
PsiType.BYTE -> "kotlin.Byte"
|
||||
PsiType.CHAR -> "kotlin.Char"
|
||||
PsiType.DOUBLE -> "kotlin.Double"
|
||||
PsiType.FLOAT -> "kotlin.Float"
|
||||
else -> null
|
||||
}
|
||||
if (typeName == null)
|
||||
typeName = JavaToKotlinClassMap.mapJavaToKotlin(FqName(str.canonicalText), DefaultBuiltIns.Instance)?.fqNameSafe?.asString()
|
||||
|
||||
return typeName ?: str.canonicalText
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : KtElement> UElement.asKtElement(): T? =
|
||||
(psi as? KtLightElement<*, *>?)?.kotlinOrigin as? T
|
||||
|
||||
private fun CallableBuilder.paramsFromInfo(info: MethodInsertionInfo) {
|
||||
for ((index, param) in info.parameters.withIndex()) {
|
||||
param(param.name ?: "arg${index + 1}", typeString(param.type))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAddMethodAction(info: MethodInsertionInfo.Method): IntentionAction? {
|
||||
val visibilityStr = info.modifiers.map { javaVisibilityMapping.get(it) ?: it }.joinToString(" ")
|
||||
val functionString = CallableBuilder(FUNCTION).apply {
|
||||
modifier(visibilityStr)
|
||||
typeParams()
|
||||
name(info.name)
|
||||
paramsFromInfo(info)
|
||||
info.returnType.let {
|
||||
when (it) {
|
||||
PsiType.VOID -> noReturnType()
|
||||
else -> returnType(typeString(it))
|
||||
}
|
||||
}
|
||||
blockBody("")
|
||||
}
|
||||
|
||||
return Fix(info.containingClass, "Add method", "Add method '${info.name}' to '${info.containingClass.name}'") {
|
||||
uClass ->
|
||||
val psiFactory = KtPsiFactory(uClass)
|
||||
val function = psiFactory.createFunction(functionString.asString())
|
||||
val ktClassOrObject = uClass.asKtElement<KtClassOrObject>()!!
|
||||
insertMembersAfter(null, ktClassOrObject, listOf(function), ktClassOrObject.declarations.lastOrNull())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun createAddConstructorActions(info: MethodInsertionInfo.Constructor): List<IntentionAction> {
|
||||
val constructorString = CallableBuilder(CONSTRUCTOR).apply {
|
||||
modifier("")
|
||||
typeParams()
|
||||
name()
|
||||
paramsFromInfo(info)
|
||||
noReturnType()
|
||||
blockBody("")
|
||||
}.asString()
|
||||
val primaryConstructor = info.containingClass.asKtElement<KtClass>()!!.primaryConstructor
|
||||
|
||||
val addConstructorAction = if (primaryConstructor == null)
|
||||
Fix(info.containingClass,
|
||||
"Add method",
|
||||
"Add primary constructor to '${info.containingClass.name}'",
|
||||
{ uClass ->
|
||||
val psiFactory = KtPsiFactory(uClass)
|
||||
val constructor = psiFactory.createSecondaryConstructor(constructorString)
|
||||
val ktClass = uClass.asKtElement<KtClass>()!!
|
||||
val newPrimaryConstructor = ktClass.createPrimaryConstructorIfAbsent()
|
||||
newPrimaryConstructor.valueParameterList!!.replace(constructor.valueParameterList!!)
|
||||
ShortenReferences.DEFAULT.process(newPrimaryConstructor)
|
||||
})
|
||||
else Fix(info.containingClass,
|
||||
"Add method",
|
||||
"Add secondary constructor to '${info.containingClass.name}'",
|
||||
{ uClass ->
|
||||
val psiFactory = KtPsiFactory(uClass)
|
||||
val constructor = psiFactory.createSecondaryConstructor(constructorString)
|
||||
val ktClassOrObject = uClass.asKtElement<KtClassOrObject>()!!
|
||||
insertMembersAfter(null, ktClassOrObject, listOf(constructor), null)
|
||||
})
|
||||
|
||||
val changePrimaryConstructorAction = run {
|
||||
if (primaryConstructor == null) return@run null
|
||||
QuickFixFactory.getInstance()
|
||||
.createChangeMethodSignatureFromUsageFix(
|
||||
LightClassUtil.getLightClassMethod(primaryConstructor)!!,
|
||||
fakeParametersExpressions(info.parameters),
|
||||
PsiSubstitutor.EMPTY, info.containingClass, false, 2
|
||||
).takeIf { it.isAvailable(info.containingClass.project, null, info.containingClass.containingFile) }
|
||||
}
|
||||
|
||||
return listOf(changePrimaryConstructorAction, addConstructorAction).filterNotNull()
|
||||
}
|
||||
|
||||
private fun fakeParametersExpressions(parameters: List<PsiParameter>): Array<PsiExpression> =
|
||||
when {
|
||||
parameters.isEmpty() -> emptyArray<PsiExpression>()
|
||||
else -> JavaPsiFacade.getElementFactory(parameters.first().project)
|
||||
.createParameterList(
|
||||
parameters.map { it.name }.toTypedArray(),
|
||||
parameters.map { it.type }.toTypedArray()
|
||||
).parameters.map { FakeExpressionFromParameter(it) }.toTypedArray()
|
||||
}
|
||||
|
||||
private class FakeExpressionFromParameter(private val psiParam: PsiParameter) : PsiReferenceExpressionImpl() {
|
||||
|
||||
override fun getText(): String = psiParam.name!!
|
||||
|
||||
override fun getProject(): Project = psiParam.project
|
||||
|
||||
override fun getParent(): PsiElement = psiParam.parent
|
||||
|
||||
override fun getType(): PsiType? = psiParam.type
|
||||
|
||||
override fun isValid(): Boolean = true
|
||||
|
||||
override fun getContainingFile(): PsiFile = psiParam.containingFile
|
||||
|
||||
override fun getReferenceName(): String? = psiParam.name
|
||||
|
||||
override fun resolve(): PsiElement? = psiParam
|
||||
}
|
||||
|
||||
private class Fix(uClass: UClass, private val familyName: String, private val text: String, private val action: (uClass: UClass) -> Unit) : LocalQuickFixAndIntentionActionOnPsiElement(uClass) {
|
||||
override fun getFamilyName(): String = familyName
|
||||
|
||||
override fun getText(): String = text
|
||||
|
||||
override fun invoke(project: Project, file: PsiFile, editor: Editor?, startElement: PsiElement, endElement: PsiElement) =
|
||||
action(startElement as UClass)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import com.intellij.codeInsight.hints.InlayParameterHintsExtension
|
||||
import com.intellij.internal.statistic.UsagesCollector
|
||||
import com.intellij.internal.statistic.beans.GroupDescriptor
|
||||
import com.intellij.internal.statistic.beans.UsageDescriptor
|
||||
import com.intellij.internal.statistic.utils.getBooleanUsage
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.util.compat.statistic.getBooleanUsage
|
||||
|
||||
class KotlinInlayParameterHintsUsageCollector : UsagesCollector() {
|
||||
override fun getGroupId(): GroupDescriptor = GroupDescriptor.create(GROUP_ID)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
|
||||
abstract class KotlinCrossLanguageQuickFixAction<out T : PsiElement>(element: T) : QuickFixActionBase<T>(element) {
|
||||
override val isCrossLanguageFix: Boolean
|
||||
get() = true
|
||||
|
||||
override final fun invoke(project: Project, editor: Editor?, file: PsiFile) {
|
||||
val element = element
|
||||
if (element != null && FileModificationService.getInstance().prepareFileForWrite(element.containingFile)) {
|
||||
invokeImpl(project, editor, file)
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun invokeImpl(project: Project, editor: Editor?, file: PsiFile)
|
||||
}
|
||||
@@ -17,18 +17,42 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.psi.CREATEBYPATTERN_MAY_NOT_REFORMAT
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||
|
||||
abstract class KotlinQuickFixAction<out T : PsiElement>(element: T) : QuickFixActionBase<T>(element) {
|
||||
protected open fun isAvailable(project: Project, editor: Editor?, file: KtFile) = true
|
||||
abstract class KotlinQuickFixAction<out T : PsiElement>(element: T) : IntentionAction {
|
||||
private val elementPointer = element.createSmartPointer()
|
||||
|
||||
override fun isAvailableImpl(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
val ktFile = file as? KtFile ?: return false
|
||||
return isAvailable(project, editor, ktFile)
|
||||
protected val element: T?
|
||||
get() = elementPointer.element
|
||||
|
||||
final override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
CREATEBYPATTERN_MAY_NOT_REFORMAT = true
|
||||
}
|
||||
try {
|
||||
val element = element ?: return false
|
||||
return element.isValid &&
|
||||
!element.project.isDisposed &&
|
||||
(file.manager.isInProject(file) || file is KtCodeFragment) &&
|
||||
(file is KtFile) &&
|
||||
isAvailable(project, editor, file)
|
||||
}
|
||||
finally {
|
||||
CREATEBYPATTERN_MAY_NOT_REFORMAT = false
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
final override fun invoke(project: Project, editor: Editor?, file: PsiFile) {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.psi.CREATEBYPATTERN_MAY_NOT_REFORMAT
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||
|
||||
abstract class QuickFixActionBase<out T : PsiElement>(element: T) : IntentionAction {
|
||||
private val elementPointer = element.createSmartPointer()
|
||||
|
||||
protected val element: T?
|
||||
get() = elementPointer.element
|
||||
|
||||
open val isCrossLanguageFix: Boolean = false
|
||||
|
||||
protected open fun isAvailableImpl(project: Project, editor: Editor?, file: PsiFile) = true
|
||||
|
||||
final override fun isAvailable(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
CREATEBYPATTERN_MAY_NOT_REFORMAT = true
|
||||
}
|
||||
try {
|
||||
val element = element ?: return false
|
||||
return element.isValid &&
|
||||
!element.project.isDisposed &&
|
||||
(file.manager.isInProject(file) || file is KtCodeFragment) &&
|
||||
(file is KtFile || isCrossLanguageFix) &&
|
||||
isAvailableImpl(project, editor, file)
|
||||
}
|
||||
finally {
|
||||
CREATEBYPATTERN_MAY_NOT_REFORMAT = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun startInWriteAction() = true
|
||||
}
|
||||
@@ -464,34 +464,16 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
|
||||
val psiFactory = KtPsiFactory(currentFile)
|
||||
|
||||
val modifiers = buildString {
|
||||
val modifierList = callableInfo.modifierList?.copied() ?: psiFactory.createEmptyModifierList()
|
||||
val visibilityKeyword = modifierList.visibilityModifierType()
|
||||
if (visibilityKeyword == null) {
|
||||
val defaultVisibility =
|
||||
if (callableInfo.isAbstract) ""
|
||||
else if (containingElement is KtClassOrObject
|
||||
&& !(containingElement is KtClass && containingElement.isInterface())
|
||||
&& containingElement.isAncestor(config.originalElement)
|
||||
&& callableInfo.kind != CallableKind.CONSTRUCTOR) "private "
|
||||
else if (isExtension) "private "
|
||||
else ""
|
||||
append(defaultVisibility)
|
||||
}
|
||||
|
||||
// TODO: Get rid of isAbstract
|
||||
if (callableInfo.isAbstract
|
||||
&& containingElement is KtClass
|
||||
&& !containingElement.isInterface()
|
||||
&& !modifierList.hasModifier(KtTokens.ABSTRACT_KEYWORD)) {
|
||||
modifierList.appendModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||
}
|
||||
|
||||
val text = modifierList.normalize().text
|
||||
if (text.isNotEmpty()) {
|
||||
append("$text ")
|
||||
}
|
||||
}
|
||||
val modifiers =
|
||||
if (callableInfo.isAbstract) {
|
||||
if (containingElement is KtClass && containingElement.isInterface()) "" else "abstract "
|
||||
}
|
||||
else if (containingElement is KtClassOrObject
|
||||
&& !(containingElement is KtClass && containingElement.isInterface())
|
||||
&& containingElement.isAncestor(config.originalElement)
|
||||
&& callableInfo.kind != CallableKind.CONSTRUCTOR) "private "
|
||||
else if (isExtension) "private "
|
||||
else ""
|
||||
|
||||
val isExpectClassMember by lazy {
|
||||
containingElement is KtClassOrObject && containingElement.resolveToDescriptorIfAny()?.isExpect ?: false
|
||||
@@ -500,7 +482,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
val declaration: KtNamedDeclaration = when (callableInfo.kind) {
|
||||
CallableKind.FUNCTION, CallableKind.CONSTRUCTOR -> {
|
||||
val body = when {
|
||||
callableInfo is ConstructorInfo -> if (callableInfo.withBody) "{\n\n}" else ""
|
||||
callableInfo.kind == CallableKind.CONSTRUCTOR -> ""
|
||||
callableInfo.isAbstract -> ""
|
||||
containingElement is KtClass && containingElement.hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
||||
containingElement is KtObjectDeclaration && containingElement.hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
||||
@@ -508,12 +490,14 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
&& containingElement.parent.parent is KtClass
|
||||
&& (containingElement.parent.parent as KtClass).hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
||||
isExpectClassMember -> ""
|
||||
else -> "{\n\n}"
|
||||
else -> "{}"
|
||||
|
||||
}
|
||||
@Suppress("USELESS_CAST") // KT-10755
|
||||
if (callableInfo is FunctionInfo) {
|
||||
psiFactory.createFunction("${modifiers}fun<> $header $body") as KtNamedDeclaration
|
||||
val operatorModifier = if (callableInfo.isOperator) "operator " else ""
|
||||
val infixModifier = if (callableInfo.isInfix) "infix " else ""
|
||||
psiFactory.createFunction("$modifiers$infixModifier${operatorModifier}fun<> $header $body") as KtNamedDeclaration
|
||||
}
|
||||
else if ((callableInfo as ConstructorInfo).isPrimary) {
|
||||
val constructorText = if (modifiers.isNotEmpty()) "${modifiers}constructor$paramList" else paramList
|
||||
@@ -572,11 +556,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
return assignmentToReplace.replace(declaration) as KtCallableDeclaration
|
||||
}
|
||||
|
||||
val container = if (containingElement is KtClass && callableInfo.isForCompanion) {
|
||||
containingElement.getOrCreateCompanionObject()
|
||||
}
|
||||
else containingElement
|
||||
val declarationInPlace = placeDeclarationInContainer(declaration, container, config.originalElement, jetFileToEdit)
|
||||
val declarationInPlace = placeDeclarationInContainer(declaration, containingElement, config.originalElement, jetFileToEdit)
|
||||
|
||||
if (declarationInPlace is KtSecondaryConstructor) {
|
||||
val containingClass = declarationInPlace.containingClassOrObject!!
|
||||
@@ -613,11 +593,14 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
}
|
||||
|
||||
private fun setupTypeReferencesForShortening(declaration: KtNamedDeclaration,
|
||||
parameterTypeExpressions: List<TypeExpression>) {
|
||||
parameterTypeExpressions: List<TypeExpression>): List<KtElement> {
|
||||
val typeRefsToShorten = ArrayList<KtElement>()
|
||||
|
||||
if (config.isExtension) {
|
||||
val receiverTypeText = receiverTypeCandidate!!.theType.renderLong(typeParameterNameMap).first()
|
||||
val replacingTypeRef = KtPsiFactory(declaration).createType(receiverTypeText)
|
||||
(declaration as KtCallableDeclaration).setReceiverTypeReference(replacingTypeRef)!!
|
||||
val newTypeRef = (declaration as KtCallableDeclaration).setReceiverTypeReference(replacingTypeRef)!!
|
||||
typeRefsToShorten.add(newTypeRef)
|
||||
}
|
||||
|
||||
val returnTypeRefs = declaration.getReturnTypeReferences()
|
||||
@@ -628,6 +611,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
if (returnType != null) {
|
||||
// user selected a given type
|
||||
replaceWithLongerName(returnTypeRefs, returnType)
|
||||
typeRefsToShorten.addAll(declaration.getReturnTypeReferences())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +630,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val expandedValueParameters = declaration.getValueParameters()
|
||||
parameterIndicesToShorten.mapNotNullTo(typeRefsToShorten) { expandedValueParameters[it].typeReference }
|
||||
|
||||
return typeRefsToShorten
|
||||
}
|
||||
|
||||
private fun postprocessDeclaration(declaration: KtNamedDeclaration) {
|
||||
@@ -656,22 +645,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
if (TypeUtils.isNullableType(returnType) || KotlinBuiltIns.isPrimitiveType(returnType)) return
|
||||
declaration.addModifier(KtTokens.LATEINIT_KEYWORD)
|
||||
}
|
||||
|
||||
if (callableInfo.isAbstract) {
|
||||
val containingClass = declaration.containingClassOrObject
|
||||
if (containingClass is KtClass && containingClass.isInterface()) {
|
||||
declaration.removeModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupDeclarationBody(func: KtDeclarationWithBody) {
|
||||
if (func !is KtNamedFunction && func !is KtPropertyAccessor) return
|
||||
if (skipReturnType && callableInfo is FunctionInfo && callableInfo.preferEmptyBody) return
|
||||
val oldBody = func.bodyExpression ?: return
|
||||
val templateKind = when (func) {
|
||||
is KtSecondaryConstructor -> TemplateKind.SECONDARY_CONSTRUCTOR
|
||||
is KtNamedFunction, is KtPropertyAccessor -> TemplateKind.FUNCTION
|
||||
else -> throw AssertionError("Unexpected declaration: " + func.getElementTextWithContext())
|
||||
}
|
||||
val bodyText = getFunctionBodyTextFromTemplate(
|
||||
func.project,
|
||||
TemplateKind.FUNCTION,
|
||||
templateKind,
|
||||
if (callableInfo.name.isNotEmpty()) callableInfo.name else null,
|
||||
if (skipReturnType) "Unit" else (func as? KtFunction)?.typeReference?.text ?: "",
|
||||
receiverClassDescriptor?.importableFqName ?: receiverClassDescriptor?.name?.let { FqName.topLevel(it) }
|
||||
@@ -778,7 +763,13 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
|
||||
// add parameter name to the template
|
||||
val possibleNamesFromExpression = parameter.typeInfo.getPossibleNamesFromExpression(currentFileContext)
|
||||
val possibleNames = arrayOf(*parameter.nameSuggestions.toTypedArray(), *possibleNamesFromExpression)
|
||||
val preferredName = parameter.preferredName
|
||||
val possibleNames = if (preferredName != null) {
|
||||
arrayOf(preferredName, *possibleNamesFromExpression)
|
||||
}
|
||||
else {
|
||||
possibleNamesFromExpression
|
||||
}
|
||||
|
||||
// figure out suggested names for each type option
|
||||
val parameterTypeToNamesMap = HashMap<String, Array<String>>()
|
||||
@@ -972,14 +963,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
|
||||
if (newDeclaration is KtProperty) {
|
||||
newDeclaration.getter?.let { setupDeclarationBody(it) }
|
||||
|
||||
if (newDeclaration.getter == null
|
||||
&& newDeclaration.initializer == null
|
||||
&& callableInfo is PropertyInfo
|
||||
&& callableInfo.withInitializer
|
||||
&& !callableInfo.isLateinitPreferred) {
|
||||
newDeclaration.initializer = KtPsiFactory(newDeclaration).createExpression("TODO(\"initialize me\")")
|
||||
}
|
||||
}
|
||||
|
||||
val callElement = config.originalElement as? KtCallElement
|
||||
@@ -990,9 +973,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
CodeStyleManager.getInstance(project).reformat(newDeclaration)
|
||||
|
||||
// change short type names to fully qualified ones (to be shortened below)
|
||||
setupTypeReferencesForShortening(newDeclaration, parameterTypeExpressions)
|
||||
val typeRefsToShorten = setupTypeReferencesForShortening(newDeclaration, parameterTypeExpressions)
|
||||
if (!transformToJavaMemberIfApplicable(newDeclaration)) {
|
||||
elementsToShorten.add(newDeclaration)
|
||||
elementsToShorten.addAll(typeRefsToShorten)
|
||||
setupEditor(newDeclaration)
|
||||
}
|
||||
}
|
||||
@@ -1119,24 +1102,17 @@ internal fun <D : KtNamedDeclaration> placeDeclarationInContainer(
|
||||
}
|
||||
|
||||
container is KtClassOrObject -> {
|
||||
var sibling: PsiElement? = container.declarations.lastOrNull { it::class == declaration::class }
|
||||
if (sibling == null && declaration is KtProperty) {
|
||||
sibling = container.getBody()?.lBrace
|
||||
}
|
||||
|
||||
insertMember(null, container, declaration, sibling)
|
||||
insertMember(null, container, declaration, container.declarations.lastOrNull())
|
||||
}
|
||||
else -> throw AssertionError("Invalid containing element: ${container.text}")
|
||||
}
|
||||
|
||||
if (declaration !is KtPrimaryConstructor) {
|
||||
val parent = declarationInPlace.parent
|
||||
calcNecessaryEmptyLines(declarationInPlace, false).let {
|
||||
if (it > 0) parent.addBefore(psiFactory.createNewLine(it), declarationInPlace)
|
||||
}
|
||||
calcNecessaryEmptyLines(declarationInPlace, true).let {
|
||||
if (it > 0) parent.addAfter(psiFactory.createNewLine(it), declarationInPlace)
|
||||
}
|
||||
val parent = declarationInPlace.parent
|
||||
calcNecessaryEmptyLines(declarationInPlace, false).let {
|
||||
if (it > 0) parent.addBefore(psiFactory.createNewLine(it), declarationInPlace)
|
||||
}
|
||||
calcNecessaryEmptyLines(declarationInPlace, true).let {
|
||||
if (it > 0) parent.addAfter(psiFactory.createNewLine(it), declarationInPlace)
|
||||
}
|
||||
return declarationInPlace
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassInfo
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.idea.util.getResolvableApproximations
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
@@ -71,10 +70,6 @@ abstract class TypeInfo(val variance: Variance) {
|
||||
(builder.placement as CallablePlacement.WithReceiver).receiverTypeCandidate.theType.getPossibleSupertypes(variance, builder)
|
||||
}
|
||||
|
||||
class ByExplicitCandidateTypes(val types: List<KotlinType>) : TypeInfo(Variance.INVARIANT) {
|
||||
override fun getPossibleTypes(builder: CallableBuilder) = types
|
||||
}
|
||||
|
||||
abstract class DelegatingTypeInfo(val delegate: TypeInfo): TypeInfo(delegate.variance) {
|
||||
override val substitutionsAllowed: Boolean = delegate.substitutionsAllowed
|
||||
override fun getPossibleNamesFromExpression(bindingContext: BindingContext) = delegate.getPossibleNamesFromExpression(bindingContext)
|
||||
@@ -160,10 +155,8 @@ fun TypeInfo.ofThis() = TypeInfo.OfThis(this)
|
||||
*/
|
||||
class ParameterInfo(
|
||||
val typeInfo: TypeInfo,
|
||||
val nameSuggestions: List<String>
|
||||
) {
|
||||
constructor(typeInfo: TypeInfo, preferredName: String? = null): this(typeInfo, listOfNotNull(preferredName))
|
||||
}
|
||||
val preferredName: String? = null
|
||||
)
|
||||
|
||||
enum class CallableKind {
|
||||
FUNCTION,
|
||||
@@ -178,17 +171,14 @@ abstract class CallableInfo (
|
||||
val returnTypeInfo: TypeInfo,
|
||||
val possibleContainers: List<KtElement>,
|
||||
val typeParameterInfos: List<TypeInfo>,
|
||||
val isForCompanion: Boolean = false,
|
||||
val modifierList: KtModifierList? = null
|
||||
val isAbstract: Boolean = false
|
||||
) {
|
||||
abstract val kind: CallableKind
|
||||
abstract val parameterInfos: List<ParameterInfo>
|
||||
|
||||
val isAbstract get() = modifierList?.hasModifier(KtTokens.ABSTRACT_KEYWORD) == true
|
||||
|
||||
abstract fun copy(receiverTypeInfo: TypeInfo = this.receiverTypeInfo,
|
||||
possibleContainers: List<KtElement> = this.possibleContainers,
|
||||
modifierList: KtModifierList? = this.modifierList): CallableInfo
|
||||
isAbstract: Boolean = this.isAbstract): CallableInfo
|
||||
}
|
||||
|
||||
class FunctionInfo(name: String,
|
||||
@@ -197,59 +187,42 @@ class FunctionInfo(name: String,
|
||||
possibleContainers: List<KtElement> = Collections.emptyList(),
|
||||
override val parameterInfos: List<ParameterInfo> = Collections.emptyList(),
|
||||
typeParameterInfos: List<TypeInfo> = Collections.emptyList(),
|
||||
isForCompanion: Boolean = false,
|
||||
modifierList: KtModifierList? = null,
|
||||
val preferEmptyBody: Boolean = false
|
||||
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isForCompanion, modifierList) {
|
||||
val isOperator: Boolean = false,
|
||||
val isInfix: Boolean = false,
|
||||
isAbstract: Boolean = false
|
||||
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isAbstract) {
|
||||
override val kind: CallableKind get() = CallableKind.FUNCTION
|
||||
|
||||
override fun copy(
|
||||
receiverTypeInfo: TypeInfo,
|
||||
possibleContainers: List<KtElement>,
|
||||
modifierList: KtModifierList?
|
||||
) = FunctionInfo(
|
||||
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = FunctionInfo(
|
||||
name,
|
||||
receiverTypeInfo,
|
||||
returnTypeInfo,
|
||||
possibleContainers,
|
||||
parameterInfos,
|
||||
typeParameterInfos,
|
||||
isForCompanion,
|
||||
modifierList
|
||||
isOperator,
|
||||
isInfix,
|
||||
isAbstract
|
||||
)
|
||||
}
|
||||
|
||||
class ClassWithPrimaryConstructorInfo(
|
||||
val classInfo: ClassInfo,
|
||||
expectedTypeInfo: TypeInfo,
|
||||
modifierList: KtModifierList? = null
|
||||
): CallableInfo(
|
||||
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments, false, modifierList = modifierList
|
||||
class ClassWithPrimaryConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInfo): CallableInfo(
|
||||
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments, false
|
||||
) {
|
||||
override val kind: CallableKind get() = CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR
|
||||
override val parameterInfos: List<ParameterInfo> get() = classInfo.parameterInfos
|
||||
|
||||
override fun copy(
|
||||
receiverTypeInfo: TypeInfo,
|
||||
possibleContainers: List<KtElement>,
|
||||
modifierList: KtModifierList?
|
||||
) = throw UnsupportedOperationException()
|
||||
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
class ConstructorInfo(
|
||||
override val parameterInfos: List<ParameterInfo>,
|
||||
val targetClass: PsiElement,
|
||||
val isPrimary: Boolean = false,
|
||||
modifierList: KtModifierList? = null,
|
||||
val withBody: Boolean = false
|
||||
): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList(), false, modifierList = modifierList) {
|
||||
val isPrimary: Boolean = false
|
||||
): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList(), false) {
|
||||
override val kind: CallableKind get() = CallableKind.CONSTRUCTOR
|
||||
|
||||
override fun copy(
|
||||
receiverTypeInfo: TypeInfo,
|
||||
possibleContainers: List<KtElement>,
|
||||
modifierList: KtModifierList?
|
||||
) = throw UnsupportedOperationException()
|
||||
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
class PropertyInfo(name: String,
|
||||
@@ -258,35 +231,20 @@ class PropertyInfo(name: String,
|
||||
val writable: Boolean,
|
||||
possibleContainers: List<KtElement> = Collections.emptyList(),
|
||||
typeParameterInfos: List<TypeInfo> = Collections.emptyList(),
|
||||
val isLateinitPreferred: Boolean = false,
|
||||
isForCompanion: Boolean = false,
|
||||
modifierList: KtModifierList? = null,
|
||||
val withInitializer: Boolean = false
|
||||
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isForCompanion, modifierList) {
|
||||
isAbstract: Boolean = false,
|
||||
val isLateinitPreferred: Boolean = false
|
||||
) : CallableInfo(name, receiverTypeInfo, returnTypeInfo, possibleContainers, typeParameterInfos, isAbstract) {
|
||||
override val kind: CallableKind get() = CallableKind.PROPERTY
|
||||
override val parameterInfos: List<ParameterInfo> get() = Collections.emptyList()
|
||||
|
||||
override fun copy(
|
||||
receiverTypeInfo: TypeInfo,
|
||||
possibleContainers: List<KtElement>,
|
||||
modifierList: KtModifierList?
|
||||
) = copyProperty(receiverTypeInfo, possibleContainers, modifierList)
|
||||
|
||||
fun copyProperty(
|
||||
receiverTypeInfo: TypeInfo = this.receiverTypeInfo,
|
||||
possibleContainers: List<KtElement> = this.possibleContainers,
|
||||
modifierList: KtModifierList? = this.modifierList,
|
||||
isLateinitPreferred: Boolean = this.isLateinitPreferred
|
||||
) = PropertyInfo(
|
||||
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = PropertyInfo(
|
||||
name,
|
||||
receiverTypeInfo,
|
||||
returnTypeInfo,
|
||||
writable,
|
||||
possibleContainers,
|
||||
typeParameterInfos,
|
||||
isLateinitPreferred,
|
||||
isForCompanion,
|
||||
modifierList,
|
||||
withInitializer
|
||||
isAbstract,
|
||||
isLateinitPreferred
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,13 +29,11 @@ fun setupEditorSelection(editor: Editor, declaration: KtNamedDeclaration) {
|
||||
val caretModel = editor.caretModel
|
||||
val selectionModel = editor.selectionModel
|
||||
|
||||
val offset = when (declaration) {
|
||||
is KtPrimaryConstructor -> declaration.getConstructorKeyword()?.endOffset ?: declaration.valueParameterList?.startOffset
|
||||
is KtSecondaryConstructor -> declaration.getConstructorKeyword().endOffset
|
||||
else -> declaration.nameIdentifier?.endOffset
|
||||
if (declaration is KtSecondaryConstructor) {
|
||||
caretModel.moveToOffset(declaration.getConstructorKeyword().endOffset)
|
||||
}
|
||||
if (offset != null) {
|
||||
caretModel.moveToOffset(offset)
|
||||
else {
|
||||
caretModel.moveToOffset(declaration.nameIdentifier!!.endOffset)
|
||||
}
|
||||
|
||||
fun positionBetween(left: PsiElement, right: PsiElement) {
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
@@ -56,12 +55,8 @@ object CreateBinaryOperationActionFactory : CreateCallableMemberFromUsageFactory
|
||||
}
|
||||
val parameters = Collections.singletonList(ParameterInfo(TypeInfo(argumentExpr, Variance.IN_VARIANCE)))
|
||||
val isOperator = token != KtTokens.IDENTIFIER
|
||||
return FunctionInfo(
|
||||
operationName,
|
||||
receiverType,
|
||||
returnType,
|
||||
parameterInfos = parameters,
|
||||
modifierList = KtPsiFactory(element).createModifierList(if (isOperator) KtTokens.OPERATOR_KEYWORD else KtTokens.INFIX_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(operationName, receiverType, returnType, parameterInfos = parameters,
|
||||
isOperator = isOperator,
|
||||
isInfix = !isOperator)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,10 +153,7 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
|
||||
|
||||
if (!receiverType.isAbstract() && TypeUtils.getAllSupertypes(receiverType).all { !it.isAbstract() }) return null
|
||||
|
||||
return mainCallable.copy(
|
||||
receiverTypeInfo = receiverTypeInfo,
|
||||
possibleContainers = emptyList(),
|
||||
modifierList = KtPsiFactory(originalExpression).createModifierList(KtTokens.ABSTRACT_KEYWORD))
|
||||
return mainCallable.copy(receiverTypeInfo = receiverTypeInfo, possibleContainers = emptyList(), isAbstract = true)
|
||||
}
|
||||
|
||||
protected fun getCallableWithReceiverInsideExtension(
|
||||
|
||||
@@ -17,18 +17,14 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.ide.util.EditorHelper
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinCrossLanguageQuickFixAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary
|
||||
@@ -37,31 +33,30 @@ import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.isAbstract
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import java.util.*
|
||||
|
||||
open class CreateCallableFromUsageFix<E : KtElement>(
|
||||
originalExpression: E,
|
||||
callableInfos: List<CallableInfo>
|
||||
class CreateCallableFromUsageFix<E : KtElement>(
|
||||
originalExpression: E,
|
||||
callableInfos: List<CallableInfo>
|
||||
) : CreateCallableFromUsageFixBase<E>(originalExpression, callableInfos, false)
|
||||
|
||||
class CreateExtensionCallableFromUsageFix<E : KtElement>(
|
||||
originalExpression: E,
|
||||
callableInfos: List<CallableInfo>
|
||||
originalExpression: E,
|
||||
callableInfos: List<CallableInfo>
|
||||
) : CreateCallableFromUsageFixBase<E>(originalExpression, callableInfos, true), LowPriorityAction
|
||||
|
||||
abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
originalExpression: E,
|
||||
protected val callableInfos: List<CallableInfo>,
|
||||
val isExtension: Boolean
|
||||
) : KotlinCrossLanguageQuickFixAction<E>(originalExpression) {
|
||||
originalExpression: E,
|
||||
private val callableInfos: List<CallableInfo>,
|
||||
val isExtension: Boolean
|
||||
) : CreateFromUsageFixBase<E>(originalExpression) {
|
||||
init {
|
||||
assert(callableInfos.isNotEmpty()) { "No CallableInfos: ${originalExpression.getElementTextWithContext()}" }
|
||||
assert (callableInfos.isNotEmpty()) { "No CallableInfos: ${originalExpression.getElementTextWithContext()}" }
|
||||
if (callableInfos.size > 1) {
|
||||
val receiverSet = callableInfos.mapTo(HashSet()) { it.receiverTypeInfo }
|
||||
val receiverSet = callableInfos.mapTo(HashSet<TypeInfo>()) { it.receiverTypeInfo }
|
||||
if (receiverSet.size > 1) throw AssertionError("All functions must have common receiver: $receiverSet")
|
||||
|
||||
val possibleContainerSet = callableInfos.mapTo(HashSet()) { it.possibleContainers }
|
||||
val possibleContainerSet = callableInfos.mapTo(HashSet<List<KtElement>>()) { it.possibleContainers }
|
||||
if (possibleContainerSet.size > 1) throw AssertionError("All functions must have common containers: $possibleContainerSet")
|
||||
}
|
||||
}
|
||||
@@ -82,8 +77,6 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
return if (isExtension || declaration.canRefactor()) declaration else null
|
||||
}
|
||||
|
||||
override fun getFamilyName(): String = KotlinBundle.message("create.from.usage.family")
|
||||
|
||||
override fun getText(): String {
|
||||
val element = element ?: return ""
|
||||
val receiverTypeInfo = callableInfos.first().receiverTypeInfo
|
||||
@@ -106,18 +99,20 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
|
||||
val receiverType = if (!receiverTypeInfo.isOfThis) {
|
||||
CallableBuilderConfiguration(callableInfos, element, isExtension = isExtension)
|
||||
.createBuilder()
|
||||
.computeTypeCandidates(receiverTypeInfo)
|
||||
.firstOrNull()
|
||||
?.theType
|
||||
} else null
|
||||
.createBuilder()
|
||||
.computeTypeCandidates(receiverTypeInfo)
|
||||
.firstOrNull()
|
||||
?.theType
|
||||
}
|
||||
else null
|
||||
|
||||
if (receiverType != null) {
|
||||
if (isExtension) {
|
||||
val receiverTypeText = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(receiverType)
|
||||
val isFunctionType = receiverType.constructor.declarationDescriptor is FunctionClassDescriptor
|
||||
append(if (isFunctionType) "($receiverTypeText)" else receiverTypeText).append('.')
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
receiverType.constructor.declarationDescriptor?.let {
|
||||
append(IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderClassifierName(it)).append('.')
|
||||
}
|
||||
@@ -132,10 +127,12 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
return StringBuilder().apply {
|
||||
append("Create ")
|
||||
|
||||
val receiverInfo = receiverTypeInfo
|
||||
if (!callableInfos.any { it.isAbstract }) {
|
||||
if (isExtension) {
|
||||
append("extension ")
|
||||
} else if (receiverTypeInfo != TypeInfo.Empty) {
|
||||
}
|
||||
else if (receiverInfo !is TypeInfo.Empty) {
|
||||
append("member ")
|
||||
}
|
||||
}
|
||||
@@ -144,12 +141,12 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
}.toString()
|
||||
}
|
||||
|
||||
override fun isAvailableImpl(project: Project, editor: Editor?, file: PsiFile): Boolean {
|
||||
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean {
|
||||
val element = element ?: return false
|
||||
|
||||
val receiverInfo = callableInfos.first().receiverTypeInfo
|
||||
|
||||
if (receiverInfo == TypeInfo.Empty) {
|
||||
if (receiverInfo is TypeInfo.Empty) {
|
||||
if (callableInfos.any { it is PropertyInfo && it.possibleContainers.isEmpty() }) return false
|
||||
return !isExtension
|
||||
}
|
||||
@@ -176,25 +173,12 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
}
|
||||
}
|
||||
|
||||
override fun invokeImpl(project: Project, editor: Editor?, file: PsiFile) {
|
||||
if (editor == null) return
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val element = element ?: return
|
||||
val callableInfo = callableInfos.first()
|
||||
|
||||
val fileForBuilder: KtFile
|
||||
val editorForBuilder: Editor
|
||||
if (file is KtFile) {
|
||||
fileForBuilder = file
|
||||
editorForBuilder = editor
|
||||
} else {
|
||||
fileForBuilder = element.containingKtFile
|
||||
EditorHelper.openInEditor(element)
|
||||
editorForBuilder = FileEditorManager.getInstance(project).selectedTextEditor!!
|
||||
}
|
||||
|
||||
val callableBuilder =
|
||||
CallableBuilderConfiguration(callableInfos, element as KtElement, fileForBuilder, editorForBuilder, isExtension).createBuilder()
|
||||
CallableBuilderConfiguration(callableInfos, element as KtElement, file, editor!!, isExtension).createBuilder()
|
||||
|
||||
fun runBuilder(placement: CallablePlacement) {
|
||||
callableBuilder.placement = placement
|
||||
@@ -207,24 +191,19 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
}
|
||||
|
||||
val popupTitle = "Choose target class or interface"
|
||||
val receiverTypeInfo = callableInfo.receiverTypeInfo
|
||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(receiverTypeInfo).let {
|
||||
if (callableInfo.isAbstract)
|
||||
it.filter { it.theType.isAbstract() }
|
||||
else if (!isExtension && receiverTypeInfo != TypeInfo.Empty)
|
||||
it.filter { !it.theType.isTypeParameter() }
|
||||
else
|
||||
it
|
||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo).let {
|
||||
if (callableInfo.isAbstract) it.filter { it.theType.isAbstract() } else it
|
||||
}
|
||||
if (receiverTypeCandidates.isNotEmpty()) {
|
||||
val containers = receiverTypeCandidates
|
||||
.mapNotNull { candidate -> getDeclarationIfApplicable(project, candidate)?.let { candidate to it } }
|
||||
.mapNotNull { candidate -> getDeclarationIfApplicable(project, candidate)?.let { candidate to it } }
|
||||
|
||||
chooseContainerElementIfNecessary(containers, editor, popupTitle, false, { it.second }) {
|
||||
runBuilder(CallablePlacement.WithReceiver(it.first))
|
||||
}
|
||||
} else {
|
||||
assert(receiverTypeInfo == TypeInfo.Empty) {
|
||||
}
|
||||
else {
|
||||
assert(callableInfo.receiverTypeInfo is TypeInfo.Empty) {
|
||||
"No receiver type candidates: ${element.text} in ${file.text}"
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.SmartPsiElementPointer
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.quickfix.IntentionActionPriority
|
||||
@@ -36,7 +35,7 @@ abstract class CreateCallableMemberFromUsageFactory<E : KtElement>(
|
||||
originalElementPointer: SmartPsiElementPointer<E>,
|
||||
priority: IntentionActionPriority,
|
||||
quickFixDataFactory: () -> List<CallableInfo>?,
|
||||
quickFixFactory: (E, List<CallableInfo>) -> IntentionAction?
|
||||
quickFixFactory: (E, List<CallableInfo>) -> CreateFromUsageFixBase<E>?
|
||||
): QuickFixWithDelegateFactory {
|
||||
return QuickFixWithDelegateFactory(priority) {
|
||||
val data = quickFixDataFactory().orEmpty()
|
||||
|
||||
@@ -23,10 +23,8 @@ import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -54,11 +52,6 @@ object CreateComponentFunctionActionFactory : CreateCallableMemberFromUsageFacto
|
||||
val entry = entries[componentNumber]
|
||||
val returnTypeInfo = TypeInfo(entry, Variance.OUT_VARIANCE)
|
||||
|
||||
return FunctionInfo(
|
||||
name.identifier,
|
||||
ownerTypeInfo,
|
||||
returnTypeInfo,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(name.identifier, ownerTypeInfo, returnTypeInfo, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.Callab
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import java.util.*
|
||||
@@ -36,12 +34,7 @@ object CreateGetFunctionActionFactory : CreateGetSetFunctionActionFactory(isGet
|
||||
val parameters = element.indexExpressions.map { ParameterInfo(TypeInfo(it, Variance.IN_VARIANCE)) }
|
||||
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
OperatorNameConventions.GET.asString(),
|
||||
arrayType,
|
||||
returnType,
|
||||
Collections.emptyList(),
|
||||
parameters,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
OperatorNameConventions.GET.asString(), arrayType, returnType, Collections.emptyList(), parameters, isOperator = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,7 @@ import org.jetbrains.kotlin.idea.project.builtIns
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
@@ -40,11 +38,6 @@ object CreateHasNextFunctionActionFactory : CreateCallableMemberFromUsageFactory
|
||||
DiagnosticFactory.cast(diagnostic, Errors.HAS_NEXT_MISSING, Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE)
|
||||
val ownerType = TypeInfo(diagnosticWithParameters.a, Variance.IN_VARIANCE)
|
||||
val returnType = TypeInfo(element.builtIns.booleanType, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
OperatorNameConventions.HAS_NEXT.asString(),
|
||||
ownerType,
|
||||
returnType,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(OperatorNameConventions.HAS_NEXT.asString(), ownerType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,7 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.Callab
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
@@ -50,12 +48,6 @@ object CreateInvokeFunctionActionFactory : CreateCallableMemberFromUsageFactory<
|
||||
}
|
||||
|
||||
val returnType = TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
OperatorNameConventions.INVOKE.asString(),
|
||||
receiverType,
|
||||
returnType,
|
||||
parameterInfos = parameters,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(OperatorNameConventions.INVOKE.asString(), receiverType, returnType, parameterInfos = parameters, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,9 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.Callab
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -59,11 +57,6 @@ object CreateIteratorFunctionActionFactory : CreateCallableMemberFromUsageFactor
|
||||
returnJetType.isMarkedNullable,
|
||||
returnJetType.memberScope)
|
||||
val returnType = TypeInfo(newReturnJetType, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
OperatorNameConventions.ITERATOR.asString(),
|
||||
iterableType,
|
||||
returnType,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(OperatorNameConventions.ITERATOR.asString(), iterableType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,10 +23,8 @@ import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
@@ -41,11 +39,6 @@ object CreateNextFunctionActionFactory : CreateCallableMemberFromUsageFactory<Kt
|
||||
|
||||
val variableExpr = element.loopParameter ?: element.destructuringDeclaration ?: return null
|
||||
val returnType = TypeInfo(variableExpr as KtExpression, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
OperatorNameConventions.NEXT.asString(),
|
||||
ownerType,
|
||||
returnType,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(OperatorNameConventions.NEXT.asString(), ownerType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,8 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.Callab
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
@@ -71,15 +69,13 @@ object CreatePropertyDelegateAccessorsActionFactory : CreateCallableMemberFromUs
|
||||
|
||||
val callableInfos = SmartList<CallableInfo>()
|
||||
|
||||
val psiFactory = KtPsiFactory(element)
|
||||
|
||||
if (isApplicableForAccessor(propertyDescriptor.getter)) {
|
||||
val getterInfo = FunctionInfo(
|
||||
name = OperatorNameConventions.GET_VALUE.asString(),
|
||||
receiverTypeInfo = accessorReceiverType,
|
||||
returnTypeInfo = TypeInfo(propertyType, Variance.OUT_VARIANCE),
|
||||
parameterInfos = listOf(thisRefParam, metadataParam),
|
||||
modifierList = psiFactory.createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
isOperator = true
|
||||
)
|
||||
callableInfos.add(getterInfo)
|
||||
}
|
||||
@@ -91,7 +87,7 @@ object CreatePropertyDelegateAccessorsActionFactory : CreateCallableMemberFromUs
|
||||
receiverTypeInfo = accessorReceiverType,
|
||||
returnTypeInfo = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE),
|
||||
parameterInfos = listOf(thisRefParam, metadataParam, newValueParam),
|
||||
modifierList = psiFactory.createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
isOperator = true
|
||||
)
|
||||
callableInfos.add(setterInfo)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.Callab
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -59,12 +58,7 @@ object CreateSetFunctionActionFactory : CreateGetSetFunctionActionFactory(isGet
|
||||
|
||||
val returnType = TypeInfo(builtIns.unitType, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
OperatorNameConventions.SET.asString(),
|
||||
arrayType,
|
||||
returnType,
|
||||
Collections.emptyList(),
|
||||
parameters,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
OperatorNameConventions.SET.asString(), arrayType, returnType, Collections.emptyList(), parameters, isOperator = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,6 @@ import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.Callab
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.FunctionInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.lexer.KtToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtUnaryExpression
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
@@ -41,11 +39,6 @@ object CreateUnaryOperationActionFactory: CreateCallableMemberFromUsageFactory<K
|
||||
|
||||
val receiverType = TypeInfo(receiverExpr, Variance.IN_VARIANCE)
|
||||
val returnType = if (incDec) TypeInfo.ByReceiverType(Variance.OUT_VARIANCE) else TypeInfo(element, Variance.OUT_VARIANCE)
|
||||
return FunctionInfo(
|
||||
operationName.asString(),
|
||||
receiverType,
|
||||
returnType,
|
||||
modifierList = KtPsiFactory(element).createModifierList(KtTokens.OPERATOR_KEYWORD)
|
||||
)
|
||||
return FunctionInfo(operationName.asString(), receiverType, returnType, isOperator = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.idea.quickfix.crossLanguage
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory
|
||||
import com.intellij.lang.jvm.*
|
||||
import com.intellij.lang.jvm.actions.*
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||
import org.jetbrains.kotlin.asJava.toLightMethods
|
||||
import org.jetbrains.kotlin.asJava.unwrapped
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.appendModifier
|
||||
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.RemoveModifierFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateCallableFromUsageFix
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.approximateFlexibleTypes
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.components.TypeUsage
|
||||
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
|
||||
import org.jetbrains.kotlin.load.java.lazy.child
|
||||
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeAttributes
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.annotations.JVM_FIELD_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
|
||||
class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
companion object {
|
||||
val javaPsiModifiersMapping = mapOf(
|
||||
JvmModifier.PRIVATE to KtTokens.PRIVATE_KEYWORD,
|
||||
JvmModifier.PUBLIC to KtTokens.PUBLIC_KEYWORD,
|
||||
JvmModifier.PROTECTED to KtTokens.PUBLIC_KEYWORD,
|
||||
JvmModifier.ABSTRACT to KtTokens.ABSTRACT_KEYWORD
|
||||
)
|
||||
}
|
||||
|
||||
private class FakeExpressionFromParameter(private val psiParam: PsiParameter) : PsiReferenceExpressionImpl() {
|
||||
override fun getText(): String = psiParam.name!!
|
||||
override fun getProject(): Project = psiParam.project
|
||||
override fun getParent(): PsiElement = psiParam.parent
|
||||
override fun getType(): PsiType? = psiParam.type
|
||||
override fun isValid(): Boolean = true
|
||||
override fun getContainingFile(): PsiFile = psiParam.containingFile
|
||||
override fun getReferenceName(): String? = psiParam.name
|
||||
override fun resolve(): PsiElement? = psiParam
|
||||
}
|
||||
|
||||
private class ModifierBuilder(
|
||||
private val targetContainer: KtElement,
|
||||
private val allowJvmStatic: Boolean = true
|
||||
) {
|
||||
private val psiFactory = KtPsiFactory(targetContainer.project)
|
||||
|
||||
val modifierList = psiFactory.createEmptyModifierList()
|
||||
|
||||
private fun JvmModifier.transformAndAppend(): Boolean {
|
||||
javaPsiModifiersMapping[this]?.let {
|
||||
modifierList.appendModifier(it)
|
||||
return true
|
||||
}
|
||||
|
||||
when (this) {
|
||||
JvmModifier.STATIC -> {
|
||||
if (allowJvmStatic && targetContainer is KtClassOrObject) {
|
||||
addAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME)
|
||||
}
|
||||
}
|
||||
JvmModifier.ABSTRACT -> modifierList.appendModifier(KtTokens.ABSTRACT_KEYWORD)
|
||||
JvmModifier.FINAL -> modifierList.appendModifier(KtTokens.FINAL_KEYWORD)
|
||||
else -> return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
var isValid = true
|
||||
private set
|
||||
|
||||
fun addJvmModifier(modifier: JvmModifier) {
|
||||
isValid = isValid && modifier.transformAndAppend()
|
||||
}
|
||||
|
||||
fun addJvmModifiers(modifiers: Iterable<JvmModifier>) {
|
||||
modifiers.forEach { addJvmModifier(it) }
|
||||
}
|
||||
|
||||
fun addAnnotation(fqName: FqName) {
|
||||
if (!isValid) return
|
||||
modifierList.add(psiFactory.createAnnotationEntry("@${fqName.asString()}"))
|
||||
}
|
||||
}
|
||||
|
||||
class CreatePropertyFix(
|
||||
private val targetClass: JvmClass,
|
||||
contextElement: KtElement,
|
||||
propertyInfo: PropertyInfo
|
||||
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
|
||||
override fun getFamilyName() = "Add property"
|
||||
override fun getText(): String {
|
||||
val info = callableInfos.first() as PropertyInfo
|
||||
return buildString {
|
||||
append("Add '")
|
||||
if (info.isLateinitPreferred) {
|
||||
append("lateinit ")
|
||||
}
|
||||
append(if (info.writable) "var" else "val")
|
||||
append("' property '${info.name}' to '${targetClass.name}'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun JvmClass.toKtClassOrFile(): KtElement? {
|
||||
val psi = sourceElement
|
||||
return when (psi) {
|
||||
is KtClassOrObject -> psi
|
||||
is KtLightClassForSourceDeclaration -> psi.kotlinOrigin
|
||||
is KtLightClassForFacade -> psi.files.firstOrNull()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : KtElement> JvmElement.toKtElement() = sourceElement?.unwrapped as? T
|
||||
|
||||
private fun fakeParametersExpressions(parameters: List<JvmParameter>, project: Project): Array<PsiExpression>? =
|
||||
when {
|
||||
parameters.isEmpty() -> emptyArray()
|
||||
else -> JavaPsiFacade
|
||||
.getElementFactory(project)
|
||||
.createParameterList(
|
||||
parameters.map { it.name }.toTypedArray(),
|
||||
parameters.map { it.type as? PsiType ?: return null }.toTypedArray()
|
||||
)
|
||||
.parameters
|
||||
.map(::FakeExpressionFromParameter)
|
||||
.toTypedArray()
|
||||
}
|
||||
|
||||
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
|
||||
val results = ArrayList<PsiTypeParameter>()
|
||||
accept(
|
||||
object : PsiTypeVisitor<Unit>() {
|
||||
override fun visitArrayType(arrayType: PsiArrayType) {
|
||||
arrayType.componentType.accept(this)
|
||||
}
|
||||
|
||||
override fun visitClassType(classType: PsiClassType) {
|
||||
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
|
||||
classType.parameters.forEach { it.accept(this) }
|
||||
}
|
||||
|
||||
override fun visitWildcardType(wildcardType: PsiWildcardType) {
|
||||
wildcardType.bound?.accept(this)
|
||||
}
|
||||
}
|
||||
)
|
||||
return results
|
||||
}
|
||||
|
||||
private fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType? {
|
||||
val typeParameters = collectTypeParameters()
|
||||
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
|
||||
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
|
||||
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
|
||||
val dummyClassDescriptor = ClassDescriptorImpl(
|
||||
dummyPackageDescriptor,
|
||||
Name.identifier("Dummy"),
|
||||
Modality.FINAL,
|
||||
ClassKind.CLASS,
|
||||
emptyList(),
|
||||
SourceElement.NO_SOURCE,
|
||||
false
|
||||
)
|
||||
val typeParameterResolver = object : TypeParameterResolver {
|
||||
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
|
||||
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
|
||||
val index = typeParameters.indexOf(psiTypeParameter)
|
||||
if (index < 0) return null
|
||||
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
|
||||
}
|
||||
}
|
||||
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
|
||||
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
|
||||
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
|
||||
}
|
||||
|
||||
private fun ExpectedTypes.toKotlinTypeInfo(resolutionFacade: ResolutionFacade): TypeInfo {
|
||||
val candidateTypes = flatMapTo(LinkedHashSet<KotlinType>()) {
|
||||
val ktType = (it.theType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: return@flatMapTo emptyList()
|
||||
when (it.theKind) {
|
||||
ExpectedType.Kind.EXACT, ExpectedType.Kind.SUBTYPE -> listOf(ktType)
|
||||
ExpectedType.Kind.SUPERTYPE -> listOf(ktType) + ktType.supertypes()
|
||||
}
|
||||
}
|
||||
if (candidateTypes.isEmpty()) {
|
||||
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
|
||||
return TypeInfo(nullableAnyType, Variance.INVARIANT)
|
||||
}
|
||||
return TypeInfo.ByExplicitCandidateTypes(candidateTypes.toList())
|
||||
}
|
||||
|
||||
override fun createChangeModifierActions(target: JvmModifiersOwner, request: MemberRequest.Modifier): List<IntentionAction> {
|
||||
val kModifierOwner = target.toKtElement<KtModifierListOwner>() ?: return emptyList()
|
||||
|
||||
val modifier = request.modifier
|
||||
val shouldPresent = request.shouldPresent
|
||||
val (kToken, shouldPresentMapped) = if (JvmModifier.FINAL == modifier)
|
||||
KtTokens.OPEN_KEYWORD to !shouldPresent
|
||||
else
|
||||
javaPsiModifiersMapping[modifier] to shouldPresent
|
||||
if (kToken == null) return emptyList()
|
||||
|
||||
val action = if (shouldPresentMapped)
|
||||
AddModifierFix.createIfApplicable(kModifierOwner, kToken)
|
||||
else
|
||||
RemoveModifierFix(kModifierOwner, kToken, false)
|
||||
return listOfNotNull(action)
|
||||
}
|
||||
|
||||
override fun createAddConstructorActions(targetClass: JvmClass, request: MemberRequest.Constructor): List<IntentionAction> {
|
||||
val targetKtClass = targetClass.toKtClassOrFile() as? KtClass ?: return emptyList()
|
||||
|
||||
if (request.typeParameters.isNotEmpty()) return emptyList()
|
||||
|
||||
val modifierBuilder = ModifierBuilder(targetKtClass).apply { addJvmModifiers(request.modifiers) }
|
||||
if (!modifierBuilder.isValid) return emptyList()
|
||||
|
||||
val resolutionFacade = targetKtClass.getResolutionFacade()
|
||||
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
|
||||
val parameterInfos = request.parameters.mapIndexed { index, param ->
|
||||
val ktType = (param.type as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
|
||||
val name = param.name ?: "arg${index + 1}"
|
||||
ParameterInfo(TypeInfo(ktType, Variance.IN_VARIANCE), listOf(name))
|
||||
}
|
||||
val needPrimary = !targetKtClass.hasExplicitPrimaryConstructor()
|
||||
val constructorInfo = ConstructorInfo(
|
||||
parameterInfos,
|
||||
targetKtClass,
|
||||
isPrimary = needPrimary,
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
withBody = true
|
||||
)
|
||||
val addConstructorAction = object : CreateCallableFromUsageFix<KtElement>(targetKtClass, listOf(constructorInfo)) {
|
||||
override fun getFamilyName() = "Add method"
|
||||
override fun getText() = "Add ${if (needPrimary) "primary" else "secondary"} constructor to '${targetClass.name}'"
|
||||
}
|
||||
|
||||
val changePrimaryConstructorAction = run {
|
||||
val primaryConstructor = targetKtClass.primaryConstructor ?: return@run null
|
||||
val lightMethod = primaryConstructor.toLightMethods().firstOrNull() ?: return@run null
|
||||
val project = targetKtClass.project
|
||||
val fakeParametersExpressions = fakeParametersExpressions(request.parameters, project) ?: return@run null
|
||||
QuickFixFactory.getInstance()
|
||||
.createChangeMethodSignatureFromUsageFix(
|
||||
lightMethod,
|
||||
fakeParametersExpressions,
|
||||
PsiSubstitutor.EMPTY,
|
||||
targetKtClass,
|
||||
false,
|
||||
2
|
||||
).takeIf { it.isAvailable(project, null, targetKtClass.containingFile) }
|
||||
}
|
||||
|
||||
return listOfNotNull(changePrimaryConstructorAction, addConstructorAction)
|
||||
}
|
||||
|
||||
override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List<IntentionAction> {
|
||||
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
|
||||
|
||||
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifier(request.visibilityModifier) }
|
||||
if (!modifierBuilder.isValid) return emptyList()
|
||||
|
||||
val resolutionFacade = targetContainer.getResolutionFacade()
|
||||
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
|
||||
val ktType = (request.propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
|
||||
val propertyInfo = PropertyInfo(
|
||||
request.propertyName,
|
||||
TypeInfo.Empty,
|
||||
TypeInfo(ktType, Variance.INVARIANT),
|
||||
request.setterRequired,
|
||||
listOf(targetContainer),
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
withInitializer = true
|
||||
)
|
||||
val propertyInfos = if (request.setterRequired) {
|
||||
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
|
||||
}
|
||||
else {
|
||||
listOf(propertyInfo)
|
||||
}
|
||||
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
|
||||
}
|
||||
|
||||
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
|
||||
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
|
||||
|
||||
val modifierBuilder = ModifierBuilder(targetContainer, allowJvmStatic = false).apply {
|
||||
addJvmModifiers(request.modifiers)
|
||||
addAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME)
|
||||
}
|
||||
if (!modifierBuilder.isValid) return emptyList()
|
||||
|
||||
val resolutionFacade = targetContainer.getResolutionFacade()
|
||||
val typeInfo = request.fieldType.toKotlinTypeInfo(resolutionFacade)
|
||||
val writable = JvmModifier.FINAL !in request.modifiers
|
||||
val propertyInfo = PropertyInfo(
|
||||
request.fieldName,
|
||||
TypeInfo.Empty,
|
||||
typeInfo,
|
||||
writable,
|
||||
listOf(targetContainer),
|
||||
isForCompanion = JvmModifier.STATIC in request.modifiers,
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
withInitializer = true
|
||||
)
|
||||
val propertyInfos = if (writable) {
|
||||
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
|
||||
}
|
||||
else {
|
||||
listOf(propertyInfo)
|
||||
}
|
||||
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
|
||||
}
|
||||
|
||||
override fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> {
|
||||
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
|
||||
|
||||
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(request.modifiers) }
|
||||
if (!modifierBuilder.isValid) return emptyList()
|
||||
|
||||
val resolutionFacade = targetContainer.getResolutionFacade()
|
||||
val returnTypeInfo = request.returnType.toKotlinTypeInfo(resolutionFacade)
|
||||
val parameterInfos = request.parameters.map { (suggestedNames, expectedTypes) ->
|
||||
ParameterInfo(expectedTypes.toKotlinTypeInfo(resolutionFacade), suggestedNames.names.toList())
|
||||
}
|
||||
val functionInfo = FunctionInfo(
|
||||
request.methodName,
|
||||
TypeInfo.Empty,
|
||||
returnTypeInfo,
|
||||
listOf(targetContainer),
|
||||
parameterInfos,
|
||||
isForCompanion = JvmModifier.STATIC in request.modifiers,
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
preferEmptyBody = true
|
||||
)
|
||||
val action = object : CreateCallableFromUsageFix<KtElement>(targetContainer, listOf(functionInfo)) {
|
||||
override fun getFamilyName() = "Add method"
|
||||
override fun getText() = "Add method '${request.methodName}' to '${targetClass.name}'"
|
||||
}
|
||||
return listOf(action)
|
||||
}
|
||||
}
|
||||
@@ -163,8 +163,7 @@ class MoveKotlinDeclarationsHandler : MoveHandlerDelegate() {
|
||||
}
|
||||
|
||||
private fun canMove(elements: Array<out PsiElement>, targetContainer: PsiElement?, editorMode: Boolean): Boolean {
|
||||
if (targetContainer != null && !isValidTarget(targetContainer, elements)) return false
|
||||
|
||||
if (!super.canMove(elements, targetContainer)) return false
|
||||
val container = getUniqueContainer(elements) ?: return false
|
||||
|
||||
if (container is KtClassOrObject && targetContainer != null && targetContainer !is KtClassOrObject && elements.size > 1) {
|
||||
|
||||
@@ -35,8 +35,6 @@ import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDe
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.asJava.*
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightField
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
@@ -137,15 +135,7 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() {
|
||||
|
||||
fun findUsagesByJavaProcessor(element: PsiElement, forceReferencedElementUnwrapping: Boolean): NonCodeUsageSearchInfo? {
|
||||
val javaUsages = ArrayList<UsageInfo>()
|
||||
|
||||
val elementToPassToJava = when (element) {
|
||||
is KtLightFieldImpl<*> -> object : KtLightField by element {
|
||||
// Suppress walking through initializer compiled PSI (it doesn't contain any reference expressions anyway)
|
||||
override fun getInitializer() = null
|
||||
}
|
||||
else -> element
|
||||
}
|
||||
val searchInfo = super.findUsages(elementToPassToJava, asLightElements(allElementsToDelete), javaUsages)
|
||||
val searchInfo = super.findUsages(element, asLightElements(allElementsToDelete), javaUsages)
|
||||
|
||||
javaUsages.filterIsInstance<SafeDeleteOverridingMethodUsageInfo>().mapNotNullTo(deleteSet) { it.element }
|
||||
|
||||
|
||||
@@ -16,65 +16,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.slicer
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.Nullness
|
||||
import com.intellij.ide.util.treeView.AbstractTreeStructure
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.slicer.*
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.idea.references.KtReference
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isPlainWithEscapes
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.types.isNullabilityFlexible
|
||||
|
||||
class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer {
|
||||
companion object {
|
||||
val LEAF_ELEMENT_EQUALITY = object : SliceLeafEquality() {
|
||||
override fun substituteElement(element: PsiElement) = (element as? KtReference)?.resolve() ?: element
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinGroupByNullnessAction(treeBuilder: SliceTreeBuilder) : GroupByNullnessActionBase(treeBuilder) {
|
||||
override fun isAvailable() = true
|
||||
}
|
||||
|
||||
val leafAnalyzer by lazy { SliceLeafAnalyzer(LEAF_ELEMENT_EQUALITY, this) }
|
||||
val nullnessAnalyzer: SliceNullnessAnalyzerBase by lazy {
|
||||
object : SliceNullnessAnalyzerBase(LEAF_ELEMENT_EQUALITY, this) {
|
||||
override fun checkNullness(element: PsiElement?): Nullness {
|
||||
val types = when (element) {
|
||||
is KtCallableDeclaration -> listOfNotNull((element.resolveToDescriptorIfAny() as? CallableDescriptor)?.returnType)
|
||||
is KtDeclaration -> emptyList()
|
||||
is KtExpression -> listOfNotNull(element.analyze(BodyResolveMode.PARTIAL).getType(element))
|
||||
else -> emptyList()
|
||||
}
|
||||
return when {
|
||||
types.isEmpty() -> return Nullness.UNKNOWN
|
||||
types.all { KotlinBuiltIns.isNullableNothing(it) } -> Nullness.NULLABLE
|
||||
types.any { it.isError || TypeUtils.isNullableType(it) || it.isNullabilityFlexible() } -> Nullness.UNKNOWN
|
||||
else -> Nullness.NOT_NULL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinSliceProvider : SliceLanguageSupportProvider {
|
||||
override fun createRootUsage(element: PsiElement, params: SliceAnalysisParams) = KotlinSliceUsage(element, params)
|
||||
|
||||
override fun transform(usage: SliceUsage): Collection<SliceUsage>? {
|
||||
if (usage is KotlinSliceUsage) return null
|
||||
return listOf(KotlinSliceUsage(usage.element, usage.parent, 0, false))
|
||||
}
|
||||
|
||||
override fun getExpressionAtCaret(atCaret: PsiElement?, dataFlowToThis: Boolean): KtExpression? {
|
||||
val element =
|
||||
atCaret?.parentsWithSelf
|
||||
@@ -102,17 +55,14 @@ class KotlinSliceProvider : SliceLanguageSupportProvider, SliceUsageTransformer
|
||||
override fun getRenderer() = KotlinSliceUsageCellRenderer
|
||||
|
||||
override fun startAnalyzeLeafValues(structure: AbstractTreeStructure, finalRunnable: Runnable) {
|
||||
leafAnalyzer.startAnalyzeValues(structure, finalRunnable)
|
||||
|
||||
}
|
||||
|
||||
override fun startAnalyzeNullness(structure: AbstractTreeStructure, finalRunnable: Runnable) {
|
||||
nullnessAnalyzer.startAnalyzeNullness(structure, finalRunnable)
|
||||
|
||||
}
|
||||
|
||||
override fun registerExtraPanelActions(group: DefaultActionGroup, builder: SliceTreeBuilder) {
|
||||
if (builder.dataFlowToThis) {
|
||||
group.add(GroupByLeavesAction(builder))
|
||||
group.add(KotlinGroupByNullnessAction(builder))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -19,13 +19,10 @@ package org.jetbrains.kotlin.idea.slicer
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.slicer.SliceAnalysisParams
|
||||
import com.intellij.slicer.SliceUsage
|
||||
import com.intellij.usageView.UsageInfo
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
open class KotlinSliceUsage : SliceUsage {
|
||||
class UsageInfoLambdaWrapper(element: PsiElement) : UsageInfo(element)
|
||||
|
||||
val lambdaLevel: Int
|
||||
val forcedExpressionMode: Boolean
|
||||
|
||||
@@ -45,18 +42,6 @@ open class KotlinSliceUsage : SliceUsage {
|
||||
return KotlinSliceUsage(element, parent, lambdaLevel, forcedExpressionMode)
|
||||
}
|
||||
|
||||
override fun getUsageInfo(): UsageInfo {
|
||||
val originalInfo = super.getUsageInfo()
|
||||
if (lambdaLevel > 0 && forcedExpressionMode) {
|
||||
val element = originalInfo.element ?: return originalInfo
|
||||
// Do not let IDEA consider usages of the same anonymous function as duplicates when their levels differ
|
||||
return UsageInfoLambdaWrapper(element)
|
||||
}
|
||||
return originalInfo
|
||||
}
|
||||
|
||||
override fun canBeLeaf() = element != null && lambdaLevel == 0
|
||||
|
||||
public override fun processUsagesFlownDownTo(element: PsiElement, uniqueProcessor: Processor<SliceUsage>) {
|
||||
InflowSlicer(element as? KtExpression ?: return, uniqueProcessor, this).processChildren()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.util.compat.statistic
|
||||
|
||||
typealias AbstractProjectsUsagesCollector = com.intellij.internal.statistic.AbstractApplicationUsagesCollector
|
||||
|
||||
fun getEnumUsage(key: String, value: Enum<*>?) = com.intellij.internal.statistic.getEnumUsage(key, value)
|
||||
|
||||
fun getBooleanUsage(key: String, value: Boolean) = com.intellij.internal.statistic.getBooleanUsage(key, value)
|
||||
@@ -177,7 +177,7 @@ private fun <T : BinaryVersion> getLibraryRootsWithAbiIncompatibleVersion(
|
||||
"Only library roots were requested, and only class files should be indexed with the $id key. " +
|
||||
"File: ${indexedFile.path}"
|
||||
)
|
||||
badRoots.add(BinaryVersionedFile(VfsUtil.getLocalFile(libraryRoot), version, supportedVersion))
|
||||
badRoots.add(BinaryVersionedFile(com.intellij.util.PathUtil.getLocalFile(libraryRoot), version, supportedVersion))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
operator fun Any.get(a: Int) {
|
||||
if (a > 0) {
|
||||
<lineMarker descr="Recursive call">this</lineMarker>[a - 1]
|
||||
<lineMarker descr="Recursive call">this[a - 1]</lineMarker>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
class K {
|
||||
fun foo(i: Int, s: String): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// "Add method 'foo' to 'K'" "true"
|
||||
class J {
|
||||
void test(K k) {
|
||||
boolean b = k.<caret>foo(1, "2");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
class K {
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// "Add method 'foo' to 'K'" "true"
|
||||
class J {
|
||||
void test(K k) {
|
||||
boolean b = k.<caret>foo(1, "2");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
class K {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun foo(i: Int, s: String): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add method 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test() {
|
||||
boolean b = K.<caret>foo(1, "2");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
class K {
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add method 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test() {
|
||||
boolean b = K.<caret>foo(1, "2");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
@file:JvmName("TestKt")
|
||||
|
||||
fun test() {}
|
||||
|
||||
fun foo(i: Int, s: String): Boolean {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// "Add method 'foo' to 'TestKt'" "true"
|
||||
class J {
|
||||
void test() {
|
||||
boolean b = TestKt.<caret>foo(1, "2");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@file:JvmName("TestKt")
|
||||
|
||||
fun test() {}
|
||||
@@ -1,6 +0,0 @@
|
||||
// "Add method 'foo' to 'TestKt'" "true"
|
||||
class J {
|
||||
void test() {
|
||||
boolean b = TestKt.<caret>foo(1, "2");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
// "Create type parameter 'Test' in class 'C'" "false"
|
||||
// ACTION: Add 'testng' to classpath
|
||||
// ACTION: Add 'JUnit4' to classpath
|
||||
// ACTION: Add 'JUnit5.0' to classpath
|
||||
// ACTION: Create annotation 'Test'
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
class K {
|
||||
@JvmField
|
||||
lateinit var foo: String
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'lateinit var' property 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test(K k) {
|
||||
String s = k.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
class K {
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'lateinit var' property 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test(K k) {
|
||||
String s = k.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
class K {
|
||||
@JvmField
|
||||
var foo: String = TODO("initialize me")
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'var' property 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test(K k) {
|
||||
String s = k.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
class K {
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'var' property 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test(K k) {
|
||||
String s = k.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
class K {
|
||||
companion object {
|
||||
@JvmField
|
||||
var foo: String = TODO("initialize me")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'var' property 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test() {
|
||||
String s = K.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
class K {
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'var' property 'foo' to 'K'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test() {
|
||||
String s = K.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
@file:JvmName("TestKt")
|
||||
|
||||
fun test() {}
|
||||
|
||||
@JvmField
|
||||
var foo: String = TODO("initialize me")
|
||||
@@ -1,7 +0,0 @@
|
||||
// "Add 'var' property 'foo' to 'TestKt'" "true"
|
||||
// WITH_RUNTIME
|
||||
class J {
|
||||
void test() {
|
||||
String s = TestKt.<caret>foo;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
@file:JvmName("TestKt")
|
||||
|
||||
fun test() {}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user