Javafx: Add inspection in FXML to validate that RGB color components are in valid range (IDEA-103956)

This commit is contained in:
Pavel Dolgov
2016-03-11 18:22:45 +03:00
parent 8873b64d42
commit 5bc0d94602
6 changed files with 170 additions and 0 deletions
@@ -0,0 +1,34 @@
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.openapi.application.PluginPathManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxColorRgbInspection;
/**
* @author Pavel.Dolgov
*/
public class JavaFxColorRgbInspectionTest extends AbstractJavaFXTestCase {
@Override
protected void enableInspections() {
myFixture.enableInspections(new JavaFxColorRgbInspection());
}
public void testAttributeHighlighting() throws Exception {
doTestHighlighting();
}
public void testTagHighlighting() throws Exception {
doTestHighlighting();
}
private void doTestHighlighting() {
myFixture.configureByFiles(getTestName(true) + ".fxml");
myFixture.checkHighlighting();
}
@NotNull
@Override
protected String getTestDataPath() {
return PluginPathManager.getPluginHomePath("javaFX") + "/testData/inspections/colorRgb/";
}
}
@@ -0,0 +1,7 @@
<html>
<body>
This inspection reports RGB color components which are out of valid range.
<!-- tooltip end -->
<p>
</body>
</html>
@@ -24,6 +24,8 @@
enabledByDefault="true" level="WARNING" displayName="JavaFX unused imports" groupName="JavaFX"/>
<localInspection language="XML" shortName="JavaFxRedundantPropertyValue" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxRedundantPropertyValueInspection"
enabledByDefault="true" level="WARNING" displayName="JavaFX redundant property values" groupName="JavaFX"/>
<localInspection language="XML" shortName="JavaFxColorRgb" displayName="Color component is out of range" groupName="JavaFX"
enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxColorRgbInspection"/>
<applicationService serviceInterface="org.jetbrains.plugins.javaFX.JavaFxSettings" serviceImplementation="org.jetbrains.plugins.javaFX.JavaFxSettings"/>
<applicationConfigurable groupId="language" displayName="JavaFX" id="preferences.JavaFX" instance="org.jetbrains.plugins.javaFX.JavaFxSettingsConfigurable"/>
@@ -0,0 +1,84 @@
package org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.XmlSuppressableInspectionTool;
import com.intellij.psi.*;
import com.intellij.psi.xml.*;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyAttributeDescriptor;
import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyElementDescriptor;
/**
* @author Pavel.Dolgov
*/
public class JavaFxColorRgbInspection extends XmlSuppressableInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new XmlElementVisitor() {
@Override
public void visitXmlFile(XmlFile file) {
if (!JavaFxFileTypeFactory.isFxml(file)) return;
super.visitXmlFile(file);
}
@Override
public void visitXmlAttribute(XmlAttribute attribute) {
super.visitXmlAttribute(attribute);
final String attributeValue = attribute.getValue();
if (attributeValue == null) return;
final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
if (descriptor instanceof JavaFxPropertyAttributeDescriptor) {
final PsiClass psiClass = ((JavaFxPropertyAttributeDescriptor)descriptor).getPsiClass();
if (JavaFxCommonNames.JAVAFX_SCENE_COLOR.equals(psiClass.getQualifiedName())) {
final XmlAttributeValue valueElement = attribute.getValueElement();
final PsiElement location = valueElement != null ? valueElement : attribute;
validateColorComponent(psiClass, attribute.getName(), attributeValue, location);
}
}
}
@Override
public void visitXmlTag(XmlTag tag) {
super.visitXmlTag(tag);
if (tag.getSubTags().length != 0) return;
final XmlElementDescriptor descriptor = tag.getDescriptor();
if (descriptor instanceof JavaFxPropertyElementDescriptor) {
final PsiClass psiClass = ((JavaFxPropertyElementDescriptor)descriptor).getPsiClass();
if (JavaFxCommonNames.JAVAFX_SCENE_COLOR.equals(psiClass.getQualifiedName())) {
final XmlTagValue valueElement = tag.getValue();
final XmlText[] textElements = valueElement.getTextElements();
final PsiElement location = textElements.length == 1 ? textElements[0] : tag;
validateColorComponent(psiClass, tag.getName(), valueElement.getTrimmedText(), location);
}
}
}
private void validateColorComponent(@NotNull PsiClass psiClass,
@NotNull String propertyName,
@NotNull String propertyValue,
@NotNull PsiElement location) {
final PsiMember declaration = JavaFxPsiUtil.collectProperties(psiClass).get(propertyName);
final String boxedQName = JavaFxPsiUtil.getBoxedPropertyType(psiClass, declaration);
if (CommonClassNames.JAVA_LANG_FLOAT.equals(boxedQName) || CommonClassNames.JAVA_LANG_DOUBLE.equals(boxedQName)) {
try {
double value = Double.parseDouble(propertyValue);
if (value < 0.0 || value > 1.0) {
holder.registerProblem(location, "Color component has to be a number between 0.0 and 1.0, inclusively");
}
}
catch (NumberFormatException ignored) {
}
}
}
};
}
}
@@ -0,0 +1,18 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.paint.Color?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<Label text="Red">
<textFill>
<Color red="0.9" green="0.1" blue="0.2" opacity="0.99"/>
</textFill>
</Label>
<Label text="Bad">
<textFill>
<Color red=<warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">"1.9"</warning>
green=<warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">"-0.1"</warning>
blue=<warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">"Infinity"</warning>
opacity=<warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">"-Infinity"</warning>/>
</textFill>
</Label>
</GridPane>
@@ -0,0 +1,25 @@
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.paint.Color?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<Label text="Red">
<textFill>
<Color>
<red>0.9</red>
<green>0.1</green>
<blue>0.2</blue>
<opacity>0.99</opacity>
</Color>
</textFill>
</Label>
<Label text="Bad">
<textFill>
<Color>
<red><warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">1.9</warning></red>
<green><warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">-0.1</warning></green>
<blue><warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">Infinity</warning></blue>
<opacity><warning descr="Color component has to be a number between 0.0 and 1.0, inclusively">-Infinity</warning></opacity>
</Color>
</textFill>
</Label>
</GridPane>