Add initial support for injecting languages with comment or annotation
#KT-11472 Fixed
This commit is contained in:
@@ -1433,6 +1433,12 @@
|
||||
<filetype.decompiler filetype="kotlin_builtins" implementationClass="com.intellij.psi.impl.compiled.ClassFileDecompiler"/>
|
||||
|
||||
<pathMacroExpandableProtocol protocol="kotlin-js-meta"/>
|
||||
|
||||
<languageInjector implementation="org.jetbrains.kotlin.idea.injection.KotlinLanguageInjector" />
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.intellij.intelliLang">
|
||||
<languageSupport implementation="org.jetbrains.kotlin.idea.injection.KotlinLanguageInjectionSupport"/>
|
||||
</extensions>
|
||||
|
||||
<xi:include href="extensions/ide.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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.injection
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.util.PsiTreeUtil.getDeepestLast
|
||||
import com.intellij.util.ArrayUtil
|
||||
import com.intellij.util.Processor
|
||||
import org.intellij.plugins.intelliLang.Configuration
|
||||
import org.intellij.plugins.intelliLang.inject.AbstractLanguageInjectionSupport
|
||||
import org.intellij.plugins.intelliLang.inject.InjectLanguageAction
|
||||
import org.intellij.plugins.intelliLang.inject.InjectedLanguage
|
||||
import org.intellij.plugins.intelliLang.inject.TemporaryPlacesRegistry
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import org.jetbrains.kotlin.idea.util.addAnnotation
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.findAnnotation
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
@NonNls val KOTLIN_SUPPORT_ID = "kotlin"
|
||||
val LINE_LANGUAGE_REGEXP_COMMENT = Regex("//\\s*language=[\\w-]+")
|
||||
|
||||
class KotlinLanguageInjectionSupport : AbstractLanguageInjectionSupport() {
|
||||
override fun getId(): String = KOTLIN_SUPPORT_ID
|
||||
|
||||
override fun getPatternClasses() = ArrayUtil.EMPTY_CLASS_ARRAY
|
||||
|
||||
override fun isApplicableTo(host: PsiLanguageInjectionHost?) = host is KtElement
|
||||
|
||||
override fun addInjectionInPlace(language: Language?, host: PsiLanguageInjectionHost?): Boolean {
|
||||
if (language == null || host == null) return false
|
||||
|
||||
val configuration = Configuration.getProjectInstance(host.project).advancedConfiguration
|
||||
if (!configuration.isSourceModificationAllowed) {
|
||||
// It's not allowed to modify code without explicit permission. Postpone adding @Inject or comment till it granted.
|
||||
host.putUserData(InjectLanguageAction.FIX_KEY, Processor { host -> addInjectionInstructionInCode(language, host) })
|
||||
return false
|
||||
}
|
||||
|
||||
if (!addInjectionInstructionInCode(language, host)) {
|
||||
return false
|
||||
}
|
||||
|
||||
TemporaryPlacesRegistry.getInstance(host.project).addHostWithUndo(host, InjectedLanguage.create(language.id))
|
||||
return true
|
||||
}
|
||||
|
||||
override fun removeInjectionInPlace(psiElement: PsiLanguageInjectionHost?): Boolean {
|
||||
if (psiElement == null || psiElement !is KtElement) return false
|
||||
|
||||
val project = psiElement.getProject()
|
||||
|
||||
val injectionAnnotation = findAnnotationInjection(psiElement)
|
||||
val injectionComment = findInjectionComment(psiElement)
|
||||
|
||||
val injectInstructions = listOf(injectionAnnotation, injectionComment).filterNotNull()
|
||||
|
||||
val configuration = Configuration.getProjectInstance(project)
|
||||
|
||||
TemporaryPlacesRegistry.getInstance(project).removeHostWithUndo(project, psiElement)
|
||||
configuration.replaceInjectionsWithUndo(project, listOf(), listOf(), injectInstructions)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun findInjectionComment(host: KtElement): PsiComment? {
|
||||
if (findCommentInjection(host, null) == null) return null
|
||||
|
||||
val commentsToCheck: Sequence<PsiComment> =
|
||||
findElementToInjectWithAnnotation(host)?.findChildrenComments() ?:
|
||||
findElementToInjectWithComment(host)?.findCommentsBeforeElement() ?:
|
||||
return null
|
||||
|
||||
return commentsToCheck.firstOrNull {
|
||||
it.node.elementType == KtTokens.EOL_COMMENT && it.text.matches(LINE_LANGUAGE_REGEXP_COMMENT)
|
||||
}
|
||||
}
|
||||
|
||||
fun findAnnotationInjectionLanguageId(host: KtElement): String? = doFindAnnotationInjectionLanguageId(host)
|
||||
}
|
||||
|
||||
private fun doFindAnnotationInjectionLanguageId(host: KtElement): String? {
|
||||
val annotationEntry = findAnnotationInjection(host) ?: return null
|
||||
val firstArgument: ValueArgument = annotationEntry.valueArguments.firstOrNull() ?: return null
|
||||
|
||||
val firstStringArgument = firstArgument.getArgumentExpression() as? KtStringTemplateExpression ?: return null
|
||||
val firstStringEntry = firstStringArgument.entries.singleOrNull() ?: return null
|
||||
|
||||
return firstStringEntry.text
|
||||
}
|
||||
|
||||
private fun findAnnotationInjection(host: KtElement): KtAnnotationEntry? {
|
||||
val modifierListOwner = findElementToInjectWithAnnotation(host) ?: return null
|
||||
|
||||
val modifierList = modifierListOwner.modifierList ?: return null
|
||||
|
||||
// Host can't be before annotation
|
||||
if (host.startOffset < modifierList.endOffset) return null
|
||||
|
||||
return modifierListOwner.findAnnotation(FqName(AnnotationUtil.LANGUAGE))
|
||||
}
|
||||
|
||||
private fun canInjectWithAnnotation(host: PsiElement): Boolean {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(host) ?: return false
|
||||
val javaPsiFacade = JavaPsiFacade.getInstance(module.project)
|
||||
|
||||
return javaPsiFacade.findClass(AnnotationUtil.LANGUAGE, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)) != null
|
||||
}
|
||||
|
||||
private fun findElementToInjectWithAnnotation(host: KtElement): KtModifierListOwner? {
|
||||
return PsiTreeUtil.getParentOfType(
|
||||
host,
|
||||
KtModifierListOwner::class.java,
|
||||
false, /* strict */
|
||||
KtBlockExpression::class.java, KtParameterList::class.java, KtTypeParameterList::class.java /* Stop at */
|
||||
)
|
||||
}
|
||||
|
||||
private fun findElementToInjectWithComment(host: KtElement): KtExpression? {
|
||||
val parentBlockExpression = PsiTreeUtil.getParentOfType(
|
||||
host,
|
||||
KtBlockExpression::class.java,
|
||||
true, /* strict */
|
||||
KtDeclaration::class.java /* Stop at */
|
||||
) ?: return null
|
||||
|
||||
return parentBlockExpression.statements.firstOrNull { statement ->
|
||||
PsiTreeUtil.isAncestor(statement, host, false) && checkIsValidPlaceForInjectionWithLineComment(statement, host)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addInjectionInstructionInCode(language: Language, host: PsiLanguageInjectionHost): Boolean {
|
||||
val ktHost = host as? KtElement ?: return false
|
||||
val project = ktHost.project
|
||||
|
||||
// Find the place where injection can be stated with annotation or comment
|
||||
val modifierListOwner = findElementToInjectWithAnnotation(ktHost)
|
||||
|
||||
if (modifierListOwner != null && canInjectWithAnnotation(ktHost)) {
|
||||
project.executeWriteCommand("Add injection annotation") {
|
||||
modifierListOwner.addAnnotation(FqName(AnnotationUtil.LANGUAGE), "\"${language.id}\"")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Find the place where injection can be done with one-line comment
|
||||
val commentBeforeAnchor: PsiElement =
|
||||
modifierListOwner?.firstNonCommentChild() ?:
|
||||
findElementToInjectWithComment(ktHost) ?:
|
||||
return false
|
||||
|
||||
val psiFactory = KtPsiFactory(project)
|
||||
val injectComment = psiFactory.createComment("//language=" + language.id)
|
||||
|
||||
project.executeWriteCommand("Add injection comment") {
|
||||
commentBeforeAnchor.parent.addBefore(injectComment, commentBeforeAnchor)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Inspired with InjectorUtils.findCommentInjection()
|
||||
private fun checkIsValidPlaceForInjectionWithLineComment(statement: KtExpression, host: KtElement): Boolean {
|
||||
// make sure comment is close enough and ...
|
||||
val statementStartOffset = statement.startOffset
|
||||
val hostStart = host.startOffset
|
||||
if (hostStart < statementStartOffset || hostStart - statementStartOffset > 120) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (hostStart - statementStartOffset > 2) {
|
||||
// ... there's no non-empty valid host in between comment and e2
|
||||
if (prevWalker(host, statement).asSequence().takeWhile { it != null }.any {
|
||||
it is PsiLanguageInjectionHost && it.isValidHost && !StringUtil.isEmptyOrSpaces(it.text)
|
||||
}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun PsiElement.findChildrenComments(): Sequence<PsiComment> {
|
||||
return firstChild.siblings().takeWhile { it is PsiComment || it is PsiWhiteSpace }.filterIsInstance<PsiComment>()
|
||||
}
|
||||
|
||||
private fun PsiElement.findCommentsBeforeElement(): Sequence<PsiComment> {
|
||||
return siblings(forward = false, withItself = false).takeWhile { it is PsiComment || it is PsiWhiteSpace }.filterIsInstance<PsiComment>()
|
||||
}
|
||||
|
||||
private fun PsiElement.firstNonCommentChild(): PsiElement? {
|
||||
return firstChild.siblings().dropWhile { it is PsiComment || it is PsiWhiteSpace }.firstOrNull()
|
||||
}
|
||||
|
||||
// Based on InjectorUtils.prevWalker
|
||||
private fun prevWalker(element: PsiElement, scope: PsiElement): Iterator<PsiElement?> {
|
||||
return object : Iterator<PsiElement?> {
|
||||
private var e: PsiElement? = element
|
||||
|
||||
override fun hasNext(): Boolean = true
|
||||
override fun next(): PsiElement? {
|
||||
val current = e
|
||||
|
||||
if (current == null || current === scope) return null
|
||||
val prev = current.prevSibling
|
||||
if (prev != null) {
|
||||
e = getDeepestLast(prev)
|
||||
return e
|
||||
}
|
||||
else {
|
||||
val parent = current.parent
|
||||
e = if (parent === scope || parent is PsiFile) null else parent
|
||||
return e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.injection
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.InjectedLanguagePlaces
|
||||
import com.intellij.psi.LanguageInjector
|
||||
import com.intellij.psi.PsiLanguageInjectionHost
|
||||
import org.intellij.plugins.intelliLang.inject.InjectorUtils
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import java.util.*
|
||||
|
||||
class KotlinLanguageInjector : LanguageInjector {
|
||||
val kotlinSupport: KotlinLanguageInjectionSupport? by lazy {
|
||||
ArrayList(InjectorUtils.getActiveInjectionSupports()).filterIsInstance(KotlinLanguageInjectionSupport::class.java).firstOrNull()
|
||||
}
|
||||
|
||||
override fun getLanguagesToInject(host: PsiLanguageInjectionHost, injectionPlacesRegistrar: InjectedLanguagePlaces) {
|
||||
if (host !is KtElement) return
|
||||
if (!host.isValidHost) return
|
||||
val support = kotlinSupport ?: return
|
||||
|
||||
val languageId = support.findAnnotationInjectionLanguageId(host) ?: return
|
||||
|
||||
val language = InjectorUtils.getLanguageByString(languageId) ?: return
|
||||
|
||||
injectionPlacesRegistrar.addPlace(language, TextRange.from(0, host.getTextLength()), null, null)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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.psi
|
||||
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference
|
||||
import com.intellij.psi.injection.Injectable
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
|
||||
import junit.framework.TestCase
|
||||
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.references.FileReferenceInjector
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import java.io.File
|
||||
|
||||
class KotlinInjectionTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
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 testInjectionWithCommentOnProperty() = doTestInjection(
|
||||
"""
|
||||
|//language=file-reference
|
||||
|val test = "<caret>simple"
|
||||
""")
|
||||
|
||||
fun testInjectionWithMultipleCommentsOnFun() = doTestInjection(
|
||||
"""
|
||||
|// Some comment
|
||||
|// Other comment
|
||||
|//language=file-reference
|
||||
|fun test() = "<caret>simple"
|
||||
""")
|
||||
|
||||
fun testInjectionWithAnnotationOnPropertyWithAnnotation() = doTestInjection(
|
||||
"""
|
||||
|@org.intellij.lang.annotations.Language("file-reference")
|
||||
|val test = "<caret>simple"
|
||||
""")
|
||||
|
||||
fun testInjectWithCommentOnProperty() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|//language=file-reference
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testInjectWithCommentOnCommentedProperty() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|// Hello
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|// Hello
|
||||
|//language=file-reference
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testInjectWithCommentOnPropertyWithKDoc() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|/**
|
||||
| * Hi
|
||||
| */
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|/**
|
||||
| * Hi
|
||||
| */
|
||||
|//language=file-reference
|
||||
|val test = "<caret>simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testInjectWithCommentOnExpression() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|fun test() {
|
||||
| "<caret>"
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| //language=file-reference
|
||||
| "<caret>"
|
||||
|}
|
||||
"""
|
||||
)
|
||||
|
||||
fun testInjectWithCommentOnDeepExpression() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|fun test() {
|
||||
| "" + "<caret>"
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| "" + "<caret>"
|
||||
|}
|
||||
"""
|
||||
)
|
||||
|
||||
fun testInjectOnPropertyWithAnnotation() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|import org.intellij.lang.annotations.Language
|
||||
|
|
||||
|@Language("file-reference")
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testInjectWithOnExpressionWithAnnotation() = doFileReferenceInjectTest(
|
||||
"""
|
||||
|fun test() {
|
||||
| "<caret>"
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| //language=file-reference
|
||||
| "<caret>"
|
||||
|}
|
||||
"""
|
||||
)
|
||||
|
||||
// TODO: add test for non-default language annotation
|
||||
|
||||
fun testRemoveInjectionWithAnnotation() = doRemoveInjectionTest(
|
||||
"""
|
||||
|import org.intellij.lang.annotations.Language
|
||||
|
|
||||
|@Language("file-reference")
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|import org.intellij.lang.annotations.Language
|
||||
|
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testRemoveInjectionWithComment() = doRemoveInjectionTest(
|
||||
"""
|
||||
|//language=file-reference
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testRemoveInjectionWithCommentNotFirst() = doRemoveInjectionTest(
|
||||
"""
|
||||
|// Some comment. To do a language injection, add a line comment language=some instruction.
|
||||
|// language=file-reference
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|// Some comment. To do a language injection, add a line comment language=some instruction.
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testRemoveInjectionWithCommentAfterKDoc() = doRemoveInjectionTest(
|
||||
"""
|
||||
|/**Property*/
|
||||
|// language=file-reference
|
||||
|val test = "<caret>simple"
|
||||
""",
|
||||
"""
|
||||
|/**Property*/
|
||||
|val test = "simple"
|
||||
"""
|
||||
)
|
||||
|
||||
fun testRemoveInjectionWithCommentInExpression() = doRemoveInjectionTest(
|
||||
"""
|
||||
|fun test() {
|
||||
| // This is my favorite part
|
||||
| // language=RegExp
|
||||
| "<caret>something"
|
||||
|}
|
||||
""",
|
||||
"""
|
||||
|fun test() {
|
||||
| // This is my favorite part
|
||||
| "something"
|
||||
|}
|
||||
"""
|
||||
)
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor {
|
||||
if (getTestName(true).endsWith("WithAnnotation")) {
|
||||
return PROJECT_DESCRIPTOR_WITH_LANGUAGE_ANNOTATION_LIB
|
||||
}
|
||||
|
||||
return JAVA_LATEST
|
||||
}
|
||||
|
||||
private fun doTestInjection(text: String) {
|
||||
myFixture.configureByText("${getTestName(true)}.kt", text.trimMargin())
|
||||
|
||||
TestCase.assertFalse(InjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
||||
TestCase.assertTrue(UnInjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
||||
}
|
||||
|
||||
private fun doRemoveInjectionTest(before: String, after: String) {
|
||||
myFixture.setCaresAboutInjection(false)
|
||||
|
||||
myFixture.configureByText("${getTestName(true)}.kt", before.trimMargin())
|
||||
|
||||
TestCase.assertTrue(UnInjectLanguageAction().isAvailable(project, myFixture.editor, myFixture.file))
|
||||
UnInjectLanguageAction.invokeImpl(project, myFixture.editor, myFixture.file)
|
||||
|
||||
myFixture.checkResult(after.trimMargin())
|
||||
}
|
||||
|
||||
private fun doFileReferenceInjectTest(before: String, after: String) {
|
||||
doTest(FileReferenceInjector(), before, after)
|
||||
}
|
||||
|
||||
private fun doTest(injectable: Injectable, before: String, after: String) {
|
||||
val configuration = Configuration.getProjectInstance(project).advancedConfiguration
|
||||
val allowed = configuration.isSourceModificationAllowed
|
||||
|
||||
configuration.isSourceModificationAllowed = true
|
||||
try {
|
||||
myFixture.configureByText("${getTestName(true)}.kt", before.trimMargin())
|
||||
InjectLanguageAction.invokeImpl(project, myFixture.editor, myFixture.file, injectable)
|
||||
myFixture.checkResult(after.trimMargin())
|
||||
}
|
||||
finally {
|
||||
configuration.isSourceModificationAllowed = allowed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val PROJECT_DESCRIPTOR_WITH_LANGUAGE_ANNOTATION_LIB = object : DefaultLightProjectDescriptor() {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
|
||||
val jarUrl = VfsUtil.getUrlForLibraryRoot(File("ideaSDK/lib/annotations.jar"))
|
||||
val libraryModel = model.moduleLibraryTable.modifiableModel.createLibrary("annotations").modifiableModel
|
||||
libraryModel.addRoot(jarUrl, OrderRootType.CLASSES)
|
||||
|
||||
libraryModel.commit()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user