package org.jetbrains.plugins.ruby.motion.paramdefs; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.Pair; import com.intellij.util.containers.hash.HashMap; import org.jetbrains.annotations.TestOnly; import org.jetbrains.plugins.ruby.motion.bridgesupport.BridgeSupportLoader; import org.jetbrains.plugins.ruby.motion.bridgesupport.Class; import org.jetbrains.plugins.ruby.motion.bridgesupport.Framework; import org.jetbrains.plugins.ruby.motion.bridgesupport.Function; import org.jetbrains.plugins.ruby.motion.symbols.MotionSymbolUtil; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.AnyParamDef; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.ParamDefManager; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.ParamDefProvider; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.matcher.ParamDefExpression; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.matcher.ParamDefHash; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.matcher.ParamDefLeaf; import org.jetbrains.plugins.ruby.ruby.codeInsight.paramDefs.matcher.ParamDefSeq; import org.jetbrains.plugins.ruby.ruby.codeInsight.symbols.fqn.FQN; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; /** * @author Dennis.Ushakov */ public class RubyMotionParamdefsProvider implements ParamDefProvider { private static boolean ourParamdefsLoaded = false; @Override public void registerParamDefs(final ParamDefManager manager) { if (ApplicationManager.getApplication().isUnitTestMode()) { doRegisterParamdefs(manager); } } private static void doRegisterParamdefs(ParamDefManager manager) { final Map<String, Map<String, Collection<Function>>> mergedFunctions = new HashMap<>(); BridgeSupportLoader.getInstance().processFrameworks(framework -> loadAvailableSelectors(framework, mergedFunctions)); for (Map.Entry<String, Map<String, Collection<Function>>> entry : mergedFunctions.entrySet()) { registerParamDef(manager, entry.getKey(), entry.getValue()); } } private static void loadAvailableSelectors(Framework framework, Map<String, Map<String, Collection<Function>>> mergedFunctions) { final String version = framework.getVersion(); for (Class clazz : framework.getClasses()) { for (Function function : clazz.getFunctions()) { if (!canHaveParamdef(function)) continue; final String name = clazz.getName() + "." + MotionSymbolUtil.getSelectorNames(function).get(0); Map<String, Collection<Function>> allFunctions = mergedFunctions.get(name); if (allFunctions == null) { allFunctions = new HashMap<>(); mergedFunctions.put(name, allFunctions); } Collection<Function> frameworkFunctions = allFunctions.get(version); if (frameworkFunctions == null) { frameworkFunctions = new ArrayList<>(); allFunctions.put(version, frameworkFunctions); } frameworkFunctions.add(function); } } } private static boolean canHaveParamdef(Function function) { final List<Pair<String,String>> arguments = function.getArguments(); return arguments.size() >= 2 || (arguments.size() == 1 && "SEL".equals(arguments.get(0).second)); } private static void registerParamDef(final ParamDefManager manager, final String name, final Map<String, Collection<Function>> functions) { final FQN fqn = FQN.Builder.fromString(name); if (manager.getParamDefExpression(fqn) == null) { manager.registerParamDefExpression(fqn, buildExpression(functions)); } } private static ParamDefExpression buildExpression(final Map<String, Collection<Function>> functions) { boolean hadOneArg = false; boolean hadMoreArg = false; for (Collection<Function> collection : functions.values()) { for (Function function : collection) { hadOneArg |= function.getArguments().size() == 1; hadMoreArg |= function.getArguments().size() > 1; } } if (hadOneArg && !hadMoreArg) { return new ParamDefLeaf(SelectorKeysProvider.METHOD_REF_PARAM); } final ParamDefHash hash = new ParamDefHash(false, true, null); final SelectorKeysProvider provider = new SelectorKeysProvider(functions); hash.addKey(provider, new ParamDefLeaf(AnyParamDef.getInstance())); return new ParamDefSeq(new ParamDefLeaf(hadOneArg ? SelectorKeysProvider.METHOD_REF_PARAM : AnyParamDef.getInstance()), hash); } public static void ensureParamdefsLoaded() { if (ourParamdefsLoaded) return; doRegisterParamdefs(ParamDefManager.getInstance()); ourParamdefsLoaded = true; } @TestOnly public static void reset() { ourParamdefsLoaded = false; } }