IDEA-199839 Support deprecation in xsd schemas

This commit is contained in:
Dmitry Avdeev
2018-10-04 14:46:41 +03:00
parent 3a15ba8021
commit 8d78ec1a0f
9 changed files with 109 additions and 23 deletions
@@ -172,6 +172,7 @@ xml.inspections.unused.schema.remove=Remove unused namespace declaration
xml.inspections.path.resolve=File path resolving in XML
xml.inspections.default.attribute.value=Redundant default attribute value assignment
xml.inspections.deprecated=Deprecated elements
xml.inspections.global=XML highlighting
@@ -438,6 +438,10 @@
bundle="messages.XmlBundle" key="xml.inspections.default.attribute.value"
groupBundle="messages.XmlBundle" groupKey="xml.inspections.group.name"
implementationClass="com.intellij.codeInsight.daemon.impl.analysis.XmlDefaultAttributeValueInspection"/>
<localInspection language="XML" enabledByDefault="true" level="WARNING"
bundle="messages.XmlBundle" key="xml.inspections.deprecated"
groupBundle="messages.XmlBundle" groupKey="xml.inspections.group.name"
implementationClass="com.intellij.codeInsight.daemon.impl.analysis.XmlDeprecatedElementInspection"/>
<localInspection language="XML" shortName="CheckEmptyScriptTag" enabledByDefault="true" level="WARNING"
bundle="messages.XmlBundle" key="html.inspections.check.empty.tag"
@@ -92,7 +92,7 @@ public class XmlDocumentationProvider implements DocumentationProvider {
@Override
public String generateDoc(PsiElement element, final PsiElement originalElement) {
if (element instanceof XmlElementDecl) {
PsiElement curElement = findPreviousComment(element);
PsiElement curElement = XmlUtil.findPreviousComment(element);
if (curElement!=null) {
return formatDocFromComment(curElement, ((XmlElementDecl)element).getNameElement().getText());
@@ -138,7 +138,7 @@ public class XmlDocumentationProvider implements DocumentationProvider {
}
}
if (processor.result == null) {
final PsiElement comment = findPreviousComment(element);
final PsiElement comment = XmlUtil.findPreviousComment(element);
if (comment != null) {
return formatDocFromComment(comment, ((XmlTag)element).getName());
}
@@ -153,7 +153,7 @@ public class XmlDocumentationProvider implements DocumentationProvider {
} else if (element instanceof XmlAttributeDecl) {
// Check for comment before attlist, it should not be right after previous declaration
final PsiElement parent = element.getParent();
final PsiElement previousComment = findPreviousComment(parent);
final PsiElement previousComment = XmlUtil.findPreviousComment(parent);
final String referenceName = ((XmlAttributeDecl)element).getNameElement().getText();
if (previousComment instanceof PsiComment) {
@@ -249,26 +249,6 @@ public class XmlDocumentationProvider implements DocumentationProvider {
return null;
}
@Nullable
public static PsiElement findPreviousComment(final PsiElement element) {
PsiElement curElement = element;
while(curElement!=null && !(curElement instanceof XmlComment)) {
curElement = curElement.getPrevSibling();
if (curElement instanceof XmlText && StringUtil.isEmptyOrSpaces(curElement.getText())) {
continue;
}
if (!(curElement instanceof PsiWhiteSpace) &&
!(curElement instanceof XmlProlog) &&
!(curElement instanceof XmlComment)
) {
curElement = null; // finding comment fails, we found another similar declaration
break;
}
}
return curElement;
}
private String formatDocFromComment(final PsiElement curElement, final String name) {
String text = curElement.getText();
text = text.substring("<!--".length(),text.length()-"-->".length()).trim();
@@ -16,6 +16,7 @@
package com.intellij.codeInsight.daemon;
import com.intellij.codeInsight.daemon.impl.analysis.XmlDefaultAttributeValueInspection;
import com.intellij.codeInsight.daemon.impl.analysis.XmlDeprecatedElementInspection;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.ide.highlighter.HtmlFileType;
import com.intellij.ide.highlighter.XmlFileType;
@@ -72,6 +73,11 @@ public class XmlInspectionsTest extends LightPlatformCodeInsightFixtureTestCase
myFixture.testHighlighting("def.xml", "def.xsd");
}
public void testDeprecations() {
myFixture.enableInspections(new XmlDeprecatedElementInspection());
myFixture.testHighlighting("deprecated.xml", "deprecated.xsd");
}
@Override
protected String getTestDataPath() {
return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/') + "/xml/tests/testData/xml";
+3
View File
@@ -0,0 +1,3 @@
<root xmlns="test.deprecated" <warning descr="The attribute is marked as deprecated">deprecated</warning>="">
<<warning descr="The tag is marked as deprecated">deprecated</warning>/>
</root>
+12
View File
@@ -0,0 +1,12 @@
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="test.deprecated" elementFormDefault="qualified">
<element name="root">
<complexType>
<sequence>
<!-- deprecated -->
<element name="deprecated"/>
</sequence>
<!-- deprecated -->
<attribute name="deprecated"/>
</complexType>
</element>
</schema>
@@ -0,0 +1,6 @@
<html>
<body>
This inspection checks for deprecated XML elements.
<p>The elements can be marked by XML comment or documentation tag with text "deprecated".
</body>
</html>
@@ -0,0 +1,54 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.daemon.impl.analysis;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.XmlSuppressableInspectionTool;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.XmlElementVisitor;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlChildRole;
import com.intellij.psi.xml.XmlTag;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Locale;
public class XmlDeprecatedElementInspection extends XmlSuppressableInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new XmlElementVisitor() {
@Override
public void visitXmlTag(XmlTag tag) {
if (checkDeprecated(tag.getDescriptor())) {
ASTNode nameNode = XmlChildRole.START_TAG_NAME_FINDER.findChild(tag.getNode());
if (nameNode != null) {
holder.registerProblem(nameNode.getPsi(), "The tag is marked as deprecated", ProblemHighlightType.LIKE_DEPRECATED);
}
}
}
@Override
public void visitXmlAttribute(XmlAttribute attribute) {
if (checkDeprecated(attribute.getDescriptor())) {
holder.registerProblem(attribute.getNameElement(), "The attribute is marked as deprecated", ProblemHighlightType.LIKE_DEPRECATED);
}
}
};
}
private static boolean checkDeprecated(@Nullable PsiMetaData metaData) {
if (metaData == null) return false;
PsiElement declaration = metaData.getDeclaration();
if (declaration == null) return false;
PsiElement comment = XmlUtil.findPreviousComment(declaration);
if (comment == null) return false;
return StringUtil.trimStart(comment.getText(), "<!--").toLowerCase(Locale.ENGLISH).trim().startsWith("deprecated");
}
}
@@ -1413,6 +1413,26 @@ public class XmlUtil {
return descriptor != null && !(descriptor instanceof AnyXmlElementDescriptor);
}
@Nullable
public static PsiElement findPreviousComment(final PsiElement element) {
PsiElement curElement = element;
while(curElement!=null && !(curElement instanceof XmlComment)) {
curElement = curElement.getPrevSibling();
if (curElement instanceof XmlText && StringUtil.isEmptyOrSpaces(curElement.getText())) {
continue;
}
if (!(curElement instanceof PsiWhiteSpace) &&
!(curElement instanceof XmlProlog) &&
!(curElement instanceof XmlComment)
) {
curElement = null; // finding comment fails, we found another similar declaration
break;
}
}
return curElement;
}
public interface DuplicationInfoProvider<T extends PsiElement> {
@Nullable
String getName(@NotNull T t);