diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java index b854594982e1..c02e5785eca9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefJavaManagerImpl.java @@ -246,15 +246,7 @@ public class RefJavaManagerImpl extends RefJavaManager { } @Override - public void removeReference(@NotNull final RefElement refElement) { - if (refElement instanceof RefMethod) { - RefMethod refMethod = (RefMethod)refElement; - RefParameter[] params = refMethod.getParameters(); - for (RefParameter param : params) { - myRefManager.removeReference(param); - } - } - } + public void removeReference(@NotNull final RefElement refElement) { } @Override @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java index 18ec1744bcad..eb86fa4eb274 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefMethodImpl.java @@ -490,11 +490,6 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { for (RefMethod subMethod : getDerivedMethods()) { subMethod.getSuperMethods().remove(this); } - - ArrayList deletedRefs = new ArrayList<>(); - for (RefParameter parameter : getParameters()) { - getRefManager().removeRefElement(parameter, deletedRefs); - } } @Override diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 7442ed23d2ce..2dfde213c650 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -54,6 +54,7 @@ import com.intellij.util.text.CharArrayUtil; import com.intellij.util.text.DateFormatUtil; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; +import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -234,20 +235,43 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta @Override protected boolean applyFix(@NotNull final RefEntity[] refElements) { if (!super.applyFix(refElements)) return false; - final PsiElement[] psiElements = Arrays - .stream(refElements) - .filter((obj) -> obj instanceof RefJavaElement && getFilter().accepts((RefJavaElement)obj)) - .map(e -> ((RefElement) e).getElement()) - .filter(e -> e != null) - .toArray(PsiElement[]::new); - if (psiElements.length == 0) return false; + + //filter only elements applicable to be deleted (exclude entry points) + RefElement[] filteredRefElements = Arrays.stream(refElements) + .filter(entry -> entry instanceof RefJavaElement && getFilter().accepts((RefJavaElement)entry)) + .toArray(RefElement[]::new); + ApplicationManager.getApplication().invokeLater(() -> { final Project project = getContext().getProject(); if (isDisposed() || project.isDisposed()) return; - SafeDeleteHandler.invoke(project, psiElements, false, + List psiElements = new ArrayList<>(); + Set classes = new THashSet<>(); + for (RefEntity obj : filteredRefElements) { + PsiElement e = ((RefElement)obj).getElement(); + if (e != null) { + psiElements.add(e); + if (e instanceof PsiClass) { + classes.add((PsiClass)e); + } + } + } + + if (psiElements.size() == 0) return; + + //filter out elements inside classes to be deleted + PsiElement[] elements = psiElements.stream().filter(e -> { + if (e instanceof PsiMember) { + PsiClass containingClass = ((PsiMember)e).getContainingClass(); + if (containingClass != null && classes.contains(containingClass)) { + return false; + } + } + return true; + }).toArray(PsiElement[]::new); + SafeDeleteHandler.invoke(project, elements, false, () -> { - removeElements(refElements, project, myToolWrapper); - for (RefEntity ref : refElements) { + removeElements(filteredRefElements, project, myToolWrapper); + for (RefEntity ref : filteredRefElements) { myFixedElements.put(ref, UnusedDeclarationHint.DELETE); } }); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/BatchModeInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/BatchModeInspectionTest.java new file mode 100644 index 000000000000..d1a67d0eee4a --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/BatchModeInspectionTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2017 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.java.codeInspection; + +import com.intellij.analysis.AnalysisScope; +import com.intellij.codeInspection.InspectionManager; +import com.intellij.codeInspection.reference.RefElement; +import com.intellij.codeInspection.reference.RefEntity; +import com.intellij.codeInspection.reference.RefManagerImpl; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiClass; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; + +import java.util.ArrayList; +import java.util.List; + +public class BatchModeInspectionTest extends LightCodeInsightFixtureTestCase { + public void testEnsureReferencesAreRemoved() throws Exception { + PsiClass aClass = myFixture.addClass("class Foo {public void bar(int i){}}"); + Project project = myFixture.getProject(); + RefManagerImpl refManager = new RefManagerImpl(project, new AnalysisScope(aClass.getContainingFile()), InspectionManager.getInstance( + project).createNewGlobalContext(false)); + refManager.findAllDeclarations(); + List sortedElements = refManager.getSortedElements(); + + RefElement refMethod = refManager.getReference(aClass.getMethods()[0]); + List children = refMethod.getChildren(); + ArrayList deletedRefs = new ArrayList<>(); + refManager.removeRefElement(refMethod, deletedRefs); + assertTrue(deletedRefs.containsAll(children)); + assertTrue(deletedRefs.contains(refMethod)); + + //check that table was not reinitialized due to full table traversal + assertTrue(sortedElements == refManager.getSortedElements()); + } +} diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java index e1b048b51644..aee04dff4b45 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/reference/RefManagerImpl.java @@ -381,7 +381,7 @@ public class RefManagerImpl extends RefManager { } @NotNull - List getSortedElements() { + public List getSortedElements() { List answer = myCachedSortedRefs; if (answer != null) return answer; @@ -682,7 +682,12 @@ public class RefManagerImpl extends RefManager { ((RefManagerImpl)refElement.getRefManager()).removeReference(refElement); ((RefElementImpl)refElement).referenceRemoved(); - if (!deletedRefs.contains(refElement)) deletedRefs.add(refElement); + if (!deletedRefs.contains(refElement)) { + deletedRefs.add(refElement); + } + else { + LOG.error("deleted second time"); + } } boolean isValidPointForReference() {