Javafx: Resolve $null symbol and ${null} expression in FXML (IDEA-112153)

This commit is contained in:
Pavel Dolgov
2016-06-14 16:18:53 +03:00
parent cc86e8fe17
commit 528c63497e
7 changed files with 60 additions and 3 deletions
@@ -374,6 +374,14 @@ public class JavaFXHighlightingTest extends AbstractJavaFXTestCase {
doTest();
}
public void testNullObjectValue() throws Exception {
doTest();
}
public void testNullPrimitiveValue() throws Exception {
doTest();
}
public void testFactoryMethod() throws Exception {
doTest();
}
@@ -15,8 +15,10 @@
*/
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@@ -51,6 +53,9 @@ public class FxmlConstants {
@NonNls public static final String SOURCE = "source";
@NonNls public static final String NULL_EXPRESSION = "${null}";
@NonNls private static final String NULL_VALUE = "$null";
public static final Set<String> FX_BUILT_IN_ATTRIBUTES =
ContainerUtil.immutableSet(FX_ID, FX_CONTROLLER, VALUE, FX_VALUE, FX_FACTORY, FX_CONSTANT);
@@ -71,4 +76,7 @@ public class FxmlConstants {
.put(FX_COPY, Collections.singletonList(SOURCE))
.build();
public static boolean isNullValue(@NotNull String value) {
return NULL_VALUE.equals(StringUtil.trimTrailing(value));
}
}
@@ -38,6 +38,7 @@ import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -804,11 +805,19 @@ public class JavaFxPsiUtil {
@Nullable
public static PsiClass getWritablePropertyClass(@Nullable XmlAttributeValue xmlAttributeValue) {
if (xmlAttributeValue != null) {
return getPropertyClass(getWritablePropertyType(xmlAttributeValue), xmlAttributeValue);
}
return null;
}
@Nullable
public static PsiType getWritablePropertyType(@Nullable XmlAttributeValue xmlAttributeValue) {
final PsiClass tagClass = getTagClass(xmlAttributeValue);
if (tagClass != null) {
final PsiElement declaration = getAttributeDeclaration(xmlAttributeValue);
if (declaration != null) {
return getPropertyClass(getWritablePropertyType(tagClass, declaration), xmlAttributeValue);
return getWritablePropertyType(tagClass, declaration);
}
}
return null;
@@ -843,6 +852,7 @@ public class JavaFxPsiUtil {
return null;
}
@Contract("null->false")
public static boolean isPrimitiveOrBoxed(@Nullable PsiType psiType) {
return psiType instanceof PsiPrimitiveType || PsiPrimitiveType.getUnboxedType(psiType) != null;
}
@@ -9,6 +9,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.xml.impl.BasicXmlAttributeDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
@@ -129,6 +130,9 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript
if (value.startsWith("$")) {
return validatePropertyExpression(xmlAttributeValue, value);
}
else if (StringUtil.trimLeading(value).startsWith("$")) {
return "Spaces aren't allowed before property or expression";
}
else {
return validateLiteral(xmlAttributeValue, value);
}
@@ -160,9 +164,17 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript
if (isIncompletePropertyChain(propertyNames)) {
return "Incorrect expression syntax";
}
if (FxmlConstants.NULL_EXPRESSION.equals(value)) return null;
final XmlTag currentTag = PsiTreeUtil.getParentOfType(xmlAttributeValue, XmlTag.class);
final PsiClass targetPropertyClass = JavaFxPsiUtil.getWritablePropertyClass(xmlAttributeValue);
final PsiType targetPropertyType = JavaFxPsiUtil.getWritablePropertyType(xmlAttributeValue);
if (FxmlConstants.isNullValue(value)) {
if (JavaFxPsiUtil.isPrimitiveOrBoxed(targetPropertyType)) {
return "Unable to coerce to " + targetPropertyType.getPresentableText();
}
return null;
}
final PsiClass targetPropertyClass = JavaFxPsiUtil.getPropertyClass(targetPropertyType, xmlAttributeValue);
if (targetPropertyClass == null || JavaFxPsiUtil.hasConversionFromAnyType(targetPropertyClass)) return null;
final String firstPropertyName = propertyNames.get(0);
@@ -242,7 +254,7 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript
@Override
public PsiReference[] getValueReferences(XmlElement element, @NotNull String text) {
return !text.startsWith("${") ? super.getValueReferences(element, text) : PsiReference.EMPTY_ARRAY;
return !text.startsWith("${") && !FxmlConstants.isNullValue(text) ? super.getValueReferences(element, text) : PsiReference.EMPTY_ARRAY;
}
@Override
@@ -81,6 +81,7 @@ public class JavaFxComponentIdReferenceProvider extends PsiReferenceProvider {
@NotNull XmlAttributeValue xmlAttributeValue,
@NotNull String value,
@NotNull Map<String, XmlAttributeValue> fileIds) {
if (FxmlConstants.NULL_EXPRESSION.equals(value)) return PsiReference.EMPTY_ARRAY;
final String expressionBody = value.substring(2, value.length() - 1);
final List<String> propertyNames = StringUtil.split(expressionBody, ".", true, false);
if (JavaFxPropertyAttributeDescriptor.isIncompletePropertyChain(propertyNames)) return PsiReference.EMPTY_ARRAY;
@@ -115,6 +116,7 @@ public class JavaFxComponentIdReferenceProvider extends PsiReferenceProvider {
private static PsiReference[] getSinglePropertyReferences(@NotNull XmlAttributeValue xmlAttributeValue,
@NotNull String value,
@NotNull Map<String, XmlAttributeValue> fileIds) {
if (FxmlConstants.isNullValue(value)) return PsiReference.EMPTY_ARRAY;
return getSinglePropertyReferences(xmlAttributeValue, fileIds, value.substring(1), 1);
}
@@ -0,0 +1,9 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<VBox xmlns="http://javafx.com/javafx/8.0.91">
<Label text="${null}" textAlignment="$null "/>
<Button text="$null " tooltip="$null" textAlignment="${null}"/>
<Label text=<error descr="Spaces aren't allowed before property or expression">" ${null}"</error>/>
<Label text=<error descr="Spaces aren't allowed before property or expression">" $null"</error>/>
</VBox>
@@ -0,0 +1,8 @@
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<VBox xmlns="http://javafx.com/javafx/8.0.91">
<Button text="Button1" prefWidth=<error descr="Unable to coerce to double">"$null"</error>/>
<Button text="Button2" prefWidth="${null}"/>
<Button text="Button3" defaultButton=<error descr="Unable to coerce to boolean">"$null"</error>/>
</VBox>