/*
* Copyright 2012-2015 Sergey Ignatov
*
* 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.intellij.erlang.completion;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiPolyVariantReference;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.erlang.psi.*;
import org.intellij.erlang.psi.impl.ErlangPsiImplUtil;
import org.intellij.erlang.types.ErlangExpressionType;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class ErlangCompletionUtil {
private ErlangCompletionUtil() {
}
@NotNull
static Set<ErlangExpressionType> expectedArgumentTypes(@NotNull PsiElement elementInCallArgument) {
ErlangExpression expr = PsiTreeUtil.getParentOfType(elementInCallArgument, ErlangExpression.class);
ErlangArgumentList argList = ObjectUtils.tryCast(expr != null ? expr.getParent() : null, ErlangArgumentList.class);
PsiElement argListOwner = argList != null ? argList.getParent() : null;
ErlangFunctionCallExpression call = ObjectUtils.tryCast(argListOwner, ErlangFunctionCallExpression.class);
int argIndex = call != null ? ContainerUtil.indexOfIdentity(argList.getExpressionList(), expr) : -1;
return argIndex != -1 ? expectedArgumentTypes(call, argIndex) : Collections.<ErlangExpressionType>emptySet();
}
static boolean containsType(@NotNull Set<ErlangExpressionType> typeSet, @NotNull ErlangExpressionType type) {
for (ErlangExpressionType setItem : typeSet) {
if (setItem.accept(type)) return true;
}
return false;
}
@NotNull
private static Set<ErlangExpressionType> expectedArgumentTypes(@NotNull ErlangFunctionCallExpression call, int argIndex) {
PsiPolyVariantReference reference = (PsiPolyVariantReference) call.getReference();
if (reference == null) return Collections.emptySet();
HashSet<ErlangExpressionType> expectedArgumentTypes = ContainerUtil.newHashSet();
ResolveResult[] resolveResults = reference.multiResolve(true);
for (ResolveResult r : resolveResults) {
ErlangFunction function = ObjectUtils.tryCast(r.getElement(), ErlangFunction.class);
ErlangSpecification spec = function != null ? function.findSpecification() : null;
ErlangFunTypeSigs signature = ErlangPsiImplUtil.getSignature(spec);
List<ErlangTypeSig> sigs = signature != null ? signature.getTypeSigList() : ContainerUtil.<ErlangTypeSig>emptyList();
for (ErlangTypeSig sig : sigs) {
ErlangFunTypeArguments arguments = sig.getFunType().getFunTypeArguments();
ErlangType type = arguments.getTypeList().get(argIndex);
if (type != null) {
collectExpressionTypes(type, expectedArgumentTypes);
}
}
}
return expectedArgumentTypes;
}
private static void collectExpressionTypes(@NotNull ErlangType type, @NotNull Set<ErlangExpressionType> types) {
for (ErlangType childType : PsiTreeUtil.getChildrenOfTypeAsList(type, ErlangType.class)) {
collectExpressionTypes(childType, types);
}
ErlangTypeRef typeRef = type.getTypeRef();
String key = typeRef != null ? typeRef.getText() : type.getFirstChild().getText();
ErlangExpressionType et = ErlangExpressionType.TYPE_MAP.get(key);
ContainerUtil.addIfNotNull(types, et);
}
}