mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-08 15:09:39 +07:00
blocking calls detection inspection : minor changes
This commit is contained in:
committed by
Nicolay Mitropolsky
parent
afc9d936e9
commit
76e2d4b06b
@@ -1,9 +1,9 @@
|
||||
<idea-plugin>
|
||||
<extensionPoints>
|
||||
<extensionPoint qualifiedName="com.intellij.blockingMethodChecker"
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.blockingMethodChecker"
|
||||
interface="com.intellij.codeInspection.blockingCallsDetection.BlockingMethodChecker"/>
|
||||
<extensionPoint qualifiedName="com.intellij.nonblockingMethodChecker"
|
||||
interface="com.intellij.codeInspection.blockingCallsDetection.NonblockingContextChecker"/>
|
||||
<extensionPoint qualifiedName="com.intellij.codeInsight.nonBlockingContextChecker"
|
||||
interface="com.intellij.codeInspection.blockingCallsDetection.NonBlockingContextChecker"/>
|
||||
</extensionPoints>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<localInspection language="UAST" enabledByDefault="true" level="WARNING" shortName="UnstableApiUsage"
|
||||
@@ -15,6 +15,8 @@
|
||||
enabledByDefault="true" level="WARNING"
|
||||
key="method.name.contains.blocking.word.display.name" bundle="com.intellij.jvm.analysis.JvmAnalysisBundle"
|
||||
implementationClass="com.intellij.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection"/>
|
||||
</extensions>
|
||||
<extensions defaultExtensionNs="com.intellij.codeInsight">
|
||||
<blockingMethodChecker implementation="com.intellij.codeInspection.blockingCallsDetection.ThrowsTypeBlockingMethodChecker"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -6,13 +6,13 @@ jvm.inspections.unstable.api.usage.ignore.inside.imports=Ignore inside imports
|
||||
jvm.inspections.unstable.api.usage.description=''{0}'' is marked unstable
|
||||
|
||||
method.name.contains.blocking.word.problem.descriptor=Inappropriate blocking method call
|
||||
method.name.contains.blocking.word.display.name=Inappropriate thread-blocking method call found
|
||||
inspection.blocking.method.annotation.blocking=Blocking Annotations
|
||||
inspection.blocking.method.annotation.nonblocking=Non-blocking Annotations
|
||||
inspection.blocking.method.annotation.configure.add.blocking.title=Add Blocking Annotation
|
||||
inspection.blocking.method.annotation.configure.add.nonblocking.title=Add Non-Blocking Annotation
|
||||
inspection.blocking.method.annotation.configure.empty.text=No annotations added.
|
||||
inspection.blocking.method.annotation.configure.add.text=Add annotation
|
||||
method.name.contains.blocking.word.display.name=Inappropriate thread-blocking method call
|
||||
jvm.inspections.blocking.method.annotation.blocking=Blocking Annotations
|
||||
jvm.inspections.blocking.method.annotation.non-blocking=Non-Blocking Annotations
|
||||
jvm.inspections.blocking.method.annotation.configure.add.blocking.title=Add Blocking Annotation
|
||||
jvm.inspections.blocking.method.annotation.configure.add.non-blocking.title=Add Non-Blocking Annotation
|
||||
jvm.inspections.blocking.method.annotation.configure.empty.text=No annotations added.
|
||||
jvm.inspections.blocking.method.annotation.configure.add.text=Add annotation
|
||||
|
||||
|
||||
jvm.inspections.string.touppercase.tolowercase.without.locale.display.name=Call to 'String.toUpperCase()' or 'toLowerCase()' without a Locale
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
package com.intellij.codeInspection.blockingCallsDetection;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiAnnotation;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -12,17 +10,20 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DefaultBlockingMethodChecker implements BlockingMethodChecker {
|
||||
public class AnnotationBasedBlockingMethodChecker implements BlockingMethodChecker {
|
||||
|
||||
private final List<String> myBlockingAnnotations;
|
||||
|
||||
public DefaultBlockingMethodChecker(List<String> blockingAnnotations) {
|
||||
public AnnotationBasedBlockingMethodChecker(List<String> blockingAnnotations) {
|
||||
myBlockingAnnotations = blockingAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(Project project) {
|
||||
return !myBlockingAnnotations.isEmpty();
|
||||
public boolean isActive(@NotNull PsiFile file) {
|
||||
if (myBlockingAnnotations.isEmpty()) return false;
|
||||
PsiClass annotationClass = JavaPsiFacade.getInstance(file.getProject())
|
||||
.findClass(BlockingMethodInNonBlockingContextInspection.DEFAULT_BLOCKING_ANNOTATION, file.getResolveScope());
|
||||
return annotationClass != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2,9 +2,7 @@
|
||||
package com.intellij.codeInspection.blockingCallsDetection;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.uast.UCallExpression;
|
||||
import org.jetbrains.uast.UMethod;
|
||||
@@ -16,19 +14,19 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DefaultNonblockingContextChecker implements NonblockingContextChecker {
|
||||
public class AnnotationBasedNonBlockingContextChecker implements NonBlockingContextChecker {
|
||||
|
||||
private final List<String> myNonblockingAnnotations;
|
||||
private final List<String> myNonBlockingAnnotations;
|
||||
|
||||
public DefaultNonblockingContextChecker(List<String> nonblockingAnnotations) {
|
||||
myNonblockingAnnotations = nonblockingAnnotations;
|
||||
public AnnotationBasedNonBlockingContextChecker(List<String> nonBlockingAnnotations) {
|
||||
myNonBlockingAnnotations = nonBlockingAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive(Project project) {
|
||||
if (myNonblockingAnnotations.isEmpty()) return false;
|
||||
PsiClass annotationClass = JavaPsiFacade.getInstance(project)
|
||||
.findClass(BlockingMethodInNonBlockingContextInspection.DEFAULT_NONBLOCKING_ANNOTATION, ProjectScope.getProjectScope(project));
|
||||
public boolean isActive(@NotNull PsiFile file) {
|
||||
if (myNonBlockingAnnotations.isEmpty()) return false;
|
||||
PsiClass annotationClass = JavaPsiFacade.getInstance(file.getProject())
|
||||
.findClass(BlockingMethodInNonBlockingContextInspection.DEFAULT_NONBLOCKING_ANNOTATION, file.getResolveScope());
|
||||
return annotationClass != null;
|
||||
}
|
||||
|
||||
@@ -48,7 +46,7 @@ public class DefaultNonblockingContextChecker implements NonblockingContextCheck
|
||||
HashSet<String> setOfAnnotations = Arrays.stream(AnnotationUtil.getAllAnnotations(method, true, null))
|
||||
.map(PsiAnnotation::getQualifiedName).collect(Collectors.toCollection(HashSet::new));
|
||||
|
||||
return myNonblockingAnnotations.stream()
|
||||
return myNonBlockingAnnotations.stream()
|
||||
.anyMatch(annotation -> setOfAnnotations.contains(annotation));
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.ide.util.TreeClassChooser;
|
||||
import com.intellij.ide.util.TreeClassChooserFactory;
|
||||
import com.intellij.openapi.actionSystem.Shortcut;
|
||||
import com.intellij.openapi.actionSystem.ShortcutSet;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -14,7 +13,6 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
@@ -25,7 +23,6 @@ import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableColumnModel;
|
||||
import javax.swing.table.TableColumn;
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -41,15 +38,15 @@ class BlockingAnnotationsPanel {
|
||||
private final String myCustomAddLinkText;
|
||||
|
||||
BlockingAnnotationsPanel(Project project,
|
||||
String name,
|
||||
String defaultAnnotation,
|
||||
List<String> annotations,
|
||||
String[] defaultAnnotations,
|
||||
String customEmptyText,
|
||||
String customAddLinkText) {
|
||||
String name,
|
||||
String defaultAnnotation,
|
||||
List<String> annotations,
|
||||
List<String> defaultAnnotations,
|
||||
String customEmptyText,
|
||||
String customAddLinkText) {
|
||||
myProject = project;
|
||||
myDefaultAnnotation = defaultAnnotation;
|
||||
myDefaultAnnotations = new HashSet<>(Arrays.asList(defaultAnnotations));
|
||||
myDefaultAnnotations = new HashSet<>(defaultAnnotations);
|
||||
myCustomEmptyText = customEmptyText;
|
||||
myCustomAddLinkText = customAddLinkText;
|
||||
myTableModel = new ListWrappingTableModel(annotations, name) {
|
||||
@@ -93,16 +90,14 @@ class BlockingAnnotationsPanel {
|
||||
.appendSecondaryText(myCustomAddLinkText, SimpleTextAttributes.LINK_ATTRIBUTES, e -> chooseAnnotation(name));
|
||||
|
||||
ShortcutSet shortcutSet = CommonActionsPanel.getCommonShortcut(CommonActionsPanel.Buttons.ADD);
|
||||
Shortcut shortcut = ArrayUtil.getFirstElement(shortcutSet.getShortcuts());
|
||||
if (shortcut != null) {
|
||||
emptyText.appendSecondaryText(" (" + KeymapUtil.getShortcutText(shortcut) + ")", StatusText.DEFAULT_ATTRIBUTES, null);
|
||||
}
|
||||
String shortcutText = KeymapUtil.getFirstKeyboardShortcutText(shortcutSet);
|
||||
emptyText.appendSecondaryText(" (" + shortcutText + ")", StatusText.DEFAULT_ATTRIBUTES, null);
|
||||
}
|
||||
return emptyText;
|
||||
}
|
||||
};
|
||||
|
||||
final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTable).disableUpDownActions()
|
||||
final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTable)
|
||||
.setAddAction(b -> chooseAnnotation(name))
|
||||
.setRemoveAction(new AnActionButtonRunnable() {
|
||||
@Override
|
||||
@@ -119,7 +114,9 @@ class BlockingAnnotationsPanel {
|
||||
final JPanel panel = toolbarDecorator.createPanel();
|
||||
myComponent = new JPanel(new BorderLayout());
|
||||
myComponent.setBorder(IdeBorderFactory.createEmptyBorder(JBUI.insetsTop(10)));
|
||||
myComponent.add(new JLabel(name), BorderLayout.NORTH);
|
||||
final JLabel label = new JLabel(name + ":");
|
||||
label.setBorder(IdeBorderFactory.createEmptyBorder(JBUI.insetsBottom(10)));
|
||||
myComponent.add(label, BorderLayout.NORTH);
|
||||
myComponent.add(panel, BorderLayout.CENTER);
|
||||
myComponent.setPreferredSize(new JBDimension(myComponent.getPreferredSize().width, 200));
|
||||
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
package com.intellij.codeInspection.blockingCallsDetection;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface BlockingMethodChecker {
|
||||
ExtensionPointName<BlockingMethodChecker> EP_NAME = ExtensionPointName.create("com.intellij.blockingMethodChecker");
|
||||
ExtensionPointName<BlockingMethodChecker> EP_NAME = ExtensionPointName.create("com.intellij.codeInsight.blockingMethodChecker");
|
||||
|
||||
boolean isActive(Project project);
|
||||
boolean isActive(@NotNull PsiFile file);
|
||||
|
||||
boolean isMethodBlocking(@NotNull PsiMethod method);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ package com.intellij.codeInspection.blockingCallsDetection;
|
||||
import com.intellij.analysis.JvmAnalysisBundle;
|
||||
import com.intellij.codeInspection.AbstractBaseUastLocalInspectionTool;
|
||||
import com.intellij.codeInspection.AnalysisUastUtil;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
@@ -15,6 +14,7 @@ import com.intellij.openapi.wm.IdeFocusManager;
|
||||
import com.intellij.openapi.wm.IdeFrame;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.uast.UCallExpression;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockingMethodInNonBlockingContextInspection extends AbstractBaseUastLocalInspectionTool {
|
||||
@@ -37,7 +38,7 @@ public class BlockingMethodInNonBlockingContextInspection extends AbstractBaseUa
|
||||
public static final String DEFAULT_NONBLOCKING_ANNOTATION = "org.jetbrains.annotations.NonBlocking";
|
||||
|
||||
public List<String> myBlockingAnnotations = new SmartList<>();
|
||||
public List<String> myNonblockingAnnotations = new SmartList<>();
|
||||
public List<String> myNonBlockingAnnotations = new SmartList<>();
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@@ -58,27 +59,26 @@ public class BlockingMethodInNonBlockingContextInspection extends AbstractBaseUa
|
||||
|
||||
List<BlockingMethodChecker> blockingMethodCheckers =
|
||||
ContainerUtil.append(BlockingMethodChecker.EP_NAME.getExtensionList(),
|
||||
new DefaultBlockingMethodChecker(myBlockingAnnotations));
|
||||
new AnnotationBasedBlockingMethodChecker(myBlockingAnnotations));
|
||||
|
||||
List<NonblockingContextChecker> nonblockingContextCheckers =
|
||||
ContainerUtil.append(NonblockingContextChecker.EP_NAME.getExtensionList(),
|
||||
new DefaultNonblockingContextChecker(myNonblockingAnnotations));
|
||||
List<NonBlockingContextChecker> nonBlockingContextCheckers =
|
||||
ContainerUtil.append(NonBlockingContextChecker.EP_NAME.getExtensionList(),
|
||||
new AnnotationBasedNonBlockingContextChecker(myNonBlockingAnnotations));
|
||||
|
||||
if (!isInspectionActive(holder.getProject(), blockingMethodCheckers, nonblockingContextCheckers)) {
|
||||
if (!isInspectionActive(holder.getFile(), blockingMethodCheckers, nonBlockingContextCheckers)) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
return new BlockingMethodInNonBlockingContextVisitor(holder, blockingMethodCheckers, nonblockingContextCheckers);
|
||||
return new BlockingMethodInNonBlockingContextVisitor(holder, blockingMethodCheckers, nonBlockingContextCheckers);
|
||||
}
|
||||
|
||||
private static boolean isInspectionActive(Project project,
|
||||
private static boolean isInspectionActive(PsiFile file,
|
||||
List<BlockingMethodChecker> myBlockingMethodCheckers,
|
||||
List<NonblockingContextChecker> myNonblockingContextCheckers) {
|
||||
return myBlockingMethodCheckers.stream().anyMatch(extension -> extension.isActive(project)) &&
|
||||
myNonblockingContextCheckers.stream().anyMatch(extension -> extension.isActive(project));
|
||||
List<NonBlockingContextChecker> myNonBlockingContextCheckers) {
|
||||
return myBlockingMethodCheckers.stream().anyMatch(extension -> extension.isActive(file)) &&
|
||||
myNonBlockingContextCheckers.stream().anyMatch(extension -> extension.isActive(file));
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class OptionsPanel extends JPanel {
|
||||
private OptionsPanel() {
|
||||
super(new BorderLayout());
|
||||
@@ -89,27 +89,27 @@ public class BlockingMethodInNonBlockingContextInspection extends AbstractBaseUa
|
||||
new BlockingAnnotationsPanel(
|
||||
project,
|
||||
JvmAnalysisBundle
|
||||
.message("inspection.blocking.method.annotation.blocking"),
|
||||
.message("jvm.inspections.blocking.method.annotation.blocking"),
|
||||
DEFAULT_BLOCKING_ANNOTATION,
|
||||
myBlockingAnnotations,
|
||||
new String[]{DEFAULT_BLOCKING_ANNOTATION},
|
||||
JvmAnalysisBundle.message("inspection.blocking.method.annotation.configure.empty.text"),
|
||||
JvmAnalysisBundle.message("inspection.blocking.method.annotation.configure.add.blocking.title"));
|
||||
Collections.singletonList(DEFAULT_BLOCKING_ANNOTATION),
|
||||
JvmAnalysisBundle.message("jvm.inspections.blocking.method.annotation.configure.empty.text"),
|
||||
JvmAnalysisBundle.message("jvm.inspections.blocking.method.annotation.configure.add.blocking.title"));
|
||||
|
||||
|
||||
BlockingAnnotationsPanel nonblockingAnnotationsPanel =
|
||||
BlockingAnnotationsPanel nonBlockingAnnotationsPanel =
|
||||
new BlockingAnnotationsPanel(
|
||||
project,
|
||||
JvmAnalysisBundle.message(
|
||||
"inspection.blocking.method.annotation.nonblocking"),
|
||||
"jvm.inspections.blocking.method.annotation.non-blocking"),
|
||||
DEFAULT_NONBLOCKING_ANNOTATION,
|
||||
myNonblockingAnnotations,
|
||||
new String[]{DEFAULT_NONBLOCKING_ANNOTATION},
|
||||
JvmAnalysisBundle.message("inspection.blocking.method.annotation.configure.add.nonblocking.title"),
|
||||
JvmAnalysisBundle.message("inspection.blocking.method.annotation.configure.add.nonblocking.title"));
|
||||
myNonBlockingAnnotations,
|
||||
Collections.singletonList(DEFAULT_NONBLOCKING_ANNOTATION),
|
||||
JvmAnalysisBundle.message("jvm.inspections.blocking.method.annotation.configure.empty.text"),
|
||||
JvmAnalysisBundle.message("jvm.inspections.blocking.method.annotation.configure.add.non-blocking.title"));
|
||||
|
||||
mainPanel.setFirstComponent(blockingAnnotationsPanel.getComponent());
|
||||
mainPanel.setSecondComponent(nonblockingAnnotationsPanel.getComponent());
|
||||
mainPanel.setSecondComponent(nonBlockingAnnotationsPanel.getComponent());
|
||||
|
||||
add(mainPanel, BorderLayout.CENTER);
|
||||
}
|
||||
@@ -129,14 +129,14 @@ public class BlockingMethodInNonBlockingContextInspection extends AbstractBaseUa
|
||||
private static class BlockingMethodInNonBlockingContextVisitor extends PsiElementVisitor {
|
||||
private final ProblemsHolder myHolder;
|
||||
private final List<BlockingMethodChecker> myBlockingMethodCheckers;
|
||||
private final List<NonblockingContextChecker> myNonblockingContextCheckers;
|
||||
private final List<NonBlockingContextChecker> myNonBlockingContextCheckers;
|
||||
|
||||
public BlockingMethodInNonBlockingContextVisitor(@NotNull ProblemsHolder holder,
|
||||
List<BlockingMethodChecker> blockingMethodCheckers,
|
||||
List<NonblockingContextChecker> nonblockingContextCheckers) {
|
||||
List<NonBlockingContextChecker> nonBlockingContextCheckers) {
|
||||
myHolder = holder;
|
||||
this.myBlockingMethodCheckers = blockingMethodCheckers;
|
||||
this.myNonblockingContextCheckers = nonblockingContextCheckers;
|
||||
this.myNonBlockingContextCheckers = nonBlockingContextCheckers;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,27 +150,32 @@ public class BlockingMethodInNonBlockingContextInspection extends AbstractBaseUa
|
||||
PsiMethod referencedMethod = callExpression.resolve();
|
||||
if (referencedMethod == null) return;
|
||||
|
||||
boolean isReferencedMethodBlocking = CachedValuesManager.getCachedValue(referencedMethod, () -> {
|
||||
boolean isBlocking =
|
||||
StreamEx.of(referencedMethod).append(referencedMethod.findDeepestSuperMethods()).anyMatch(method -> isMethodBlocking(method));
|
||||
return CachedValueProvider.Result.create(isBlocking, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
});
|
||||
|
||||
if (!isReferencedMethodBlocking) return;
|
||||
if (!CachedValuesManager.getCachedValue(referencedMethod, getIsBlockingProvider(referencedMethod, myBlockingMethodCheckers))) {
|
||||
return;
|
||||
}
|
||||
|
||||
PsiElement elementToHighLight = AnalysisUastUtil.getMethodIdentifierSourcePsi(callExpression);
|
||||
if (elementToHighLight == null) return;
|
||||
myHolder.registerProblem(elementToHighLight,
|
||||
JvmAnalysisBundle.message("method.name.contains.blocking.word.problem.descriptor"),
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
|
||||
JvmAnalysisBundle.message("method.name.contains.blocking.word.problem.descriptor"));
|
||||
}
|
||||
|
||||
private static CachedValueProvider<Boolean> getIsBlockingProvider(PsiMethod referencedMethod,
|
||||
List<BlockingMethodChecker> blockingMethodCheckers) {
|
||||
return () -> {
|
||||
boolean isBlocking =
|
||||
StreamEx.of(referencedMethod).append(referencedMethod.findDeepestSuperMethods())
|
||||
.anyMatch(method -> isMethodBlocking(method, blockingMethodCheckers));
|
||||
return CachedValueProvider.Result.create(isBlocking, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isContextNonBlockingFor(PsiElement element) {
|
||||
return myNonblockingContextCheckers.stream().anyMatch(extension -> extension.isContextNonBlockingFor(element));
|
||||
return myNonBlockingContextCheckers.stream().anyMatch(extension -> extension.isContextNonBlockingFor(element));
|
||||
}
|
||||
|
||||
private boolean isMethodBlocking(PsiMethod method) {
|
||||
return myBlockingMethodCheckers.stream().anyMatch(extension -> extension.isMethodBlocking(method));
|
||||
private static boolean isMethodBlocking(PsiMethod method, List<BlockingMethodChecker> blockingMethodCheckers) {
|
||||
return blockingMethodCheckers.stream().anyMatch(extension -> extension.isMethodBlocking(method));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
package com.intellij.codeInspection.blockingCallsDetection;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface NonblockingContextChecker {
|
||||
ExtensionPointName<NonblockingContextChecker> EP_NAME = ExtensionPointName.create("com.intellij.nonblockingMethodChecker");
|
||||
public interface NonBlockingContextChecker {
|
||||
ExtensionPointName<NonBlockingContextChecker> EP_NAME = ExtensionPointName.create("com.intellij.codeInsight.nonBlockingContextChecker");
|
||||
|
||||
boolean isActive(Project project);
|
||||
boolean isActive(@NotNull PsiFile file);
|
||||
|
||||
boolean isContextNonBlockingFor(@NotNull PsiElement element);
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
// 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.blockingCallsDetection;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ThrowsTypeBlockingMethodChecker implements BlockingMethodChecker {
|
||||
private static final HashSet<String> BLOCKING_EXCEPTION_TYPES = new HashSet<>(Arrays.asList(
|
||||
private static final Set<String> BLOCKING_EXCEPTION_TYPES = ContainerUtil.immutableSet(
|
||||
"java.lang.InterruptedException",
|
||||
"java.io.IOException"));
|
||||
"java.io.IOException");
|
||||
|
||||
@Override
|
||||
public boolean isActive(Project project) {
|
||||
return !BLOCKING_EXCEPTION_TYPES.isEmpty();
|
||||
public boolean isActive(@NotNull PsiFile file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -58,7 +58,7 @@ public class BlockingMethodInNonBlockingContextInspectionTest extends UsefulTest
|
||||
BlockingMethodInNonBlockingContextInspection myInspection = new BlockingMethodInNonBlockingContextInspection();
|
||||
myInspection.myBlockingAnnotations =
|
||||
Collections.singletonList(BlockingMethodInNonBlockingContextInspection.DEFAULT_BLOCKING_ANNOTATION);
|
||||
myInspection.myNonblockingAnnotations =
|
||||
myInspection.myNonBlockingAnnotations =
|
||||
Collections.singletonList(BlockingMethodInNonBlockingContextInspection.DEFAULT_NONBLOCKING_ANNOTATION);
|
||||
myFixture.enableInspections(myInspection);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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.codeInspection.blockingCallsDetection.BlockingMethodInNonBlockingContextInspection;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class BlockingCallDetectionKotlinTest extends JavaCodeInsightFixtureTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
BlockingMethodInNonBlockingContextInspection myInspection = new BlockingMethodInNonBlockingContextInspection();
|
||||
myInspection.myBlockingAnnotations =
|
||||
Collections.singletonList(BlockingMethodInNonBlockingContextInspection.DEFAULT_BLOCKING_ANNOTATION);
|
||||
myInspection.myNonBlockingAnnotations =
|
||||
Collections.singletonList(BlockingMethodInNonBlockingContextInspection.DEFAULT_NONBLOCKING_ANNOTATION);
|
||||
myFixture.enableInspections(myInspection);
|
||||
}
|
||||
|
||||
public void testKotlinCodeInspecting() {
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface Blocking {}");
|
||||
myFixture.addClass("package org.jetbrains.annotations;\n" +
|
||||
"public @interface NonBlocking {}");
|
||||
myFixture.addFileToProject("/TestKotlinCodeInspection.kt",
|
||||
"import org.jetbrains.annotations.Blocking\n" +
|
||||
"import org.jetbrains.annotations.NonBlocking\n" +
|
||||
"@NonBlocking\n" +
|
||||
"fun nonBlockingFunction() {\n" +
|
||||
" <warning descr=\"Inappropriate blocking method call\">blockingFunction</warning>();\n" +
|
||||
"}\n" +
|
||||
"@Blocking\n" +
|
||||
"fun blockingFunction() {}");
|
||||
|
||||
myFixture.testHighlighting(true, false, true, "TestKotlinCodeInspection.kt");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user