mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Javafx: Fixed resolving variables and getter chains in FXML property expressions. Tests added (IDEA-153754)
This commit is contained in:
+12
@@ -276,6 +276,18 @@ public class JavaFXHighlightingTest extends AbstractJavaFXTestCase {
|
||||
doTest("s1.js");
|
||||
}
|
||||
|
||||
public void testPropertyNameExpression() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testPropertyChainExpression() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIncorrectPropertyExpressionSyntax() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest(String additionalPath) {
|
||||
myFixture.configureByFiles(getTestName(true) + ".fxml", additionalPath);
|
||||
myFixture.testHighlighting(false, false, false, getTestName(true) + ".fxml");
|
||||
|
||||
-13
@@ -252,19 +252,6 @@ public class JavaFxCompletionTest extends LightFixtureCompletionTestCase {
|
||||
assertSameElements(myFixture.getLookupElementStrings(),"pane", "node", "box", "model", "text", "target");
|
||||
}
|
||||
|
||||
public void testVariableCompletionBooleanFirst() throws Exception {
|
||||
doOrderTest("zAssignable", "dConvertible", "tConvertible", "controller", "mUnknown");
|
||||
}
|
||||
|
||||
public void testVariableCompletionTooltipFirst() throws Exception {
|
||||
doOrderTest("tAssignable", "controller", "mUnknown", "dIncompatible");
|
||||
}
|
||||
|
||||
private void doOrderTest(String... expected) {
|
||||
configureAndComplete();
|
||||
assertOrderedEquals(myFixture.getLookupElementStrings(), expected);
|
||||
}
|
||||
|
||||
private void configureAndComplete(final String... extraFiles) {
|
||||
final String fxmlFileName = getTestName(true) + ".fxml";
|
||||
if (extraFiles.length != 0) {
|
||||
|
||||
@@ -361,8 +361,20 @@ public class JavaFxPsiUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isExpressionBinding(String value) {
|
||||
return value.startsWith("${") && value.endsWith("}") && value.contains(".");
|
||||
public static boolean isExpressionBinding(@Nullable String value) {
|
||||
return value != null && value.startsWith("${") && value.endsWith("}");
|
||||
}
|
||||
|
||||
public static boolean isIncorrectExpressionBinding(@Nullable String value) {
|
||||
if (value == null || !value.startsWith("$")) return false;
|
||||
if (value.length() == 1) return true;
|
||||
final boolean expressionStarts = value.startsWith("${");
|
||||
final boolean expressionEnds = value.endsWith("}");
|
||||
if (expressionStarts && expressionEnds && value.length() == 3) return true;
|
||||
if (expressionStarts != expressionEnds) return true;
|
||||
if (expressionStarts && value.indexOf('{', 2) >= 2) return true;
|
||||
if (expressionEnds && value.indexOf('}') < value.length() - 1) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -697,7 +709,7 @@ public class JavaFxPsiUtil {
|
||||
|
||||
|
||||
@Nullable
|
||||
public static PsiType getReadablePropertyType(PsiElement declaration) {
|
||||
public static PsiType getReadablePropertyType(@Nullable PsiElement declaration) {
|
||||
if (declaration instanceof PsiField) {
|
||||
return getWrappedPropertyType((PsiField)declaration, declaration.getProject(), JavaFxCommonNames.ourReadOnlyMap);
|
||||
}
|
||||
@@ -751,7 +763,7 @@ public class JavaFxPsiUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClass getTagClassById(String id, PsiElement context, XmlAttributeValue xmlAttributeValue) {
|
||||
public static PsiClass getTagClassById(@Nullable XmlAttributeValue xmlAttributeValue, @Nullable String id, @NotNull PsiElement context) {
|
||||
return FxmlConstants.CONTROLLER.equals(id) ? getControllerClass(context.getContainingFile()) : getTagClass(xmlAttributeValue);
|
||||
}
|
||||
|
||||
@@ -768,7 +780,7 @@ public class JavaFxPsiUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClass getPropertyClass(PsiType propertyType, PsiElement context) {
|
||||
public static PsiClass getPropertyClass(@Nullable PsiType propertyType, @NotNull PsiElement context) {
|
||||
if (propertyType instanceof PsiPrimitiveType) {
|
||||
PsiClassType boxedType = ((PsiPrimitiveType)propertyType).getBoxedType(context);
|
||||
return boxedType != null ? boxedType.resolve() : null;
|
||||
@@ -801,17 +813,17 @@ public class JavaFxPsiUtil {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<PsiMember> collectReadableProperties(@Nullable PsiClass psiClass) {
|
||||
public static Map<String, PsiMember> collectReadableProperties(@Nullable PsiClass psiClass) {
|
||||
if (psiClass != null) {
|
||||
return CachedValuesManager.getCachedValue(psiClass, () ->
|
||||
CachedValueProvider.Result.create(prepareReadableProperties(psiClass), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
private static List<PsiMember> prepareReadableProperties(@NotNull PsiClass psiClass) {
|
||||
private static Map<String, PsiMember> prepareReadableProperties(@NotNull PsiClass psiClass) {
|
||||
final Map<String, PsiMember> acceptableMembers = new THashMap<>();
|
||||
for (PsiMethod method : psiClass.getAllMethods()) {
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) || !method.hasModifierProperty(PsiModifier.PUBLIC)) continue;
|
||||
@@ -821,7 +833,7 @@ public class JavaFxPsiUtil {
|
||||
acceptableMembers.put(propertyName, method);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(acceptableMembers.values());
|
||||
return acceptableMembers;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+30
-31
@@ -2,8 +2,6 @@ package org.jetbrains.plugins.javaFX.fxml.descriptors;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
@@ -19,6 +17,7 @@ import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -171,40 +170,40 @@ public class JavaFxPropertyAttributeDescriptor extends BasicXmlAttributeDescript
|
||||
|
||||
@Nullable
|
||||
private static String validatePropertyExpression(@NotNull XmlAttributeValue xmlAttributeValue, @NotNull String value) {
|
||||
final String referencesId = value.substring(1);
|
||||
if (JavaFxPsiUtil.isIncorrectExpressionBinding(value)) {
|
||||
return "Incorrect expression syntax";
|
||||
}
|
||||
final List<String> propertyNames = JavaFxPsiUtil.isExpressionBinding(value)
|
||||
? StringUtil.split(value.substring(2, value.length() - 1), ".", true, false)
|
||||
: Collections.singletonList(value.substring(1));
|
||||
if (isIncompletePropertyChain(propertyNames)) {
|
||||
return "Incorrect expression syntax";
|
||||
}
|
||||
|
||||
final XmlTag currentTag = PsiTreeUtil.getParentOfType(xmlAttributeValue, XmlTag.class);
|
||||
final Map<String, XmlAttributeValue> fileIds = JavaFxPsiUtil.collectFileIds(currentTag);
|
||||
final PsiClass targetPropertyClass = JavaFxPsiUtil.getWritablePropertyClass(xmlAttributeValue);
|
||||
if (targetPropertyClass == null || JavaFxPsiUtil.hasConversionFromAnyType(targetPropertyClass)) return null;
|
||||
final PsiClass valueClass;
|
||||
if (JavaFxPsiUtil.isExpressionBinding(value)) {
|
||||
final String expressionText = referencesId.substring(1, referencesId.length() - 1);
|
||||
final String newId = StringUtil.getPackageName(expressionText);
|
||||
final PsiClass tagClass = JavaFxPsiUtil.getTagClassById(newId, xmlAttributeValue, fileIds.get(newId));
|
||||
if (tagClass == null) return null;
|
||||
|
||||
final String fieldRef = StringUtil.getShortName(expressionText);
|
||||
final String fieldName =
|
||||
JavaCodeStyleManager.getInstance(tagClass.getProject()).propertyNameToVariableName(fieldRef, VariableKind.FIELD);
|
||||
PsiField psiField = tagClass.findFieldByName(fieldName, true);
|
||||
final String firstPropertyName = propertyNames.get(0);
|
||||
final Map<String, XmlAttributeValue> fileIds = JavaFxPsiUtil.collectFileIds(currentTag);
|
||||
final PsiClass tagClass = JavaFxPsiUtil.getTagClassById(fileIds.get(firstPropertyName), firstPropertyName, xmlAttributeValue);
|
||||
if (tagClass != null) {
|
||||
PsiClass aClass = tagClass;
|
||||
final List<String> remainingPropertyNames = propertyNames.subList(1, propertyNames.size());
|
||||
for (String propertyName : remainingPropertyNames) {
|
||||
if (aClass == null) break;
|
||||
final PsiMember member = JavaFxPsiUtil.collectReadableProperties(aClass).get(propertyName);
|
||||
aClass = JavaFxPsiUtil.getPropertyClass(JavaFxPsiUtil.getReadablePropertyType(member), xmlAttributeValue);
|
||||
}
|
||||
if (aClass != null && !InheritanceUtil.isInheritorOrSelf(aClass, targetPropertyClass, true)) {
|
||||
return "Invalid value: unable to coerce to " + targetPropertyClass.getQualifiedName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiMember propertyDeclaration;
|
||||
if (psiField != null && psiField.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
propertyDeclaration = psiField;
|
||||
}
|
||||
else {
|
||||
propertyDeclaration = JavaFxPsiUtil.findPropertyGetter(fieldRef, tagClass);
|
||||
}
|
||||
if (propertyDeclaration == null) return null;
|
||||
valueClass = JavaFxPsiUtil.getPropertyClass(JavaFxPsiUtil.getReadablePropertyType(propertyDeclaration), xmlAttributeValue);
|
||||
}
|
||||
else {
|
||||
valueClass = JavaFxPsiUtil.getTagClassById(referencesId, xmlAttributeValue, fileIds.get(referencesId));
|
||||
}
|
||||
if (valueClass == null || InheritanceUtil.isInheritorOrSelf(valueClass, targetPropertyClass, true)) {
|
||||
return null;
|
||||
}
|
||||
return "Invalid value: unable to coerce to " + targetPropertyClass.getQualifiedName();
|
||||
public static boolean isIncompletePropertyChain(@NotNull List<String> propertyNames) {
|
||||
return propertyNames.isEmpty() || propertyNames.contains("");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -58,7 +58,8 @@ public class JavaFxAnnotator implements Annotator {
|
||||
if (!JavaFxFileTypeFactory.isFxml(containingFile)) return;
|
||||
if (element instanceof XmlAttributeValue) {
|
||||
final PsiReference[] references = element.getReferences();
|
||||
if (!JavaFxPsiUtil.isExpressionBinding(((XmlAttributeValue)element).getValue())) {
|
||||
final String value = ((XmlAttributeValue)element).getValue();
|
||||
if (!JavaFxPsiUtil.isExpressionBinding(value) && !JavaFxPsiUtil.isIncorrectExpressionBinding(value)) {
|
||||
for (PsiReference reference : references) {
|
||||
final PsiElement resolve = reference.resolve();
|
||||
if (resolve instanceof PsiMember) {
|
||||
|
||||
+93
-51
@@ -34,6 +34,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.javaFX.fxml.FxmlConstants;
|
||||
import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
|
||||
import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyAttributeDescriptor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -42,69 +43,110 @@ import java.util.stream.Collectors;
|
||||
* User: anna
|
||||
*/
|
||||
class JavaFxComponentIdReferenceProvider extends PsiReferenceProvider {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
|
||||
@NotNull ProcessingContext context) {
|
||||
final XmlAttributeValue xmlAttributeValue = (XmlAttributeValue)element;
|
||||
final XmlTag currentTag = PsiTreeUtil.getParentOfType(xmlAttributeValue, XmlTag.class);
|
||||
final String value = xmlAttributeValue.getValue();
|
||||
final boolean startsWithDollar = value.startsWith("$");
|
||||
final String referencesId = startsWithDollar ? value.substring(1) : value;
|
||||
if (JavaFxPsiUtil.isIncorrectExpressionBinding(value)) {
|
||||
return PsiReference.EMPTY_ARRAY;
|
||||
}
|
||||
final XmlTag currentTag = PsiTreeUtil.getParentOfType(xmlAttributeValue, XmlTag.class);
|
||||
final Map<String, XmlAttributeValue> fileIds = JavaFxPsiUtil.collectFileIds(currentTag);
|
||||
|
||||
if (JavaFxPsiUtil.isExpressionBinding(value)) {
|
||||
final String expressionText = referencesId.substring(1, referencesId.length() - 1);
|
||||
final String newId = StringUtil.getPackageName(expressionText);
|
||||
final String fieldRef = StringUtil.getShortName(expressionText);
|
||||
|
||||
final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(element.getContainingFile());
|
||||
final PsiReferenceBase idReferenceBase = getIdReferenceBase(xmlAttributeValue, newId, fileIds, Collections.emptyMap(), controllerClass);
|
||||
final TextRange range = idReferenceBase.getRangeInElement();
|
||||
final int startOffset = range.getStartOffset() + 2;
|
||||
final int endOffset = startOffset + newId.length();
|
||||
idReferenceBase.setRangeInElement(new TextRange(startOffset, endOffset));
|
||||
if (fileIds.containsKey(newId)) {
|
||||
final PsiClass tagClass = FxmlConstants.CONTROLLER.equals(newId) ? controllerClass : JavaFxPsiUtil.getTagClass(fileIds.get(newId));
|
||||
if (tagClass != null) {
|
||||
final JavaFxExpressionReferenceBase referenceBase = new JavaFxExpressionReferenceBase(xmlAttributeValue, tagClass, fieldRef);
|
||||
final TextRange textRange = referenceBase.getRangeInElement();
|
||||
referenceBase.setRangeInElement(new TextRange(endOffset + 1, textRange.getEndOffset() - 1));
|
||||
return new PsiReference[] {idReferenceBase, referenceBase};
|
||||
return getExpressionReferences(element, xmlAttributeValue, value, fileIds);
|
||||
}
|
||||
if (value.startsWith("$")) {
|
||||
return getSinglePropertyReferences(xmlAttributeValue, value, fileIds);
|
||||
}
|
||||
final Set<String> acceptableIds = new HashSet<String>();
|
||||
if (currentTag != null) {
|
||||
final XmlTag parentTag = currentTag.getParentTag();
|
||||
for (final String id : fileIds.keySet()) {
|
||||
final XmlAttributeValue resolvedAttrValue = fileIds.get(id);
|
||||
if (JavaFxPsiUtil.isClassAcceptable(parentTag, JavaFxPsiUtil.getTagClass(resolvedAttrValue))) {
|
||||
acceptableIds.add(id);
|
||||
}
|
||||
}
|
||||
return new PsiReference[] {idReferenceBase};
|
||||
}
|
||||
if (startsWithDollar) {
|
||||
final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(element.getContainingFile());
|
||||
return new PsiReference[]{new JavaFxIdReferenceBase(xmlAttributeValue, fileIds, acceptableIds, value)};
|
||||
}
|
||||
|
||||
final PsiClass targetPropertyClass = JavaFxPsiUtil.getWritablePropertyClass(xmlAttributeValue);
|
||||
final boolean isConvertible = targetPropertyClass != null && JavaFxPsiUtil.hasConversionFromAnyType(targetPropertyClass);
|
||||
|
||||
final Map<String, TypeMatch> typeMatches = fileIds.entrySet().stream().collect(
|
||||
Collectors.toMap(Map.Entry::getKey, e -> {
|
||||
final PsiClass valueClass = JavaFxPsiUtil.getTagClassById(e.getKey(), xmlAttributeValue, e.getValue());
|
||||
return TypeMatch.getMatch(valueClass, targetPropertyClass, isConvertible);
|
||||
}));
|
||||
|
||||
final PsiReferenceBase idReferenceBase = getIdReferenceBase(xmlAttributeValue, referencesId, fileIds, typeMatches, controllerClass);
|
||||
final TextRange rangeInElement = idReferenceBase.getRangeInElement();
|
||||
idReferenceBase.setRangeInElement(new TextRange(rangeInElement.getStartOffset() + 1, rangeInElement.getEndOffset()));
|
||||
return new PsiReference[]{idReferenceBase};
|
||||
} else {
|
||||
final Set<String> acceptableIds = new HashSet<String>();
|
||||
if (currentTag != null) {
|
||||
final XmlTag parentTag = currentTag.getParentTag();
|
||||
for (final String id : fileIds.keySet()) {
|
||||
final XmlAttributeValue resolvedAttrValue = fileIds.get(id);
|
||||
if (JavaFxPsiUtil.isClassAcceptable(parentTag, JavaFxPsiUtil.getTagClass(resolvedAttrValue))) {
|
||||
acceptableIds.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
JavaFxIdReferenceBase idReferenceBase = new JavaFxIdReferenceBase(xmlAttributeValue, fileIds, acceptableIds, referencesId);
|
||||
return new PsiReference[]{idReferenceBase};
|
||||
@NotNull
|
||||
private static PsiReference[] getExpressionReferences(@NotNull PsiElement element,
|
||||
@NotNull XmlAttributeValue xmlAttributeValue,
|
||||
@NotNull String value,
|
||||
@NotNull Map<String, XmlAttributeValue> fileIds) {
|
||||
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;
|
||||
if (propertyNames.size() == 1) {
|
||||
return getSinglePropertyReferences(xmlAttributeValue, fileIds, expressionBody, 2);
|
||||
}
|
||||
|
||||
final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(element.getContainingFile());
|
||||
final String firstPropertyName = propertyNames.get(0);
|
||||
int positionInExpression = 2;
|
||||
final List<PsiReference> result = new ArrayList<>();
|
||||
final PsiReferenceBase firstReference =
|
||||
getIdReferenceBase(xmlAttributeValue, firstPropertyName, fileIds, Collections.emptyMap(), controllerClass);
|
||||
positionInExpression = adjustTextRange(firstPropertyName, firstReference, positionInExpression);
|
||||
PsiClass propertyOwnerClass = FxmlConstants.CONTROLLER.equals(firstPropertyName) ?
|
||||
controllerClass : JavaFxPsiUtil.getTagClass(fileIds.get(firstPropertyName));
|
||||
result.add(firstReference);
|
||||
|
||||
final List<String> remainingPropertyNames = propertyNames.subList(1, propertyNames.size());
|
||||
for (String propertyName : remainingPropertyNames) {
|
||||
final JavaFxExpressionReferenceBase reference =
|
||||
new JavaFxExpressionReferenceBase(xmlAttributeValue, propertyOwnerClass, propertyName);
|
||||
positionInExpression = adjustTextRange(propertyName, reference, positionInExpression);
|
||||
final PsiType propertyType = JavaFxPsiUtil.getReadablePropertyType(reference.resolve());
|
||||
propertyOwnerClass = propertyType instanceof PsiClassType ? ((PsiClassType)propertyType).resolve() : null;
|
||||
result.add(reference);
|
||||
}
|
||||
return result.toArray(PsiReference.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiReference[] getSinglePropertyReferences(@NotNull XmlAttributeValue xmlAttributeValue,
|
||||
@NotNull String value,
|
||||
@NotNull Map<String, XmlAttributeValue> fileIds) {
|
||||
return getSinglePropertyReferences(xmlAttributeValue, fileIds, value.substring(1), 1);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiReference[] getSinglePropertyReferences(@NotNull XmlAttributeValue xmlAttributeValue,
|
||||
@NotNull Map<String, XmlAttributeValue> fileIds,
|
||||
@NotNull String propertyName,
|
||||
int positionInExpression) {
|
||||
final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(xmlAttributeValue.getContainingFile());
|
||||
final Map<String, TypeMatch> typeMatches = getTypeMatches(xmlAttributeValue, fileIds);
|
||||
final PsiReferenceBase reference = getIdReferenceBase(xmlAttributeValue, propertyName, fileIds, typeMatches, controllerClass);
|
||||
adjustTextRange(propertyName, reference, positionInExpression);
|
||||
return new PsiReference[]{reference};
|
||||
}
|
||||
|
||||
private static Map<String, TypeMatch> getTypeMatches(@NotNull XmlAttributeValue xmlAttributeValue,
|
||||
@NotNull Map<String, XmlAttributeValue> fileIds) {
|
||||
final PsiClass targetPropertyClass = JavaFxPsiUtil.getWritablePropertyClass(xmlAttributeValue);
|
||||
final boolean isConvertible = targetPropertyClass != null && JavaFxPsiUtil.hasConversionFromAnyType(targetPropertyClass);
|
||||
|
||||
return fileIds.entrySet().stream().collect(
|
||||
Collectors.toMap(Map.Entry::getKey, e -> {
|
||||
final PsiClass valueClass = JavaFxPsiUtil.getTagClassById(e.getValue(), e.getKey(), xmlAttributeValue);
|
||||
return TypeMatch.getMatch(valueClass, targetPropertyClass, isConvertible);
|
||||
}));
|
||||
}
|
||||
|
||||
private static int adjustTextRange(@NotNull String propertyName, @NotNull PsiReferenceBase reference, int positionInExpression) {
|
||||
final TextRange range = reference.getRangeInElement();
|
||||
final int startOffset = range.getStartOffset() + positionInExpression;
|
||||
final int endOffset = startOffset + propertyName.length();
|
||||
reference.setRangeInElement(new TextRange(startOffset, endOffset));
|
||||
return positionInExpression + propertyName.length() + 1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -203,7 +245,7 @@ class JavaFxComponentIdReferenceProvider extends PsiReferenceProvider {
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement resolve() {
|
||||
return myTagClass.findFieldByName(myFieldName, true);
|
||||
return JavaFxPsiUtil.collectReadableProperties(myTagClass).get(myFieldName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -221,7 +263,7 @@ class JavaFxComponentIdReferenceProvider extends PsiReferenceProvider {
|
||||
private Object[] collectProperties(@NotNull PsiType propertyType, @NotNull Project project) {
|
||||
final PsiType resolvedType = JavaFxPsiUtil.getWritablePropertyType(propertyType, project);
|
||||
final List<LookupElement> objs = new ArrayList<>();
|
||||
final List<PsiMember> readableProperties = JavaFxPsiUtil.collectReadableProperties(myTagClass);
|
||||
final Collection<PsiMember> readableProperties = JavaFxPsiUtil.collectReadableProperties(myTagClass).values();
|
||||
for (PsiMember readableMember : readableProperties) {
|
||||
final PsiType readableType = JavaFxPsiUtil.getReadablePropertyType(readableMember);
|
||||
if (readableType == null) continue;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import java.lang.Double?>
|
||||
<?import java.lang.Boolean?>
|
||||
<?import sample.UnknownModel?>
|
||||
<GridPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml">
|
||||
<fx:define>
|
||||
<Tooltip text="tooltip" fx:id="tConvertible"/>
|
||||
</fx:define>
|
||||
|
||||
<fx:define>
|
||||
<Double fx:value="123.45" fx:id="dConvertible"/>
|
||||
</fx:define>
|
||||
|
||||
<fx:define>
|
||||
<Boolean fx:value="123.45" fx:id="zAssignable"/>
|
||||
</fx:define>
|
||||
|
||||
<fx:define>
|
||||
<UnknownModel fx:id="mUnknown"/>
|
||||
</fx:define>
|
||||
|
||||
<Button onAction="#sayHello" text="Hello" fx:id="b1" defaultButton="$<caret>" />
|
||||
</GridPane>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Tooltip?>
|
||||
<?import java.lang.Double?>
|
||||
<?import sample.UnknownModel?>
|
||||
<GridPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml">
|
||||
<fx:define>
|
||||
<Tooltip text="tooltip" fx:id="tAssignable"/>
|
||||
</fx:define>
|
||||
|
||||
<fx:define>
|
||||
<Double fx:value="123.45" fx:id="dIncompatible"/>
|
||||
</fx:define>
|
||||
|
||||
<fx:define>
|
||||
<UnknownModel fx:id="mUnknown"/>
|
||||
</fx:define>
|
||||
|
||||
<Button onAction="#sayHello" text="Hello" fx:id="b1" tooltip="$<caret>" />
|
||||
</GridPane>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import java.lang.Double?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml">
|
||||
<fx:define>
|
||||
<Label fx:id="barLabel" text="bar"/>
|
||||
<Double fx:id="myDouble" fx:value="31.5"/>
|
||||
</fx:define>
|
||||
|
||||
<Label text=<error descr="Incorrect expression syntax">"$"</error>
|
||||
opacity=<error descr="Incorrect expression syntax">"${}"</error>
|
||||
minHeight=<error descr="Incorrect expression syntax">"${.myDouble}"</error>
|
||||
maxHeight=<error descr="Incorrect expression syntax">"${myDouble.}"</error>
|
||||
prefHeight=<error descr="Incorrect expression syntax">"${"</error>
|
||||
minWidth=<error descr="Incorrect expression syntax">"${barLabel..minWidth}"</error>
|
||||
maxWidth=<error descr="Incorrect expression syntax">"${barLabel.maxWidth.}"</error>
|
||||
prefWidth=<error descr="Incorrect expression syntax">"${.barLabel.maxWidth}"</error>
|
||||
alignment=<error descr="Incorrect expression syntax">"${{"</error>
|
||||
disable=<error descr="Incorrect expression syntax">"${}}"</error>
|
||||
effect=<error descr="Incorrect expression syntax">"$}"</error>
|
||||
/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml">
|
||||
<fx:define>
|
||||
<Label fx:id="barLabel" text="bar"/>
|
||||
</fx:define>
|
||||
<Label disable="${barLabel.border.empty}"/>
|
||||
<Label disable="${<error descr="Cannot resolve symbol 'unknown'">unknown</error>.<error descr="Cannot resolve symbol 'border'">border</error>.<error descr="Cannot resolve symbol 'empty'">empty</error>}"/>
|
||||
<Label padding=<error descr="Invalid value: unable to coerce to javafx.geometry.Insets">"${barLabel.border.empty}"</error>/>
|
||||
<Label padding="${barLabel.border.<error descr="Cannot resolve symbol 'full'">full</error>}"/>
|
||||
</VBox>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import java.lang.Double?>
|
||||
<?import java.lang.String?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml">
|
||||
<fx:define>
|
||||
<Label fx:id="barLabel" text="bar"/>
|
||||
<Double fx:id="myDouble" fx:value="31.5"/>
|
||||
<String fx:id="myString" fx:value="Press Me"/>
|
||||
</fx:define>
|
||||
|
||||
<Label text="foo" minHeight="${myDouble}"/>
|
||||
<Label text="${barLabel.text}"/>
|
||||
<Button text="${myString}"/>
|
||||
</VBox>
|
||||
Reference in New Issue
Block a user