diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java index d14d7c3b300a..830e9c42ae2a 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxRedundantPropertyValueInspection.java @@ -62,6 +62,8 @@ public class JavaFxRedundantPropertyValueInspection extends XmlSuppressableInspe attributeValue.startsWith("#") || attributeValue.startsWith("%") || FxmlConstants.FX_ID.equals(attributeName) || + FxmlConstants.FX_VALUE.equals(attributeName) || + FxmlConstants.FX_CONSTANT.equals(attributeName) || FxmlConstants.FX_CONTROLLER.equals(attributeName)) { return; } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInAttributeDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInAttributeDescriptor.java index 317f1bb07d33..1e7df2b75965 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInAttributeDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInAttributeDescriptor.java @@ -17,9 +17,10 @@ package org.jetbrains.plugins.javaFX.fxml.descriptors; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; -import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.xml.XmlAttributeValue; -import com.intellij.psi.xml.XmlElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.javaFX.fxml.FxmlConstants; import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil; @@ -35,27 +36,33 @@ public class JavaFxBuiltInAttributeDescriptor extends JavaFxPropertyAttributeDes private final String myParentTagName; - public JavaFxBuiltInAttributeDescriptor(String name, PsiClass psiClass) { + private JavaFxBuiltInAttributeDescriptor(String name, PsiClass psiClass) { super(name, psiClass); myParentTagName = null; } - public JavaFxBuiltInAttributeDescriptor(String name, String parentTagName) { + private JavaFxBuiltInAttributeDescriptor(String name, String parentTagName) { super(name, null); myParentTagName = parentTagName; } - @Override - public boolean hasIdType() { - return getName().equals(FxmlConstants.FX_ID); + public static JavaFxBuiltInAttributeDescriptor create(String name, PsiClass psiClass) { + if (FxmlConstants.FX_ID.equals(name)) return new FxIdAttributeDescriptor(psiClass); + if (FxmlConstants.FX_VALUE.equals(name)) return new FxValueAttributeDescriptor(psiClass); + if (FxmlConstants.FX_CONSTANT.equals(name)) return new FxConstantAttributeDescriptor(psiClass); + return new JavaFxBuiltInAttributeDescriptor(name, psiClass); + } + + public static JavaFxBuiltInAttributeDescriptor create(String name, String parentTagName) { + if (FxmlConstants.FX_ID.equals(name)) return new FxIdAttributeDescriptor(parentTagName); + if (FxmlConstants.FX_VALUE.equals(name)) return new FxValueAttributeDescriptor(parentTagName); + if (FxmlConstants.FX_CONSTANT.equals(name)) return new FxConstantAttributeDescriptor(parentTagName); + return new JavaFxBuiltInAttributeDescriptor(name, parentTagName); } @Override public boolean isEnumerated() { - final PsiClass psiClass = getPsiClass(); - if (psiClass == null) return false; - final String name = getName(); - return FxmlConstants.FX_CONSTANT.equals(name) || psiClass.isEnum() && FxmlConstants.FX_VALUE.equals(name); + return false; } @Override @@ -65,53 +72,121 @@ public class JavaFxBuiltInAttributeDescriptor extends JavaFxPropertyAttributeDes return requiredAttrs != null && requiredAttrs.contains(getName()); } - @Override - protected PsiClass getEnum() { - return isEnumerated() ? getPsiClass() : null ; - } - - protected boolean isConstant(PsiField field, boolean inEnum) { - if (inEnum) return field instanceof PsiEnumConstant; - return field.hasModifierProperty(PsiModifier.STATIC) && field.hasModifierProperty(PsiModifier.FINAL) && field.hasModifierProperty(PsiModifier.PUBLIC); - } - - @Nullable - @Override - public String validateValue(XmlElement context, String value) { - if (context instanceof XmlAttributeValue) { - final PsiElement parent = context.getParent(); - if (parent instanceof XmlAttribute) { - final XmlAttribute attribute = (XmlAttribute)parent; - final String attributeName = attribute.getName(); - if (FxmlConstants.FX_VALUE.equals(attributeName)) { - final PsiClass tagClass = JavaFxPsiUtil.getTagClass((XmlAttributeValue)context); - if (tagClass != null) { - if (tagClass.isEnum()) { - return JavaFxPsiUtil.validateEnumConstant(tagClass, value); - } - final PsiMethod method = JavaFxPsiUtil.findValueOfMethod(tagClass); - if (method == null) { - return "Unable to coerce '" + value + "' to " + tagClass.getQualifiedName() + "."; - } - } - } - else if (FxmlConstants.FX_CONSTANT.equals(attributeName)) { - final PsiClass tagClass = JavaFxPsiUtil.getTagClass((XmlAttributeValue)context); - if (tagClass != null) { - final PsiField constField = tagClass.findFieldByName(value, true); - if (constField == null) { - return "Constant '" + value + "' is not found"; - } - } - return null; - } - } - } - return super.validateValue(context, value); - } - @Override public String toString() { return myParentTagName != null ? myParentTagName + "#" + getName() : super.toString(); } + + + private static class FxIdAttributeDescriptor extends JavaFxBuiltInAttributeDescriptor { + private FxIdAttributeDescriptor(PsiClass psiClass) { + super(FxmlConstants.FX_ID, psiClass); + } + + private FxIdAttributeDescriptor(String parentTagName) { + super(FxmlConstants.FX_ID, parentTagName); + } + + @Override + public boolean hasIdType() { + return true; + } + + @Nullable + @Override + protected String validateAttributeValue(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) { + final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(xmlAttributeValue.getContainingFile()); + if (controllerClass != null) { + final PsiClass tagClass = JavaFxPsiUtil.getTagClass(xmlAttributeValue); + if (tagClass != null) { + final PsiField field = controllerClass.findFieldByName(value, true); + if (field != null && !InheritanceUtil.isInheritorOrSelf(tagClass, PsiUtil.resolveClassInType(field.getType()), true)) { + return "Cannot set " + tagClass.getQualifiedName() + " to field \'" + field.getName() + "\'"; + } + } + } + return null; + } + } + + private static class FxValueAttributeDescriptor extends JavaFxBuiltInAttributeDescriptor { + private FxValueAttributeDescriptor(PsiClass psiClass) { + super(FxmlConstants.FX_VALUE, psiClass); + } + + private FxValueAttributeDescriptor(String parentTagName) { + super(FxmlConstants.FX_VALUE, parentTagName); + } + + @Override + public boolean isEnumerated() { + final PsiClass psiClass = getPsiClass(); + return psiClass != null && psiClass.isEnum(); + } + + @Override + protected PsiClass getEnum() { + final PsiClass psiClass = getPsiClass(); + return psiClass.isEnum() ? psiClass : null; + } + + protected boolean isConstant(PsiField field) { + return field instanceof PsiEnumConstant; + } + + @Nullable + @Override + protected String validateAttributeValue(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) { + final PsiClass tagClass = JavaFxPsiUtil.getTagClass(xmlAttributeValue); + if (tagClass != null) { + if (tagClass.isEnum()) { + return JavaFxPsiUtil.validateEnumConstant(tagClass, value); + } + final PsiMethod method = JavaFxPsiUtil.findValueOfMethod(tagClass); + if (method == null) { + return "Unable to coerce '" + value + "' to " + tagClass.getQualifiedName() + "."; + } + } + return super.validateAttributeValue(xmlAttributeValue, value); + } + } + + private static class FxConstantAttributeDescriptor extends JavaFxBuiltInAttributeDescriptor { + private FxConstantAttributeDescriptor(PsiClass psiClass) { + super(FxmlConstants.FX_CONSTANT, psiClass); + } + + private FxConstantAttributeDescriptor(String parentTagName) { + super(FxmlConstants.FX_CONSTANT, parentTagName); + } + + @Override + public boolean isEnumerated() { + return getPsiClass() != null; + } + + @Override + protected PsiClass getEnum() { + return getPsiClass(); + } + + protected boolean isConstant(PsiField field) { + return field.hasModifierProperty(PsiModifier.STATIC) && + field.hasModifierProperty(PsiModifier.FINAL) && + field.hasModifierProperty(PsiModifier.PUBLIC); + } + + @Nullable + @Override + protected String validateAttributeValue(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) { + final PsiClass tagClass = JavaFxPsiUtil.getTagClass(xmlAttributeValue); + if (tagClass != null) { + final PsiField constField = tagClass.findFieldByName(value, true); + if (constField == null || !isConstant(constField)) { + return "Constant '" + value + "' is not found"; + } + } + return null; + } + } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInTagDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInTagDescriptor.java index 0b16301076d3..53ac109b5cf4 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInTagDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxBuiltInTagDescriptor.java @@ -80,7 +80,7 @@ public class JavaFxBuiltInTagDescriptor implements XmlElementDescriptor, Validat final List builtInAttributeNames = FxmlConstants.FX_BUILT_IN_TAG_SUPPORTED_ATTRIBUTES.get(getName()); if (builtInAttributeNames != null) { for (String attrName : builtInAttributeNames) { - descriptors.add(new JavaFxBuiltInAttributeDescriptor(attrName, getName())); + descriptors.add(JavaFxBuiltInAttributeDescriptor.create(attrName, getName())); } } JavaFxClassTagDescriptorBase.collectStaticAttributesDescriptors(context, descriptors); @@ -112,7 +112,7 @@ public class JavaFxBuiltInTagDescriptor implements XmlElementDescriptor, Validat final List defaultAttributeList = FxmlConstants.FX_BUILT_IN_TAG_SUPPORTED_ATTRIBUTES.get(getName()); if (defaultAttributeList != null) { if (defaultAttributeList.contains(attributeName)) { - return new JavaFxBuiltInAttributeDescriptor(attributeName, getName()); + return JavaFxBuiltInAttributeDescriptor.create(attributeName, getName()); } final PsiMethod propertySetter = JavaFxPsiUtil.findStaticPropertySetter(attributeName, context); if (propertySetter != null) { @@ -236,36 +236,29 @@ public class JavaFxBuiltInTagDescriptor implements XmlElementDescriptor, Validat @Override public void validate(@NotNull XmlTag context, @NotNull ValidationHost host) { - final String contextName = context.getName(); - if (FxmlConstants.FX_ROOT.equals(contextName)) { - if (context.getParentTag() != null) { - host.addMessage(context.getNavigationElement(), " is valid only as the root node of an FXML document", - ValidationHost.ErrorType.ERROR); - } - } else { - final XmlTag referencedTag = getReferencedTag(context); - if (referencedTag != null) { - final XmlElementDescriptor descriptor = referencedTag.getDescriptor(); - if (descriptor != null) { - final PsiElement declaration = descriptor.getDeclaration(); - if (declaration instanceof PsiClass) { - final PsiClass psiClass = (PsiClass)declaration; - JavaFxPsiUtil.isClassAcceptable(context.getParentTag(), psiClass, (errorMessage, errorType) -> - host.addMessage(context.getNavigationElement(), errorMessage, errorType)); - if (FxmlConstants.FX_COPY.equals(contextName)) { - boolean copyConstructorFound = false; - for (PsiMethod constructor : psiClass.getConstructors()) { - final PsiParameter[] parameters = constructor.getParameterList().getParameters(); - if (parameters.length == 1 && psiClass == PsiUtil.resolveClassInType(parameters[0].getType())) { - copyConstructorFound = true; - break; - } - } - if (!copyConstructorFound) { - host.addMessage(context.getNavigationElement(), "Copy constructor not found for \'" + psiClass.getName() + "\'", - ValidationHost.ErrorType.ERROR); + final XmlTag referencedTag = getReferencedTag(context); + if (referencedTag != null) { + final XmlElementDescriptor descriptor = referencedTag.getDescriptor(); + if (descriptor != null) { + final PsiElement declaration = descriptor.getDeclaration(); + if (declaration instanceof PsiClass) { + final PsiClass psiClass = (PsiClass)declaration; + JavaFxPsiUtil.isClassAcceptable(context.getParentTag(), psiClass, (errorMessage, errorType) -> + host.addMessage(context.getNavigationElement(), errorMessage, errorType)); + final String contextName = context.getName(); + if (FxmlConstants.FX_COPY.equals(contextName)) { + boolean copyConstructorFound = false; + for (PsiMethod constructor : psiClass.getConstructors()) { + final PsiParameter[] parameters = constructor.getParameterList().getParameters(); + if (parameters.length == 1 && psiClass == PsiUtil.resolveClassInType(parameters[0].getType())) { + copyConstructorFound = true; + break; } } + if (!copyConstructorFound) { + host.addMessage(context.getNavigationElement(), "Copy constructor not found for \'" + psiClass.getName() + "\'", + ValidationHost.ErrorType.ERROR); + } } } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassTagDescriptorBase.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassTagDescriptorBase.java index 2fbe497fe9ad..0d71984fd0cb 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassTagDescriptorBase.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassTagDescriptorBase.java @@ -217,7 +217,7 @@ public abstract class JavaFxClassTagDescriptorBase implements XmlElementDescript collectInstanceProperties(descriptors); collectStaticAttributesDescriptors(context, descriptors); for (String builtInAttributeName : FxmlConstants.FX_BUILT_IN_ATTRIBUTES) { - descriptors.add(new JavaFxBuiltInAttributeDescriptor(builtInAttributeName, psiClass)); + descriptors.add(JavaFxBuiltInAttributeDescriptor.create(builtInAttributeName, psiClass)); } return descriptors.isEmpty() ? XmlAttributeDescriptor.EMPTY : descriptors.toArray(XmlAttributeDescriptor.EMPTY); } @@ -244,7 +244,7 @@ public abstract class JavaFxClassTagDescriptorBase implements XmlElementDescript final PsiClass psiClass = getPsiClass(); if (psiClass == null) return null; if (FxmlConstants.FX_BUILT_IN_ATTRIBUTES.contains(attributeName)) { - return new JavaFxBuiltInAttributeDescriptor(attributeName, psiClass); + return JavaFxBuiltInAttributeDescriptor.create(attributeName, psiClass); } final PsiMethod propertySetter = JavaFxPsiUtil.findStaticPropertySetter(attributeName, context); if (propertySetter != null) { diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java index 857193a76572..4033999d169f 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyAttributeDescriptor.java @@ -4,13 +4,11 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.psi.xml.*; 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; @@ -77,7 +75,7 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript final PsiField[] fields = aClass.getAllFields(); final List enumConstants = new ArrayList(); for (PsiField enumField : fields) { - if (isConstant(enumField, aClass.isEnum())) { + if (isConstant(enumField)) { enumConstants.add(enumField.getName()); } } @@ -94,8 +92,8 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript return null; } - protected boolean isConstant(PsiField field, boolean inEnum) { - return inEnum && field instanceof PsiEnumConstant; + protected boolean isConstant(PsiField field) { + return field instanceof PsiEnumConstant; } protected PsiClass getEnum() { @@ -117,27 +115,25 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript @Override public String validateValue(XmlElement context, String value) { if (context instanceof XmlAttributeValue && value != null) { - final XmlAttributeValue xmlAttributeValue = (XmlAttributeValue)context; - final PsiElement parent = xmlAttributeValue.getParent(); - if (parent instanceof XmlAttribute) { - final XmlAttribute xmlAttribute = (XmlAttribute)parent; - if (JavaFxPsiUtil.isEventHandlerProperty(xmlAttribute)) { - return validateAttributeHandler(xmlAttributeValue, value); - } - if (FxmlConstants.FX_ID.equals(xmlAttribute.getName())) { - return validateFxId(xmlAttributeValue, value); - } - if (value.startsWith("$")) { - return validatePropertyExpression(xmlAttributeValue, value); - } - else { - return validateLiteral(xmlAttributeValue, value); - } - } + return validateAttributeValue((XmlAttributeValue)context, value); } return null; } + @Nullable + protected String validateAttributeValue(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) { + final PsiElement parent = xmlAttributeValue.getParent(); + if (parent instanceof XmlAttribute && JavaFxPsiUtil.isEventHandlerProperty((XmlAttribute)parent)) { + return validateAttributeHandler(xmlAttributeValue, value); + } + if (value.startsWith("$")) { + return validatePropertyExpression(xmlAttributeValue, value); + } + else { + return validateLiteral(xmlAttributeValue, value); + } + } + @Nullable private static String validateAttributeHandler(@NotNull XmlElement context, @NotNull String value) { if (value.startsWith("#")) { @@ -153,21 +149,6 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript return null; } - @Nullable - private static String validateFxId(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) { - final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(xmlAttributeValue.getContainingFile()); - if (controllerClass != null) { - final PsiClass tagClass = JavaFxPsiUtil.getTagClass(xmlAttributeValue); - if (tagClass != null) { - final PsiField field = controllerClass.findFieldByName(value, true); - if (field != null && !InheritanceUtil.isInheritorOrSelf(tagClass, PsiUtil.resolveClassInType(field.getType()), true)) { - return "Cannot set " + tagClass.getQualifiedName() + " to field \'" + field.getName() + "\'"; - } - } - } - return null; - } - @Nullable private static String validatePropertyExpression(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) { if (JavaFxPsiUtil.isIncorrectExpressionBinding(value)) { diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxRootTagDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxRootTagDescriptor.java index e3c672153532..485dccc9531c 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxRootTagDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxRootTagDescriptor.java @@ -100,7 +100,7 @@ public class JavaFxRootTagDescriptor extends JavaFxClassTagDescriptorBase { return null; } - protected boolean isConstant(PsiField field, boolean inEnum) { + protected boolean isConstant(PsiField field) { return false; }