mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Javafx: Refactor descriptors of built-in FXML attributes - extract attribute-specific validation and completion from the base class to specific classes, remove redundant code (IDEA-154239)
This commit is contained in:
+2
@@ -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;
|
||||
}
|
||||
|
||||
+131
-56
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-30
@@ -80,7 +80,7 @@ public class JavaFxBuiltInTagDescriptor implements XmlElementDescriptor, Validat
|
||||
final List<String> 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<String> 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(), "<fx:root> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+18
-37
@@ -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<String> enumConstants = new ArrayList<String>();
|
||||
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)) {
|
||||
|
||||
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user