blob: ea482b0d0ce7fdd2d028084b387ac67ffdca6f00 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.javaFX.fxml;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
import com.intellij.lang.ASTNode;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.*;
import com.intellij.psi.xml.*;
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.JavaFxDefaultPropertyElementDescriptor;
import org.jetbrains.plugins.javaFX.fxml.descriptors.JavaFxPropertyElementDescriptor;
import java.util.*;
/**
* User: anna
*/
public class JavaFxPsiUtil {
private static final Logger LOG = Logger.getInstance("#" + JavaFxPsiUtil.class.getName());
public static XmlProcessingInstruction createSingleImportInstruction(String qualifiedName, Project project) {
final String importText = "<?import " + qualifiedName + "?>";
final PsiElement child =
PsiFileFactory.getInstance(project).createFileFromText("a.fxml", XMLLanguage.INSTANCE, importText).getFirstChild();
return PsiTreeUtil.findChildOfType(child, XmlProcessingInstruction.class);
}
public static List<String> parseImports(XmlFile file) {
return parseInstructions(file, "import");
}
public static List<String> parseInjectedLanguages(XmlFile file) {
return parseInstructions(file, "language");
}
private static List<String> parseInstructions(XmlFile file, String instructionName) {
List<String> definedImports = new ArrayList<String>();
XmlDocument document = file.getDocument();
if (document != null) {
XmlProlog prolog = document.getProlog();
final Collection<XmlProcessingInstruction>
instructions = new ArrayList<XmlProcessingInstruction>(PsiTreeUtil.findChildrenOfType(prolog, XmlProcessingInstruction.class));
for (final XmlProcessingInstruction instruction : instructions) {
final String instructionTarget = getInstructionTarget(instructionName, instruction);
if (instructionTarget != null) {
definedImports.add(instructionTarget);
}
}
}
return definedImports;
}
@Nullable
public static String getInstructionTarget(String instructionName, XmlProcessingInstruction instruction) {
final ASTNode node = instruction.getNode();
ASTNode xmlNameNode = node.findChildByType(XmlTokenType.XML_NAME);
ASTNode importNode = node.findChildByType(XmlTokenType.XML_TAG_CHARACTERS);
if (!(xmlNameNode == null || !instructionName.equals(xmlNameNode.getText()) || importNode == null)) {
return importNode.getText();
}
return null;
}
public static PsiClass findPsiClass(String name, XmlTag tag) {
final Project project = tag.getProject();
if (!StringUtil.getShortName(name).equals(name)) {
return JavaPsiFacade.getInstance(project).findClass(name, GlobalSearchScope.allScope(project));
}
return findPsiClass(name, parseImports((XmlFile)tag.getContainingFile()), tag, project);
}
private static PsiClass findPsiClass(String name, List<String> imports, XmlTag tag, Project project) {
PsiClass psiClass = null;
if (imports != null) {
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
PsiFile file = tag.getContainingFile();
for (String anImport : imports) {
if (StringUtil.getShortName(anImport).equals(name)) {
psiClass = psiFacade.findClass(anImport, file.getResolveScope());
} else if (StringUtil.endsWith(anImport, ".*")) {
psiClass = psiFacade.findClass(StringUtil.trimEnd(anImport, "*") + name, file.getResolveScope());
}
if (psiClass != null) {
return psiClass;
}
}
}
return psiClass;
}
public static void insertImportWhenNeeded(XmlFile xmlFile,
String shortName,
String qualifiedName) {
if (shortName != null && findPsiClass(shortName, xmlFile.getRootTag()) == null) {
final XmlDocument document = xmlFile.getDocument();
if (document != null) {
final XmlProcessingInstruction processingInstruction = createSingleImportInstruction(qualifiedName, xmlFile.getProject());
final XmlProlog prolog = document.getProlog();
if (prolog != null) {
prolog.add(processingInstruction);
} else {
document.addBefore(processingInstruction, document.getRootTag());
}
PostprocessReformattingAspect.getInstance(xmlFile.getProject()).doPostponedFormatting(xmlFile.getViewProvider());
}
}
}
public static PsiClass getPropertyClass(PsiElement field) {
final PsiClassType classType = getPropertyClassType(field);
return classType != null ? classType.resolve() : null;
}
public static PsiClassType getPropertyClassType(PsiElement field) {
return getPropertyClassType(field, JavaFxCommonClassNames.JAVAFX_BEANS_PROPERTY_OBJECT_PROPERTY);
}
public static PsiClassType getPropertyClassType(PsiElement field, final String superTypeFQN) {
if (field instanceof PsiMember) {
final PsiType type = PropertyUtil.getPropertyType((PsiMember)field);
if (type instanceof PsiClassType) {
final PsiClassType.ClassResolveResult resolveResult = ((PsiClassType)type).resolveGenerics();
final PsiClass attributeClass = resolveResult.getElement();
if (attributeClass != null) {
final PsiClass objectProperty = JavaPsiFacade.getInstance(attributeClass.getProject())
.findClass(superTypeFQN, attributeClass.getResolveScope());
if (objectProperty != null) {
final PsiSubstitutor superClassSubstitutor = TypeConversionUtil
.getClassSubstitutor(objectProperty, attributeClass, resolveResult.getSubstitutor());
if (superClassSubstitutor != null) {
final PsiType propertyType = superClassSubstitutor.substitute(objectProperty.getTypeParameters()[0]);
if (propertyType instanceof PsiClassType) {
return (PsiClassType)propertyType;
}
}
else {
return (PsiClassType)type;
}
}
}
}
}
return null;
}
public static PsiMethod findPropertySetter(String attributeName, XmlTag context) {
final String packageName = StringUtil.getPackageName(attributeName);
if (context != null && !StringUtil.isEmptyOrSpaces(packageName)) {
final PsiClass classWithStaticProperty = findPsiClass(packageName, context);
if (classWithStaticProperty != null) {
return findPropertySetter(attributeName, classWithStaticProperty);
}
}
return null;
}
public static PsiMethod findPropertySetter(String attributeName, PsiClass classWithStaticProperty) {
final String setterName = PropertyUtil.suggestSetterName(StringUtil.getShortName(attributeName));
final PsiMethod[] setters = classWithStaticProperty.findMethodsByName(setterName, true);
if (setters.length >= 1) {
return setters[0];
}
return null;
}
public static PsiMethod findPropertyGetter(String attributeName, PsiClass classWithStaticProperty) {
PsiMethod getter = findPropertyGetter(attributeName, classWithStaticProperty, null);
if (getter != null) {
return getter;
}
return findPropertyGetter(attributeName, classWithStaticProperty, PsiType.BOOLEAN);
}
private static PsiMethod findPropertyGetter(final String attributeName,
final PsiClass classWithStaticProperty,
final PsiType propertyType) {
final String getterName = PropertyUtil.suggestGetterName(StringUtil.getShortName(attributeName), propertyType);
final PsiMethod[] getters = classWithStaticProperty.findMethodsByName(getterName, true);
if (getters.length >= 1) {
return getters[0];
}
return null;
}
private static final Key<CachedValue<PsiClass>> INJECTED_CONTROLLER = Key.create("javafx.injected.controller");
private static final RecursionGuard ourGuard = RecursionManager.createGuard("javafx.controller");
public static PsiClass getControllerClass(final PsiFile containingFile) {
if (containingFile instanceof XmlFile) {
final XmlTag rootTag = ((XmlFile)containingFile).getRootTag();
final Project project = containingFile.getProject();
if (rootTag != null) {
XmlAttribute attribute = rootTag.getAttribute(FxmlConstants.FX_CONTROLLER);
if (attribute != null) {
final PsiClass controllerClass = findControllerClass(containingFile, project, attribute);
if (controllerClass != null) {
return controllerClass;
}
}
}
final CachedValuesManager manager = CachedValuesManager.getManager(containingFile.getProject());
final PsiClass injectedControllerClass = ourGuard.doPreventingRecursion(containingFile, true, new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return manager.getCachedValue(containingFile, INJECTED_CONTROLLER,
new JavaFxControllerCachedValueProvider(containingFile.getProject(), containingFile), true);
}
});
if (injectedControllerClass != null) {
return injectedControllerClass;
}
if (rootTag != null && FxmlConstants.FX_ROOT.equals(rootTag.getName())) {
final XmlAttribute rootTypeAttr = rootTag.getAttribute(FxmlConstants.TYPE);
if (rootTypeAttr != null) {
return findControllerClass(containingFile, project, rootTypeAttr);
}
}
}
return null;
}
private static PsiClass findControllerClass(PsiFile containingFile, Project project, XmlAttribute attribute) {
final String attributeValue = attribute.getValue();
if (!StringUtil.isEmptyOrSpaces(attributeValue)) {
final GlobalSearchScope customScope = GlobalSearchScope.projectScope(project).intersectWith(containingFile.getResolveScope());
return JavaPsiFacade.getInstance(project).findClass(attributeValue, customScope);
}
return null;
}
public static boolean checkIfAttributeHandler(XmlAttribute attribute) {
final String attributeName = attribute.getName();
final XmlTag xmlTag = attribute.getParent();
final XmlElementDescriptor descriptor = xmlTag.getDescriptor();
if (descriptor == null) return false;
final PsiElement currentTagClass = descriptor.getDeclaration();
if (!(currentTagClass instanceof PsiClass)) return false;
final PsiField handlerField = ((PsiClass)currentTagClass).findFieldByName(attributeName, true);
if (handlerField == null) {
final String suggestedSetterName = PropertyUtil.suggestSetterName(attributeName);
final PsiMethod[] existingSetters = ((PsiClass)currentTagClass).findMethodsByName(suggestedSetterName, true);
for (PsiMethod setter : existingSetters) {
final PsiParameter[] parameters = setter.getParameterList().getParameters();
if (parameters.length == 1 && InheritanceUtil.isInheritor(parameters[0].getType(), JavaFxCommonClassNames.JAVAFX_EVENT_EVENT_HANDLER)) {
return true;
}
}
return false;
}
final PsiClass objectPropertyClass = getPropertyClass(handlerField);
if (objectPropertyClass == null || !InheritanceUtil.isInheritor(objectPropertyClass, JavaFxCommonClassNames.JAVAFX_EVENT_EVENT_HANDLER)) {
return false;
}
return true;
}
@Nullable
public static PsiClass getTagClass(XmlAttributeValue xmlAttributeValue) {
if (xmlAttributeValue == null) return null;
final PsiElement xmlAttribute = xmlAttributeValue.getParent();
final XmlTag xmlTag = ((XmlAttribute)xmlAttribute).getParent();
if (xmlTag != null) {
return getTagClass(xmlTag);
}
return null;
}
public static PsiClass getTagClass(XmlTag xmlTag) {
final XmlElementDescriptor descriptor = xmlTag.getDescriptor();
if (descriptor != null) {
final PsiElement declaration = descriptor.getDeclaration();
if (declaration instanceof PsiClass) {
return (PsiClass)declaration;
}
}
return null;
}
public static boolean isVisibleInFxml(PsiMember psiMember) {
return psiMember.hasModifierProperty(PsiModifier.PUBLIC) ||
AnnotationUtil.isAnnotated(psiMember, JavaFxCommonClassNames.JAVAFX_FXML_ANNOTATION, false);
}
public static PsiMethod findValueOfMethod(@NotNull final PsiClass tagClass) {
final PsiMethod[] methods = tagClass.findMethodsByName(JavaFxCommonClassNames.VALUE_OF, false);
for (PsiMethod method : methods) {
if (method.hasModifierProperty(PsiModifier.STATIC)) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length == 1) {
final PsiType type = parameters[0].getType();
if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING) || type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
if (method.hasModifierProperty(PsiModifier.STATIC) && tagClass.equals(PsiUtil.resolveClassInType(method.getReturnType()))) {
return method;
}
}
}
}
}
return null;
}
public static boolean isReadOnly(String attributeName, XmlTag tag) {
final XmlElementDescriptor descriptor = tag.getDescriptor();
if (descriptor != null) {
final PsiElement declaration = descriptor.getDeclaration();
if (declaration instanceof PsiClass) {
final PsiClass psiClass = (PsiClass)declaration;
final PsiField psiField = psiClass.findFieldByName(attributeName, true);
if (psiField != null) {
return isReadOnly(psiClass, psiField);
}
}
}
return false;
}
public static boolean isReadOnly(PsiClass psiClass, PsiField psiField) {
final String name = psiField.getName();
if (findPropertySetter(name, psiClass) == null &&
!InheritanceUtil.isInheritor(psiField.getType(), "javafx.collections.ObservableList")) {
//todo read only condition?
final PsiMethod[] constructors = psiClass.getConstructors();
for (PsiMethod constructor : constructors) {
for (PsiParameter parameter : constructor.getParameterList().getParameters()) {
if (psiField.getType().equals(parameter.getType())) {
return false;
}
}
}
return true;
}
return false;
}
public static boolean isExpressionBinding(String value) {
if (!value.startsWith("$")) return false;
value = value.substring(1);
return value.startsWith("{") && value.endsWith("}") && value.contains(".");
}
@Nullable
public static PsiType getPropertyType(final PsiType type, final Project project) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(type);
final PsiClass psiClass = resolveResult.getElement();
if (psiClass != null) {
final PsiClass propertyClass = JavaPsiFacade.getInstance(project).findClass(JavaFxCommonClassNames.JAVAFX_BEANS_PROPERTY,
GlobalSearchScope.allScope(project));
if (propertyClass != null) {
final PsiSubstitutor substitutor =
TypeConversionUtil.getClassSubstitutor(propertyClass, psiClass, resolveResult.getSubstitutor());
if (substitutor != null) {
return substitutor.substitute(propertyClass.getTypeParameters()[0]);
}
}
}
return null;
}
public static PsiType getDefaultPropertyExpectedType(PsiClass aClass) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(aClass, Collections.singleton(JavaFxCommonClassNames.JAVAFX_BEANS_DEFAULT_PROPERTY));
if (annotation != null) {
final PsiAnnotationMemberValue memberValue = annotation.findAttributeValue(null);
if (memberValue != null) {
final String propertyName = StringUtil.stripQuotesAroundValue(memberValue.getText());
final PsiMethod getter = findPropertyGetter(propertyName, aClass);
if (getter != null) {
return getter.getReturnType();
}
}
}
return null;
}
public static String getDefaultPropertyName(PsiClass aClass) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(aClass,
Collections.singleton(JavaFxCommonClassNames.JAVAFX_BEANS_DEFAULT_PROPERTY));
if (annotation != null) {
final PsiAnnotationMemberValue memberValue = annotation.findAttributeValue(null);
if (memberValue != null) {
return StringUtil.stripQuotesAroundValue(memberValue.getText());
}
}
return null;
}
public static String isAbleToInstantiate(final PsiClass psiClass) {
if(psiClass.getConstructors().length > 0) {
for (PsiMethod constr : psiClass.getConstructors()) {
if (constr.getParameterList().getParametersCount() == 0) return null;
}
final PsiMethod valueOf = findValueOfMethod(psiClass);
if (valueOf == null) {
if (!hasBuilder(psiClass)) return "Unable to instantiate";
}
}
return null;
}
public static boolean hasBuilder(@NotNull final PsiClass psiClass) {
final Project project = psiClass.getProject();
return CachedValuesManager.getManager(project).getCachedValue(psiClass, new CachedValueProvider<Boolean>() {
@Nullable
@Override
public Result<Boolean> compute() {
final PsiClass builderClass = JavaPsiFacade.getInstance(project).findClass(JavaFxCommonClassNames.JAVAFX_FXML_BUILDER,
GlobalSearchScope.allScope(project));
if (builderClass != null) {
final PsiMethod[] buildMethods = builderClass.findMethodsByName("build", false);
if (buildMethods.length == 1 && buildMethods[0].getParameterList().getParametersCount() == 0) {
if (ClassInheritorsSearch.search(builderClass).forEach(new Processor<PsiClass>() {
@Override
public boolean process(PsiClass aClass) {
PsiType returnType = null;
final PsiMethod method = MethodSignatureUtil.findMethodBySuperMethod(aClass, buildMethods[0], false);
if (method != null) {
returnType = method.getReturnType();
}
return !Comparing.equal(psiClass, PsiUtil.resolveClassInClassTypeOnly(returnType));
}
})) {
return Result.create(false, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
}
}
}
return Result.create(true, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
}
});
}
public static String isClassAcceptable(@Nullable XmlTag parentTag, final PsiClass aClass) {
if (parentTag == null) {
return null;
}
if (aClass != null && aClass.isValid()) {
XmlElementDescriptor descriptor = parentTag.getDescriptor();
if (descriptor instanceof JavaFxDefaultPropertyElementDescriptor) {
descriptor = ((JavaFxDefaultPropertyElementDescriptor)descriptor).getRootTagDescriptor(parentTag);
}
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) {
PsiType collectionItemType = JavaGenericsUtil.getCollectionItemType(type, aClass.getResolveScope());
if (collectionItemType == null && InheritanceUtil.isInheritor(type, JavaFxCommonClassNames.JAVAFX_BEANS_PROPERTY)) {
collectionItemType = getPropertyType(type, aClass.getProject());
}
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;
}
public static boolean isOutOfHierarchy(final XmlAttributeValue element) {
XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
while (tag != null) {
if (FxmlConstants.FX_DEFINE.equals(tag.getName())) {
return true;
}
tag = tag.getParentTag();
}
return false;
}
public static PsiType getWrappedPropertyType(PsiField field, final Project project, final Map<String, PsiType> typeMap) {
final PsiType fieldType = field.getType();
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(fieldType);
final PsiClass fieldClass = resolveResult.getElement();
if (fieldClass == null) return fieldType;
return CachedValuesManager.getManager(project).getCachedValue(field, new CachedValueProvider<PsiType>() {
@Nullable
@Override
public Result<PsiType> compute() {
PsiType substitute = null;
for (String typeName : typeMap.keySet()) {
if (InheritanceUtil.isInheritor(fieldType, typeName)) {
substitute = typeMap.get(typeName);
break;
}
}
if (substitute == null) {
if (!InheritanceUtil.isInheritor(fieldType, JavaFxCommonClassNames.JAVAFX_BEANS_VALUE_OBSERVABLE_VALUE)) {
return Result.create(fieldType, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
}
final PsiClass aClass = JavaPsiFacade.getInstance(project)
.findClass(JavaFxCommonClassNames.JAVAFX_BEANS_VALUE_OBSERVABLE_VALUE, GlobalSearchScope.allScope(project));
LOG.assertTrue(aClass != null);
final PsiSubstitutor substitutor =
TypeConversionUtil.getSuperClassSubstitutor(aClass, fieldClass, resolveResult.getSubstitutor());
final PsiMethod[] values = aClass.findMethodsByName("getValue", false);
substitute = substitutor.substitute(values[0].getReturnType());
}
return Result.create(substitute, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
}
});
}
private static class JavaFxControllerCachedValueProvider implements CachedValueProvider<PsiClass> {
private final Project myProject;
private final PsiFile myContainingFile;
public JavaFxControllerCachedValueProvider(Project project, PsiFile containingFile) {
myProject = project;
myContainingFile = containingFile;
}
@Nullable
@Override
public Result<PsiClass> compute() {
final Ref<PsiClass> injectedController = new Ref<PsiClass>();
final Ref<PsiFile> dep = new Ref<PsiFile>();
final PsiClass fxmlLoader =
JavaPsiFacade.getInstance(myProject).findClass(JavaFxCommonClassNames.JAVAFX_FXML_FXMLLOADER, GlobalSearchScope.allScope(myProject));
if (fxmlLoader != null) {
final PsiMethod[] injectControllerMethods = fxmlLoader.findMethodsByName("setController", false);
if (injectControllerMethods.length == 1) {
final JavaFxRetrieveControllerProcessor processor = new JavaFxRetrieveControllerProcessor() {
@Override
protected boolean isResolveToSetter(PsiMethodCallExpression methodCallExpression) {
return methodCallExpression.resolveMethod() == injectControllerMethods[0];
}
};
final GlobalSearchScope globalSearchScope = GlobalSearchScope
.notScope(GlobalSearchScope.getScopeRestrictedByFileTypes(myContainingFile.getResolveScope(), StdFileTypes.XML));
ReferencesSearch.search(myContainingFile, globalSearchScope).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference reference) {
final PsiElement element = reference.getElement();
if (element instanceof PsiLiteralExpression) {
final PsiNewExpression expression = PsiTreeUtil.getParentOfType(element, PsiNewExpression.class);
if (expression != null) {
final PsiType type = expression.getType();
if (type != null && type.equalsToText(JavaFxCommonClassNames.JAVAFX_FXML_FXMLLOADER)) {
final PsiElement parent = expression.getParent();
if (parent instanceof PsiLocalVariable) {
ReferencesSearch.search(parent).forEach(processor);
final PsiClass controller = processor.getInjectedController();
if (controller != null) {
injectedController.set(controller);
dep.set(processor.getContainingFile());
return false;
}
}
}
}
}
return true;
}
});
}
}
return new Result<PsiClass>(injectedController.get(), dep.get() != null ? dep.get() : PsiModificationTracker.MODIFICATION_COUNT);
}
private static abstract class JavaFxRetrieveControllerProcessor implements Processor<PsiReference> {
private final Ref<PsiClass> myInjectedController = new Ref<PsiClass>();
private final Ref<PsiFile> myContainingFile = new Ref<PsiFile>();
protected abstract boolean isResolveToSetter(PsiMethodCallExpression methodCallExpression);
@Override
public boolean process(PsiReference reference) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression) {
final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
if (methodCallExpression != null && isResolveToSetter(methodCallExpression)) {
final PsiExpression[] expressions = methodCallExpression.getArgumentList().getExpressions();
if (expressions.length > 0) {
final PsiClass psiClass = PsiUtil.resolveClassInType(expressions[0].getType());
if (psiClass != null) {
myInjectedController.set(psiClass);
myContainingFile.set(methodCallExpression.getContainingFile());
return false;
}
}
}
}
return true;
}
private PsiClass getInjectedController() {
return myInjectedController.get();
}
private PsiFile getContainingFile() {
return myContainingFile.get();
}
}
}
}