Skip to content

Commit

Permalink
HTML: add unknown boolean attribute inspection
Browse files Browse the repository at this point in the history
  • Loading branch information
zolotov committed Dec 24, 2014
1 parent c488d3e commit 4ca9b67
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,13 @@ html.inspections.non.existent.internet.resource.name=Non-existent web resource

html.inspections.unknown.tag=Unknown HTML tag
html.inspections.unknown.attribute=Unknown HTML tag attribute
html.inspections.unknown.boolean.attribute=Unknown HTML boolean tag attribute
html.inspections.unknown.tag.checkbox.title=Custom HTML tags:
html.inspections.unknown.tag.title=Edit custom tags
html.inspections.unknown.tag.attribute.checkbox.title=Custom HTML tag attributes:
html.inspections.unknown.tag.boolean.attribute.checkbox.title=Custom HTML boolean tag attributes:
html.inspections.unknown.tag.attribute.title=Edit custom attributes
html.inspections.unknown.tag.boolean.attribute.title=Edit custom boolean attributes
xml.schema.create.complex.type.intention.name=Create Complex Type {0}
xml.schema.create.attribute.intention.name=Create Attribute {0}
xml.schema.create.element.intention.name=Create Element {0}
Expand Down Expand Up @@ -130,6 +133,7 @@ no.ignored.resources=No ignored resources
custom.html.tag=Custom Html Tag
add.custom.html.tag=Add {0} to custom html tags
add.custom.html.attribute=Add {0} to custom html attributes
add.custom.html.boolean.attribute=Add {0} to custom html boolean attributes
add.optional.html.attribute=Add {0} to not required html attributes
fix.html.family=Fix Html

Expand Down
3 changes: 3 additions & 0 deletions platform/platform-resources/src/META-INF/XmlPlugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@
<localInspection language="XML" shortName="HtmlUnknownAttribute" bundle="messages.XmlBundle" key="html.inspections.unknown.attribute" groupName="HTML"
enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.codeInspection.htmlInspections.HtmlUnknownAttributeInspection"/>
<localInspection language="XML" bundle="messages.XmlBundle" key="html.inspections.unknown.boolean.attribute" groupName="HTML"
enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.codeInspection.htmlInspections.HtmlUnknownBooleanAttributeInspection"/>
<localInspection language="XML" shortName="XmlUnboundNsPrefix" bundle="messages.XmlBundle" key="xml.inspections.unbound.prefix"
groupKey="xml.inspections.group.name" enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.codeInsight.daemon.impl.analysis.XmlUnboundNsPrefixInspection"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

import com.intellij.codeInsight.daemon.impl.analysis.CreateNSDeclarationIntentionFix;
import com.intellij.codeInsight.daemon.impl.analysis.InsertRequiredAttributeFix;
import com.intellij.codeInspection.htmlInspections.AddAttributeValueIntentionFix;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlToken;
import org.jetbrains.annotations.NotNull;
Expand All @@ -35,4 +37,10 @@ public LocalQuickFixAndIntentionActionOnPsiElement insertRequiredAttributeFix(@N
public LocalQuickFix createNSDeclarationIntentionFix(@NotNull PsiElement element, @NotNull String namespacePrefix, @Nullable XmlToken token) {
return new CreateNSDeclarationIntentionFix(element, namespacePrefix, token);
}

@NotNull
@Override
public LocalQuickFixAndIntentionActionOnPsiElement addAttributeValueFix(@NotNull XmlAttribute attribute) {
return new AddAttributeValueIntentionFix(attribute);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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.
*/

package com.intellij.codeInspection.htmlInspections;

import com.intellij.codeInsight.AutoPopupController;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.XmlErrorMessages;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.XmlElementFactory;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class AddAttributeValueIntentionFix extends LocalQuickFixAndIntentionActionOnPsiElement {
public AddAttributeValueIntentionFix(@Nullable PsiElement element) {
super(element);
}

@NotNull
@Override
public String getText() {
return XmlErrorMessages.message("add.attribute.value.quickfix.text");
}

@Override
@NotNull
public String getFamilyName() {
return getName();
}

@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable("is null when called from inspection") final Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final XmlAttribute attribute = PsiTreeUtil.getNonStrictParentOfType(startElement, XmlAttribute.class);
if (attribute == null || attribute.getValue() != null) {
return;
}

if (!FileModificationService.getInstance().prepareFileForWrite(attribute.getContainingFile())) {
return;
}

new WriteCommandAction(project) {
@Override
protected void run(@NotNull final Result result) {
final XmlAttribute attributeWithValue = XmlElementFactory.getInstance(getProject()).createXmlAttribute(attribute.getName(), "");
final PsiElement newAttribute = attribute.replace(attributeWithValue);

if (editor != null && newAttribute != null && newAttribute instanceof XmlAttribute && newAttribute.isValid()) {
final XmlAttributeValue valueElement = ((XmlAttribute)newAttribute).getValueElement();
if (valueElement != null) {
editor.getCaretModel().moveToOffset(valueElement.getTextOffset());
AutoPopupController.getInstance(newAttribute.getProject()).scheduleAutoPopup(editor);
}
}
}
}.execute();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* 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.
*/

package com.intellij.codeInspection.htmlInspections;

import org.jetbrains.annotations.Nullable;

import javax.swing.*;

public class HtmlUnknownBooleanAttributeInspection extends HtmlUnknownBooleanAttributeInspectionBase {

public HtmlUnknownBooleanAttributeInspection() {
super("");
}

@Nullable
@Override
public JComponent createOptionsPanel() {
return HtmlUnknownTagInspection.createOptionsPanel(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.intellij.openapi.components.ServiceManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlToken;
import org.jetbrains.annotations.NotNull;
Expand All @@ -34,4 +35,7 @@ public static XmlQuickFixFactory getInstance() {
public abstract LocalQuickFix createNSDeclarationIntentionFix(@NotNull final PsiElement element,
@NotNull String namespacePrefix,
@Nullable final XmlToken token);

@NotNull
public abstract LocalQuickFixAndIntentionActionOnPsiElement addAttributeValueFix(@NotNull XmlAttribute attribute);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<html>
<body>
This inspection highlights HTML none-boolean tag attributes without value as invalid, and lets mark such attributes as Custom to avoid highlighting them as
invalid.<br>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.intellij.codeInsight.intention.QuickFixes;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlToken;
import org.jetbrains.annotations.NotNull;
Expand All @@ -38,4 +39,10 @@ public LocalQuickFix createNSDeclarationIntentionFix(@NotNull PsiElement element
@Nullable XmlToken token) {
return QuickFixes.EMPTY_ACTION;
}

@NotNull
@Override
public LocalQuickFixAndIntentionActionOnPsiElement addAttributeValueFix(@NotNull XmlAttribute attribute) {
return QuickFixes.EMPTY_FIX;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* 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.
*/
package com.intellij.codeInspection.htmlInspections;

import com.intellij.codeInsight.daemon.XmlErrorMessages;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.XmlQuickFixFactory;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlBundle;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

public abstract class HtmlUnknownBooleanAttributeInspectionBase extends HtmlUnknownElementInspection {
private static final Key<HtmlUnknownElementInspection> BOOLEAN_ATTRIBUTE_KEY = Key.create(BOOLEAN_ATTRIBUTE_SHORT_NAME);
private static final Logger LOG = Logger.getInstance(HtmlUnknownBooleanAttributeInspectionBase.class);

public HtmlUnknownBooleanAttributeInspectionBase(String defaultValues) {
super(defaultValues);
}

@Override
@Nls
@NotNull
public String getDisplayName() {
return XmlBundle.message("html.inspections.unknown.boolean.attribute");
}

@Override
@NonNls
@NotNull
public String getShortName() {
return BOOLEAN_ATTRIBUTE_SHORT_NAME;
}

@Override
protected String getCheckboxTitle() {
return XmlBundle.message("html.inspections.unknown.tag.boolean.attribute.checkbox.title");
}

@NotNull
@Override
protected String getPanelTitle() {
return XmlBundle.message("html.inspections.unknown.tag.boolean.attribute.title");
}

@Override
@NotNull
protected Logger getLogger() {
return LOG;
}

@Override
protected void checkAttribute(@NotNull final XmlAttribute attribute, @NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
if (attribute.getValueElement() == null) {
final XmlTag tag = attribute.getParent();

if (tag instanceof HtmlTag) {
XmlElementDescriptor elementDescriptor = tag.getDescriptor();
if (elementDescriptor == null || elementDescriptor instanceof AnyXmlElementDescriptor) {
return;
}

XmlAttributeDescriptor attributeDescriptor = elementDescriptor.getAttributeDescriptor(attribute);
if (attributeDescriptor != null) {
String name = attribute.getName();
if (!HtmlUtil.isBooleanAttribute(attributeDescriptor) && (!isCustomValuesEnabled() || !isCustomValue(name))) {
LocalQuickFix[] quickFixes = new LocalQuickFix[]{
new AddCustomHtmlElementIntentionAction(BOOLEAN_ATTRIBUTE_KEY, name, XmlBundle.message("add.custom.html.boolean.attribute", name)),
XmlQuickFixFactory.getInstance().addAttributeValueFix(attribute),
new RemoveAttributeIntentionAction(name),
};

registerProblemOnAttributeName(attribute, XmlErrorMessages.message("attribute.is.not.boolean", attribute.getName()), holder,
quickFixes);
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ wrong.root.element=Wrong root element
unbound.namespace=Namespace ''{0}'' is not bound
unbound.namespace.no.param=Namespace is not bound
attribute.is.not.allowed.here=Attribute {0} is not allowed here
attribute.is.not.boolean=Attribute {0} is not boolean
empty.attribute.is.not.allowed=Empty attribute {0} is not allowed
duplicate.attribute=Duplicate attribute {0}
duplicate.id.reference=Duplicate id reference
Expand All @@ -27,6 +28,7 @@ insert.required.attribute.quickfix.text=Insert required attribute {0}
insert.required.attribute.quickfix.family=Insert required attribute
remove.attribute.quickfix.text=Remove attribute {0}
remove.attribute.quickfix.family=Remove attribute
add.attribute.value.quickfix.text=Add attribute value
remove.extra.closing.tag.quickfix=Remove extra closing tag
create.namespace.declaration.quickfix=Create {0} declaration
select.namespace.title={0} To Import
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Date: 16-Dec-2005
*/
public interface XmlEntitiesInspection {
@NonNls String BOOLEAN_ATTRIBUTE_SHORT_NAME = "HtmlUnknownBooleanAttribute";
@NonNls String ATTRIBUTE_SHORT_NAME = "HtmlUnknownAttribute";
@NonNls String TAG_SHORT_NAME = "HtmlUnknownTag";
@NonNls String REQUIRED_ATTRIBUTES_SHORT_NAME = "RequiredAttributes";
Expand Down
Loading

0 comments on commit 4ca9b67

Please sign in to comment.