IDEA-64291 groovy parsing get stuck and is wrong
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / lang / psi / impl / types / GrClosureSignatureImpl.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.jetbrains.plugins.groovy.lang.psi.impl.types;
17
18 import com.intellij.openapi.util.Comparing;
19 import com.intellij.psi.*;
20 import org.jetbrains.annotations.NotNull;
21 import org.jetbrains.annotations.Nullable;
22 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
23 import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
24 import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
25
26 /**
27  * @author Maxim.Medvedev
28  */
29 public class GrClosureSignatureImpl implements GrClosureSignature {
30   private final boolean myIsVarargs;
31   @Nullable private final PsiType myReturnType;
32   @NotNull private final GrClosureParameter[] myParameters;
33   @NotNull private final PsiSubstitutor mySubstitutor;
34
35   public GrClosureSignatureImpl(@NotNull PsiParameter[] parameters, @Nullable PsiType returnType, @NotNull PsiSubstitutor substitutor) {
36     myReturnType = substitutor.substitute(returnType);
37     final int length = parameters.length;
38     myParameters = new GrClosureParameter[length];
39     for (int i = 0; i < length; i++) {
40       myParameters[i] = new GrClosureParameterImpl(parameters[i], substitutor);
41     }
42     if (length > 0) {
43       myIsVarargs = myParameters[length - 1].getType() instanceof PsiArrayType;
44     }
45     else {
46       myIsVarargs = false;
47     }
48     mySubstitutor = substitutor;
49   }
50
51   public GrClosureSignatureImpl(PsiParameter[] parameters, PsiType returnType) {
52     this(parameters, returnType, PsiSubstitutor.EMPTY);
53   }
54
55   GrClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs) {
56     myParameters = params;
57     myReturnType = returnType;
58     myIsVarargs = isVarArgs;
59     mySubstitutor = PsiSubstitutor.EMPTY;
60   }
61
62
63   public boolean isVarargs() {
64     return myIsVarargs;
65   }
66
67
68   @Nullable
69   public PsiType getReturnType() {
70     return myReturnType;
71   }
72
73   @NotNull
74   public PsiSubstitutor getSubstitutor() {
75     return mySubstitutor;
76   }
77
78   @NotNull
79   public GrClosureParameter[] getParameters() {
80     GrClosureParameter[] result = new GrClosureParameter[myParameters.length];
81     System.arraycopy(myParameters, 0, result, 0, myParameters.length);
82     return result;
83   }
84
85   @Nullable
86   public GrClosureSignature curry(int count) {
87     if (count > myParameters.length) {
88       if (isVarargs()) {
89         return new DerivedClosureSignature();
90       }
91       else {
92         return null;
93       }
94     }
95     GrClosureParameter[] newParams = new GrClosureParameter[myParameters.length - count];
96     System.arraycopy(myParameters, count, newParams, 0, newParams.length);
97     return new DerivedClosureSignature(newParams, null, myIsVarargs);
98   }
99
100   public boolean isValid() {
101     for (GrClosureParameter parameter : myParameters) {
102       if (!parameter.isValid()) return false;
103     }
104     final PsiType returnType = getReturnType();
105     return returnType == null || returnType.isValid();
106   }
107
108   @Override
109   public boolean equals(Object obj) {
110     if (obj instanceof GrClosureSignature) {
111       return Comparing.equal(myParameters, ((GrClosureSignature)obj).getParameters()) &&
112              Comparing.equal(myIsVarargs, ((GrClosureSignature)obj).isVarargs());
113     }
114     return super.equals(obj);
115   }
116
117   @Nullable
118   public static GrClosureSignature getLeastUpperBound(@NotNull GrClosureSignature signature1,
119                                                       @NotNull GrClosureSignature signature2,
120                                                       PsiManager manager) {
121     GrClosureParameter[] parameters1 = signature1.getParameters();
122     GrClosureParameter[] parameters2 = signature2.getParameters();
123
124     if (parameters1.length == parameters2.length) {
125       GrClosureParameter[] params = new GrClosureParameter[parameters1.length];
126       for (int i = 0; i < params.length; i++) {
127         final PsiType type = GenericsUtil.getGreatestLowerBound(parameters1[i].getType(), parameters2[i].getType());
128         boolean opt = parameters1[i].isOptional() && parameters2[i].isOptional();
129         params[i] = new GrClosureParameterImpl(type, opt, null);
130       }
131       final PsiType s1type = signature1.getReturnType();
132       final PsiType s2type = signature2.getReturnType();
133       PsiType returnType = null;
134       if (s1type != null && s2type != null) {
135         returnType = TypesUtil.getLeastUpperBound(s1type, s2type, manager);
136       }
137       boolean isVarArgs = signature1.isVarargs() && signature2.isVarargs();
138       return new GrClosureSignatureImpl(params, returnType, isVarArgs);
139     }
140     return null; //todo
141   }
142
143   private class DerivedClosureSignature extends GrClosureSignatureImpl {
144     DerivedClosureSignature() {
145       super(PsiParameter.EMPTY_ARRAY, null);
146     }
147
148     DerivedClosureSignature(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs) {
149       super(params, returnType, isVarArgs);
150     }
151
152     @Override
153     public PsiType getReturnType() {
154       return GrClosureSignatureImpl.this.getReturnType();
155     }
156   }
157 }
158