KT-3248 Highlight Java members with invalid annotations in IDE
#KT-3248 fixed
This commit is contained in:
+102
-22
@@ -20,6 +20,7 @@ import com.intellij.codeHighlighting.Pass;
|
|||||||
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
|
import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
import com.intellij.codeInsight.daemon.LineMarkerInfo;
|
||||||
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
import com.intellij.codeInsight.daemon.LineMarkerProvider;
|
||||||
|
import com.intellij.icons.AllIcons;
|
||||||
import com.intellij.ide.DataManager;
|
import com.intellij.ide.DataManager;
|
||||||
import com.intellij.ide.util.PropertiesComponent;
|
import com.intellij.ide.util.PropertiesComponent;
|
||||||
import com.intellij.openapi.actionSystem.ActionGroup;
|
import com.intellij.openapi.actionSystem.ActionGroup;
|
||||||
@@ -27,13 +28,18 @@ import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
|||||||
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
import com.intellij.openapi.editor.markup.GutterIconRenderer;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.psi.PsiAnnotation;
|
import com.intellij.psi.*;
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.psi.PsiModifierListOwner;
|
|
||||||
import com.intellij.util.Function;
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.ui.UIUtil;
|
import com.intellij.util.ui.UIUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.jet.di.InjectorForJavaSemanticServices;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
|
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
import org.jetbrains.jet.plugin.JetIcons;
|
import org.jetbrains.jet.plugin.JetIcons;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
@@ -45,20 +51,6 @@ import static org.jetbrains.jet.plugin.codeInsight.ktSignature.KotlinSignatureUt
|
|||||||
public class KotlinSignatureInJavaMarkerProvider implements LineMarkerProvider {
|
public class KotlinSignatureInJavaMarkerProvider implements LineMarkerProvider {
|
||||||
private static final String SHOW_MARKERS_PROPERTY = "kotlin.signature.markers.enabled";
|
private static final String SHOW_MARKERS_PROPERTY = "kotlin.signature.markers.enabled";
|
||||||
|
|
||||||
private static final Function<PsiElement, String> TOOLTIP_PROVIDER = new Function<PsiElement, String>() {
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public String fun(PsiElement element) {
|
|
||||||
PsiAnnotation annotation = findKotlinSignatureAnnotation(element);
|
|
||||||
|
|
||||||
if (annotation == null) return null;
|
|
||||||
|
|
||||||
String signature = getKotlinSignature(annotation);
|
|
||||||
return "Alternative Kotlin signature is available for this method:\n"
|
|
||||||
+ StringUtil.escapeXml(signature);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final GutterIconNavigationHandler<PsiModifierListOwner> NAVIGATION_HANDLER = new GutterIconNavigationHandler<PsiModifierListOwner>() {
|
private static final GutterIconNavigationHandler<PsiModifierListOwner> NAVIGATION_HANDLER = new GutterIconNavigationHandler<PsiModifierListOwner>() {
|
||||||
@Override
|
@Override
|
||||||
public void navigate(MouseEvent e, PsiModifierListOwner element) {
|
public void navigate(MouseEvent e, PsiModifierListOwner element) {
|
||||||
@@ -72,14 +64,70 @@ public class KotlinSignatureInJavaMarkerProvider implements LineMarkerProvider {
|
|||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
|
public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
|
||||||
if (isMarkersEnabled(element.getProject()) && findKotlinSignatureAnnotation(element) != null) {
|
|
||||||
return new MyLineMarkerInfo((PsiModifierListOwner) element);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
|
public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
|
||||||
|
if (elements.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Project project = elements.get(0).getProject();
|
||||||
|
if (!isMarkersEnabled(project)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InjectorForJavaSemanticServices injector = new InjectorForJavaSemanticServices(project);
|
||||||
|
JavaDescriptorResolver javaDescriptorResolver = injector.getJavaDescriptorResolver();
|
||||||
|
BindingContext bindingContext = injector.getBindingTrace().getBindingContext();
|
||||||
|
|
||||||
|
for (PsiElement element : elements) {
|
||||||
|
if (!(element instanceof PsiMember)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiMember member = (PsiMember) element;
|
||||||
|
if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiClass containingClass = member.getContainingClass();
|
||||||
|
if (containingClass == null) { // e.g., type parameter
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String qualifiedName = containingClass.getQualifiedName();
|
||||||
|
assert qualifiedName != null;
|
||||||
|
|
||||||
|
FqName classFqName = new FqName(qualifiedName);
|
||||||
|
ClassDescriptor klass = javaDescriptorResolver.resolveClass(classFqName);
|
||||||
|
assert klass != null : " Couldn't find class " + classFqName;
|
||||||
|
|
||||||
|
String memberNameAsString = member.getName();
|
||||||
|
assert memberNameAsString != null;
|
||||||
|
|
||||||
|
Name name = Name.identifier(memberNameAsString);
|
||||||
|
if (element instanceof PsiMethod) {
|
||||||
|
klass.getDefaultType().getMemberScope().getFunctions(name);
|
||||||
|
}
|
||||||
|
else if (element instanceof PsiField) {
|
||||||
|
klass.getDefaultType().getMemberScope().getProperties(name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiModifierListOwner annotationOwner = getAnnotationOwner(element);
|
||||||
|
DeclarationDescriptor memberDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, annotationOwner);
|
||||||
|
assert memberDescriptor != null : "Couldn't find descriptor for " + annotationOwner;
|
||||||
|
List<String> errors = bindingContext.get(BindingContext.LOAD_FROM_JAVA_SIGNATURE_ERRORS, memberDescriptor);
|
||||||
|
boolean hasSignatureAnnotation = findKotlinSignatureAnnotation(element) != null;
|
||||||
|
|
||||||
|
if (errors != null || hasSignatureAnnotation) {
|
||||||
|
result.add(new MyLineMarkerInfo((PsiModifierListOwner) element, errors, hasSignatureAnnotation));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isMarkersEnabled(@NotNull Project project) {
|
public static boolean isMarkersEnabled(@NotNull Project project) {
|
||||||
@@ -92,8 +140,9 @@ public class KotlinSignatureInJavaMarkerProvider implements LineMarkerProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class MyLineMarkerInfo extends LineMarkerInfo<PsiModifierListOwner> {
|
private static class MyLineMarkerInfo extends LineMarkerInfo<PsiModifierListOwner> {
|
||||||
public MyLineMarkerInfo(PsiModifierListOwner element) {
|
public MyLineMarkerInfo(PsiModifierListOwner element, @Nullable List<String> errors, boolean hasAnnotation) {
|
||||||
super(element, element.getTextOffset(), JetIcons.SMALL_LOGO, Pass.UPDATE_ALL, TOOLTIP_PROVIDER, NAVIGATION_HANDLER);
|
super(element, element.getTextOffset(), errors != null ? AllIcons.Ide.Error : JetIcons.SMALL_LOGO, Pass.UPDATE_ALL,
|
||||||
|
new TooltipProvider(errors), hasAnnotation ? NAVIGATION_HANDLER : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -111,4 +160,35 @@ public class KotlinSignatureInJavaMarkerProvider implements LineMarkerProvider {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TooltipProvider implements Function<PsiElement, String> {
|
||||||
|
private final @Nullable List<String> errors;
|
||||||
|
|
||||||
|
private TooltipProvider(@Nullable List<String> errors) {
|
||||||
|
this.errors = errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String fun(PsiElement element) {
|
||||||
|
PsiAnnotation annotation = findKotlinSignatureAnnotation(element);
|
||||||
|
|
||||||
|
if (annotation == null) return errorsString();
|
||||||
|
|
||||||
|
String signature = getKotlinSignature(annotation);
|
||||||
|
String text = "Alternative Kotlin signature is available for this method:\n"
|
||||||
|
+ StringUtil.escapeXml(signature);
|
||||||
|
if (errors == null) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text + "\nIt has the following " + StringUtil.pluralize("error", errors.size()) + ":\n"
|
||||||
|
+ errorsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private String errorsString() {
|
||||||
|
assert errors != null;
|
||||||
|
return StringUtil.escapeXml(StringUtil.join(errors, "\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user