diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java
index 70c5151212eb..70b65cc3d874 100644
--- a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java
+++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFXQuickfixTest.java
@@ -60,6 +60,14 @@ public class JavaFXQuickfixTest extends LightCodeInsightFixtureTestCase {
doTest("Create method 'void bar(ActionEvent)'", ".groovy");
}
+ public void testCreateControllerMethodGeneric() throws Exception {
+ doTest("Create method 'void onSort(SortEvent)'", ".java");
+ }
+
+ public void testCreateControllerMethodHalfRaw() throws Exception {
+ doTest("Create method 'void onSort(SortEvent)'", ".java");
+ }
+
public void testCreateFieldPublicVisibility() throws Exception {
doTestWithDefaultVisibility("Create field 'btn'", "CreateField", PsiModifier.PUBLIC, ".java");
}
diff --git a/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java
new file mode 100644
index 000000000000..d7548ba56ba9
--- /dev/null
+++ b/plugins/javaFX/javaFX-CE/testSrc/org/jetbrains/plugins/javaFX/fxml/JavaFxEventHandlerInspectionTest.java
@@ -0,0 +1,55 @@
+package org.jetbrains.plugins.javaFX.fxml;
+
+import com.intellij.openapi.application.PluginPathManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections.JavaFxEventHandlerInspection;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class JavaFxEventHandlerInspectionTest extends AbstractJavaFXTestCase {
+
+ @Override
+ protected void enableInspections() {
+ myFixture.enableInspections(new JavaFxEventHandlerInspection());
+ }
+
+
+ public void testHighlightExact() throws Exception {
+ doHighlightingTest();
+ }
+
+ public void testHighlightNonVoid() throws Exception {
+ final JavaFxEventHandlerInspection inspection = new JavaFxEventHandlerInspection();
+ inspection.myDetectNonVoidReturnType = true;
+ myFixture.enableInspections(inspection);
+ doHighlightingTest();
+ }
+
+ public void testHighlightAmbiguous() throws Exception {
+ doHighlightingTest();
+ }
+
+ public void testHighlightSimpleGeneric() throws Exception {
+ doHighlightingTest();
+ }
+
+ public void testHighlightMixedGeneric() throws Exception {
+ doHighlightingTest();
+ }
+
+ public void testHighlightWildcard() throws Exception {
+ doHighlightingTest();
+ }
+
+ private void doHighlightingTest() throws Exception {
+ myFixture.configureByFiles(getTestName(true) + ".fxml", getTestName(false) + "Controller.java");
+ myFixture.checkHighlighting();
+ }
+
+ @NotNull
+ @Override
+ protected String getTestDataPath() {
+ return PluginPathManager.getPluginHomePath("javaFX") + "/testData/inspections/eventHandler/";
+ }
+}
diff --git a/plugins/javaFX/resources/inspectionDescriptions/JavaFxEventHandler.html b/plugins/javaFX/resources/inspectionDescriptions/JavaFxEventHandler.html
new file mode 100644
index 000000000000..823157cb5c92
--- /dev/null
+++ b/plugins/javaFX/resources/inspectionDescriptions/JavaFxEventHandler.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports event handler issues, including incompatible argument type, ambiguous event handler method, and incorrect return type.
+
+
diff --git a/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml b/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml
index 8a4ae2897de2..4254ed7768e6 100644
--- a/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml
+++ b/plugins/javaFX/src/META-INF/common-javaFX-plugin.xml
@@ -26,6 +26,8 @@
enabledByDefault="true" level="WARNING" displayName="JavaFX redundant property values" groupName="JavaFX"/>
+
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 07608b6e1949..74ace5e83b0d 100644
--- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java
+++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java
@@ -820,6 +820,40 @@ public class JavaFxPsiUtil {
InheritanceUtil.isInheritor(fieldType, JavaFxCommonNames.JAVAFX_COLLECTIONS_OBSERVABLE_MAP);
}
+ public static boolean isNotFullyResolvedGeneric(@NotNull PsiClassType classType) {
+ final PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
+ final PsiClass psiClass = resolveResult.getElement();
+ if (psiClass == null || psiClass instanceof PsiTypeParameter) return true;
+ final PsiSubstitutor substitutor = resolveResult.getSubstitutor();
+ for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(psiClass)) {
+ final PsiType substitute = substitutor.substitute(parameter);
+ if (substitute == null || substitute instanceof PsiClassType && isNotFullyResolvedGeneric((PsiClassType)substitute)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Nullable
+ public static PsiSubstitutor getTagClassSubstitutor(@NotNull XmlTag xmlTag,
+ @Nullable PsiClass fieldClass,
+ @Nullable PsiClass controllerClass) {
+ if (fieldClass != null && controllerClass != null) {
+ final String tagFieldName = xmlTag.getAttributeValue(FxmlConstants.FX_ID);
+ if (tagFieldName != null) {
+ final PsiField tagField = controllerClass.findFieldByName(tagFieldName, true);
+ if (tagField != null && !tagField.hasModifierProperty(PsiModifier.STATIC) && isVisibleInFxml(tagField)) {
+ final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(tagField.getType());
+ final PsiClass resolvedClass = resolveResult.getElement();
+ if (resolvedClass != null) {
+ return TypeConversionUtil.getClassSubstitutor(fieldClass, resolvedClass, resolveResult.getSubstitutor());
+ }
+ }
+ }
+ }
+ return null;
+ }
+
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/codeInsight/inspections/JavaFxEventHandlerInspection.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxEventHandlerInspection.java
new file mode 100644
index 000000000000..6fce1ce6d307
--- /dev/null
+++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/codeInsight/inspections/JavaFxEventHandlerInspection.java
@@ -0,0 +1,219 @@
+package org.jetbrains.plugins.javaFX.fxml.codeInsight.inspections;
+
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.codeInspection.XmlSuppressableInspectionTool;
+import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PropertyUtil;
+import com.intellij.psi.xml.XmlAttribute;
+import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.xml.XmlElementDescriptor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.javaFX.fxml.JavaFxCommonNames;
+import org.jetbrains.plugins.javaFX.fxml.JavaFxFileTypeFactory;
+import org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil;
+
+import javax.swing.*;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.jetbrains.plugins.javaFX.fxml.JavaFxPsiUtil.isNotFullyResolvedGeneric;
+
+/**
+ * @author Pavel.Dolgov
+ */
+public class JavaFxEventHandlerInspection extends XmlSuppressableInspectionTool {
+ public boolean myDetectNonVoidReturnType;
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+ return new XmlElementVisitor() {
+ @Override
+ public void visitXmlFile(XmlFile file) {
+ if (!JavaFxFileTypeFactory.isFxml(file)) return;
+ super.visitXmlFile(file);
+ }
+
+ @Override
+ public void visitXmlAttribute(XmlAttribute attribute) {
+ super.visitXmlAttribute(attribute);
+
+ final PsiFile containingFile = attribute.getContainingFile();
+ final PsiClass controllerClass = JavaFxPsiUtil.getControllerClass(containingFile);
+ if (controllerClass == null) return;
+
+ final String valueText = attribute.getValue();
+ if (valueText == null || !valueText.startsWith("#")) return;
+ final String eventHandlerMethodName = valueText.substring(1);
+
+ List eventHandlerMethods =
+ Arrays.stream(controllerClass.findMethodsByName(eventHandlerMethodName, true))
+ .filter(method -> !method.hasModifierProperty(PsiModifier.STATIC) && JavaFxPsiUtil.isVisibleInFxml(method))
+ .filter(JavaFxEventHandlerInspection::hasEventArgument)
+ .collect(Collectors.toList());
+ if (eventHandlerMethods.size() == 0) return;
+ if (eventHandlerMethods.size() != 1) {
+ holder.registerProblem(getHighlightedElement(attribute), "Ambiguous event handler name: more than one matching method found");
+ }
+
+ if (myDetectNonVoidReturnType) {
+ eventHandlerMethods.stream()
+ .map(PsiMethod::getReturnType)
+ .filter(returnType -> !PsiType.VOID.equals(returnType))
+ .findAny()
+ .ifPresent(ignored -> holder.registerProblem(getHighlightedElement(attribute), "Return type of event handler should be void"));
+ }
+
+ final PsiClassType eventClassType = getHandlerArgumentClassType(attribute, controllerClass);
+ if (eventClassType == null) return;
+ final boolean eventClassTypeNotFullyResolved = isNotFullyResolvedGeneric(eventClassType);
+
+ eventHandlerMethods.stream()
+ .map(method -> method.getParameterList().getParameters())
+ .filter(parameters -> parameters.length == 1)
+ .map(parameters -> parameters[0].getType())
+ .forEach(argType -> {
+ if (argType instanceof PsiClassType) {
+ final boolean assignable;
+ if (eventClassTypeNotFullyResolved || isNotFullyResolvedGeneric((PsiClassType)argType)) {
+ assignable = isAssignableFromIgnoringUnresolved((PsiClassType)argType, eventClassType);
+ }
+ else {
+ assignable = argType.isAssignableFrom(eventClassType);
+ }
+ if (!assignable) {
+ holder.registerProblem(getHighlightedElement(attribute),
+ "Incompatible event handler argument: " + argType.getPresentableText() +
+ " is not assignable from " + eventClassType.getPresentableText());
+ }
+ }
+ else {
+ holder.registerProblem(getHighlightedElement(attribute),
+ "Unresolved event handler argument type " + argType.getCanonicalText());
+ }
+ });
+ }
+ };
+ }
+
+ private static boolean isAssignableFromIgnoringUnresolved(@Nullable PsiClassType left, @Nullable PsiClassType right) {
+ if (left == null || right == null) return true;
+ final PsiClassType.ClassResolveResult leftResolveResult = left.resolveGenerics();
+ final PsiClassType.ClassResolveResult rightResolveResult = right.resolveGenerics();
+
+ final PsiClass leftClass = leftResolveResult.getElement();
+ final PsiClass rightClass = rightResolveResult.getElement();
+
+ if (leftClass == null || rightClass == null || leftClass instanceof PsiTypeParameter || rightClass instanceof PsiTypeParameter) {
+ return true;
+ }
+ if (leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) {
+ // generic args are assignable or unresolved
+ if (!leftClass.hasTypeParameters()) return true;
+ final PsiSubstitutor leftSubstitutor = leftResolveResult.getSubstitutor();
+ final PsiSubstitutor rightSubstitutor = rightResolveResult.getSubstitutor();
+ final PsiTypeParameter[] typeParameters = leftClass.getTypeParameters();
+ for (PsiTypeParameter typeParameter : typeParameters) {
+ final PsiType leftParameter = leftSubstitutor.substitute(typeParameter);
+ if (leftParameter == null || leftParameter instanceof PsiTypeParameter) continue;
+ final PsiType rightParameter = rightSubstitutor.substitute(typeParameter);
+ if (rightParameter == null || rightParameter instanceof PsiTypeParameter) continue;
+ final PsiClassType leftParameterClass = getBoundClassType(leftParameter, true);
+ final PsiClassType rightParameterClass = getBoundClassType(rightParameter, false);
+ if (!isAssignableFromIgnoringUnresolved(leftParameterClass, rightParameterClass)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ else if (leftClass.isInheritor(rightClass, true)) {
+ // generic args are equal
+ final PsiType rightSubstitute = leftResolveResult.getSubstitutor().substitute(right);
+ return rightSubstitute.isAssignableFrom(left);
+ }
+ return false;
+ }
+
+ @Nullable
+ private static PsiClassType getBoundClassType(PsiType psiType, boolean isSuper) {
+ if (psiType instanceof PsiClassType) {
+ return (PsiClassType)psiType;
+ }
+ if (psiType instanceof PsiWildcardType) {
+ PsiWildcardType wildcardType = (PsiWildcardType)psiType;
+ if (isSuper && wildcardType.isSuper() || !isSuper && wildcardType.isExtends()) {
+ final PsiType bound = wildcardType.getBound();
+ if (bound instanceof PsiClassType) return (PsiClassType)bound;
+ }
+ }
+ return null;
+ }
+
+ private static PsiElement getHighlightedElement(XmlAttribute attribute) {
+ final XmlAttributeValue valueElement = attribute.getValueElement();
+ return valueElement != null ? valueElement : attribute;
+ }
+
+ @Nullable
+ private static PsiClassType getHandlerArgumentClassType(@NotNull XmlAttribute attribute, PsiClass controllerClass) {
+ final XmlTag xmlTag = attribute.getParent();
+ final XmlElementDescriptor descriptor = xmlTag.getDescriptor();
+ if (descriptor == null) return null;
+ final PsiElement declaration = descriptor.getDeclaration();
+ if (!(declaration instanceof PsiClass)) return null;
+ final PsiClass tagClass = (PsiClass)declaration;
+
+ final String handlerSetterName = PropertyUtil.suggestSetterName(attribute.getName());
+ final PsiMethod[] handlerSetterCandidates = tagClass.findMethodsByName(handlerSetterName, true);
+ if (handlerSetterCandidates.length == 0) return null;
+
+ final Project project = attribute.getProject();
+ final PsiClass javaFxEventHandlerClass = JavaPsiFacade.getInstance(project).findClass(JavaFxCommonNames.JAVAFX_EVENT_EVENT_HANDLER,
+ GlobalSearchScope.allScope(project));
+ if (javaFxEventHandlerClass != null) {
+ final PsiTypeParameter[] typeParameters = javaFxEventHandlerClass.getTypeParameters();
+ if (typeParameters.length == 1) {
+ final PsiTypeParameter javaFxEventHandlerTypeParameter = typeParameters[0];
+ final PsiSubstitutor tagClassSubstitutor = JavaFxPsiUtil.getTagClassSubstitutor(xmlTag, tagClass, controllerClass);
+ for (PsiMethod handlerSetter : handlerSetterCandidates) {
+ if (handlerSetter.hasModifierProperty(PsiModifier.STATIC) || !handlerSetter.hasModifierProperty(PsiModifier.PUBLIC)) continue;
+ final PsiParameter[] parameters = handlerSetter.getParameterList().getParameters();
+ if (parameters.length == 1) {
+ PsiType handlerParameterType = parameters[0].getType();
+ if (tagClassSubstitutor != null) {
+ handlerParameterType = tagClassSubstitutor.substitute(handlerParameterType);
+ }
+ if (handlerParameterType instanceof PsiClassType &&
+ InheritanceUtil.isInheritorOrSelf(((PsiClassType)handlerParameterType).resolve(), javaFxEventHandlerClass, true)) {
+ final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)handlerParameterType).resolveGenerics();
+ final PsiType eventType = resolveResult.getSubstitutor().substitute(javaFxEventHandlerTypeParameter);
+ PsiClassType eventClassType = getBoundClassType(eventType, true);
+ if (eventClassType != null) return eventClassType;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static boolean hasEventArgument(@NotNull PsiMethod method) {
+ final PsiParameter[] parameters = method.getParameterList().getParameters();
+ return parameters.length == 0 ||
+ parameters.length == 1 && InheritanceUtil.isInheritor(parameters[0].getType(), JavaFxCommonNames.JAVAFX_EVENT);
+ }
+
+ @Nullable
+ @Override
+ public JComponent createOptionsPanel() {
+ return new SingleCheckboxOptionsPanel("Detect event handler method having non-void return type", this, "myDetectNonVoidReturnType");
+ }
+}
diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java
index 12bda8520d26..387dde67d20a 100644
--- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java
+++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/refs/JavaFxEventHandlerReference.java
@@ -26,6 +26,7 @@ import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -71,7 +72,8 @@ public class JavaFxEventHandlerReference extends PsiReferenceBase new JavaFxEventHandlerReference(xmlAttributeValue, currentTagClass, handlerMethod, controllerClass))
+ .toArray(PsiReference.ARRAY_FACTORY::create);
+
+ if (references.length == 1) {
+ return references;
}
- if (handlerMethod == null) {
+ if (references.length > 1) {
+ return new PsiReference[]{new PsiMultiReference(references, xmlAttributeValue)};
+ }
+
+ if (references.length == 0) {
final XmlTag rootTag = ((XmlFile)xmlAttributeValue.getContainingFile()).getRootTag();
if (rootTag == null || FxmlConstants.FX_ROOT.equals(rootTag.getName())) {
return PsiReference.EMPTY_ARRAY;
}
}
- return new PsiReference[]{new JavaFxEventHandlerReference(xmlAttributeValue, (PsiClass)currentTagClass, handlerMethod, controllerClass)};
+ return new PsiReference[]{new JavaFxEventHandlerReference(xmlAttributeValue, currentTagClass, null, controllerClass)};
}
}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightAmbiguousController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightAmbiguousController.java
new file mode 100644
index 000000000000..0a10fd7fbe4c
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightAmbiguousController.java
@@ -0,0 +1,12 @@
+import javafx.event.ActionEvent;
+import javafx.event.Event;
+
+public class HighlightAmbiguousController {
+ public void onArgType(ActionEvent e) {}
+ public void onArgType(Event e) {}
+ public void onNoArg(ActionEvent e) {}
+ public void onNoArg() {}
+ public void onNotEvent(Event e) {}
+ public void onNotEvent(String notEvent) {}
+ public void onNotEvent(int notEvent) {}
+}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightExactController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightExactController.java
new file mode 100644
index 000000000000..6c68372c9569
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightExactController.java
@@ -0,0 +1,13 @@
+import javafx.event.ActionEvent;
+import javafx.event.Event;
+import javafx.scene.input.ScrollEvent;
+
+public class HighlightExactController {
+ public void onSameArg(ActionEvent e) {}
+ public void onSuperArg(Event e) {}
+ public void onNoArg() {}
+ public String onSameArgNotVoid(ActionEvent e) {return "";}
+ public Boolean onSuperArgNotVoid(Event e) {return false;}
+ public int onNoArgNotVoid() {return 1;}
+ public void onIncompatible(ScrollEvent e) {}
+}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java
new file mode 100644
index 000000000000..32c5e07d3f3c
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightMixedGenericController.java
@@ -0,0 +1,37 @@
+import javafx.fxml.FXML;
+import javafx.scene.control.*;
+import javafx.util.Pair;
+import java.util.Map;
+
+public class HighlightMixedGenericController {
+ @FXML TableView> specificTable;
+ @FXML TableView> specificTableHalfRawArg;
+ @FXML TableView> specificTableIncompatibleArg;
+ @FXML TableView> specificTableIncompatibleHalfRawArg;
+
+ @FXML TableView halfRawTable;
+ @FXML TableView halfRawTableHalfRawArg;
+ @FXML TableView halfRawTableIncompatibleArg;
+ @FXML TableView halfRawTableIncompatibleHalfRawArg;
+
+ @FXML TableView rawTable;
+ @FXML TableView rawTableHalfRawArg;
+ @FXML TableView rawTableIncompatibleArg;
+ @FXML TableView rawTableIncompatibleHalfRawArg;
+
+ public void onSort(SortEvent>> e) {}
+ public void onScrollTo(ScrollToEvent e) {}
+ public void onScrollToColumn(ScrollToEvent, ?>> e) {}
+
+ public void onSortHalfRawArg(SortEvent e) {}
+ public void onScrollToHalfRawArg(ScrollToEvent extends Number> e) {}
+ public void onScrollToColumnHalfRawArg(ScrollToEvent e) {}
+
+ public void onSortIncompatibleArg(SortEvent>> e) {}
+ public void onScrollToIncompatibleArg(ScrollToEvent e) {}
+ public void onScrollToColumnIncompatibleArg(ScrollToEvent, ?>> e) {}
+
+ public void onSortIncompatibleHalfRawArg(SortEvent> e) {}
+ public void onScrollToIncompatibleHalfRawArg(ScrollToEvent super Number> e) {}
+ public void onScrollToColumnIncompatibleHalfRawArg(ScrollToEvent> e) {}
+}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoidController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoidController.java
new file mode 100644
index 000000000000..d14be2642bd5
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightNonVoidController.java
@@ -0,0 +1,8 @@
+import javafx.event.ActionEvent;
+import javafx.event.Event;
+
+public class HighlightNonVoidController {
+ public String onSameArgNotVoid(ActionEvent e) {return "";}
+ public Boolean onSuperArgNotVoid(Event e) {return false;}
+ public int onNoArgNotVoid() {return 1;}
+}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightSimpleGenericController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightSimpleGenericController.java
new file mode 100644
index 000000000000..de82494ff233
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightSimpleGenericController.java
@@ -0,0 +1,10 @@
+import javafx.fxml.FXML;
+import javafx.scene.control.*;
+
+public class HighlightSimpleGenericController {
+ @FXML ListView list;
+
+ public void onEditStart(ListView.EditEvent> e) {}
+ public void onEditCancel(ListView.EditEvent e) {}
+ public void onEditCommit(ListView.EditEvent e) {}
+}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcardController.java b/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcardController.java
new file mode 100644
index 000000000000..4bb1b0f45474
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/HighlightWildcardController.java
@@ -0,0 +1,13 @@
+import javafx.event.Event;
+import javafx.fxml.FXML;
+import javafx.scene.control.SortEvent;
+import javafx.scene.input.MouseDragEvent;
+import javafx.scene.input.MouseEvent;
+
+public class HighlightWildcardController {
+ @FXML private void onSameArg(MouseEvent e) {}
+ @FXML private void onSuperArg(Event e) {}
+ @FXML private void onNoArg() {}
+ @FXML private void onNotSuper(MouseDragEvent e) {}
+ @FXML private void onNotRelated(SortEvent e) {}
+}
diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml
new file mode 100644
index 000000000000..56b8dab341dc
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/highlightAmbiguous.fxml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightExact.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightExact.fxml
new file mode 100644
index 000000000000..81acca5c58d7
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/highlightExact.fxml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+ "#onIncompatible"/>
+
diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightMixedGeneric.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightMixedGeneric.fxml
new file mode 100644
index 000000000000..3a7b63e96c54
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/highlightMixedGeneric.fxml
@@ -0,0 +1,71 @@
+
+
+
+
+
+ "#onSortIncompatibleArg"
+ onScrollTo="#onScrollToIncompatibleArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleArg"/>
+ "#onSortIncompatibleHalfRawArg"
+ onScrollTo="#onScrollToIncompatibleHalfRawArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleHalfRawArg"/>
+
+
+
+ "#onScrollToIncompatibleArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleArg"/>
+ "#onSortIncompatibleHalfRawArg"
+ onScrollTo="#onScrollToIncompatibleHalfRawArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleHalfRawArg"/>
+
+
+
+ "#onScrollToIncompatibleArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleArg"/>
+ "#onSortIncompatibleHalfRawArg"
+ onScrollTo="#onScrollToIncompatibleHalfRawArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleHalfRawArg"/>
+
+
+
+ "#onScrollToIncompatibleArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleArg"/>
+ "#onSortIncompatibleHalfRawArg"
+ onScrollTo="#onScrollToIncompatibleHalfRawArg"
+ onScrollToColumn="#onScrollToColumnIncompatibleHalfRawArg"/>
+
diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightNonVoid.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightNonVoid.fxml
new file mode 100644
index 000000000000..6f60a5c5619c
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/highlightNonVoid.fxml
@@ -0,0 +1,7 @@
+
+
+
+ "#onSameArgNotVoid"/>
+ "#onSuperArgNotVoid"/>
+ "#onNoArgNotVoid"/>
+
diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightSimpleGeneric.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightSimpleGeneric.fxml
new file mode 100644
index 000000000000..876e91685271
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/highlightSimpleGeneric.fxml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/plugins/javaFX/testData/inspections/eventHandler/highlightWildcard.fxml b/plugins/javaFX/testData/inspections/eventHandler/highlightWildcard.fxml
new file mode 100644
index 000000000000..1bd00483437b
--- /dev/null
+++ b/plugins/javaFX/testData/inspections/eventHandler/highlightWildcard.fxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/plugins/javaFX/testData/quickfix/CreateControllerMethodGeneric.java b/plugins/javaFX/testData/quickfix/CreateControllerMethodGeneric.java
new file mode 100644
index 000000000000..ec702d015fc4
--- /dev/null
+++ b/plugins/javaFX/testData/quickfix/CreateControllerMethodGeneric.java
@@ -0,0 +1,9 @@
+import javafx.fxml.FXML;
+import javafx.scene.control.TableView;
+
+import java.util.Map;
+
+public class CreateControllerMethodGeneric {
+ @FXML
+ TableView