Code Insight: Support file path references inside of Kotlin string literals
#KT-11704 Fixed
This commit is contained in:
@@ -22,6 +22,7 @@ New features:
|
|||||||
- Enable injection from Java or Kotlin function declaration by annotating parameter with @Language annotation
|
- Enable injection from Java or Kotlin function declaration by annotating parameter with @Language annotation
|
||||||
- [KT-11807](https://youtrack.jetbrains.com/issue/KT-11807) Use function body template when generating overriding functions with default body
|
- [KT-11807](https://youtrack.jetbrains.com/issue/KT-11807) Use function body template when generating overriding functions with default body
|
||||||
- [KT-12079](https://youtrack.jetbrains.com/issue/KT-12079) Support "Autowired members defined in invalid Spring bean" inspection on Kotlin declarations
|
- [KT-12079](https://youtrack.jetbrains.com/issue/KT-12079) Support "Autowired members defined in invalid Spring bean" inspection on Kotlin declarations
|
||||||
|
- [KT-11704](https://youtrack.jetbrains.com/issue/KT-11704) Support file path references inside of Kotlin string literals
|
||||||
|
|
||||||
Issues fixed:
|
Issues fixed:
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// NUMBER: 1
|
||||||
|
// EXIST: foo.txt
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val s = "fo<caret>"
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// NUMBER: 3
|
||||||
|
// EXIST: foo.txt
|
||||||
|
// EXIST: bar.txt
|
||||||
|
// EXIST: FileRefInStringLiteralNoPrefix.kt
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
val s = "<caret>"
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = "fo<caret>something"
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// Empty file to satisfy test framework requirements
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = "foo.txt"
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = "fo<caret>something"
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// Empty file to satisfy test framework requirements
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = "foo.txt"
|
||||||
|
}
|
||||||
+12
@@ -125,6 +125,18 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FileRefInStringLiteral")
|
||||||
|
public void testFileRefInStringLiteral() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/FileRefInStringLiteral/");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FileRefInStringLiteralNoPrefix")
|
||||||
|
public void testFileRefInStringLiteralNoPrefix() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/FileRefInStringLiteralNoPrefix/");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("GroovyClassNameCompletionFromDefaultPackage")
|
@TestMetadata("GroovyClassNameCompletionFromDefaultPackage")
|
||||||
public void testGroovyClassNameCompletionFromDefaultPackage() throws Exception {
|
public void testGroovyClassNameCompletionFromDefaultPackage() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/GroovyClassNameCompletionFromDefaultPackage/");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/GroovyClassNameCompletionFromDefaultPackage/");
|
||||||
|
|||||||
+8
@@ -85,6 +85,14 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
|
|||||||
doTest('\t', "TestBundle.properties")
|
doTest('\t', "TestBundle.properties")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testFileRefInStringLiteralEnter() {
|
||||||
|
doTest('\n', "foo.txt", "bar.txt")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testFileRefInStringLiteralTab() {
|
||||||
|
doTest('\t', "foo.txt", "bar.txt")
|
||||||
|
}
|
||||||
|
|
||||||
fun testNotImportedExtension() {
|
fun testNotImportedExtension() {
|
||||||
doTest()
|
doTest()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -395,6 +395,7 @@
|
|||||||
<weigher key="completion" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinLookupElementProximityWeigher" id="kotlin.proximity" order="after proximity"/>
|
<weigher key="completion" implementationClass="org.jetbrains.kotlin.idea.completion.KotlinLookupElementProximityWeigher" id="kotlin.proximity" order="after proximity"/>
|
||||||
|
|
||||||
<psi.referenceContributor language="kotlin" implementation="org.jetbrains.kotlin.idea.references.KotlinReferenceContributor"/>
|
<psi.referenceContributor language="kotlin" implementation="org.jetbrains.kotlin.idea.references.KotlinReferenceContributor"/>
|
||||||
|
<psi.referenceContributor language="kotlin" implementation="org.jetbrains.kotlin.idea.references.KotlinFilePathReferenceContributor"/>
|
||||||
|
|
||||||
<renamePsiElementProcessor id="KotlinClass"
|
<renamePsiElementProcessor id="KotlinClass"
|
||||||
implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinClassProcessor"
|
implementation="org.jetbrains.kotlin.idea.refactoring.rename.RenameKotlinClassProcessor"
|
||||||
|
|||||||
@@ -22,12 +22,17 @@ import org.jetbrains.kotlin.KtNodeTypes.*
|
|||||||
import org.jetbrains.kotlin.psi.KtContainerNode
|
import org.jetbrains.kotlin.psi.KtContainerNode
|
||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
|
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
|
||||||
class KotlinWordSelectionFilter : Condition<PsiElement>{
|
class KotlinWordSelectionFilter : Condition<PsiElement>{
|
||||||
override fun value(e: PsiElement): Boolean {
|
override fun value(e: PsiElement): Boolean {
|
||||||
if (e.language != KotlinLanguage.INSTANCE) return true
|
if (e.language != KotlinLanguage.INSTANCE) return true
|
||||||
|
|
||||||
if (KotlinListSelectioner.canSelect(e)) return false
|
if (KotlinListSelectioner.canSelect(e)) return false
|
||||||
|
|
||||||
|
val elementType = e.node.elementType
|
||||||
|
if (elementType == KtTokens.REGULAR_STRING_PART || elementType == KtTokens.ESCAPE_SEQUENCE) return true
|
||||||
|
|
||||||
if (e is KtContainerNode) return false
|
if (e is KtContainerNode) return false
|
||||||
if (e.parent.firstChild.nextSibling == null && e.parent !is KtContainerNode) return false // skip nodes with the same range as their parent
|
if (e.parent.firstChild.nextSibling == null && e.parent !is KtContainerNode) return false // skip nodes with the same range as their parent
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.references
|
||||||
|
|
||||||
|
import com.intellij.patterns.PlatformPatterns
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.psi.PsiReferenceRegistrar
|
||||||
|
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FilePathReferenceProvider
|
||||||
|
import com.intellij.util.ProcessingContext
|
||||||
|
import org.jetbrains.kotlin.psi.KtStringTemplateExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getContentRange
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isPlainWithEscapes
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.plainContent
|
||||||
|
|
||||||
|
class KotlinFilePathReferenceContributor : AbstractKotlinReferenceContributor() {
|
||||||
|
object KotlinFilePathReferenceProvider : FilePathReferenceProvider() {
|
||||||
|
override fun getReferencesByElement(element: PsiElement, context: ProcessingContext): Array<out PsiReference> {
|
||||||
|
if (element !is KtStringTemplateExpression) return PsiReference.EMPTY_ARRAY
|
||||||
|
if (!element.isPlainWithEscapes()) return PsiReference.EMPTY_ARRAY
|
||||||
|
return getReferencesByElement(element, element.plainContent, element.getContentRange().startOffset, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun registerReferenceProviders(registrar: PsiReferenceRegistrar) {
|
||||||
|
registrar.registerReferenceProvider(
|
||||||
|
PlatformPatterns.psiElement(KtStringTemplateExpression::class.java),
|
||||||
|
KotlinFilePathReferenceProvider
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class Foo {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = """idea/testData/resolve/references/<caret>fileRefInRawStringLiteral.Data.java"""
|
||||||
|
}
|
||||||
|
|
||||||
|
// REF: /src/<test dir>/resolve/references.fileRefInRawStringLiteral.Data.java
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
class Foo {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
val s = "idea/testData/resolve/references/<caret>fileRefInStringLiteral.Data.java"
|
||||||
|
}
|
||||||
|
|
||||||
|
// REF: /src/<test dir>/resolve/references.fileRefInStringLiteral.Data.java
|
||||||
@@ -179,6 +179,18 @@ public class ReferenceResolveTestGenerated extends AbstractReferenceResolveTest
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("fileRefInRawStringLiteral.kt")
|
||||||
|
public void testFileRefInRawStringLiteral() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/references/fileRefInRawStringLiteral.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("fileRefInStringLiteral.kt")
|
||||||
|
public void testFileRefInStringLiteral() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/references/fileRefInStringLiteral.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("GenericFunctionParameter.kt")
|
@TestMetadata("GenericFunctionParameter.kt")
|
||||||
public void testGenericFunctionParameter() throws Exception {
|
public void testGenericFunctionParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/references/GenericFunctionParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/references/GenericFunctionParameter.kt");
|
||||||
|
|||||||
@@ -17,33 +17,12 @@
|
|||||||
package org.jetbrains.kotlin.psi
|
package org.jetbrains.kotlin.psi
|
||||||
|
|
||||||
import com.intellij.lang.html.HTMLLanguage
|
import com.intellij.lang.html.HTMLLanguage
|
||||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference
|
|
||||||
import junit.framework.TestCase
|
|
||||||
import org.intellij.lang.regexp.RegExpLanguage
|
import org.intellij.lang.regexp.RegExpLanguage
|
||||||
import org.intellij.plugins.intelliLang.Configuration
|
import org.intellij.plugins.intelliLang.Configuration
|
||||||
import org.intellij.plugins.intelliLang.inject.InjectLanguageAction
|
|
||||||
import org.intellij.plugins.intelliLang.inject.UnInjectLanguageAction
|
|
||||||
import org.intellij.plugins.intelliLang.inject.config.BaseInjection
|
import org.intellij.plugins.intelliLang.inject.config.BaseInjection
|
||||||
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace
|
import org.intellij.plugins.intelliLang.inject.config.InjectionPlace
|
||||||
import org.intellij.plugins.intelliLang.references.FileReferenceInjector
|
|
||||||
|
|
||||||
class KotlinInjectionTest : AbstractInjectionTest() {
|
class KotlinInjectionTest : AbstractInjectionTest() {
|
||||||
fun testInjectUnInjectOnSimpleString() {
|
|
||||||
myFixture.configureByText("test.kt",
|
|
||||||
"""val test = "<caret>simple" """)
|
|
||||||
TestCase.assertTrue(InjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
|
||||||
TestCase.assertFalse(UnInjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
|
||||||
|
|
||||||
InjectLanguageAction.invokeImpl(project, myFixture.editor, myFixture.file, FileReferenceInjector())
|
|
||||||
TestCase.assertTrue(myFixture.getReferenceAtCaretPosition() is FileReference)
|
|
||||||
|
|
||||||
TestCase.assertFalse(InjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
|
||||||
TestCase.assertTrue(UnInjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
|
||||||
|
|
||||||
UnInjectLanguageAction.invokeImpl(project, myFixture.editor, myFixture.file)
|
|
||||||
TestCase.assertNull(myFixture.getReferenceAtCaretPosition())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testInjectionOnJavaPredefinedMethodWithAnnotation() = doInjectionPresentTest(
|
fun testInjectionOnJavaPredefinedMethodWithAnnotation() = doInjectionPresentTest(
|
||||||
"""
|
"""
|
||||||
val test1 = java.util.regex.Pattern.compile("<caret>pattern")
|
val test1 = java.util.regex.Pattern.compile("<caret>pattern")
|
||||||
|
|||||||
Reference in New Issue
Block a user