/* * Copyright 2000-2014 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.groovy.lang.psi.impl.signatures; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature; import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignatureVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil; /** * @author Maxim.Medvedev */ public class GrImmediateClosureSignatureImpl implements GrClosureSignature { private static final Logger LOG = Logger.getInstance(GrImmediateClosureSignatureImpl.class); private final boolean myIsVarargs; private final boolean myCurried; @Nullable private final PsiType myReturnType; @NotNull private final GrClosureParameter[] myParameters; @NotNull private final PsiSubstitutor mySubstitutor; public GrImmediateClosureSignatureImpl(@NotNull PsiParameter[] parameters, @Nullable PsiType returnType, @NotNull PsiSubstitutor substitutor) { LOG.assertTrue(returnType == null || returnType.isValid()); LOG.assertTrue(substitutor.isValid()); myReturnType = substitutor.substitute(returnType); final int length = parameters.length; myParameters = new GrClosureParameter[length]; for (int i = 0; i < length; i++) { myParameters[i] = new GrImmediateClosureParameterImpl(parameters[i], substitutor); } myIsVarargs = GrClosureSignatureUtil.isVarArgsImpl(myParameters); mySubstitutor = substitutor; myCurried = false; } public GrImmediateClosureSignatureImpl(PsiParameter[] parameters, @Nullable PsiType returnType) { this(parameters, returnType, PsiSubstitutor.EMPTY); } public GrImmediateClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs, boolean isCurried) { myParameters = params; myReturnType = returnType; myIsVarargs = isVarArgs; myCurried = isCurried; mySubstitutor = PsiSubstitutor.EMPTY; } @Override public boolean isVarargs() { return myIsVarargs; } @Override @Nullable public PsiType getReturnType() { return myReturnType; } @Override @NotNull public PsiSubstitutor getSubstitutor() { return mySubstitutor; } @Override @NotNull public GrClosureParameter[] getParameters() { GrClosureParameter[] result = new GrClosureParameter[myParameters.length]; System.arraycopy(myParameters, 0, result, 0, myParameters.length); return result; } @Override public int getParameterCount() { return myParameters.length; } @Override @Nullable public GrSignature curry(@NotNull PsiType[] args, int position, @NotNull PsiElement context) { return GrClosureSignatureUtil.curryImpl(this, args, position, context); } @Override public boolean isValid() { for (GrClosureParameter parameter : myParameters) { if (!parameter.isValid()) return false; } final PsiType returnType = getReturnType(); return returnType == null || returnType.isValid(); } @Override public boolean equals(Object obj) { if (obj instanceof GrClosureSignature) { return Comparing.equal(myParameters, ((GrClosureSignature)obj).getParameters()) && Comparing.equal(myIsVarargs, ((GrClosureSignature)obj).isVarargs()); } return super.equals(obj); } @Override public boolean isCurried() { return myCurried; } @Nullable public static GrClosureSignature getLeastUpperBound(@NotNull GrClosureSignature signature1, @NotNull GrClosureSignature signature2, PsiManager manager) { GrClosureParameter[] parameters1 = signature1.getParameters(); GrClosureParameter[] parameters2 = signature2.getParameters(); if (parameters1.length == parameters2.length) { GrClosureParameter[] params = new GrClosureParameter[parameters1.length]; for (int i = 0; i < params.length; i++) { final PsiType type = GenericsUtil.getGreatestLowerBound(parameters1[i].getType(), parameters2[i].getType()); boolean opt = parameters1[i].isOptional() && parameters2[i].isOptional(); String name = StringUtil.equals(parameters1[i].getName(), parameters2[i].getName()) ? parameters1[i].getName() : null; params[i] = new GrImmediateClosureParameterImpl(type, name, opt, null); } final PsiType s1type = signature1.getReturnType(); final PsiType s2type = signature2.getReturnType(); PsiType returnType = null; if (s1type != null && s2type != null) { returnType = TypesUtil.getLeastUpperBound(s1type, s2type, manager); } boolean isVarArgs = signature1.isVarargs() && signature2.isVarargs(); return new GrImmediateClosureSignatureImpl(params, returnType, isVarArgs, false); } return null; //todo } @Override public void accept(@NotNull GrSignatureVisitor visitor) { visitor.visitClosureSignature(this); } }