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
|
||||
- [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-11704](https://youtrack.jetbrains.com/issue/KT-11704) Support file path references inside of Kotlin string literals
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGroovyClassNameCompletionFromDefaultPackage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/multifile/GroovyClassNameCompletionFromDefaultPackage/");
|
||||
|
||||
+8
@@ -85,6 +85,14 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
|
||||
doTest('\t', "TestBundle.properties")
|
||||
}
|
||||
|
||||
fun testFileRefInStringLiteralEnter() {
|
||||
doTest('\n', "foo.txt", "bar.txt")
|
||||
}
|
||||
|
||||
fun testFileRefInStringLiteralTab() {
|
||||
doTest('\t', "foo.txt", "bar.txt")
|
||||
}
|
||||
|
||||
fun testNotImportedExtension() {
|
||||
doTest()
|
||||
}
|
||||
|
||||
@@ -395,6 +395,7 @@
|
||||
<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.KotlinFilePathReferenceContributor"/>
|
||||
|
||||
<renamePsiElementProcessor id="KotlinClass"
|
||||
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.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
class KotlinWordSelectionFilter : Condition<PsiElement>{
|
||||
override fun value(e: PsiElement): Boolean {
|
||||
if (e.language != KotlinLanguage.INSTANCE) return true
|
||||
|
||||
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.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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testGenericFunctionParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/resolve/references/GenericFunctionParameter.kt");
|
||||
|
||||
@@ -17,33 +17,12 @@
|
||||
package org.jetbrains.kotlin.psi
|
||||
|
||||
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.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.InjectionPlace
|
||||
import org.intellij.plugins.intelliLang.references.FileReferenceInjector
|
||||
|
||||
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(
|
||||
"""
|
||||
val test1 = java.util.regex.Pattern.compile("<caret>pattern")
|
||||
|
||||
Reference in New Issue
Block a user