KT-11701 Add Maven Dependency quick fix could be supported in Kotlin sources

~ initial draft
This commit is contained in:
Sergey Mashkov
2016-03-31 14:37:35 +03:00
parent 01fa6d5718
commit 64a63476f7
3 changed files with 151 additions and 1 deletions
+2
View File
@@ -24,6 +24,8 @@
<className>org.jetbrains.kotlin.idea.configuration.MavenPluginSourcesMoveToExecutionIntention</className>
<category>Kotlin</category>
</intentionAction>
<codeInsight.unresolvedReferenceQuickFixProvider
implementation="org.jetbrains.kotlin.idea.configuration.KotlinMavenUnresolvedReferenceQuickFixProvider" />
</extensions>
<module-components>
@@ -0,0 +1,146 @@
/*
* 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.configuration
import com.intellij.codeInsight.daemon.HighlightDisplayKey
import com.intellij.codeInsight.daemon.QuickFixActionRegistrar
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.util.Condition
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.SmartPsiElementPointer
import com.intellij.psi.xml.XmlFile
import org.jetbrains.idea.maven.dom.MavenDomUtil
import org.jetbrains.idea.maven.indices.MavenArtifactSearchDialog
import org.jetbrains.idea.maven.project.MavenProjectsManager
import org.jetbrains.idea.maven.utils.MavenArtifactScope
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
import org.jetbrains.kotlin.idea.quickfix.IntentionActionPriority
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionFactoryWithDelegate
import org.jetbrains.kotlin.idea.quickfix.QuickFixWithDelegateFactory
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import java.util.*
class KotlinMavenUnresolvedReferenceQuickFixProvider : UnresolvedReferenceQuickFixProvider<KtSimpleNameReference>() {
override fun getReferenceClass(): Class<KtSimpleNameReference> = KtSimpleNameReference::class.java
override fun registerFixes(ref: KtSimpleNameReference, registrar: QuickFixActionRegistrar) {
val module = ModuleUtilCore.findModuleForPsiElement(ref.expression) ?: return
if (!MavenProjectsManager.getInstance(module.project).isMavenizedModule(module)) {
return
}
val expression = ref.expression
val importDirective = expression.getParentOfType<KtImportDirective>(true)
val name = if (importDirective != null) {
if (importDirective.isAllUnder) {
null
} else {
importDirective.importedFqName?.asString()
}
}
else {
val typeReference = expression.getParentOfType<KtTypeReference>(true)
val referenced = typeReference?.text ?: expression.getReferencedName()
expression.getContainingKtFile()
.importDirectives
.firstOrNull { !it.isAllUnder && it.aliasName == referenced || it.importedFqName?.shortName()?.asString() == referenced }
?.let { it.importedFqName?.asString() }
?: referenced
}
if (name != null) {
registrar.register(AddMavenDependencyQuickFix(name, expression.createSmartPointer()))
}
}
}
class AddMavenDependencyQuickFix(val className: String, val smartPsiElementPointer: SmartPsiElementPointer<KtSimpleNameExpression>) : IntentionAction, LowPriorityAction {
override fun getText() = "Add dependency..."
override fun getFamilyName() = "Kotlin"
override fun startInWriteAction() = false
override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?) =
smartPsiElementPointer.element.let { it != null && it.isValid } && file != null && MavenDomUtil.findContainingProject(file) != null
override fun invoke(project: Project, editor: Editor?, file: PsiFile?) {
if (editor == null || file == null) {
return
}
val virtualFile = file.originalFile.virtualFile ?: return
val mavenProject = MavenDomUtil.findContainingProject(file) ?: return
val xmlFile = PsiManager.getInstance(project).findFile(mavenProject.file) as? XmlFile ?: return
val ids = MavenArtifactSearchDialog.searchForClass(project, className)
if (ids.isEmpty()) return
runWriteAction {
val isTestSource = ProjectRootManager.getInstance(project).fileIndex.isInTestSourceContent(virtualFile)
val scope = if (isTestSource) MavenArtifactScope.TEST else null
val pom = PomFile(xmlFile)
ids.forEach {
pom.addDependency(it, scope)
}
}
}
}
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(IntentionActionPriority.LOW) { action } )
}
override fun register(fixRange: TextRange, action: IntentionAction, key: HighlightDisplayKey?) {
register(action)
}
override fun unregister(condition: Condition<IntentionAction>) {
}
})
}
return result
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.idea.configuration.PlatformUnresolvedProvider
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementAsConstructorParameter
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.inspections.AddModifierFixFactory
@@ -318,7 +319,8 @@ class QuickFixRegistrar : QuickFixContributor {
UNRESOLVED_REFERENCE.registerFactory(CreateClassFromTypeReferenceActionFactory,
CreateClassFromReferenceExpressionActionFactory,
CreateClassFromCallWithConstructorCalleeActionFactory)
CreateClassFromCallWithConstructorCalleeActionFactory,
PlatformUnresolvedProvider)
PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.registerFactory(InsertDelegationCallQuickfix.InsertThisDelegationCallFactory)