192: Fix variance related problems for 192
This commit is contained in:
+254
@@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* 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.Ref
|
||||||
|
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.Processor
|
||||||
|
import org.intellij.plugins.intelliLang.Configuration
|
||||||
|
import org.intellij.plugins.intelliLang.inject.*
|
||||||
|
import org.intellij.plugins.intelliLang.inject.config.BaseInjection
|
||||||
|
import org.jetbrains.annotations.NonNls
|
||||||
|
import org.jetbrains.kotlin.idea.patterns.KotlinPatterns
|
||||||
|
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.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"
|
||||||
|
|
||||||
|
class KotlinLanguageInjectionSupport : AbstractLanguageInjectionSupport() {
|
||||||
|
override fun getId(): String = KOTLIN_SUPPORT_ID
|
||||||
|
|
||||||
|
override fun getPatternClasses() = arrayOf(KotlinPatterns::class.java)
|
||||||
|
|
||||||
|
override fun isApplicableTo(host: PsiLanguageInjectionHost?) = host is KtElement
|
||||||
|
|
||||||
|
override fun useDefaultInjector(host: PsiLanguageInjectionHost?): Boolean = false
|
||||||
|
|
||||||
|
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 { fixHost: PsiLanguageInjectionHost? ->
|
||||||
|
fixHost != null && addInjectionInstructionInCode(language, fixHost)
|
||||||
|
})
|
||||||
|
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 injectInstructions = listOfNotNull(
|
||||||
|
findAnnotationInjection(psiElement),
|
||||||
|
findInjectionComment(psiElement)
|
||||||
|
)
|
||||||
|
|
||||||
|
TemporaryPlacesRegistry.getInstance(project).removeHostWithUndo(project, psiElement)
|
||||||
|
|
||||||
|
project.executeWriteCommand("remove injection in-code instructions") {
|
||||||
|
injectInstructions.forEach(PsiElement::delete)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findCommentInjection(host: PsiElement, commentRef: Ref<in PsiElement>?): BaseInjection? {
|
||||||
|
// Do not inject through CommentLanguageInjector, because it injects as simple injection.
|
||||||
|
// We need to behave special for interpolated strings.
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findCommentInjection(host: KtElement): BaseInjection? {
|
||||||
|
return InjectorUtils.findCommentInjection(host, "", null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findInjectionComment(host: KtElement): PsiComment? {
|
||||||
|
val commentRef = Ref.create<PsiElement>(null)
|
||||||
|
InjectorUtils.findCommentInjection(host, "", commentRef) ?: return null
|
||||||
|
|
||||||
|
return commentRef.get() as? PsiComment
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun findAnnotationInjectionLanguageId(host: KtElement): InjectionInfo? {
|
||||||
|
val annotationEntry = findAnnotationInjection(host) ?: return null
|
||||||
|
val extractLanguageFromInjectAnnotation = extractLanguageFromInjectAnnotation(annotationEntry) ?: return null
|
||||||
|
val prefix = extractStringArgumentByName(annotationEntry, "prefix")
|
||||||
|
val suffix = extractStringArgumentByName(annotationEntry, "suffix")
|
||||||
|
return InjectionInfo(extractLanguageFromInjectAnnotation, prefix, suffix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractStringArgumentByName(annotationEntry: KtAnnotationEntry, name: String): String? {
|
||||||
|
val namedArgument: ValueArgument = annotationEntry.valueArguments.firstOrNull { it.getArgumentName()?.asName?.asString() == name } ?: return null
|
||||||
|
return extractStringValue(namedArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun extractLanguageFromInjectAnnotation(annotationEntry: KtAnnotationEntry): String? {
|
||||||
|
val firstArgument: ValueArgument = annotationEntry.valueArguments.firstOrNull() ?: return null
|
||||||
|
return extractStringValue(firstArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractStringValue(valueArgument: ValueArgument): String? {
|
||||||
|
val firstStringArgument = valueArgument.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.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
|
||||||
|
e = if (prev != null) {
|
||||||
|
getDeepestLast(prev)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val parent = current.parent
|
||||||
|
if (parent === scope || parent is PsiFile) null else parent
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-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.idea.actions.generate
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.CodeInsightBundle
|
||||||
|
import com.intellij.codeInsight.CodeInsightSettings
|
||||||
|
import com.intellij.codeInsight.generation.ui.AbstractGenerateEqualsWizard
|
||||||
|
import com.intellij.ide.wizard.StepAdapter
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.ui.VerticalFlowLayout
|
||||||
|
import com.intellij.refactoring.classMembers.AbstractMemberInfoModel
|
||||||
|
import com.intellij.ui.NonFocusableCheckBox
|
||||||
|
import com.intellij.util.containers.HashMap
|
||||||
|
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberInfo
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.memberInfo.KotlinMemberSelectionPanel
|
||||||
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
|
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||||
|
import org.jetbrains.kotlin.utils.keysToMap
|
||||||
|
import javax.swing.JLabel
|
||||||
|
import javax.swing.JPanel
|
||||||
|
|
||||||
|
class KotlinGenerateEqualsWizard(
|
||||||
|
project: Project,
|
||||||
|
klass: KtClass,
|
||||||
|
properties: List<KtNamedDeclaration>,
|
||||||
|
needEquals: Boolean,
|
||||||
|
needHashCode: Boolean
|
||||||
|
) : AbstractGenerateEqualsWizard<KtClass, KtNamedDeclaration, KotlinMemberInfo>(
|
||||||
|
project, BuilderImpl(klass, properties, needEquals, needHashCode)
|
||||||
|
) {
|
||||||
|
private object MemberInfoModelImpl : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>()
|
||||||
|
|
||||||
|
private class BuilderImpl(
|
||||||
|
private val klass: KtClass,
|
||||||
|
properties: List<KtNamedDeclaration>,
|
||||||
|
needEquals: Boolean,
|
||||||
|
needHashCode: Boolean
|
||||||
|
) : AbstractGenerateEqualsWizard.Builder<KtClass, KtNamedDeclaration, KotlinMemberInfo>() {
|
||||||
|
private val equalsPanel: KotlinMemberSelectionPanel?
|
||||||
|
private val hashCodePanel: KotlinMemberSelectionPanel?
|
||||||
|
|
||||||
|
private val memberInfos = properties.map { createMemberInfo(it) }
|
||||||
|
|
||||||
|
private val membersToHashCode = HashMap(properties.keysToMap { createMemberInfo(it) })
|
||||||
|
|
||||||
|
init {
|
||||||
|
equalsPanel = if (needEquals) {
|
||||||
|
KotlinMemberSelectionPanel("Choose properties to be included in equals()", memberInfos, null).apply {
|
||||||
|
table.memberInfoModel = MemberInfoModelImpl
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
|
||||||
|
hashCodePanel = if (needHashCode) {
|
||||||
|
KotlinMemberSelectionPanel("Choose properties to be included in hashCode()", memberInfos, null).apply {
|
||||||
|
table.memberInfoModel = MemberInfoModelImpl
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createMemberInfo(it: KtNamedDeclaration) = KotlinMemberInfo(it).apply { isChecked = true }
|
||||||
|
|
||||||
|
override fun getPsiClass() = klass
|
||||||
|
|
||||||
|
override fun getClassFields() = memberInfos
|
||||||
|
|
||||||
|
override fun getFieldsToHashCode() = membersToHashCode
|
||||||
|
|
||||||
|
override fun getFieldsToNonNull() = HashMap<KtNamedDeclaration, KotlinMemberInfo>()
|
||||||
|
|
||||||
|
override fun getEqualsPanel() = equalsPanel
|
||||||
|
|
||||||
|
override fun getHashCodePanel() = hashCodePanel
|
||||||
|
|
||||||
|
override fun getNonNullPanel() = null
|
||||||
|
|
||||||
|
override fun updateHashCodeMemberInfos(equalsMemberInfos: MutableCollection<out KotlinMemberInfo>) {
|
||||||
|
hashCodePanel?.table?.setMemberInfos(equalsMemberInfos.map { membersToHashCode[it.member] })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateNonNullMemberInfos(equalsMemberInfos: MutableCollection<out KotlinMemberInfo>?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object OptionsStep : StepAdapter() {
|
||||||
|
private val panel = JPanel(VerticalFlowLayout())
|
||||||
|
|
||||||
|
init {
|
||||||
|
with(NonFocusableCheckBox(CodeInsightBundle.message("generate.equals.hashcode.accept.sublcasses"))) {
|
||||||
|
isSelected = CodeInsightSettings.getInstance().USE_INSTANCEOF_ON_EQUALS_PARAMETER
|
||||||
|
addActionListener { CodeInsightSettings.getInstance().USE_INSTANCEOF_ON_EQUALS_PARAMETER = isSelected }
|
||||||
|
panel.add(this)
|
||||||
|
}
|
||||||
|
panel.add(JLabel(CodeInsightBundle.message("generate.equals.hashcode.accept.sublcasses.explanation")))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getComponent() = panel
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addSteps() {
|
||||||
|
if (myEqualsPanel != null && myClass.isInheritable()) {
|
||||||
|
addStep(OptionsStep)
|
||||||
|
}
|
||||||
|
super.addSteps()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doOKAction() {
|
||||||
|
myEqualsPanel?.let { updateHashCodeMemberInfos(it.table.selectedMemberInfos) }
|
||||||
|
super.doOKAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPropertiesForEquals() = myEqualsPanel?.table?.selectedMemberInfos?.map { it.member } ?: emptyList()
|
||||||
|
|
||||||
|
fun getPropertiesForHashCode() = myHashCodePanel?.table?.selectedMemberInfos?.map { it.member } ?: emptyList()
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.inspections
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.HighlightDisplayKey
|
||||||
|
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
|
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider
|
||||||
|
import com.intellij.openapi.util.Condition
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import com.intellij.psi.SmartPsiElementPointer
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionFactoryWithDelegate
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.detectPriority
|
||||||
|
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
|
||||||
|
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object PlatformUnresolvedProvider : KotlinIntentionActionFactoryWithDelegate<KtNameReferenceExpression, String>() {
|
||||||
|
override fun getElementOfInterest(diagnostic: Diagnostic) = QuickFixUtil.getParentElementOfType(diagnostic, KtNameReferenceExpression::class.java)
|
||||||
|
override fun extractFixData(element: KtNameReferenceExpression, diagnostic: Diagnostic) = element.getReferencedName()
|
||||||
|
|
||||||
|
override fun createFixes(originalElementPointer: SmartPsiElementPointer<KtNameReferenceExpression>, diagnostic: Diagnostic, quickFixDataFactory: () -> String?): List<QuickFixWithDelegateFactory> {
|
||||||
|
val result = ArrayList<QuickFixWithDelegateFactory>()
|
||||||
|
|
||||||
|
originalElementPointer.element?.references?.filterIsInstance<KtSimpleNameReference>()?.firstOrNull()?.let { reference ->
|
||||||
|
UnresolvedReferenceQuickFixProvider.registerReferenceFixes(reference, object: QuickFixActionRegistrar {
|
||||||
|
override fun register(action: IntentionAction) {
|
||||||
|
result.add(QuickFixWithDelegateFactory(action.detectPriority()) { action })
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun register(fixRange: TextRange, action: IntentionAction, key: HighlightDisplayKey?) {
|
||||||
|
register(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unregister(condition: Condition<in IntentionAction>) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.slicer
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.slicer.SliceUsage
|
||||||
|
import com.intellij.usages.UsagePresentation
|
||||||
|
import com.intellij.util.Processor
|
||||||
|
|
||||||
|
class KotlinSliceDereferenceUsage(
|
||||||
|
element: PsiElement,
|
||||||
|
parent: KotlinSliceUsage,
|
||||||
|
lambdaLevel: Int
|
||||||
|
) : KotlinSliceUsage(element, parent, lambdaLevel, false) {
|
||||||
|
override fun processChildren(processor: Processor<in SliceUsage>) {
|
||||||
|
// no children
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPresentation() = object : UsagePresentation by super.getPresentation() {
|
||||||
|
override fun getTooltipText() = "Variable dereferenced"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user