Javafx: Don't mark as an error the FXML attribute corresponding to a constructor argument annotated with @NamedArg (IDEA-165983)

This commit is contained in:
Pavel Dolgov
2017-01-12 13:14:33 +03:00
parent 6ad89ba9e7
commit 40864f8b70
4 changed files with 63 additions and 12 deletions
@@ -501,7 +501,11 @@ public class JavaFXHighlightingTest extends AbstractJavaFXTestCase {
doTest();
}
private void doTest() throws Exception {
public void testConstructorNamedArg() {
doTest();
}
private void doTest() {
myFixture.testHighlighting(false, false, false, getTestName(true) + ".fxml");
}
@@ -903,8 +903,8 @@ public class JavaFxPsiUtil {
if (!constructor.hasModifierProperty(PsiModifier.PUBLIC)) continue;
final PsiParameter[] parameters = constructor.getParameterList().getParameters();
for (PsiParameter parameter : parameters) {
String propertyName = getPropertyNameFromNamedArgAnnotation(parameter);
if (propertyName != null && !acceptableMembers.containsKey(propertyName)) {
final String propertyName = getPropertyNameFromNamedArgAnnotation(parameter);
if (!StringUtil.isEmpty(propertyName) && !acceptableMembers.containsKey(propertyName)) {
final PsiField field = psiClass.findFieldByName(propertyName, true);
if (field != null && !field.hasModifierProperty(PsiModifier.STATIC)) {
acceptableMembers.put(propertyName, field);
@@ -966,6 +966,34 @@ public class JavaFxPsiUtil {
return null;
}
/**
* Unlike normal properties (fields, getters/setters) named constructor parameters can be declared many times, possibly with different types
*/
@NotNull
public static Set<String> getConstructorNamedArgProperties(@Nullable PsiClass psiClass) {
if (psiClass != null) {
return CachedValuesManager.getCachedValue(psiClass, () -> CachedValueProvider.Result.create(
prepareConstructorNamedArgProperties(psiClass), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT));
}
return Collections.emptySet();
}
private static Set<String> prepareConstructorNamedArgProperties(@NotNull PsiClass psiClass) {
final Set<String> properties = new THashSet<>();
for (PsiMethod constructor : psiClass.getConstructors()) {
if (constructor.hasModifierProperty(PsiModifier.PUBLIC)) {
final PsiParameter[] parameters = constructor.getParameterList().getParameters();
for (PsiParameter parameter : parameters) {
final String propertyName = getPropertyNameFromNamedArgAnnotation(parameter);
if (!StringUtil.isEmpty(propertyName)) {
properties.add(propertyName);
}
}
}
}
return properties;
}
@Nullable
public static PsiMethod findInstancePropertySetter(@NotNull PsiClass psiClass, @Nullable String propertyName) {
if (StringUtil.isEmpty(propertyName)) return null;
@@ -24,10 +24,7 @@ import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* User: anna
@@ -60,7 +57,7 @@ public abstract class JavaFxClassTagDescriptorBase implements XmlElementDescript
if (psiClass != null) {
final List<XmlElementDescriptor> children = new ArrayList<>();
collectWritableProperties(children,
(member) -> new JavaFxPropertyTagDescriptor(psiClass, PropertyUtil.getPropertyName(member), false));
member -> new JavaFxPropertyTagDescriptor(psiClass, PropertyUtil.getPropertyName(member), false));
final JavaFxPropertyTagDescriptor defaultPropertyDescriptor = getDefaultPropertyDescriptor();
if (defaultPropertyDescriptor != null) {
@@ -217,15 +214,24 @@ public abstract class JavaFxClassTagDescriptorBase implements XmlElementDescript
}
protected void collectInstanceProperties(List<XmlAttributeDescriptor> simpleAttrs) {
collectWritableProperties(simpleAttrs,
(member) -> new JavaFxPropertyAttributeDescriptor(PropertyUtil.getPropertyName(member), getPsiClass()));
final PsiClass psiClass = getPsiClass();
final Set<String> propertyNames = collectWritableProperties(
simpleAttrs, member -> new JavaFxPropertyAttributeDescriptor(PropertyUtil.getPropertyName(member), psiClass));
for (String name : JavaFxPsiUtil.getConstructorNamedArgProperties(psiClass)) {
if (!propertyNames.contains(name)) {
simpleAttrs.add(new JavaFxPropertyAttributeDescriptor(name, psiClass));
}
}
}
private <T> void collectWritableProperties(final List<T> children, final Function<PsiMember, T> factory) {
@NotNull
private <T> Set<String> collectWritableProperties(final List<T> children, final Function<PsiMember, T> factory) {
final Map<String, PsiMember> fieldList = JavaFxPsiUtil.collectWritableProperties(getPsiClass());
for (PsiMember field : fieldList.values()) {
children.add(factory.fun(field));
}
return fieldList.keySet();
}
@Nullable
@@ -244,6 +250,9 @@ public abstract class JavaFxClassTagDescriptorBase implements XmlElementDescript
if (psiMember != null) {
return new JavaFxPropertyAttributeDescriptor(attributeName, psiClass);
}
if (JavaFxPsiUtil.getConstructorNamedArgProperties(psiClass).contains(attributeName)) {
return new JavaFxPropertyAttributeDescriptor(attributeName, psiClass);
}
return null;
}
@@ -321,7 +330,9 @@ public abstract class JavaFxClassTagDescriptorBase implements XmlElementDescript
public boolean isReadOnlyAttribute(String attributeName) {
final PsiClass psiClass = getPsiClass();
return psiClass != null && !JavaFxPsiUtil.collectWritableProperties(psiClass).containsKey(attributeName);
return psiClass != null &&
!JavaFxPsiUtil.collectWritableProperties(psiClass).containsKey(attributeName) &&
!JavaFxPsiUtil.getConstructorNamedArgProperties(psiClass).contains(attributeName);
}
@NotNull
@@ -0,0 +1,8 @@
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane xmlns:fx="http://javafx.com/fxml">
<Spinner GridPane.columnIndex="1" GridPane.rowIndex="2" editable="true"
amountToStepBy="1" initialValue="3"
max="6000" min="1"/>
<Spinner min="1" max="5" initialValue="1"/>
</GridPane>