diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java index ce2b38cd128b..d412eac229f8 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXHighlightingTest.java @@ -262,6 +262,10 @@ public class JavaFXHighlightingTest extends DaemonAnalyzerTestCase { doTest(); } + public void testUnexpectedNode() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false, false, getTestName(true) + ".fxml"); } diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java index a6537061b0df..af1ef5077f37 100644 --- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java +++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXImportTest.java @@ -33,7 +33,13 @@ public class JavaFXImportTest extends DaemonAnalyzerTestCase { public void testSimpleImport() throws Exception { doTest(); } - + + public void testTextField() throws Exception { + configureByFiles(null, getTestName(true) + ".fxml", getTestName(false) + ".java"); + final List infos = doHighlighting(); + findAndInvokeIntentionAction(infos, "Import Class", getEditor(), getFile()); + checkResultByFile(getTestName(true) + "_after.fxml"); + } private void doTest() throws Exception { configureByFiles(null, getTestName(true) + ".fxml"); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java index 260b85e98ed7..03c9cd312468 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java @@ -16,6 +16,8 @@ package org.jetbrains.plugins.javaFX.fxml; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil; +import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.lang.ASTNode; import com.intellij.lang.xml.XMLLanguage; import com.intellij.openapi.fileTypes.StdFileTypes; @@ -33,6 +35,8 @@ import com.intellij.util.Processor; import com.intellij.xml.XmlElementDescriptor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxClassBackedElementDescriptor; +import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyElementDescriptor; import java.util.ArrayList; import java.util.Collection; @@ -430,6 +434,54 @@ public class JavaFxPsiUtil { return null; } + public static String isClassAcceptable(@Nullable XmlTag parentTag, final PsiClass aClass) { + if (aClass != null && aClass.isValid()) { + if (parentTag == null) { + if (!InheritanceUtil.isInheritor(aClass, false, JavaFxCommonClassNames.JAVAFX_SCENE_NODE)) { + return unableToCoerceMessage(aClass, JavaFxCommonClassNames.JAVAFX_SCENE_NODE); + } + return null; + } + final XmlElementDescriptor descriptor = parentTag.getDescriptor(); + if (descriptor instanceof JavaFxPropertyElementDescriptor) { + final PsiElement declaration = descriptor.getDeclaration(); + if (declaration instanceof PsiField) { + return canCoerce(aClass, ((PsiField)declaration).getType()); + } + } + else if (descriptor instanceof JavaFxClassBackedElementDescriptor) { + final PsiElement declaration = descriptor.getDeclaration(); + if (declaration instanceof PsiClass) { + final PsiType type = getDefaultPropertyExpectedType((PsiClass)declaration); + if (type != null) { + return canCoerce(aClass, type); + } + } + } + } + return null; + } + + private static String canCoerce(PsiClass aClass, PsiType type) { + final PsiType collectionItemType = GenericsHighlightUtil.getCollectionItemType(type, aClass.getResolveScope()); + if (collectionItemType != null && PsiPrimitiveType.getUnboxedType(collectionItemType) == null) { + final PsiClass baseClass = PsiUtil.resolveClassInType(collectionItemType); + if (baseClass != null) { + final String qualifiedName = baseClass.getQualifiedName(); + if (qualifiedName != null && !Comparing.strEqual(qualifiedName, CommonClassNames.JAVA_LANG_STRING)) { + if (!InheritanceUtil.isInheritor(aClass, qualifiedName)) { + return unableToCoerceMessage(aClass, qualifiedName); + } + } + } + } + return null; + } + + private static String unableToCoerceMessage(PsiClass aClass, String qualifiedName) { + return "Unable to coerce " + HighlightUtil.formatClass(aClass)+ " to " + qualifiedName; + } + private static class JavaFxControllerCachedValueProvider implements CachedValueProvider { private final Project myProject; private final PsiFile myContainingFile; diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java index e3e9d2c8d0ca..75fd36ede233 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxClassBackedElementDescriptor.java @@ -2,7 +2,6 @@ package org.jetbrains.plugins.javaFX.fxml.descriptors; import com.intellij.codeInsight.daemon.Validator; import com.intellij.codeInsight.daemon.impl.analysis.GenericsHighlightUtil; -import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; @@ -11,7 +10,6 @@ import com.intellij.psi.impl.source.xml.XmlAttributeImpl; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PropertyUtil; -import com.intellij.psi.util.PsiUtil; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; @@ -280,7 +278,10 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor, host.addMessage(((XmlAttributeImpl)attribute).getNameElement(), "fx:controller can only be applied to root element", ValidationHost.ErrorType.ERROR); //todo add delete/move to upper tag fix } } - validateTagAccordingToFieldType(context, parentTag, host); + final String canCoerceError = JavaFxPsiUtil.isClassAcceptable(parentTag, myPsiClass); + if (canCoerceError != null) { + host.addMessage(context.getNavigationElement(), canCoerceError, ValidationHost.ErrorType.ERROR); + } if (myPsiClass != null && myPsiClass.isValid()) { final String message = JavaFxPsiUtil.isAbleToInstantiate(myPsiClass); if (message != null) { @@ -288,29 +289,4 @@ public class JavaFxClassBackedElementDescriptor implements XmlElementDescriptor, } } } - - private void validateTagAccordingToFieldType(XmlTag context, XmlTag parentTag, ValidationHost host) { - if (myPsiClass != null && myPsiClass.isValid()) { - final XmlElementDescriptor descriptor = parentTag != null ? parentTag.getDescriptor() : null; - if (descriptor instanceof JavaFxPropertyElementDescriptor) { - final PsiElement declaration = descriptor.getDeclaration(); - if (declaration instanceof PsiField) { - final PsiType type = ((PsiField)declaration).getType(); - final PsiType collectionItemType = GenericsHighlightUtil.getCollectionItemType(type, myPsiClass.getResolveScope()); - if (collectionItemType != null && PsiPrimitiveType.getUnboxedType(collectionItemType) == null) { - final PsiClass baseClass = PsiUtil.resolveClassInType(collectionItemType); - if (baseClass != null) { - final String qualifiedName = baseClass.getQualifiedName(); - if (qualifiedName != null && !Comparing.strEqual(qualifiedName, CommonClassNames.JAVA_LANG_STRING)) { - if (!InheritanceUtil.isInheritor(myPsiClass, qualifiedName)) { - host.addMessage(context.getNavigationElement(), - "Unable to coerce " + HighlightUtil.formatClass(myPsiClass)+ " to " + qualifiedName, ValidationHost.ErrorType.ERROR); - } - } - } - } - } - } - } - } } diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxImportClassFix.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxImportClassFix.java index f2ef0a51237b..04abf3baa07f 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxImportClassFix.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxImportClassFix.java @@ -66,7 +66,7 @@ abstract class JavaFxImportClassFix extends ImportClassFixBase + + + + + + <Double /> + \ No newline at end of file diff --git a/plugins/javaFX/testData/importing/TextField.java b/plugins/javaFX/testData/importing/TextField.java new file mode 100644 index 000000000000..4165dc7e7127 --- /dev/null +++ b/plugins/javaFX/testData/importing/TextField.java @@ -0,0 +1,2 @@ +package foo; +public class TextField {} \ No newline at end of file diff --git a/plugins/javaFX/testData/importing/textField.fxml b/plugins/javaFX/testData/importing/textField.fxml new file mode 100644 index 000000000000..287a3de9e50c --- /dev/null +++ b/plugins/javaFX/testData/importing/textField.fxml @@ -0,0 +1,8 @@ + + + + + + Field/> + + \ No newline at end of file diff --git a/plugins/javaFX/testData/importing/textField_after.fxml b/plugins/javaFX/testData/importing/textField_after.fxml new file mode 100644 index 000000000000..33fc9150b877 --- /dev/null +++ b/plugins/javaFX/testData/importing/textField_after.fxml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file