mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
IDEA-337197 Throwable: the expensive method should not be called inside the highlighting pass in JSP
check unresolved references in a dedicated XmlUnresolvedReferenceInspection GitOrigin-RevId: d54b7a0b933c33c8656726c84a9611c97c1268ff
This commit is contained in:
committed by
intellij-monorepo-bot
parent
63045881e6
commit
6ba55541ee
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports an unresolved references in XML.
|
||||
</body>
|
||||
</html>
|
||||
@@ -33,6 +33,6 @@ public class HtmlUnknownAnchorTargetInspection extends XmlPathReferenceInspectio
|
||||
|
||||
@Override
|
||||
protected boolean needToCheckRef(PsiReference reference) {
|
||||
return reference instanceof AnchorReference && HtmlUnknownTargetInspection.notRemoteBase(reference);
|
||||
return super.needToCheckRef(reference) && reference instanceof AnchorReference && HtmlUnknownTargetInspection.notRemoteBase(reference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class HtmlUnknownTargetInspection extends XmlPathReferenceInspection {
|
||||
|
||||
@Override
|
||||
protected boolean needToCheckRef(PsiReference reference) {
|
||||
return !(reference instanceof AnchorReference) && notRemoteBase(reference);
|
||||
return super.needToCheckRef(reference) && !(reference instanceof AnchorReference) && notRemoteBase(reference);
|
||||
}
|
||||
|
||||
static boolean notRemoteBase(PsiReference reference) {
|
||||
|
||||
@@ -27,8 +27,8 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.html.HtmlTag;
|
||||
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceOwner;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.PsiFileReference;
|
||||
import com.intellij.psi.impl.source.resolve.reference.impl.providers.*;
|
||||
import com.intellij.psi.impl.source.xml.TagNameReference;
|
||||
import com.intellij.psi.meta.PsiMetaData;
|
||||
import com.intellij.psi.templateLanguages.OuterLanguageElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -440,7 +440,7 @@ public class XmlHighlightVisitor extends XmlElementVisitor implements HighlightV
|
||||
for (int i = start; i < references.length; ++i) {
|
||||
PsiReference reference = references[i];
|
||||
ProgressManager.checkCanceled();
|
||||
if (isUrlReference(reference)) continue;
|
||||
if (!shouldCheckResolve(reference)) continue;
|
||||
if (!hasBadResolve(reference, false)) {
|
||||
continue;
|
||||
}
|
||||
@@ -484,6 +484,14 @@ public class XmlHighlightVisitor extends XmlElementVisitor implements HighlightV
|
||||
}
|
||||
}
|
||||
|
||||
static boolean shouldCheckResolve(PsiReference reference) {
|
||||
return reference instanceof TypeOrElementOrAttributeReference ||
|
||||
reference instanceof DependentNSReference ||
|
||||
reference instanceof URLReference ||
|
||||
reference instanceof TagNameReference ||
|
||||
reference instanceof PsiReferenceWithUnresolvedQuickFixes;
|
||||
}
|
||||
|
||||
static boolean isUrlReference(PsiReference reference) {
|
||||
return reference instanceof FileReferenceOwner || reference instanceof AnchorReference || reference instanceof PsiFileReference;
|
||||
}
|
||||
|
||||
@@ -1,111 +1,15 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.XmlSuppressableInspectionTool;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.XmlElementVisitor;
|
||||
import com.intellij.psi.xml.XmlAttributeValue;
|
||||
import com.intellij.psi.xml.XmlDoctype;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Dmitry Avdeev
|
||||
*/
|
||||
public class XmlPathReferenceInspection extends XmlSuppressableInspectionTool {
|
||||
@NotNull
|
||||
public class XmlPathReferenceInspection extends XmlReferenceInspectionBase {
|
||||
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
|
||||
return new XmlElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlAttributeValue(@NotNull XmlAttributeValue value) {
|
||||
checkRefs(value, holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlDoctype(@NotNull XmlDoctype xmlDoctype) {
|
||||
checkRefs(xmlDoctype, holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlTag(@NotNull XmlTag tag) {
|
||||
checkRefs(tag, holder);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void checkRefs(@NotNull XmlElement element, @NotNull ProblemsHolder holder) {
|
||||
PsiReference[] references = element.getReferences();
|
||||
if (references.length == 0) {
|
||||
return;
|
||||
}
|
||||
if (XmlHighlightVisitor.isInjectedWithoutValidation(element)) {
|
||||
return;
|
||||
}
|
||||
boolean isHtml = HtmlUtil.isHtmlTagContainingFile(element);
|
||||
if (isHtml ^ isForHtml()) {
|
||||
return;
|
||||
}
|
||||
if (!isHtml && XmlHighlightVisitor.skipValidation(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<PsiReference> unresolved = getUnresolvedReferencesToAnnotate(references);
|
||||
for (PsiReference reference : unresolved) {
|
||||
holder.registerProblem(reference, ProblemsHolder.unresolvedReferenceMessage(reference),
|
||||
isHtml ? ProblemHighlightType.GENERIC_ERROR_OR_WARNING : ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<PsiReference> getUnresolvedReferencesToAnnotate(PsiReference[] references) {
|
||||
Map<TextRange, PsiReference> unresolvedReferences = new HashMap<>();
|
||||
for (PsiReference reference : references) {
|
||||
if (!XmlHighlightVisitor.isUrlReference(reference) || !needToCheckRef(reference)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TextRange elementRange = reference.getElement().getTextRange();
|
||||
if (elementRange == null || elementRange.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TextRange rangeInElement = reference.getRangeInElement();
|
||||
if (unresolvedReferences.containsKey(rangeInElement) && unresolvedReferences.get(rangeInElement) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (XmlHighlightVisitor.hasBadResolve(reference, true)) {
|
||||
if (!reference.isSoft()) {
|
||||
unresolvedReferences.putIfAbsent(rangeInElement, reference);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the specific range has at least one resolved reference
|
||||
// no need to check any other references from that range
|
||||
unresolvedReferences.put(rangeInElement, null);
|
||||
}
|
||||
}
|
||||
|
||||
return ContainerUtil.skipNulls(unresolvedReferences.values());
|
||||
}
|
||||
|
||||
protected boolean needToCheckRef(PsiReference reference) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isForHtml() {
|
||||
return false;
|
||||
return XmlHighlightVisitor.isUrlReference(reference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.XmlSuppressableInspectionTool;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.XmlElementVisitor;
|
||||
import com.intellij.psi.xml.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.xml.util.HtmlUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class XmlReferenceInspectionBase extends XmlSuppressableInspectionTool {
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
|
||||
return new XmlElementVisitor() {
|
||||
@Override
|
||||
public void visitXmlAttributeValue(@NotNull XmlAttributeValue value) {
|
||||
checkRefs(value, holder, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlAttribute(@NotNull XmlAttribute attribute) {
|
||||
int startIndex = !attribute.getNamespacePrefix().isEmpty() ? 2 : 1;
|
||||
checkRefs(attribute, holder, startIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlDoctype(@NotNull XmlDoctype xmlDoctype) {
|
||||
checkRefs(xmlDoctype, holder, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlTag(@NotNull XmlTag tag) {
|
||||
checkRefs(tag, holder, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitXmlProcessingInstruction(@NotNull XmlProcessingInstruction processingInstruction) {
|
||||
checkRefs(processingInstruction, holder, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void checkRefs(@NotNull XmlElement element, @NotNull ProblemsHolder holder, int startIndex) {
|
||||
PsiReference[] references = element.getReferences();
|
||||
if (references.length <= startIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (XmlHighlightVisitor.isInjectedWithoutValidation(element)) {
|
||||
return;
|
||||
}
|
||||
boolean isHtml = HtmlUtil.isHtmlTagContainingFile(element);
|
||||
if (!checkHtml(element, isHtml)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<PsiReference> unresolved = getUnresolvedReferencesToAnnotate(Arrays.copyOfRange(references, startIndex, references.length));
|
||||
for (PsiReference reference : unresolved) {
|
||||
holder.registerProblem(reference, ProblemsHolder.unresolvedReferenceMessage(reference),
|
||||
isHtml ? ProblemHighlightType.GENERIC_ERROR_OR_WARNING : ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkHtml(@NotNull XmlElement element, boolean isHtml) {
|
||||
if (isHtml ^ isForHtml()) {
|
||||
return false;
|
||||
}
|
||||
if (!isHtml && XmlHighlightVisitor.skipValidation(element)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Collection<PsiReference> getUnresolvedReferencesToAnnotate(PsiReference[] references) {
|
||||
Map<TextRange, PsiReference> unresolvedReferences = new HashMap<>();
|
||||
for (PsiReference reference : references) {
|
||||
if (!needToCheckRef(reference)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!checkRanges()) {
|
||||
if (XmlHighlightVisitor.hasBadResolve(reference, false)) {
|
||||
unresolvedReferences.put(reference.getRangeInElement(), reference);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
TextRange elementRange = reference.getElement().getTextRange();
|
||||
if (elementRange == null || elementRange.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TextRange rangeInElement = reference.getRangeInElement();
|
||||
if (unresolvedReferences.containsKey(rangeInElement) && unresolvedReferences.get(rangeInElement) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (XmlHighlightVisitor.hasBadResolve(reference, true)) {
|
||||
if (!reference.isSoft()) {
|
||||
unresolvedReferences.putIfAbsent(rangeInElement, reference);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the specific range has at least one resolved reference
|
||||
// no need to check any other references from that range
|
||||
unresolvedReferences.put(rangeInElement, null);
|
||||
}
|
||||
}
|
||||
|
||||
return ContainerUtil.skipNulls(unresolvedReferences.values());
|
||||
}
|
||||
|
||||
protected boolean checkRanges() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract boolean needToCheckRef(PsiReference reference);
|
||||
|
||||
protected boolean isForHtml() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.daemon.impl.analysis
|
||||
|
||||
import com.intellij.codeInsight.quickfix.UnresolvedReferenceQuickFixProvider
|
||||
import com.intellij.psi.PsiReference
|
||||
import com.intellij.psi.xml.XmlElement
|
||||
|
||||
class XmlUnresolvedReferenceInspection: XmlReferenceInspectionBase() {
|
||||
override fun needToCheckRef(reference: PsiReference?) = !XmlHighlightVisitor.shouldCheckResolve(reference) &&
|
||||
!XmlHighlightVisitor.isUrlReference(reference)
|
||||
|
||||
override fun checkRanges() = false
|
||||
|
||||
override fun checkHtml(element: XmlElement, isHtml: Boolean) = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker interface for references associated with [UnresolvedReferenceQuickFixProvider],
|
||||
* which should be checked by [XmlHighlightVisitor]
|
||||
*/
|
||||
interface PsiReferenceWithUnresolvedQuickFixes: PsiReference
|
||||
Reference in New Issue
Block a user