inspection view: allow specify container element for every inspection for given language (IDEA-179773)

This commit is contained in:
Dmitry Batkovich
2017-09-29 13:49:39 +03:00
parent b3596b56d5
commit 0c19a4c695
8 changed files with 86 additions and 138 deletions
@@ -1,29 +1,11 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class AbstractBaseJavaLocalInspectionTool extends LocalInspectionTool {
private static final Condition<PsiElement> PROBLEM_ELEMENT_CONDITION = Conditions.and(Conditions.instanceOf(PsiFile.class, PsiClass.class, PsiMethod.class, PsiField.class), Conditions.notInstanceOf(PsiTypeParameter.class));
/**
* Override this to report problems at method level.
@@ -97,9 +79,4 @@ public abstract class AbstractBaseJavaLocalInspectionTool extends LocalInspectio
}
};
}
@Override
public PsiNamedElement getProblemElement(final PsiElement psiElement) {
return (PsiNamedElement)PsiTreeUtil.findFirstParent(psiElement, PROBLEM_ELEMENT_CONDITION);
}
}
@@ -1,18 +1,4 @@
/*
* 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.reference;
import com.intellij.codeInsight.ExternalAnnotationsManager;
@@ -26,6 +12,8 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -50,6 +38,9 @@ import java.util.Map;
* Date: 20-Dec-2007
*/
public class RefJavaManagerImpl extends RefJavaManager {
private static final Condition<PsiElement> PROBLEM_ELEMENT_CONDITION = Conditions
.and(Conditions.instanceOf(PsiFile.class, PsiClass.class, PsiMethod.class, PsiField.class), Conditions.notInstanceOf(PsiTypeParameter.class));
private static final Logger LOG = Logger.getInstance(RefJavaManagerImpl.class);
private final PsiMethod myAppMainPattern;
private final PsiMethod myAppPremainPattern;
@@ -277,6 +268,12 @@ public class RefJavaManagerImpl extends RefJavaManager {
return null;
}
@Nullable
@Override
public PsiNamedElement getElementContainer(@NotNull PsiElement psiElement) {
return (PsiNamedElement)PsiTreeUtil.findFirstParent(psiElement, PROBLEM_ELEMENT_CONDITION);
}
@Override
@Nullable
public RefEntity getReference(final String type, final String fqName) {
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2014 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection;
import com.intellij.lang.injection.InjectedLanguageManager;
@@ -167,6 +153,15 @@ public abstract class LocalInspectionTool extends InspectionProfileEntry {
};
}
/**
* The method finds problem container (ex: method, class, file) that used to be shown as inspection view tree node.
*
* Consider {@link com.intellij.codeInspection.lang.RefManagerExtension#getElementContainer(PsiElement)}
* to override container element for any inspection for given language.
*
* @param psiElement: problem element
* @return problem container element
*/
@Nullable
public PsiNamedElement getProblemElement(PsiElement psiElement) {
while (psiElement!=null && !(psiElement instanceof PsiFile)) {
@@ -1,27 +1,15 @@
/*
* Copyright 2000-2015 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.lang;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.codeInspection.reference.RefVisitor;
import com.intellij.lang.Language;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -42,6 +30,18 @@ public interface RefManagerExtension<T> {
@Nullable
RefElement createRefElement(PsiElement psiElement);
/**
* The method finds problem container (ex: method, class, file) that used to be shown as inspection view tree node.
* If method returns not null value then {@link LocalInspectionTool#getProblemElement(PsiElement)} will be ignored.
*
* @param psiElement
* @return container element for given psiElement
*/
@Nullable
default PsiNamedElement getElementContainer(@NotNull PsiElement psiElement) {
return null;
}
@Nullable
RefEntity getReference(final String type, final String fqName);
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2009 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.reference;
import com.intellij.analysis.AnalysisScope;
@@ -22,6 +8,7 @@ import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiNamedElement;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -129,4 +116,9 @@ public abstract class RefManager {
public boolean isInGraph(VirtualFile file) {
return true;
}
@Nullable
public PsiNamedElement getContainerElement(@NotNull PsiElement element) {
return null;
}
}
@@ -1,18 +1,4 @@
/*
* 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.reference;
@@ -407,6 +393,20 @@ public class RefManagerImpl extends RefManager {
return !myUnprocessedFiles.get(((VirtualFileWithId)file).getId());
}
@Nullable
@Override
public PsiNamedElement getContainerElement(@NotNull PsiElement element) {
Language language = element.getLanguage();
return myExtensions
.values()
.stream()
.filter(extension -> extension.getLanguage().equals(language))
.map(extension -> extension.getElementContainer(element))
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
private synchronized void registerUnprocessed(VirtualFileWithId virtualFile) {
myUnprocessedFiles.set(virtualFile.getId());
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.ex;
import com.intellij.codeInspection.*;
@@ -20,6 +6,7 @@ import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.reference.RefManagerImpl;
import com.intellij.codeInspection.ui.InspectionToolPresentation;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiNamedElement;
import com.intellij.util.TripleFunction;
import org.jetbrains.annotations.NotNull;
@@ -33,7 +20,7 @@ import java.util.Map;
public class LocalDescriptorsUtil {
private static final TripleFunction<LocalInspectionTool, PsiElement, GlobalInspectionContext,RefElement> CONVERT =
(tool, element, context) -> {
final PsiNamedElement problemElement = tool.getProblemElement(element);
final PsiNamedElement problemElement = getContainerElement(element, tool, context);
RefElement refElement = context.getRefManager().getReference(problemElement);
if (refElement == null && problemElement != null) { // no need to lose collected results
@@ -94,4 +81,16 @@ public class LocalDescriptorsUtil {
@NotNull LocalInspectionTool tool) {
addProblemDescriptors(descriptors, filterSuppressed, inspectionContext, tool, CONVERT, dpi);
}
public static PsiNamedElement getContainerElement(@Nullable PsiElement element,
@NotNull LocalInspectionTool tool,
@NotNull GlobalInspectionContext context) {
if (element == null) return null;
PsiNamedElement containerFromTool = tool.getProblemElement(element);
if (containerFromTool != null && !(containerFromTool instanceof PsiFile)) {
return containerFromTool;
}
PsiNamedElement container = context.getRefManager().getContainerElement(element);
return container != null ? container : containerFromTool;
}
}
@@ -1,18 +1,4 @@
/*
* 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.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.offlineViewer;
import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil;
@@ -21,10 +7,7 @@ import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.actions.RunInspectionAction;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.codeInspection.ex.*;
import com.intellij.codeInspection.offline.OfflineProblemDescriptor;
import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.reference.RefEntity;
@@ -115,7 +98,11 @@ class OfflineDescriptorResolveResult {
final PsiElement psiElement = ((RefElement)element).getElement();
if (psiElement != null) {
ProblemDescriptor descriptor = ProgressManager.getInstance().runProcess(
() -> runLocalTool(psiElement, inspectionManager, offlineProblemDescriptor, (LocalInspectionToolWrapper)toolWrapper), new DaemonProgressIndicator());
() -> runLocalTool(psiElement,
offlineProblemDescriptor,
(LocalInspectionToolWrapper)toolWrapper,
inspectionManager,
presentation.getContext()), new DaemonProgressIndicator());
if (descriptor != null) return descriptor;
}
return null;
@@ -131,9 +118,10 @@ class OfflineDescriptorResolveResult {
}
private static ProblemDescriptor runLocalTool(@NotNull PsiElement psiElement,
@NotNull InspectionManager inspectionManager,
@NotNull OfflineProblemDescriptor offlineProblemDescriptor,
@NotNull LocalInspectionToolWrapper toolWrapper) {
@NotNull LocalInspectionToolWrapper toolWrapper,
@NotNull InspectionManager inspectionManager,
@NotNull GlobalInspectionContextImpl context) {
PsiFile containingFile = psiElement.getContainingFile();
final ProblemsHolder holder = new ProblemsHolder(inspectionManager, containingFile, false);
final LocalInspectionTool localTool = toolWrapper.getTool();
@@ -159,7 +147,7 @@ class OfflineDescriptorResolveResult {
final int idx = offlineProblemDescriptor.getProblemIndex();
int curIdx = 0;
for (ProblemDescriptor descriptor : list) {
final PsiNamedElement member = localTool.getProblemElement(descriptor.getPsiElement());
final PsiNamedElement member = LocalDescriptorsUtil.getContainerElement(descriptor.getPsiElement(), localTool, context);
if (psiElement instanceof PsiFile || member != null && member.equals(psiElement)) {
if (curIdx == idx) {
return descriptor;