mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-194133 Extract AnnotatedElementInspectionBase from UnstableApiUsageInspection
This commit is contained in:
+116
@@ -0,0 +1,116 @@
|
||||
// Copyright 2000-2018 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 com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UImportStatement;
|
||||
import org.jetbrains.uast.UastContextKt;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class AnnotatedElementInspectionBase extends LocalInspectionTool {
|
||||
public boolean myIgnoreInsideImports = true;
|
||||
|
||||
|
||||
@NotNull
|
||||
protected abstract List<String> getAnnotations();
|
||||
|
||||
protected abstract void createProblem(@NotNull PsiReference reference, @NotNull ProblemsHolder holder);
|
||||
|
||||
protected abstract boolean shouldProcessElement(@NotNull PsiModifierListOwner element);
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JPanel createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(
|
||||
JvmAnalysisBundle.message("jvm.inspections.unstable.api.usage.ignore.inside.imports"), this, "myIgnoreInsideImports");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
if (!isApplicable(holder.getFile(), holder.getProject())) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
|
||||
return new PsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
super.visitElement(element);
|
||||
if (element instanceof PsiLanguageInjectionHost) {
|
||||
return; // better performance
|
||||
}
|
||||
|
||||
if (myIgnoreInsideImports && isInsideImport(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Java constructors must be handled a bit differently (works fine with Kotlin)
|
||||
PsiMethod resolvedConstructor = null;
|
||||
PsiElement elementParent = element.getParent();
|
||||
if (elementParent instanceof PsiConstructorCall) {
|
||||
resolvedConstructor = ((PsiConstructorCall)elementParent).resolveConstructor();
|
||||
}
|
||||
|
||||
for (PsiReference reference : element.getReferences()) {
|
||||
PsiModifierListOwner modifierListOwner = getModifierListOwner(reference, resolvedConstructor);
|
||||
if (modifierListOwner == null || !shouldProcessElement(modifierListOwner)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String annotation : getAnnotations()) {
|
||||
if (modifierListOwner.hasAnnotation(annotation)) {
|
||||
createProblem(reference, holder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isInsideImport(@NotNull PsiElement element) {
|
||||
return PsiTreeUtil.findFirstParent(element, parent -> UastContextKt.toUElement(parent, UImportStatement.class) != null) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiModifierListOwner getModifierListOwner(@NotNull PsiReference reference, @Nullable PsiMethod resolvedConstructor) {
|
||||
if (resolvedConstructor != null) {
|
||||
return resolvedConstructor;
|
||||
}
|
||||
|
||||
if (reference instanceof ResolvingHint && !((ResolvingHint)reference).canResolveTo(PsiModifierListOwner.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiElement resolvedElement = reference.resolve();
|
||||
if (resolvedElement instanceof PsiModifierListOwner) {
|
||||
return (PsiModifierListOwner)resolvedElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isApplicable(@Nullable PsiFile file, @Nullable Project project) {
|
||||
if (file == null || project == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
|
||||
GlobalSearchScope scope = file.getResolveScope();
|
||||
for (String annotation : getAnnotations()) {
|
||||
if (javaPsiFacade.findClass(annotation, scope) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+22
-96
@@ -2,29 +2,20 @@
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.codeInspection.util.SpecialAnnotationsUtil;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.siyeh.ig.ui.ExternalizableStringSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.uast.UImportStatement;
|
||||
import org.jetbrains.uast.UastContextKt;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
public class UnstableApiUsageInspection extends LocalInspectionTool {
|
||||
public boolean myIgnoreInsideImports = true;
|
||||
|
||||
public class UnstableApiUsageInspection extends AnnotatedElementInspectionBase {
|
||||
public final List<String> unstableApiAnnotations = new ExternalizableStringSet(
|
||||
"org.jetbrains.annotations.ApiStatus.Experimental",
|
||||
"com.google.common.annotations.Beta",
|
||||
@@ -35,11 +26,27 @@ public class UnstableApiUsageInspection extends LocalInspectionTool {
|
||||
"org.apache.http.annotation.Beta"
|
||||
);
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
SingleCheckboxOptionsPanel checkboxPanel = new SingleCheckboxOptionsPanel(
|
||||
JvmAnalysisBundle.message("jvm.inspections.unstable.api.usage.ignore.inside.imports"), this, "myIgnoreInsideImports");
|
||||
protected List<String> getAnnotations() {
|
||||
return unstableApiAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createProblem(@NotNull PsiReference reference, @NotNull ProblemsHolder holder) {
|
||||
String message = JvmAnalysisBundle.message("jvm.inspections.unstable.api.usage.description", getReferenceText(reference));
|
||||
holder.registerProblem(reference, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldProcessElement(@NotNull PsiModifierListOwner element) {
|
||||
return isLibraryElement(element);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JPanel createOptionsPanel() {
|
||||
JPanel checkboxPanel = super.createOptionsPanel();
|
||||
|
||||
//TODO in add annotation window "Include non-project items" should be enabled by default
|
||||
JPanel annotationsListControl = SpecialAnnotationsUtil.createSpecialAnnotationsListControl(
|
||||
@@ -51,55 +58,7 @@ public class UnstableApiUsageInspection extends LocalInspectionTool {
|
||||
return panel;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
if (!isApplicable(holder.getFile(), holder.getProject())) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
|
||||
return new PsiElementVisitor() {
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
super.visitElement(element);
|
||||
if (element instanceof PsiLanguageInjectionHost) {
|
||||
return; // better performance
|
||||
}
|
||||
|
||||
if (myIgnoreInsideImports && isInsideImport(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Java constructors must be handled a bit differently (works fine with Kotlin)
|
||||
PsiMethod resolvedConstructor = null;
|
||||
PsiElement elementParent = element.getParent();
|
||||
if (elementParent instanceof PsiConstructorCall) {
|
||||
resolvedConstructor = ((PsiConstructorCall)elementParent).resolveConstructor();
|
||||
}
|
||||
|
||||
for (PsiReference reference : element.getReferences()) {
|
||||
PsiModifierListOwner modifierListOwner = getModifierListOwner(reference, resolvedConstructor);
|
||||
if (modifierListOwner == null || !isLibraryElement(modifierListOwner)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (String annotation : unstableApiAnnotations) {
|
||||
if (modifierListOwner.hasAnnotation(annotation)) {
|
||||
holder.registerProblem(reference,
|
||||
JvmAnalysisBundle.message("jvm.inspections.unstable.api.usage.description", getReferenceText(reference)),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isInsideImport(@NotNull PsiElement element) {
|
||||
return PsiTreeUtil.findFirstParent(element, parent -> UastContextKt.toUElement(parent, UImportStatement.class) != null) != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
private static boolean isLibraryElement(@NotNull PsiElement element) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return true;
|
||||
@@ -127,37 +86,4 @@ public class UnstableApiUsageInspection extends LocalInspectionTool {
|
||||
// references are not PsiQualifiedReference for annotation attributes
|
||||
return StringUtil.getShortName(reference.getCanonicalText());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiModifierListOwner getModifierListOwner(@NotNull PsiReference reference, @Nullable PsiMethod resolvedConstructor) {
|
||||
if (resolvedConstructor != null) {
|
||||
return resolvedConstructor;
|
||||
}
|
||||
|
||||
if (reference instanceof ResolvingHint && !((ResolvingHint)reference).canResolveTo(PsiModifierListOwner.class)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiElement resolvedElement = reference.resolve();
|
||||
if (resolvedElement instanceof PsiModifierListOwner) {
|
||||
return (PsiModifierListOwner)resolvedElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isApplicable(@Nullable PsiFile file, @Nullable Project project) {
|
||||
if (file == null || project == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
|
||||
GlobalSearchScope scope = file.getResolveScope();
|
||||
for (String annotation : unstableApiAnnotations) {
|
||||
if (javaPsiFacade.findClass(annotation, scope) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user