mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -330,9 +330,11 @@ final class ImageEditorUI extends JPanel implements DataProvider, CopyProvider,
|
||||
EditorOptions editorOptions = options.getEditorOptions();
|
||||
ZoomOptions zoomOptions = editorOptions.getZoomOptions();
|
||||
if (zoomOptions.isWheelZooming() && e.isControlDown()) {
|
||||
if (e.getWheelRotation() < 0) {
|
||||
int rotation = e.getWheelRotation();
|
||||
if (rotation < 0) {
|
||||
zoomModel.zoomOut();
|
||||
} else {
|
||||
}
|
||||
else if (rotation > 0) {
|
||||
zoomModel.zoomIn();
|
||||
}
|
||||
e.consume();
|
||||
|
||||
@@ -52,8 +52,9 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* User: Alexander Podkhalyuzin
|
||||
@@ -144,14 +145,14 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
final Ref<TextRange> textRange = new Ref<>(lineRange);
|
||||
|
||||
final PsiElementVisitor methodCollector = new JavaRecursiveElementVisitor() {
|
||||
final Stack<PsiMethod> myContextStack = new Stack<>();
|
||||
final Stack<String> myParamNameStack = new Stack<>();
|
||||
final Deque<PsiMethod> myContextStack = new LinkedList<>();
|
||||
final Deque<String> myParamNameStack = new LinkedList<>();
|
||||
private int myNextLambdaExpressionOrdinal = 0;
|
||||
private boolean myInsideLambda = false;
|
||||
|
||||
@Nullable
|
||||
private String getCurrentParamName() {
|
||||
return myParamNameStack.isEmpty() ? null : myParamNameStack.peek();
|
||||
return myParamNameStack.peekFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,7 +258,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler {
|
||||
}
|
||||
|
||||
public void visitExpressionList(PsiExpressionList expressionList) {
|
||||
final PsiMethod psiMethod = myContextStack.isEmpty()? null : myContextStack.peek();
|
||||
PsiMethod psiMethod = myContextStack.peekFirst();
|
||||
if (psiMethod != null) {
|
||||
final String methodName = psiMethod.getName();
|
||||
final PsiExpression[] expressions = expressionList.getExpressions();
|
||||
|
||||
@@ -360,15 +360,13 @@ public class LocalVariablesUtil {
|
||||
private final MultiMap<Integer, String> myNames;
|
||||
private int myCurrentSlotIndex;
|
||||
private final PsiElement myElement;
|
||||
private final Stack<Integer> myIndexStack;
|
||||
private final Deque<Integer> myIndexStack = new LinkedList<>();
|
||||
private boolean myReached = false;
|
||||
|
||||
public LocalVariableNameFinder(int startSlot, MultiMap<Integer, String> names, PsiElement element) {
|
||||
myNames = names;
|
||||
myCurrentSlotIndex = startSlot;
|
||||
myElement = element;
|
||||
myIndexStack = new Stack<>();
|
||||
|
||||
}
|
||||
|
||||
private boolean shouldVisit(PsiElement scope) {
|
||||
|
||||
+12
-4
@@ -165,11 +165,12 @@ public abstract class AbstractPatternBasedConfigurationProducer<T extends Module
|
||||
}
|
||||
else {
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
|
||||
PsiElement element = null;
|
||||
if (editor != null) {
|
||||
final PsiFile editorFile = CommonDataKeys.PSI_FILE.getData(dataContext);
|
||||
final List<Caret> allCarets = editor.getCaretModel().getAllCarets();
|
||||
if (allCarets.size() > 1) {
|
||||
final PsiFile editorFile = CommonDataKeys.PSI_FILE.getData(dataContext);
|
||||
if (editorFile != null) {
|
||||
if (editorFile != null) {
|
||||
if (allCarets.size() > 1) {
|
||||
final Set<PsiMethod> methods = new LinkedHashSet<>();
|
||||
for (Caret caret : allCarets) {
|
||||
ContainerUtil.addIfNotNull(methods, PsiTreeUtil.getParentOfType(editorFile.findElementAt(caret.getOffset()), PsiMethod.class));
|
||||
@@ -178,9 +179,16 @@ public abstract class AbstractPatternBasedConfigurationProducer<T extends Module
|
||||
return collectTestMembers(methods.toArray(PsiElement.EMPTY_ARRAY), checkAbstract, checkIsTest, processor, classes);
|
||||
}
|
||||
}
|
||||
else {
|
||||
element = editorFile.findElementAt(editor.getCaretModel().getOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||
|
||||
if (element == null) {
|
||||
element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
|
||||
}
|
||||
|
||||
final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
|
||||
if (files != null) {
|
||||
Project project = CommonDataKeys.PROJECT.getData(dataContext);
|
||||
|
||||
+23
-17
@@ -65,6 +65,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
private JavaSdkVersion myJavaSdkVersion;
|
||||
|
||||
@SuppressWarnings("StatefulEp") private PsiFile myFile;
|
||||
@SuppressWarnings("StatefulEp") private PsiJavaModule myJavaModule;
|
||||
|
||||
// map codeBlock->List of PsiReferenceExpression of uninitialized final variables
|
||||
private final Map<PsiElement, Collection<PsiReferenceExpression>> myUninitializedVarProblems = new THashMap<>();
|
||||
@@ -155,13 +156,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
|
||||
@Override
|
||||
public boolean analyze(@NotNull PsiFile file, boolean updateWholeFile, @NotNull HighlightInfoHolder holder, @NotNull Runnable highlight) {
|
||||
myFile = file;
|
||||
myHolder = Holder.CHECK_ELEMENT_LEVEL ? new CheckLevelHighlightInfoHolder(file, holder) : holder;
|
||||
|
||||
boolean success = true;
|
||||
try {
|
||||
myLanguageLevel = PsiUtil.getLanguageLevel(file);
|
||||
myJavaSdkVersion = notNull(JavaVersionService.getInstance().getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel));
|
||||
prepare(Holder.CHECK_ELEMENT_LEVEL ? new CheckLevelHighlightInfoHolder(file, holder) : holder, file);
|
||||
if (updateWholeFile) {
|
||||
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (progress == null) throw new IllegalStateException("Must be run under progress");
|
||||
@@ -193,6 +190,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
myReassignedParameters.clear();
|
||||
|
||||
myRefCountHolder = null;
|
||||
myJavaModule = null;
|
||||
myFile = null;
|
||||
myHolder = null;
|
||||
myDuplicateMethods.clear();
|
||||
@@ -202,6 +200,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
return success;
|
||||
}
|
||||
|
||||
protected void prepareToRunAsInspection(@NotNull HighlightInfoHolder holder) {
|
||||
prepare(holder, holder.getContextFile());
|
||||
}
|
||||
|
||||
private void prepare(HighlightInfoHolder holder, PsiFile file) {
|
||||
myHolder = holder;
|
||||
myFile = file;
|
||||
myLanguageLevel = PsiUtil.getLanguageLevel(file);
|
||||
myJavaSdkVersion = notNull(JavaVersionService.getInstance().getJavaSdkVersion(file), JavaSdkVersion.fromLanguageLevel(myLanguageLevel));
|
||||
myJavaModule = myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_9) ? ModuleHighlightUtil.getModuleDescriptor(file) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (myRefCountHolder != null && myFile instanceof ServerPageFile) {
|
||||
@@ -1030,8 +1040,14 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
|
||||
@Override
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement ref) {
|
||||
JavaResolveResult resolveResult = doVisitReferenceElement(ref);
|
||||
if (resolveResult != null && !myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(ref, resolveResult.getElement()));
|
||||
JavaResolveResult result = doVisitReferenceElement(ref);
|
||||
if (result != null) {
|
||||
PsiElement resolved = result.getElement();
|
||||
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkRawOnParameterizedType(ref, resolved));
|
||||
if (!myHolder.hasErrorResults() && resolved != null && myJavaModule != null) {
|
||||
myHolder.add(ModuleHighlightUtil.checkPackageAccessibility(ref, resolved, myJavaModule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JavaResolveResult doVisitReferenceElement(@NotNull PsiJavaCodeReferenceElement ref) {
|
||||
@@ -1688,14 +1704,4 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
|
||||
private HighlightInfo checkFeature(@NotNull PsiElement element, @NotNull Feature feature) {
|
||||
return HighlightUtil.checkFeature(element, feature, myLanguageLevel, myFile);
|
||||
}
|
||||
|
||||
protected void prepareToRunAsInspection(@NotNull HighlightInfoHolder holder) {
|
||||
PsiFile file = holder.getContextFile();
|
||||
JavaSdkVersion sdkVersion = JavaVersionService.getInstance().getJavaSdkVersion(file);
|
||||
|
||||
myHolder = holder;
|
||||
myFile = file;
|
||||
myLanguageLevel = PsiUtil.getLanguageLevel(file);
|
||||
myJavaSdkVersion = sdkVersion != null ? sdkVersion : JavaSdkVersion.fromLanguageLevel(myLanguageLevel);
|
||||
}
|
||||
}
|
||||
-137
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.FilenameIndex;
|
||||
import com.intellij.psi.util.CachedValueProvider.Result;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.graph.DFSTBuilder;
|
||||
import com.intellij.util.graph.Graph;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
|
||||
import static com.intellij.psi.SyntaxTraverser.psiTraverser;
|
||||
import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT;
|
||||
|
||||
public class JavaModuleGraphBuilder {
|
||||
private JavaModuleGraphBuilder() { }
|
||||
|
||||
@Nullable
|
||||
public static Graph<PsiJavaModule> getOrBuild(@NotNull Project project) {
|
||||
return CachedValuesManager.getManager(project).getCachedValue(project, () -> {
|
||||
Graph<PsiJavaModule> graph = ReadAction.compute(() -> build(project));
|
||||
return Result.create(graph, OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Collection<PsiJavaModule> findCycle(@NotNull Graph<PsiJavaModule> graph, @NotNull PsiJavaModule module) {
|
||||
return ((JavaModuleGraph)graph).myCycles.stream().filter(set -> set.contains(module)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
// Discovers relationships between Java modules in the project.
|
||||
// Library/JDK modules are excluded - in assumption there can't be any lib -> src dependencies.
|
||||
private static Graph<PsiJavaModule> build(Project project) {
|
||||
Set<PsiJavaModule> projectModules = ContainerUtil.newHashSet();
|
||||
for (Module module : ModuleManager.getInstance(project).getModules()) {
|
||||
Collection<VirtualFile> files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope(false));
|
||||
if (files.size() > 1) return null; // aborts the process when there are incorrect modules in the project
|
||||
VirtualFile vFile = ContainerUtil.getFirstItem(files);
|
||||
if (vFile != null) {
|
||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
|
||||
if (psiFile instanceof PsiJavaFile) {
|
||||
PsiJavaModule moduleDeclaration = ((PsiJavaFile)psiFile).getModuleDeclaration();
|
||||
if (moduleDeclaration != null) {
|
||||
projectModules.add(moduleDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MultiMap<PsiJavaModule, PsiJavaModule> relations = MultiMap.create();
|
||||
for (PsiJavaModule moduleDeclaration : projectModules) {
|
||||
for (PsiRequiresStatement statement : psiTraverser().children(moduleDeclaration).filter(PsiRequiresStatement.class)) {
|
||||
PsiJavaModule dependency = resolveDependency(statement);
|
||||
if (dependency != null && projectModules.contains(dependency)) {
|
||||
relations.putValue(moduleDeclaration, dependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new JavaModuleGraph(relations);
|
||||
}
|
||||
|
||||
private static PsiJavaModule resolveDependency(PsiRequiresStatement statement) {
|
||||
PsiJavaModuleReferenceElement refElement = statement.getReferenceElement();
|
||||
if (refElement != null) {
|
||||
PsiPolyVariantReference ref = refElement.getReference();
|
||||
if (ref != null) {
|
||||
ResolveResult[] results = ref.multiResolve(true);
|
||||
if (results.length == 1) {
|
||||
PsiElement target = results[0].getElement();
|
||||
if (target instanceof PsiJavaModule) {
|
||||
return (PsiJavaModule)target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class JavaModuleGraph implements Graph<PsiJavaModule> {
|
||||
private final MultiMap<PsiJavaModule, PsiJavaModule> myMap;
|
||||
private final List<Set<PsiJavaModule>> myCycles;
|
||||
|
||||
public JavaModuleGraph(MultiMap<PsiJavaModule, PsiJavaModule> map) {
|
||||
myMap = map;
|
||||
|
||||
DFSTBuilder<PsiJavaModule> builder = new DFSTBuilder<>(this);
|
||||
myCycles = builder.getComponents().stream()
|
||||
.map(ContainerUtil::newLinkedHashSet)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PsiJavaModule> getNodes() {
|
||||
return myMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PsiJavaModule> getIn(PsiJavaModule n) {
|
||||
return ContainerUtil.emptyIterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PsiJavaModule> getOut(PsiJavaModule n) {
|
||||
return myMap.get(n).iterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2000-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 com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.FilenameIndex;
|
||||
import com.intellij.psi.util.CachedValueProvider.Result;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.graph.DFSTBuilder;
|
||||
import com.intellij.util.graph.Graph;
|
||||
import com.intellij.util.graph.GraphGenerator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
|
||||
import static com.intellij.psi.SyntaxTraverser.psiTraverser;
|
||||
import static com.intellij.psi.util.PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT;
|
||||
|
||||
public class JavaModuleGraphUtil {
|
||||
private JavaModuleGraphUtil() { }
|
||||
|
||||
@Nullable
|
||||
public static Collection<PsiJavaModule> findCycle(@NotNull PsiJavaModule module) {
|
||||
Project project = module.getProject();
|
||||
List<Set<PsiJavaModule>> cycles = CachedValuesManager.getManager(project).getCachedValue(project, () ->
|
||||
Result.create(ReadAction.compute(() -> findCycles(project)), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT));
|
||||
return ContainerUtil.find(cycles, set -> set.contains(module));
|
||||
}
|
||||
|
||||
public static boolean reads(@NotNull PsiJavaModule source, @NotNull PsiJavaModule destination) {
|
||||
Project project = source.getProject();
|
||||
RequiresGraph graph = CachedValuesManager.getManager(project).getCachedValue(project, () ->
|
||||
Result.create(ReadAction.compute(() -> buildRequiresGraph(project)), OUT_OF_CODE_BLOCK_MODIFICATION_COUNT));
|
||||
return graph.reads(source, destination);
|
||||
}
|
||||
|
||||
// Looks for cycles between Java modules in the project sources.
|
||||
// Library/JDK modules are excluded - in assumption there can't be any lib -> src dependencies.
|
||||
// Module references are resolved "globally" (i.e., without taking project dependencies into account).
|
||||
private static List<Set<PsiJavaModule>> findCycles(Project project) {
|
||||
Set<PsiJavaModule> projectModules = ContainerUtil.newHashSet();
|
||||
for (Module module : ModuleManager.getInstance(project).getModules()) {
|
||||
Collection<VirtualFile> files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope(false));
|
||||
if (files.size() > 1) return Collections.emptyList(); // aborts the process when there are incorrect modules in the project
|
||||
Optional.ofNullable(ContainerUtil.getFirstItem(files))
|
||||
.map(PsiManager.getInstance(project)::findFile)
|
||||
.map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null)
|
||||
.ifPresent(projectModules::add);
|
||||
}
|
||||
|
||||
if (!projectModules.isEmpty()) {
|
||||
MultiMap<PsiJavaModule, PsiJavaModule> relations = MultiMap.create();
|
||||
for (PsiJavaModule module : projectModules) {
|
||||
for (PsiRequiresStatement statement : psiTraverser().children(module).filter(PsiRequiresStatement.class)) {
|
||||
Optional.ofNullable(statement.getReferenceElement())
|
||||
.map(PsiJavaModuleReferenceElement::getReference)
|
||||
.map(ref -> ref.multiResolve(true))
|
||||
.map(a -> a.length == 1 ? a[0].getElement() : null)
|
||||
.map(e -> e instanceof PsiJavaModule ? (PsiJavaModule)e : null)
|
||||
.filter(projectModules::contains)
|
||||
.ifPresent(dependency -> relations.putValue(module, dependency));
|
||||
}
|
||||
}
|
||||
|
||||
if (!relations.isEmpty()) {
|
||||
Graph<PsiJavaModule> graph = new SourceSemiGraph(relations);
|
||||
DFSTBuilder<PsiJavaModule> builder = new DFSTBuilder<>(graph);
|
||||
Collection<Collection<PsiJavaModule>> components = builder.getComponents();
|
||||
if (!components.isEmpty()) {
|
||||
return components.stream().map(ContainerUtil::newLinkedHashSet).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// Starting from source modules, collects all module dependencies in the project.
|
||||
// The resulting graph is used for tracing readability.
|
||||
private static RequiresGraph buildRequiresGraph(Project project) {
|
||||
MultiMap<PsiJavaModule, PsiJavaModule> relations = MultiMap.create();
|
||||
Set<String> publicEdges = ContainerUtil.newTroveSet();
|
||||
for (Module module : ModuleManager.getInstance(project).getModules()) {
|
||||
Collection<VirtualFile> files = FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, module.getModuleScope(false));
|
||||
Optional.ofNullable(ContainerUtil.getFirstItem(files))
|
||||
.map(PsiManager.getInstance(project)::findFile)
|
||||
.map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null)
|
||||
.ifPresent(m -> visit(m, relations, publicEdges));
|
||||
}
|
||||
|
||||
GraphGenerator<PsiJavaModule> graph = GraphGenerator.create(new RequiresSemiGraph(relations));
|
||||
return new RequiresGraph(graph, publicEdges);
|
||||
}
|
||||
|
||||
private static void visit(PsiJavaModule module, MultiMap<PsiJavaModule, PsiJavaModule> relations, Set<String> publicEdges) {
|
||||
if (!relations.containsKey(module)) {
|
||||
relations.putValues(module, Collections.emptyList());
|
||||
for (PsiRequiresStatement statement : psiTraverser().children(module).filter(PsiRequiresStatement.class)) {
|
||||
Optional.ofNullable(statement.getReferenceElement())
|
||||
.map(PsiJavaModuleReferenceElement::getReference)
|
||||
.map(PsiReference::resolve)
|
||||
.map(e -> e instanceof PsiJavaModule ? (PsiJavaModule)e : null)
|
||||
.ifPresent(dependency -> {
|
||||
relations.putValue(module, dependency);
|
||||
if (isPublic(statement)) publicEdges.add(RequiresGraph.key(dependency, module));
|
||||
visit(dependency, relations, publicEdges);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPublic(PsiRequiresStatement statement) {
|
||||
for (PsiElement child = statement.getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (PsiUtil.isJavaToken(child, JavaTokenType.PUBLIC_KEYWORD)) return true;
|
||||
if (child instanceof PsiJavaModuleReferenceElement) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class RequiresGraph {
|
||||
private final Graph<PsiJavaModule> myGraph;
|
||||
private final Set<String> myPublicEdges;
|
||||
|
||||
public RequiresGraph(Graph<PsiJavaModule> graph, Set<String> publicEdges) {
|
||||
myGraph = graph;
|
||||
myPublicEdges = publicEdges;
|
||||
}
|
||||
|
||||
public boolean reads(PsiJavaModule source, PsiJavaModule destination) {
|
||||
Iterator<PsiJavaModule> directReaders = myGraph.getOut(destination);
|
||||
while (directReaders.hasNext()) {
|
||||
PsiJavaModule next = directReaders.next();
|
||||
if (source.equals(next) || myPublicEdges.contains(key(destination, next)) && reads(source, next)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String key(PsiJavaModule module, PsiJavaModule exporter) {
|
||||
return module.getModuleName() + '/' + exporter.getModuleName();
|
||||
}
|
||||
}
|
||||
|
||||
//<editor-fold desc="Helpers.">
|
||||
private static class SourceSemiGraph implements Graph<PsiJavaModule> {
|
||||
private final MultiMap<PsiJavaModule, PsiJavaModule> myMap;
|
||||
|
||||
public SourceSemiGraph(MultiMap<PsiJavaModule, PsiJavaModule> map) {
|
||||
myMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PsiJavaModule> getNodes() {
|
||||
return myMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PsiJavaModule> getIn(PsiJavaModule n) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PsiJavaModule> getOut(PsiJavaModule n) {
|
||||
return myMap.get(n).iterator();
|
||||
}
|
||||
}
|
||||
|
||||
private static class RequiresSemiGraph implements GraphGenerator.SemiGraph<PsiJavaModule> {
|
||||
private final MultiMap<PsiJavaModule, PsiJavaModule> myMap;
|
||||
|
||||
public RequiresSemiGraph(MultiMap<PsiJavaModule, PsiJavaModule> map) {
|
||||
myMap = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PsiJavaModule> getNodes() {
|
||||
return myMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PsiJavaModule> getIn(PsiJavaModule n) {
|
||||
return myMap.get(n).iterator();
|
||||
}
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
+2
-5
@@ -113,11 +113,8 @@ public class LambdaHighlightingUtil {
|
||||
final PsiClass aClass = resolveResult.getElement();
|
||||
if (aClass != null) {
|
||||
if (aClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
|
||||
final List<HierarchicalMethodSignature> signatures = LambdaUtil.findFunctionCandidates(aClass);
|
||||
if (signatures != null && signatures.size() == 1) {
|
||||
final MethodSignature functionalMethod = signatures.get(0);
|
||||
if (functionalMethod.getTypeParameters().length > 0) return "Target method is generic";
|
||||
}
|
||||
MethodSignature functionalMethod = LambdaUtil.getFunction(aClass);
|
||||
if (functionalMethod != null && functionalMethod.getTypeParameters().length > 0) return "Target method is generic";
|
||||
if (checkReturnTypeApplicable(resolveResult, aClass)) {
|
||||
return "No instance of type " + functionalInterfaceType.getPresentableText() + " exists so that lambda expression can be type-checked";
|
||||
}
|
||||
|
||||
+98
-10
@@ -37,7 +37,6 @@ import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.JBIterable;
|
||||
import com.intellij.util.graph.Graph;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
@@ -55,6 +54,34 @@ import static com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE;
|
||||
import static com.intellij.psi.SyntaxTraverser.psiTraverser;
|
||||
|
||||
public class ModuleHighlightUtil {
|
||||
@Nullable
|
||||
static PsiJavaModule getModuleDescriptor(@NotNull PsiElement element) {
|
||||
VirtualFile file = Optional.of(element)
|
||||
.map(e -> e instanceof PsiFileSystemItem ? (PsiFileSystemItem)e : e.getContainingFile())
|
||||
.map(PsiFileSystemItem::getVirtualFile)
|
||||
.orElse(null);
|
||||
if (file == null) return null;
|
||||
|
||||
Project project = element.getProject();
|
||||
ProjectFileIndex index = ProjectFileIndex.SERVICE.getInstance(project);
|
||||
if (element instanceof PsiCompiledElement) {
|
||||
return Optional.ofNullable(index.getClassRootForFile(file))
|
||||
.map(r -> r.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE))
|
||||
.map(PsiManager.getInstance(project)::findFile)
|
||||
.map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null)
|
||||
.orElse(null);
|
||||
}
|
||||
else {
|
||||
Module module = index.getModuleForFile(file);
|
||||
return Optional.ofNullable(module)
|
||||
.map(m -> FilenameIndex.getVirtualFilesByName(project, MODULE_INFO_FILE, m.getModuleScope(false)))
|
||||
.map(c -> c.size () == 1 ? c.iterator().next() : null)
|
||||
.map(PsiManager.getInstance(project)::findFile)
|
||||
.map(f -> f instanceof PsiJavaFile ? ((PsiJavaFile)f).getModuleDeclaration() : null)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkFileName(@NotNull PsiJavaModule element, @NotNull PsiFile file) {
|
||||
if (!MODULE_INFO_FILE.equals(file.getName())) {
|
||||
@@ -198,15 +225,12 @@ public class ModuleHighlightUtil {
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refElement).description(message).create();
|
||||
}
|
||||
else {
|
||||
Graph<PsiJavaModule> graph = JavaModuleGraphBuilder.getOrBuild(target.getProject());
|
||||
if (graph != null) {
|
||||
Collection<PsiJavaModule> cycle = JavaModuleGraphBuilder.findCycle(graph, (PsiJavaModule)target);
|
||||
if (cycle != null && cycle.contains(container)) {
|
||||
Stream<String> stream = cycle.stream().map(PsiJavaModule::getModuleName);
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) stream = stream.sorted();
|
||||
String message = JavaErrorMessages.message("module.cyclic.dependence", stream.collect(Collectors.joining(", ")));
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refElement).description(message).create();
|
||||
}
|
||||
Collection<PsiJavaModule> cycle = JavaModuleGraphUtil.findCycle((PsiJavaModule)target);
|
||||
if (cycle != null && cycle.contains(container)) {
|
||||
Stream<String> stream = cycle.stream().map(PsiJavaModule::getModuleName);
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) stream = stream.sorted();
|
||||
String message = JavaErrorMessages.message("module.cyclic.dependence", stream.collect(Collectors.joining(", ")));
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(refElement).description(message).create();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -311,6 +335,70 @@ public class ModuleHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static HighlightInfo checkPackageAccessibility(@NotNull PsiJavaCodeReferenceElement ref,
|
||||
@NotNull PsiElement target,
|
||||
@NotNull PsiJavaModule refModule) {
|
||||
Module module = ModuleUtilCore.findModuleForPsiElement(ref);
|
||||
if (module != null) {
|
||||
if (target instanceof PsiClass && !(target instanceof PsiCompiledElement) && module != ModuleUtilCore.findModuleForPsiElement(target)) {
|
||||
PsiElement targetFile = target.getParent();
|
||||
if (targetFile instanceof PsiClassOwner) {
|
||||
PsiJavaModule targetModule = getModuleDescriptor(target);
|
||||
String packageName = ((PsiClassOwner)targetFile).getPackageName();
|
||||
return checkPackageAccessibility(ref, refModule, targetModule, packageName);
|
||||
}
|
||||
}
|
||||
else if (target instanceof PsiPackage) {
|
||||
PsiElement refImport = ref.getParent();
|
||||
if (refImport instanceof PsiImportStatementBase && ((PsiImportStatementBase)refImport).isOnDemand()) {
|
||||
PsiDirectory[] dirs = ((PsiPackage)target).getDirectories(module.getModuleWithDependenciesAndLibrariesScope(false));
|
||||
if (dirs.length == 1 && ModuleUtilCore.findModuleForPsiElement(dirs[0]) != module) {
|
||||
PsiJavaModule targetModule = getModuleDescriptor(dirs[0]);
|
||||
String packageName = ((PsiPackage)target).getQualifiedName();
|
||||
return checkPackageAccessibility(ref, refModule, targetModule, packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static HighlightInfo checkPackageAccessibility(PsiJavaCodeReferenceElement ref,
|
||||
PsiJavaModule refModule,
|
||||
PsiJavaModule targetModule,
|
||||
String packageName) {
|
||||
if (targetModule == null) {
|
||||
String message = JavaErrorMessages.message("module.package.on.classpath");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(ref).description(message).create();
|
||||
}
|
||||
|
||||
String refModuleName = refModule.getModuleName();
|
||||
String requiredName = targetModule.getModuleName();
|
||||
if (!(targetModule instanceof PsiCompiledElement) && !isExported(targetModule, packageName)) {
|
||||
String message = JavaErrorMessages.message("module.package.not.exported", requiredName, packageName, refModuleName);
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(ref).description(message).create();
|
||||
}
|
||||
|
||||
if (!(PsiJavaModule.JAVA_BASE.equals(requiredName) || JavaModuleGraphUtil.reads(refModule, targetModule))) {
|
||||
String message = JavaErrorMessages.message("module.not.in.requirements", refModuleName, requiredName);
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.WRONG_REF).range(ref).description(message).create();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isExported(PsiJavaModule module, String packageName) {
|
||||
for (PsiExportsStatement statement : psiTraverser().children(module).filter(PsiExportsStatement.class)) {
|
||||
String exportedName = Optional.ofNullable(statement.getPackageReference()).map(ModuleHighlightUtil::refText).orElse("");
|
||||
if (packageName.equals(exportedName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static HighlightInfo moduleResolveError(PsiJavaModuleReferenceElement refElement, PsiPolyVariantReference ref) {
|
||||
boolean missing = ref.multiResolve(true).length == 0;
|
||||
String message = JavaErrorMessages.message(missing ? "module.not.found" : "module.not.on.path", refElement.getReferenceText());
|
||||
|
||||
+1
-7
@@ -359,16 +359,10 @@ public class AnonymousCanBeLambdaInspection extends BaseJavaBatchLocalInspection
|
||||
}
|
||||
|
||||
private static class ReplaceWithLambdaFix implements LocalQuickFix, HighPriorityAction {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace with lambda";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Replace with lambda";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-8
@@ -114,17 +114,11 @@ public class AnonymousCanBeMethodReferenceInspection extends BaseJavaBatchLocalI
|
||||
private static class ReplaceWithMethodRefFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return "Replace with method reference";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (element instanceof PsiNewExpression) {
|
||||
|
||||
-6
@@ -91,12 +91,6 @@ public class BlockMarkerCommentsInspection extends BaseJavaBatchLocalInspectionT
|
||||
}
|
||||
if (MARKER_PATTERN.accepts(element)) {
|
||||
holder.registerProblem(element, "Redundant block marker", new LocalQuickFix() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
|
||||
+1
-7
@@ -82,16 +82,10 @@ public class ExplicitTypeCanBeDiamondInspection extends BaseJavaBatchLocalInspec
|
||||
}
|
||||
|
||||
private static class ReplaceWithDiamondFix implements LocalQuickFix, HighPriorityAction {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace with <>";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Replace with <>";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -587,16 +587,10 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
}
|
||||
|
||||
private static class ReplaceWithMethodRefFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace lambda with method reference";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Replace lambda with method reference";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-14
@@ -92,16 +92,10 @@ public class PossibleHeapPollutionVarargsInspection extends BaseJavaBatchLocalIn
|
||||
}
|
||||
|
||||
private static class AnnotateAsSafeVarargsQuickFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Annotate as @SafeVarargs";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Annotate as @SafeVarargs";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,16 +111,10 @@ public class PossibleHeapPollutionVarargsInspection extends BaseJavaBatchLocalIn
|
||||
}
|
||||
|
||||
private static class MakeFinalAndAnnotateQuickFix implements LocalQuickFix {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Make final and annotate as @SafeVarargs";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Make final and annotate as @SafeVarargs";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -124,16 +124,10 @@ public class RedundantLambdaCodeBlockInspection extends BaseJavaBatchLocalInspec
|
||||
}
|
||||
|
||||
private static class ReplaceWithExprFix implements LocalQuickFix, HighPriorityAction {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Replace with expression lambda";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Replace with expression lambda";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -40,7 +40,7 @@ public class RemoveAnnotationQuickFix implements LocalQuickFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return CodeInsightBundle.message("remove.annotation");
|
||||
}
|
||||
|
||||
@@ -58,10 +58,4 @@ public class RemoveAnnotationQuickFix implements LocalQuickFix {
|
||||
ExternalAnnotationsManager.getInstance(project).deannotate(myListOwner, myAnnotation.getQualifiedName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
-7
@@ -53,13 +53,6 @@ public class TrivialMethodReferenceInspection extends BaseJavaBatchLocalInspecti
|
||||
}
|
||||
|
||||
private static class ReplaceMethodRefWithQualifierFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -269,16 +269,10 @@ public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool {
|
||||
myManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return QUICK_FIX_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return QUICK_FIX_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-6
@@ -29,12 +29,6 @@ public class RemoveElementQuickFix implements LocalQuickFix {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
|
||||
+3
-13
@@ -833,7 +833,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
private static class RedundantInstanceofFix implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.data.flow.redundant.instanceof.quickfix");
|
||||
}
|
||||
|
||||
@@ -852,12 +852,6 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -901,7 +895,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
}
|
||||
|
||||
Collection<PsiCall> getAlwaysFailingCalls() {
|
||||
return StreamEx.of(myFailingCalls.keySet()).filter(this::isAlwaysFailing).map(MethodCallInstruction::getCallExpression).toList();
|
||||
return StreamEx.ofKeys(myFailingCalls, v -> v).map(MethodCallInstruction::getCallExpression).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -911,7 +905,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
DfaInstructionState[] states = super.visitMethodCall(instruction, runner, memState);
|
||||
if (hasNonTrivialFailingContracts(instruction)) {
|
||||
boolean allFail = Arrays.stream(states).allMatch(s -> s.getMemoryState().peek() == runner.getFactory().getConstFactory().getContractFail());
|
||||
myFailingCalls.put(instruction, allFail && isAlwaysFailing(instruction));
|
||||
myFailingCalls.merge(instruction, allFail, Boolean::logicalAnd);
|
||||
}
|
||||
return states;
|
||||
}
|
||||
@@ -926,10 +920,6 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
Arrays.stream(contract.arguments).anyMatch(v -> v != MethodContract.ValueConstraint.ANY_VALUE);
|
||||
}
|
||||
|
||||
private boolean isAlwaysFailing(MethodCallInstruction instruction) {
|
||||
return !Boolean.FALSE.equals(myFailingCalls.get(instruction));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkNotNullable(DfaMemoryState state, DfaValue value, NullabilityProblem problem, PsiElement anchor) {
|
||||
boolean ok = super.checkNotNullable(state, value, problem, anchor);
|
||||
|
||||
-7
@@ -100,13 +100,6 @@ public class DfaOptionalSupport {
|
||||
myClearArguments = clearArguments;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
|
||||
-14
@@ -484,13 +484,6 @@ public class Java8CollectionsApiInspection extends BaseJavaBatchLocalInspectionT
|
||||
}
|
||||
|
||||
private static class ReplaceWithListSortFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -584,13 +577,6 @@ public class Java8CollectionsApiInspection extends BaseJavaBatchLocalInspectionT
|
||||
}
|
||||
|
||||
private static class ReplaceWithRemoveIfQuickFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -325,7 +325,7 @@ public class LocalCanBeFinal extends BaseJavaBatchLocalInspectionTool {
|
||||
private static class AcceptSuggested implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.can.be.final.accept.quickfix");
|
||||
}
|
||||
|
||||
@@ -344,12 +344,6 @@ public class LocalCanBeFinal extends BaseJavaBatchLocalInspectionTool {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-14
@@ -167,7 +167,7 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase {
|
||||
private static class MyQuickFixAction implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.redundant.type.remove.quickfix");
|
||||
}
|
||||
|
||||
@@ -186,12 +186,6 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
//separate quickfix is needed to invalidate initial method reference
|
||||
@@ -199,7 +193,7 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase {
|
||||
private static class MyMethodReferenceFixAction implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.redundant.type.remove.quickfix");
|
||||
}
|
||||
|
||||
@@ -212,11 +206,5 @@ public class RedundantTypeArgsInspection extends GenericsInspectionToolBase {
|
||||
expression.replace(createMethodReference(expression, typeElement));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -43,16 +43,10 @@ class ChangeNullableDefaultsFix implements LocalQuickFix {
|
||||
myNullableName = nullable;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Make \"" + (myNotNullName != null ? myNotNullName : myNullableName) + "\" default annotation";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Make \"" + (myNotNullName != null ? myNotNullName : myNullableName) + "\" default annotation";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -133,7 +133,7 @@ public class RedundantCastInspection extends GenericsInspectionToolBase {
|
||||
private static class AcceptSuggested implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.redundant.cast.remove.quickfix");
|
||||
}
|
||||
|
||||
@@ -146,12 +146,6 @@ public class RedundantCastInspection extends GenericsInspectionToolBase {
|
||||
RedundantCastUtil.removeCast(cast);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+25
-4
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInspection.LambdaCanBeMethodReferenceInspection;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.Operation;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
@@ -72,14 +73,13 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
|
||||
PsiType expressionType) {
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
|
||||
restoreComments(foreachStatement, foreachStatement.getBody());
|
||||
if (StreamApiMigrationInspection.isDeclarationJustBefore(var, foreachStatement)) {
|
||||
InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
|
||||
if (status != InitializerUsageStatus.UNKNOWN) {
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if (ExpressionUtils.isZero(initializer)) {
|
||||
PsiType type = var.getType();
|
||||
String replacement = (type.equals(expressionType) ? "" : "(" + type.getCanonicalText() + ") ") + builder;
|
||||
initializer.replace(elementFactory.createExpressionFromText(replacement, foreachStatement));
|
||||
removeLoop(foreachStatement);
|
||||
simplifyAndFormat(project, var);
|
||||
replaceInitializer(foreachStatement, var, initializer, replacement, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,27 @@ abstract class MigrateToStreamFix implements LocalQuickFix {
|
||||
simplifyAndFormat(project, result);
|
||||
}
|
||||
|
||||
static void replaceInitializer(PsiForeachStatement foreachStatement,
|
||||
PsiVariable var,
|
||||
PsiExpression initializer,
|
||||
String replacement,
|
||||
InitializerUsageStatus status) {
|
||||
Project project = foreachStatement.getProject();
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
|
||||
if(status == InitializerUsageStatus.DECLARED_JUST_BEFORE) {
|
||||
initializer.replace(elementFactory.createExpressionFromText(replacement, foreachStatement));
|
||||
removeLoop(foreachStatement);
|
||||
simplifyAndFormat(project, var);
|
||||
} else {
|
||||
if(status == InitializerUsageStatus.AT_WANTED_PLACE_ONLY) {
|
||||
initializer.delete();
|
||||
}
|
||||
PsiElement result =
|
||||
foreachStatement.replace(elementFactory.createStatementFromText(var.getName() + " = " + replacement + ";", foreachStatement));
|
||||
simplifyAndFormat(project, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void simplifyAndFormat(@NotNull Project project, PsiElement result) {
|
||||
if (result == null) return;
|
||||
LambdaCanBeMethodReferenceInspection.replaceAllLambdasWithMethodReferences(result);
|
||||
|
||||
+16
-10
@@ -16,7 +16,9 @@
|
||||
package com.intellij.codeInspection.streamMigration;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.Operation;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
@@ -32,6 +34,8 @@ import java.util.List;
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
class ReplaceWithCollectFix extends MigrateToStreamFix {
|
||||
private static final Logger LOG = Logger.getInstance(ReplaceWithCollectFix.class);
|
||||
|
||||
final String myMethodName;
|
||||
|
||||
protected ReplaceWithCollectFix(String methodName) {
|
||||
@@ -87,16 +91,18 @@ class ReplaceWithCollectFix extends MigrateToStreamFix {
|
||||
final StringBuilder builder = generateStream(iteratedValue, operations);
|
||||
|
||||
final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression();
|
||||
final PsiExpression initializer = StreamApiMigrationInspection
|
||||
.extractReplaceableCollectionInitializer(qualifierExpression, foreachStatement);
|
||||
if (initializer != null) {
|
||||
String callText = builder.append(".collect(java.util.stream.Collectors.")
|
||||
.append(createInitializerReplacementText(qualifierExpression.getType(), initializer))
|
||||
.append(")").toString();
|
||||
PsiElement result = initializer.replace(elementFactory.createExpressionFromText(callText, null));
|
||||
simplifyAndFormat(project, result);
|
||||
removeLoop(foreachStatement);
|
||||
return;
|
||||
final PsiLocalVariable variable = StreamApiMigrationInspection.extractCollectionVariable(qualifierExpression);
|
||||
if (variable != null) {
|
||||
InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(variable, foreachStatement);
|
||||
if(status != InitializerUsageStatus.UNKNOWN) {
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
LOG.assertTrue(initializer != null);
|
||||
String callText = builder.append(".collect(java.util.stream.Collectors.")
|
||||
.append(createInitializerReplacementText(qualifierExpression.getType(), initializer))
|
||||
.append(")").toString();
|
||||
replaceInitializer(foreachStatement, variable, initializer, callText, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() + "." : "";
|
||||
|
||||
|
||||
+5
-5
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInspection.streamMigration;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.Operation;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
@@ -76,13 +77,12 @@ class ReplaceWithFindFirstFix extends MigrateToStreamFix {
|
||||
PsiExpression value = assignment.getRExpression();
|
||||
if (value == null) return;
|
||||
restoreComments(foreachStatement, body);
|
||||
if (StreamApiMigrationInspection.isDeclarationJustBefore(var, foreachStatement)) {
|
||||
InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
|
||||
if (status != InitializerUsageStatus.UNKNOWN) {
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if (initializer != null) {
|
||||
PsiElement result =
|
||||
initializer.replace(elementFactory.createExpressionFromText(generateOptionalUnwrap(stream, tb, value, initializer), initializer));
|
||||
removeLoop(foreachStatement);
|
||||
simplifyAndFormat(project, result);
|
||||
String replacementText = generateOptionalUnwrap(stream, tb, value, initializer);
|
||||
replaceInitializer(foreachStatement, var, initializer, replacementText, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInspection.streamMigration;
|
||||
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus;
|
||||
import com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.Operation;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -93,7 +94,8 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
|
||||
// for(....) if(...) {flag = true; break;}
|
||||
PsiVariable var = (PsiVariable)maybeVar;
|
||||
PsiExpression initializer = var.getInitializer();
|
||||
if(initializer != null && StreamApiMigrationInspection.isDeclarationJustBefore(var, foreachStatement)) {
|
||||
InitializerUsageStatus status = StreamApiMigrationInspection.getInitializerUsageStatus(var, foreachStatement);
|
||||
if(initializer != null && status != InitializerUsageStatus.UNKNOWN) {
|
||||
String replacement;
|
||||
if(ExpressionUtils.isLiteral(initializer, Boolean.FALSE) &&
|
||||
ExpressionUtils.isLiteral(rValue, Boolean.TRUE)) {
|
||||
@@ -104,9 +106,7 @@ class ReplaceWithMatchFix extends MigrateToStreamFix {
|
||||
} else {
|
||||
replacement = streamText + "?" + rValue.getText() + ":" + initializer.getText();
|
||||
}
|
||||
PsiElement result = initializer.replace(elementFactory.createExpressionFromText(replacement, initializer));
|
||||
removeLoop(foreachStatement);
|
||||
simplifyAndFormat(project, result);
|
||||
replaceInitializer(foreachStatement, var, initializer, replacement, status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+54
-15
@@ -49,6 +49,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.codeInspection.streamMigration.StreamApiMigrationInspection.InitializerUsageStatus.*;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
@@ -377,19 +379,17 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null;
|
||||
}
|
||||
|
||||
@Contract("null, _ -> null")
|
||||
static PsiExpression extractReplaceableCollectionInitializer(PsiExpression qualifierExpression, PsiStatement foreachStatement) {
|
||||
@Contract("null -> null")
|
||||
static PsiLocalVariable extractCollectionVariable(PsiExpression qualifierExpression) {
|
||||
if (qualifierExpression instanceof PsiReferenceExpression) {
|
||||
final PsiElement resolve = ((PsiReferenceExpression)qualifierExpression).resolve();
|
||||
if (resolve instanceof PsiLocalVariable) {
|
||||
PsiLocalVariable var = (PsiLocalVariable)resolve;
|
||||
if (isDeclarationJustBefore(var, foreachStatement)) {
|
||||
final PsiExpression initializer = var.getInitializer();
|
||||
if (initializer instanceof PsiNewExpression) {
|
||||
final PsiExpressionList argumentList = ((PsiNewExpression)initializer).getArgumentList();
|
||||
if (argumentList != null && argumentList.getExpressions().length == 0) {
|
||||
return initializer;
|
||||
}
|
||||
final PsiExpression initializer = var.getInitializer();
|
||||
if (initializer instanceof PsiNewExpression) {
|
||||
final PsiExpressionList argumentList = ((PsiNewExpression)initializer).getArgumentList();
|
||||
if (argumentList != null && argumentList.getExpressions().length == 0) {
|
||||
return var;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,6 +397,40 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
return null;
|
||||
}
|
||||
|
||||
enum InitializerUsageStatus {
|
||||
// Variable is declared just before the wanted place
|
||||
DECLARED_JUST_BEFORE,
|
||||
// All initial value usages go through wanted place and at wanted place the variable value is guaranteed to be the initial value
|
||||
AT_WANTED_PLACE_ONLY,
|
||||
// At wanted place the variable value is guaranteed to be the initial value, but this initial value might be used somewhere else
|
||||
AT_WANTED_PLACE,
|
||||
// It's not guaranteed that the variable value at wanted place is initial value
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
static InitializerUsageStatus getInitializerUsageStatus(PsiVariable var, PsiStatement nextStatement) {
|
||||
if(var.getInitializer() == null) return UNKNOWN;
|
||||
if(isDeclarationJustBefore(var, nextStatement)) return DECLARED_JUST_BEFORE;
|
||||
PsiElement declaration = var.getParent();
|
||||
// Check if variable is not referenced in the same declaration like "int a = 0, b = a;"
|
||||
if(!PsiTreeUtil.processElements(declaration, e -> !(e instanceof PsiReferenceExpression) ||
|
||||
((PsiReferenceExpression)e).resolve() != var)) return UNKNOWN;
|
||||
PsiElement block = PsiUtil.getVariableCodeBlock(var, null);
|
||||
if(block == null) return UNKNOWN;
|
||||
final ControlFlow controlFlow;
|
||||
try {
|
||||
controlFlow = ControlFlowFactory.getInstance(nextStatement.getProject())
|
||||
.getControlFlow(block, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
|
||||
}
|
||||
catch (AnalysisCanceledException ignored) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
int start = controlFlow.getEndOffset(declaration);
|
||||
int stop = controlFlow.getStartOffset(nextStatement);
|
||||
if(ControlFlowUtil.isVariableReferencedBetween(controlFlow, start, stop, var)) return UNKNOWN;
|
||||
return ControlFlowUtil.isValueUsedWithoutVisitingStop(controlFlow, start, stop, var) ? AT_WANTED_PLACE : AT_WANTED_PLACE_ONLY;
|
||||
}
|
||||
|
||||
static boolean isDeclarationJustBefore(PsiVariable var, PsiStatement nextStatement) {
|
||||
PsiElement declaration = var.getParent();
|
||||
PsiElement nextStatementParent = nextStatement.getParent();
|
||||
@@ -482,8 +516,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
methodName = "addAll";
|
||||
} else {
|
||||
PsiMethodCallExpression methodCallExpression = tb.getSingleMethodCall();
|
||||
if(methodCallExpression != null && extractReplaceableCollectionInitializer(
|
||||
methodCallExpression.getMethodExpression().getQualifierExpression(), statement) != null) {
|
||||
if(canCollect(statement, methodCallExpression)) {
|
||||
methodName = "collect";
|
||||
} else {
|
||||
if (!SUGGEST_FOREACH) return;
|
||||
@@ -535,13 +568,19 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
|
||||
}
|
||||
}
|
||||
|
||||
void handleSingleReturn(PsiForeachStatement statement,
|
||||
TerminalBlock tb,
|
||||
List<Operation> operations) {
|
||||
boolean canCollect(PsiForeachStatement statement, PsiMethodCallExpression methodCallExpression) {
|
||||
if(methodCallExpression == null) return false;
|
||||
PsiLocalVariable variable = extractCollectionVariable(methodCallExpression.getMethodExpression().getQualifierExpression());
|
||||
if(variable == null) return false;
|
||||
return getInitializerUsageStatus(variable, statement) != UNKNOWN;
|
||||
}
|
||||
|
||||
void handleSingleReturn(PsiForeachStatement statement, TerminalBlock tb, List<Operation> operations) {
|
||||
PsiReturnStatement returnStatement = (PsiReturnStatement)tb.getSingleStatement();
|
||||
PsiExpression value = returnStatement.getReturnValue();
|
||||
PsiReturnStatement nextReturnStatement = getNextReturnStatement(statement);
|
||||
if(nextReturnStatement != null && (ExpressionUtils.isLiteral(value, Boolean.TRUE) || ExpressionUtils.isLiteral(value, Boolean.FALSE))) {
|
||||
if (nextReturnStatement != null &&
|
||||
(ExpressionUtils.isLiteral(value, Boolean.TRUE) || ExpressionUtils.isLiteral(value, Boolean.FALSE))) {
|
||||
boolean foundResult = (boolean)((PsiLiteralExpression)value).getValue();
|
||||
if(ExpressionUtils.isLiteral(nextReturnStatement.getReturnValue(), !foundResult)) {
|
||||
String methodName;
|
||||
|
||||
+1
-7
@@ -156,16 +156,10 @@ public class UnnecessaryModuleDependencyInspection extends GlobalInspectionTool
|
||||
myDependency = dependency;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Remove dependency";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Remove dependency";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -201,7 +201,7 @@ public class RedundantThrows extends GlobalJavaBatchInspectionTool {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.redundant.throws.remove.quickfix");
|
||||
}
|
||||
|
||||
@@ -225,12 +225,6 @@ public class RedundantThrows extends GlobalJavaBatchInspectionTool {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
private void removeExcessiveThrows(@Nullable RefMethod refMethod, @Nullable final PsiModifierListOwner element, final CommonProblemDescriptor[] problems) {
|
||||
try {
|
||||
@Nullable final PsiMethod psiMethod;
|
||||
|
||||
+1
-7
@@ -131,16 +131,10 @@ public class UnusedLibrariesInspection extends GlobalInspectionTool {
|
||||
myFiles = files;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return myFiles == null ? InspectionsBundle.message("detach.library.quickfix.name") : InspectionsBundle.message("detach.library.roots.quickfix.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return myFiles == null ? InspectionsBundle.message("detach.library.quickfix.name") : InspectionsBundle.message("detach.library.roots.quickfix.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -47,7 +47,7 @@ import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class ExcludeTable extends ListTableWithButtons<ExcludeTable.Item> {
|
||||
private static final Pattern ourPackagePattern = Pattern.compile("(\\w+\\.)*\\w+");
|
||||
private static final Pattern ourPackagePattern = Pattern.compile("([\\w*]+\\.)*[\\w*]+");
|
||||
private static final ColumnInfo<Item, String> NAME_COLUMN = new ColumnInfo<Item, String>("Class/package/member qualified name mask") {
|
||||
@Nullable
|
||||
@Override
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateState;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.event.DocumentAdapter;
|
||||
@@ -288,7 +289,8 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> implements Type
|
||||
TextRange endRange = templateState.getVariableRange(template.getVariableNameAt(template.getVariableCount() - 1));
|
||||
if (startRange == null || endRange == null) return;
|
||||
|
||||
editor.getDocument().deleteString(startRange.getStartOffset(), endRange.getEndOffset());
|
||||
WriteCommandAction.runWriteCommandAction(editor.getProject(), () ->
|
||||
editor.getDocument().deleteString(startRange.getStartOffset(), endRange.getEndOffset()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
-6
@@ -33,12 +33,6 @@ public class CreateStaticMethodQuickFix implements LocalQuickFix {
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return QuickFixBundle.message("create.method.from.usage.family");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
|
||||
-6
@@ -70,12 +70,6 @@ public class CreateFieldOrPropertyFix implements IntentionAction, LocalQuickFix
|
||||
return QuickFixBundle.message(myMemberType == PropertyMemberType.FIELD ? "create.field.text":"create.property.text", myName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
|
||||
-7
@@ -239,13 +239,6 @@ public class CollectionAddAllCanBeReplacedWithConstructorInspection extends Base
|
||||
myAssignmentExpression = smartPointerManager.createSmartPsiElementPointer(assignmentExpression);
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
|
||||
+1
-8
@@ -42,18 +42,11 @@ public class DefaultAnnotationParamInspection extends BaseJavaBatchLocalInspecti
|
||||
if (defaultValue == null) return;
|
||||
if (areEqual(value, defaultValue)) {
|
||||
holder.registerProblem(value, "Redundant default parameter value assignment", ProblemHighlightType.LIKE_UNUSED_SYMBOL, new LocalQuickFix() {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Remove redundant parameter";
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Remove redundant parameter";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -36,7 +36,7 @@ public class RemoveInitializerFix implements LocalQuickFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.unused.assignment.remove.quickfix");
|
||||
}
|
||||
|
||||
@@ -91,10 +91,4 @@ public class RemoveInitializerFix implements LocalQuickFix {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -210,16 +210,10 @@ class UnusedParametersInspection extends GlobalJavaBatchInspectionTool {
|
||||
return myHint;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionsBundle.message("inspection.unused.parameter.delete.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return InspectionsBundle.message("inspection.unused.parameter.delete.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -84,16 +84,10 @@ public class DefaultFileTemplateUsageInspection extends BaseJavaLocalInspectionT
|
||||
myReplaceTemplateFix = replaceTemplateFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionsBundle.message("default.file.template.edit.template");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return InspectionsBundle.message("default.file.template.edit.template");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -25,13 +25,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
public abstract class ReplaceWithFileTemplateFix implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("default.file.template.replace.with.actual.file.template");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-13
@@ -307,12 +307,6 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool {
|
||||
myHint = hint;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return QUICK_FIX_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
@@ -352,7 +346,7 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return QUICK_FIX_NAME;
|
||||
}
|
||||
|
||||
@@ -361,12 +355,6 @@ public class EmptyMethodInspection extends GlobalJavaBatchInspectionTool {
|
||||
applyFix(project, new ProblemDescriptor[]{descriptor}, new ArrayList<>(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
private void deleteHierarchy(RefMethod refMethod, List<PsiElement> result) {
|
||||
Collection<RefMethod> derivedMethods = refMethod.getDerivedMethods();
|
||||
RefMethod[] refMethods = derivedMethods.toArray(new RefMethod[derivedMethods.size()]);
|
||||
|
||||
+1
-7
@@ -47,18 +47,12 @@ public class EqualsAndHashcode extends EqualsAndHashcodeBase {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return myHasEquals
|
||||
? InspectionsBundle.message("inspection.equals.hashcode.generate.hashcode.quickfix")
|
||||
: InspectionsBundle.message("inspection.equals.hashcode.generate.equals.quickfix");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
|
||||
|
||||
-7
@@ -114,13 +114,6 @@ public class StaticPseudoFunctionalStyleMethodInspection extends BaseJavaBatchLo
|
||||
myHandler = handler;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
|
||||
+1
-13
@@ -69,16 +69,10 @@ public class JavaDocReferenceInspection extends JavaDocReferenceInspectionBase {
|
||||
myUnboundParams = unboundParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "Change to ...";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Change to ...";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,12 +108,6 @@ public class JavaDocReferenceInspection extends JavaDocReferenceInspectionBase {
|
||||
this.originalClasses = originalClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return QuickFixBundle.message("add.qualifier");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
|
||||
-7
@@ -129,13 +129,6 @@ public class RedundantLambdaParameterTypeInspection extends BaseJavaBatchLocalIn
|
||||
}
|
||||
|
||||
private static class LambdaParametersFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return getFamilyName();
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -203,16 +203,10 @@ public class MagicConstantInspection extends BaseJavaLocalInspectionTool {
|
||||
String text = "No IDEA annotations attached to the JDK " + finalJdk.getName() + (path == null ? "" : " (" + FileUtil.toSystemDependentName(path) + ")")
|
||||
+", some issues will not be found";
|
||||
holder.registerProblem(file, text, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new LocalQuickFix() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Attach annotations";
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return "Attach annotations";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-6
@@ -54,12 +54,6 @@ public class RedundantArrayForVarargsCallInspection extends GenericsInspectionTo
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return InspectionsBundle.message("inspection.redundant.array.creation.quickfix");
|
||||
}
|
||||
}
|
||||
|
||||
+1
-8
@@ -45,18 +45,11 @@ public class SillyAssignmentInspection extends SillyAssignmentInspectionBase {
|
||||
|
||||
private static class RemoveSillyAssignmentFix implements LocalQuickFix {
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return InspectionsBundle.message("assignment.to.itself.quickfix.name");
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
return InspectionsBundle.message("assignment.to.itself.quickfix.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-7
@@ -154,7 +154,7 @@ public class UnusedReturnValue extends GlobalJavaBatchInspectionTool{
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.unused.return.value.make.void.quickfix");
|
||||
}
|
||||
|
||||
@@ -179,12 +179,6 @@ public class UnusedReturnValue extends GlobalJavaBatchInspectionTool{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
private static void makeMethodHierarchyVoid(Project project, @NotNull PsiMethod psiMethod) {
|
||||
replaceReturnStatements(psiMethod);
|
||||
for (final PsiMethod oMethod : OverridingMethodsSearch.search(psiMethod)) {
|
||||
|
||||
+1
-7
@@ -50,7 +50,7 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public final String getName() {
|
||||
public final String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.convert.to.local.quickfix");
|
||||
}
|
||||
|
||||
@@ -225,12 +225,6 @@ public abstract class BaseConvertToLocalQuickFix<V extends PsiVariable> implemen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getAnchorElement(PsiCodeBlock anchorBlock, @NotNull PsiElement firstElement) {
|
||||
PsiElement element = firstElement;
|
||||
|
||||
@@ -549,13 +549,24 @@ public class JavaDocumentationProvider extends DocumentationProviderEx implement
|
||||
|
||||
@Nullable
|
||||
public static String generateExternalJavadoc(@NotNull final PsiElement element) {
|
||||
List<String> docURLs = getExternalJavaDocUrl(element);
|
||||
return generateExternalJavadoc(element, docURLs);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String generateExternalJavadoc(@NotNull final PsiElement element, @Nullable List<String> docURLs) {
|
||||
final JavaDocInfoGenerator javaDocInfoGenerator = JavaDocInfoGeneratorFactory.create(element.getProject(), element);
|
||||
return generateExternalJavadoc(element, javaDocInfoGenerator);
|
||||
return generateExternalJavadoc(javaDocInfoGenerator, docURLs);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String generateExternalJavadoc(@NotNull final PsiElement element, @NotNull JavaDocInfoGenerator generator) {
|
||||
final List<String> docURLs = getExternalJavaDocUrl(element);
|
||||
return generateExternalJavadoc(generator, docURLs);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String generateExternalJavadoc(@NotNull JavaDocInfoGenerator generator, @Nullable List<String> docURLs) {
|
||||
return JavaDocExternalFilter.filterInternalDocInfo(generator.generateDocInfo(docURLs));
|
||||
}
|
||||
|
||||
|
||||
@@ -101,12 +101,17 @@ public class ReferenceChainLink {
|
||||
PsiPackage pkg = JavaPsiFacade.getInstance(project).findPackage(referenceName);
|
||||
if (pkg != null && pkg.getDirectories(scope).length > 0) return null;
|
||||
|
||||
if (!cache.processFieldsWithName(referenceName, processor, scope, null) ||
|
||||
!cache.processClassesWithName(referenceName, processor, scope, null)) {
|
||||
if (!cache.processFieldsWithName(referenceName, processor, scope, null)) {
|
||||
markExpensive(project);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cache.processClassesWithName(referenceName, processor, scope, null)) {
|
||||
markExpensive(project);
|
||||
return null;
|
||||
}
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,7 @@ import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Producer;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -122,8 +119,7 @@ public class LambdaUtil {
|
||||
public static boolean isFunctionalClass(PsiClass aClass) {
|
||||
if (aClass != null) {
|
||||
if (aClass instanceof PsiTypeParameter) return false;
|
||||
final List<HierarchicalMethodSignature> signatures = findFunctionCandidates(aClass);
|
||||
return signatures != null && signatures.size() == 1;
|
||||
return getFunction(aClass) != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -152,15 +148,69 @@ public class LambdaUtil {
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public static MethodSignature getFunction(PsiClass psiClass) {
|
||||
if (psiClass == null) return null;
|
||||
final List<HierarchicalMethodSignature> functions = findFunctionCandidates(psiClass);
|
||||
if (functions != null && functions.size() == 1) {
|
||||
return functions.get(0);
|
||||
public static MethodSignature getFunction(final PsiClass psiClass) {
|
||||
if (isPlainInterface(psiClass)) {
|
||||
return CachedValuesManager.getCachedValue(psiClass, new CachedValueProvider<MethodSignature>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<MethodSignature> compute() {
|
||||
return Result.create(calcFunction(psiClass), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isPlainInterface(PsiClass psiClass) {
|
||||
return psiClass != null && psiClass.isInterface() && !psiClass.isAnnotationType();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MethodSignature calcFunction(@NotNull PsiClass psiClass) {
|
||||
if (hasManyOwnAbstractMethods(psiClass) || hasManyInheritedAbstractMethods(psiClass)) return null;
|
||||
|
||||
final List<HierarchicalMethodSignature> functions = findFunctionCandidates(psiClass);
|
||||
return functions != null && functions.size() == 1 ? functions.get(0) : null;
|
||||
}
|
||||
|
||||
private static boolean hasManyOwnAbstractMethods(@NotNull PsiClass psiClass) {
|
||||
int abstractCount = 0;
|
||||
for (PsiMethod method : psiClass.getMethods()) {
|
||||
if (isDefinitelyAbstractInterfaceMethod(method) && ++abstractCount > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isDefinitelyAbstractInterfaceMethod(PsiMethod method) {
|
||||
return method.hasModifierProperty(PsiModifier.ABSTRACT) && !isPublicObjectMethod(method.getName());
|
||||
}
|
||||
|
||||
private static boolean isPublicObjectMethod(String methodName) {
|
||||
return "equals".equals(methodName) || "hashCode".equals(methodName) || "toString".equals(methodName);
|
||||
}
|
||||
|
||||
private static boolean hasManyInheritedAbstractMethods(@NotNull PsiClass psiClass) {
|
||||
final Set<String> abstractNames = ContainerUtil.newHashSet();
|
||||
final Set<String> defaultNames = ContainerUtil.newHashSet();
|
||||
InheritanceUtil.processSupers(psiClass, true, new Processor<PsiClass>() {
|
||||
@Override
|
||||
public boolean process(PsiClass psiClass) {
|
||||
for (PsiMethod method : psiClass.getMethods()) {
|
||||
if (isDefinitelyAbstractInterfaceMethod(method)) {
|
||||
abstractNames.add(method.getName());
|
||||
}
|
||||
else if (method.hasModifierProperty(PsiModifier.DEFAULT)) {
|
||||
defaultNames.add(method.getName());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
abstractNames.removeAll(defaultNames);
|
||||
return abstractNames.size() > 1;
|
||||
}
|
||||
|
||||
private static boolean overridesPublicObjectMethod(HierarchicalMethodSignature psiMethod) {
|
||||
final List<HierarchicalMethodSignature> signatures = psiMethod.getSuperSignatures();
|
||||
@@ -219,20 +269,9 @@ public class LambdaUtil {
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public static List<HierarchicalMethodSignature> findFunctionCandidates(final PsiClass psiClass) {
|
||||
if (psiClass != null && psiClass.isInterface() && !psiClass.isAnnotationType()) {
|
||||
return CachedValuesManager.getCachedValue(psiClass, new CachedValueProvider<List<HierarchicalMethodSignature>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<List<HierarchicalMethodSignature>> compute() {
|
||||
return Result.create(calcFunctionCandidates(psiClass), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static List<HierarchicalMethodSignature> findFunctionCandidates(@Nullable final PsiClass psiClass) {
|
||||
if (!isPlainInterface(psiClass)) return null;
|
||||
|
||||
private static List<HierarchicalMethodSignature> calcFunctionCandidates(PsiClass psiClass) {
|
||||
final List<HierarchicalMethodSignature> methods = new ArrayList<HierarchicalMethodSignature>();
|
||||
final Map<MethodSignature, Set<PsiMethod>> overrideEquivalents = PsiSuperMethodUtil.collectOverrideEquivalents(psiClass);
|
||||
final Collection<HierarchicalMethodSignature> visibleSignatures = psiClass.getVisibleSignatures();
|
||||
|
||||
@@ -26,6 +26,7 @@ public interface PsiJavaModule extends NavigatablePsiElement, PsiNamedElement, P
|
||||
String MODULE_INFO_CLASS = "module-info";
|
||||
String MODULE_INFO_FILE = MODULE_INFO_CLASS + ".java";
|
||||
String MODULE_INFO_CLS_FILE = MODULE_INFO_CLASS + ".class";
|
||||
String JAVA_BASE = "java.base";
|
||||
|
||||
@NotNull PsiJavaModuleReferenceElement getNameElement();
|
||||
@NotNull String getModuleName();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-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.
|
||||
@@ -29,6 +29,7 @@ import com.intellij.util.containers.IntArrayList;
|
||||
import com.intellij.util.containers.IntStack;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TIntArrayList;
|
||||
import gnu.trove.TIntHashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -1284,6 +1285,112 @@ public class ControlFlowUtil {
|
||||
return visitor.getResult().booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the value the variable has at start is later referenced without going through stop instruction
|
||||
*
|
||||
* @param flow ControlFlow to analyze
|
||||
* @param start the point at which variable value is created
|
||||
* @param stop the stop-point
|
||||
* @param variable the variable to examine
|
||||
* @return true if the value the variable has at start is later referenced without going through stop instruction
|
||||
*/
|
||||
public static boolean isValueUsedWithoutVisitingStop(final ControlFlow flow, final int start, final int stop, final PsiVariable variable) {
|
||||
if(start == stop) return false;
|
||||
|
||||
class MyVisitor extends InstructionClientVisitor<Boolean> {
|
||||
// true if value the variable has at given offset maybe referenced without going through stop instruction
|
||||
final boolean[] maybeReferenced = new boolean[flow.getSize() + 1];
|
||||
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction, int offset, int nextOffset) {
|
||||
if (offset == stop) {
|
||||
maybeReferenced[offset] = false;
|
||||
return;
|
||||
}
|
||||
if(instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == variable) {
|
||||
maybeReferenced[offset] = false;
|
||||
return;
|
||||
}
|
||||
if (maybeReferenced[offset]) return;
|
||||
if (nextOffset > flow.getSize()) nextOffset = flow.getSize();
|
||||
|
||||
boolean nextState = maybeReferenced[nextOffset];
|
||||
maybeReferenced[offset] =
|
||||
nextState || (instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getResult() {
|
||||
return maybeReferenced[start];
|
||||
}
|
||||
}
|
||||
MyVisitor visitor = new MyVisitor();
|
||||
depthFirstSearch(flow, visitor, start, flow.getSize());
|
||||
return visitor.getResult().booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether variable can be referenced between start and stop points. Back-edges are also considered, so the actual place
|
||||
* where it referenced might be outside of (start, stop) interval.
|
||||
*
|
||||
* @param flow ControlFlow to analyze
|
||||
* @param start start point
|
||||
* @param stop stop point
|
||||
* @param variable variable to analyze
|
||||
* @return true if variable can be referenced between start and stop points
|
||||
*/
|
||||
public static boolean isVariableReferencedBetween(final ControlFlow flow,
|
||||
final int start,
|
||||
final int stop,
|
||||
final PsiVariable variable) {
|
||||
if(start == stop) return false;
|
||||
|
||||
// DFS visits instructions mainly in backward direction while here visiting in forward direction
|
||||
// greatly reduces number of iterations. So first we just collect edges, then reverse their order.
|
||||
// contains (from, to) pairs representing control flow arcs
|
||||
final TIntArrayList list = new TIntArrayList();
|
||||
depthFirstSearch(flow, new InstructionClientVisitor<Void>() {
|
||||
@Override
|
||||
public void visitInstruction(Instruction instruction, int offset, int nextOffset) {
|
||||
list.add(offset);
|
||||
list.add(nextOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void getResult() {
|
||||
return null;
|
||||
}
|
||||
}, start, flow.getSize());
|
||||
BitSet violated = new BitSet();
|
||||
List<Instruction> instructions = flow.getInstructions();
|
||||
boolean changed = true;
|
||||
while(changed) {
|
||||
changed = false;
|
||||
for(int i=list.size()-2; i>=0; i-=2) {
|
||||
int from = list.get(i);
|
||||
int to = list.get(i+1);
|
||||
if(from == stop) continue;
|
||||
if(violated.get(from)) {
|
||||
if(!violated.get(to)) {
|
||||
if(to == stop) return true;
|
||||
violated.set(to);
|
||||
changed = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Instruction instruction = instructions.get(from);
|
||||
if((instruction instanceof ReadVariableInstruction && ((ReadVariableInstruction)instruction).variable == variable) ||
|
||||
(instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == variable)) {
|
||||
violated.set(from);
|
||||
violated.set(to);
|
||||
if(to == stop) return true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return min offset after sourceOffset which is definitely reachable from all references
|
||||
*/
|
||||
|
||||
@@ -411,6 +411,9 @@ module.service.abstract=The service implementation is an abstract class: {0}
|
||||
module.service.no.ctor=The service implementation does not have a default constructor: {0}
|
||||
module.service.hidden.ctor=The default constructor of the service implementation is not public: {0}
|
||||
module.service.unused=Service interface provided but not exported or used
|
||||
module.package.not.exported=The module ''{0}'' does not export the package ''{1}'' to the module ''{2}''
|
||||
module.package.on.classpath=A named module cannot access packages of an unnamed one
|
||||
module.not.in.requirements=The module ''{0}'' does not have the module ''{1}'' in requirements
|
||||
|
||||
feature.generics=Generics
|
||||
feature.annotations=Annotations
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
class A {
|
||||
|
||||
void foo() {
|
||||
new IterHelper<>().loopMap((k, val) -> {
|
||||
//do something
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
final class IterHelper<K, V> {
|
||||
public void loopMap(final MapIterCallback<K, V> callback) {
|
||||
//do something
|
||||
}
|
||||
public static interface MapIterCallback<K, V> {
|
||||
abstract void eval(K k, V v);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,6 +4,6 @@ import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
String found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty()) ? "yes" : "no";
|
||||
String found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty()) ? "yes" : "no";
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,6 +4,6 @@ import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
boolean found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,6 +4,6 @@ import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = !data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
boolean found = !data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found;
|
||||
if (data.size() > 10) {
|
||||
System.out.println("Big data");
|
||||
}
|
||||
found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -4,13 +4,12 @@ import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = false;
|
||||
boolean found;
|
||||
if(Math.random() > 0.5) {
|
||||
found = true;
|
||||
} else {
|
||||
if (data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty())) {
|
||||
found = true;
|
||||
}
|
||||
found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = false;
|
||||
if(Math.random() > 0.5) {
|
||||
System.out.println("oops");
|
||||
} else {
|
||||
found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found;
|
||||
try {
|
||||
found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
System.out.println(found);
|
||||
}
|
||||
catch(Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Replace with anyMatch()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testAssignment(List<String> data) {
|
||||
boolean found = false;
|
||||
try {
|
||||
found = data.stream().map(String::trim).anyMatch(trimmed -> !trimmed.isEmpty());
|
||||
}
|
||||
catch(Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,6 +6,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void test(Integer[] arr) {
|
||||
List<Integer> result = Arrays.stream(arr).filter(x -> x > 5).collect(Collectors.toList());
|
||||
List<Integer> result = Arrays.stream(arr).filter(x -> x > 5).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
class A {
|
||||
public static void main(List<String> args) {
|
||||
ArrayList<String> uniqNames = args.stream().map(name -> name.substring(1)).collect(Collectors.toCollection(ArrayList::new));
|
||||
ArrayList<String> uniqNames = args.stream().map(name -> name.substring(1)).collect(Collectors.toCollection(ArrayList::new));
|
||||
uniqNames.forEach(System.out::println);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
class Test {
|
||||
public static <T> List<TokenFilter<T>> fromString(final T src, Function<T, List<String>> extractor) {
|
||||
final List<TokenFilter<T>> result = extractor.apply(src).stream().map((Function<String, TokenFilter<T>>) TokenFilter::new).collect(Collectors.toList());
|
||||
final List<TokenFilter<T>> result = extractor.apply(src).stream().map((Function<String, TokenFilter<T>>) TokenFilter::new).collect(Collectors.toList());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -10,6 +10,6 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
|
||||
List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,6 +10,6 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
List<String> names = persons.stream().filter(Objects::nonNull).map(Person::getName).collect(Collectors.toList());
|
||||
List<String> names = persons.stream().filter(Objects::nonNull).map(Person::getName).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,6 +10,6 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Collection<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
|
||||
Collection<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
|
||||
List<String> names = persons.stream().map(Person::getName).collect(Collectors.toList());
|
||||
//some comment
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,6 +10,6 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
List<String> names = persons.stream().map(person -> "name: " + person.getName()).collect(Collectors.toList());
|
||||
List<String> names = persons.stream().map(person -> "name: " + person.getName()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void testPrimitiveMap(List<String> data) {
|
||||
List<Integer> list = data.stream().filter(str -> str.startsWith("xyz")).mapToInt(String::length).filter(len -> len > 10).boxed().collect(Collectors.toList());
|
||||
List<Integer> list = data.stream().filter(str -> str.startsWith("xyz")).mapToInt(String::length).filter(len -> len > 10).boxed().collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,6 +10,6 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Set<String> names = persons.stream().map(Person::getName).collect(Collectors.toSet());
|
||||
Set<String> names = persons.stream().map(Person::getName).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Replace with collect" "true"
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Collect {
|
||||
class Person {
|
||||
String getName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Set<String> names, other = new HashSet<>();
|
||||
names = persons.stream().map(Person::getName).collect(Collectors.toSet());
|
||||
System.out.println(names);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// "Replace with forEach" "true"
|
||||
import java.util.*;
|
||||
|
||||
public class Collect {
|
||||
class Person {
|
||||
String getName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Set<String> names = new HashSet<>();
|
||||
for(int i=0; i<10; i++) {
|
||||
persons.stream().map(Person::getName).forEach(names::add);
|
||||
}
|
||||
System.out.println(names);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
// "Replace with forEach" "true"
|
||||
import java.util.*;
|
||||
|
||||
public class Collect {
|
||||
class Person {
|
||||
String getName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Set<String> names = new HashSet<>();
|
||||
names.add("Test");
|
||||
persons.stream().map(Person::getName).forEach(names::add);
|
||||
System.out.println(names);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Replace with collect" "true"
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Collect {
|
||||
class Person {
|
||||
String getName() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Set<String> names = new HashSet<>(), other = new HashSet<>();
|
||||
if(persons != null) {
|
||||
names = persons.stream().map(Person::getName).collect(Collectors.toSet());
|
||||
}
|
||||
System.out.println(names);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,6 +10,6 @@ public class Collect {
|
||||
}
|
||||
|
||||
void collectNames(List<Person> persons){
|
||||
Set<String> names = persons.stream().map(Person::getName).collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
Set<String> names = persons.stream().map(Person::getName).collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,6 +6,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void testPrimitiveMap(List<String> data) {
|
||||
List<String> list = data.stream().filter(str -> str.startsWith("xyz")).mapToInt(String::length).filter(len -> len > 10).mapToObj(String::valueOf).collect(Collectors.toList());
|
||||
List<String> list = data.stream().filter(str -> str.startsWith("xyz")).mapToInt(String::length).filter(len -> len > 10).mapToObj(String::valueOf).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@ import java.util.stream.Collectors;
|
||||
public class Main {
|
||||
|
||||
public List<String> test(Map<String, List<String>> map) {
|
||||
List<String> result = map.entrySet().stream().filter(entry -> !entry.getKey().isEmpty()).map(Map.Entry::getValue).filter(Objects::nonNull).flatMap(Collection::stream).map(String::trim).filter(trimmed -> !trimmed.isEmpty()).collect(Collectors.toList());
|
||||
List<String> result = map.entrySet().stream().filter(entry -> !entry.getKey().isEmpty()).map(Map.Entry::getValue).filter(Objects::nonNull).flatMap(Collection::stream).map(String::trim).filter(trimmed -> !trimmed.isEmpty()).collect(Collectors.toList());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@ import java.util.stream.Collectors;
|
||||
public class Main {
|
||||
|
||||
public List<String> test(Map<String, List<String>> map) {
|
||||
List<String> result = map.entrySet().stream().filter(entry -> !entry.getKey().isEmpty()).map(Map.Entry::getValue).filter(Objects::nonNull).flatMap(Collection::stream).map(String::trim).filter(trimmed -> !trimmed.isEmpty()).collect(Collectors.toList());
|
||||
List<String> result = map.entrySet().stream().filter(entry -> !entry.getKey().isEmpty()).map(Map.Entry::getValue).filter(Objects::nonNull).flatMap(Collection::stream).map(String::trim).filter(trimmed -> !trimmed.isEmpty()).collect(Collectors.toList());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -4,6 +4,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void test(List<Set<String>> nested) {
|
||||
List<String> result = nested.stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(str -> str.startsWith("xyz")).map(String::trim).collect(Collectors.toList());
|
||||
List<String> result = nested.stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(str -> str.startsWith("xyz")).map(String::trim).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,6 +6,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void test(List<String[]> list) {
|
||||
List<String> result = list.stream().filter(arr -> arr.length > 2).flatMap(Arrays::stream).map(String::trim).filter(trimmed -> !trimmed.isEmpty()).collect(Collectors.toList());
|
||||
List<String> result = list.stream().filter(arr -> arr.length > 2).flatMap(Arrays::stream).map(String::trim).filter(trimmed -> !trimmed.isEmpty()).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,6 +7,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public void test(Map<String, String[]> map) {
|
||||
List<String> result = map.entrySet().stream().filter(entry -> entry.getKey().startsWith("x")).map(Map.Entry::getValue).flatMap(Arrays::stream).map(String::trim).collect(Collectors.toList());
|
||||
List<String> result = map.entrySet().stream().filter(entry -> entry.getKey().startsWith("x")).map(Map.Entry::getValue).flatMap(Arrays::stream).map(String::trim).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@ import java.util.Objects;
|
||||
|
||||
public class Main {
|
||||
public void testMap(Map<String, List<String>> map) throws Exception {
|
||||
int firstSize = map.values().stream().filter(Objects::nonNull).findFirst().map(List::size).orElse(0);
|
||||
int firstSize = map.values().stream().filter(Objects::nonNull).findFirst().map(List::size).orElse(0);
|
||||
// comment
|
||||
System.out.println(firstSize);
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testCast(List<Object> data) {
|
||||
String found = (String) data.stream().filter(obj -> obj instanceof String).findFirst().orElse(null);
|
||||
String found = (String) data.stream().filter(obj -> obj instanceof String).findFirst().orElse(null);
|
||||
System.out.println(found);
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Main {
|
||||
public void testMap(Map<String, List<String>> map) throws Exception {
|
||||
int firstSize;
|
||||
int other = map.size();
|
||||
if(other > 10) {
|
||||
System.out.println("Big");
|
||||
}
|
||||
// comment
|
||||
firstSize = map.values().stream().filter(Objects::nonNull).findFirst().map(List::size).orElse(0);
|
||||
System.out.println(firstSize);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Replace with findFirst()" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Main {
|
||||
public void testMap(Map<String, List<String>> map) throws Exception {
|
||||
int firstSize = 0, other = firstSize;
|
||||
// comment
|
||||
firstSize = map.values().stream().filter(Objects::nonNull).findFirst().map(List::size).orElse(firstSize);
|
||||
System.out.println(firstSize);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import java.util.Objects;
|
||||
|
||||
public class Main {
|
||||
public void testMap(Map<String, List<String>> map) throws Exception {
|
||||
String firstStr = map.values().stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(str -> !str.isEmpty()).findFirst().orElse("");
|
||||
String firstStr = map.values().stream().filter(Objects::nonNull).flatMap(Collection::stream).filter(str -> !str.isEmpty()).findFirst().orElse("");
|
||||
System.out.println(firstStr);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public List<String> test(String[][] arr) {
|
||||
List<String> result = Arrays.stream(arr).filter(Objects::nonNull).flatMap(Arrays::stream).collect(Collectors.toList());
|
||||
List<String> result = Arrays.stream(arr).filter(Objects::nonNull).flatMap(Arrays::stream).collect(Collectors.toList());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
public List<Integer> test(int[][] arr) {
|
||||
List<Integer> result = Arrays.stream(arr).filter(Objects::nonNull).flatMapToInt(Arrays::stream).boxed().collect(Collectors.toList());
|
||||
List<Integer> result = Arrays.stream(arr).filter(Objects::nonNull).flatMapToInt(Arrays::stream).boxed().collect(Collectors.toList());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Replace with sum()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testPrimitiveMap(List<String> data) {
|
||||
int sum;
|
||||
if(Math.random() > 0.5) {
|
||||
sum = 10;
|
||||
} else {
|
||||
sum = data.stream().filter(str -> str.startsWith("xyz")).mapToInt(String::length).filter(len -> len > 10).map(len -> len * 2).sum();
|
||||
}
|
||||
System.out.println(sum);
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// "Replace with sum()" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void testPrimitiveMap(List<String> data) {
|
||||
int sum = 0;
|
||||
if(Math.random() > 0.5) {
|
||||
System.out.println("oops");
|
||||
} else {
|
||||
sum = data.stream().filter(str -> str.startsWith("xyz")).mapToInt(String::length).filter(len -> len > 10).map(len -> len * 2).sum();
|
||||
}
|
||||
System.out.println(sum);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user