[groovy] extract class fixes generation into separate file, make it independent from HighlightInfo/HighlightDisplayKey

This commit is contained in:
Daniil Ovchinnikov
2019-02-21 12:16:25 +03:00
parent f0590f2969
commit dd03ec2dbd
2 changed files with 92 additions and 73 deletions
@@ -1,6 +1,4 @@
// Copyright 2000-2017 JetBrains s.r.o.
// Use of this source code is governed by the Apache 2.0 license that can be
// found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
@@ -9,6 +7,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
import com.intellij.codeInsight.intention.EmptyIntentionAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider;
import com.intellij.openapi.diagnostic.Logger;
@@ -32,20 +31,14 @@ import org.jetbrains.plugins.groovy.codeInspection.GrInspectionUtil;
import org.jetbrains.plugins.groovy.codeInspection.GroovyQuickFixFactory;
import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter;
import org.jetbrains.plugins.groovy.findUsages.MissingMethodAndPropertyUtil;
import org.jetbrains.plugins.groovy.lang.GrCreateClassKind;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GroovyDocPsiElement;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.EmptyGroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrInterfaceDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
@@ -68,6 +61,7 @@ import java.util.List;
import java.util.Map;
import static com.intellij.psi.util.PsiUtil.isInnerClass;
import static org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess.ReferenceFixesKt.generateCreateClassActions;
import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil.hasArguments;
import static org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.hasEnclosingInstanceInScope;
@@ -463,71 +457,10 @@ public class GrUnresolvedAccessChecker {
private static void registerCreateClassByTypeFix(@NotNull GrReferenceElement refElement,
@Nullable HighlightInfo info,
final HighlightDisplayKey key) {
GrPackageDefinition packageDefinition = PsiTreeUtil.getParentOfType(refElement, GrPackageDefinition.class);
if (packageDefinition != null) return;
PsiElement parent = refElement.getParent();
if (parent instanceof GrNewExpression &&
refElement.getManager().areElementsEquivalent(((GrNewExpression)parent).getReferenceElement(), refElement)) {
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFromNewAction((GrNewExpression)parent), key);
HighlightDisplayKey key) {
for (IntentionAction fix : generateCreateClassActions(refElement)) {
QuickFixAction.registerQuickFixAction(info, fix, key);
}
else if (canBeClassOrPackage(refElement)) {
if (shouldBeInterface(refElement)) {
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.INTERFACE), key);
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.TRAIT), key);
}
else if (shouldBeClass(refElement)) {
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.CLASS), key);
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.ENUM), key);
}
else if (shouldBeAnnotation(refElement)) {
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.ANNOTATION), key);
}
else {
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.CLASS), key);
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.INTERFACE), key);
if (!refElement.isQualified() || resolvesToGroovy(refElement.getQualifier())) {
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.TRAIT), key);
}
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.ENUM), key);
QuickFixAction.registerQuickFixAction(info, GroovyQuickFixFactory.getInstance().createClassFixAction(refElement, GrCreateClassKind.ANNOTATION), key);
}
}
}
private static boolean resolvesToGroovy(PsiElement qualifier) {
if (qualifier instanceof GrReferenceElement) {
return ((GrReferenceElement)qualifier).resolve() instanceof GroovyPsiElement;
}
if (qualifier instanceof GrExpression) {
PsiType type = ((GrExpression)qualifier).getType();
if (type instanceof PsiClassType) {
PsiClass resolved = ((PsiClassType)type).resolve();
return resolved instanceof GroovyPsiElement;
}
}
return false;
}
private static boolean canBeClassOrPackage(@NotNull GrReferenceElement refElement) {
return !(refElement instanceof GrReferenceExpression) || ResolveUtil.canBeClassOrPackage((GrReferenceExpression)refElement);
}
private static boolean shouldBeAnnotation(GrReferenceElement element) {
return element.getParent() instanceof GrAnnotation;
}
private static boolean shouldBeInterface(GrReferenceElement myRefElement) {
PsiElement parent = myRefElement.getParent();
return parent instanceof GrImplementsClause || parent instanceof GrExtendsClause && parent.getParent() instanceof GrInterfaceDefinition;
}
private static boolean shouldBeClass(GrReferenceElement myRefElement) {
PsiElement parent = myRefElement.getParent();
return parent instanceof GrExtendsClause && !(parent.getParent() instanceof GrInterfaceDefinition);
}
private static boolean shouldHighlightAsUnresolved(@NotNull GrReferenceExpression referenceExpression) {
@@ -0,0 +1,86 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.plugins.groovy.codeInspection.untypedUnresolvedAccess
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.psi.PsiClassType
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
import org.jetbrains.plugins.groovy.codeInspection.GroovyQuickFixFactory
import org.jetbrains.plugins.groovy.lang.GrCreateClassKind
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrInterfaceDefinition
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.canBeClassOrPackage
fun generateCreateClassActions(ref: GrReferenceElement<*>): Collection<IntentionAction> {
if (ref.parentOfType<GrPackageDefinition>() != null) {
return emptyList()
}
val factory = GroovyQuickFixFactory.getInstance()
val parent = ref.parent
if (parent is GrNewExpression && parent.referenceElement === ref) {
return listOf(factory.createClassFromNewAction(parent))
}
if (ref is GrReferenceExpression && !canBeClassOrPackage(ref)) {
return emptyList()
}
return when {
classExpected(parent) -> listOf(
factory.createClassFixAction(ref, GrCreateClassKind.CLASS),
factory.createClassFixAction(ref, GrCreateClassKind.ENUM)
)
interfaceExpected(parent) -> listOf(
factory.createClassFixAction(ref, GrCreateClassKind.INTERFACE),
factory.createClassFixAction(ref, GrCreateClassKind.TRAIT)
)
annotationExpected(parent) -> listOf(
factory.createClassFixAction(ref, GrCreateClassKind.ANNOTATION)
)
else -> {
val result = mutableListOf(
factory.createClassFixAction(ref, GrCreateClassKind.CLASS),
factory.createClassFixAction(ref, GrCreateClassKind.INTERFACE)
)
if (!ref.isQualified || resolvesToGroovy(ref.qualifier)) {
result += factory.createClassFixAction(ref, GrCreateClassKind.TRAIT)
}
result += factory.createClassFixAction(ref, GrCreateClassKind.ENUM)
result += factory.createClassFixAction(ref, GrCreateClassKind.ANNOTATION)
result
}
}
}
private fun classExpected(parent: PsiElement?): Boolean {
return parent is GrExtendsClause && parent.parent !is GrInterfaceDefinition
}
private fun interfaceExpected(parent: PsiElement?): Boolean {
return parent is GrImplementsClause || parent is GrExtendsClause && parent.parent is GrInterfaceDefinition
}
private fun annotationExpected(parent: PsiElement?): Boolean {
return parent is GrAnnotation
}
private fun resolvesToGroovy(qualifier: PsiElement?): Boolean {
return when (qualifier) {
is GrReferenceElement<*> -> qualifier.resolve() is GroovyPsiElement
is GrExpression -> {
val type = qualifier.type as? PsiClassType
type?.resolve() is GroovyPsiElement
}
else -> false
}
}