constructor reference: don't ignore constructor parameters during method reference...
[idea/community.git] / java / java-psi-impl / src / com / intellij / psi / impl / source / PsiParameterImpl.java
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.psi.impl.source;
3
4 import com.intellij.lang.ASTNode;
5 import com.intellij.navigation.ItemPresentation;
6 import com.intellij.navigation.ItemPresentationProviders;
7 import com.intellij.openapi.diagnostic.Logger;
8 import com.intellij.psi.*;
9 import com.intellij.psi.impl.CheckUtil;
10 import com.intellij.psi.impl.ElementPresentationUtil;
11 import com.intellij.psi.impl.PsiImplUtil;
12 import com.intellij.psi.impl.cache.TypeInfo;
13 import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
14 import com.intellij.psi.impl.java.stubs.PsiParameterStub;
15 import com.intellij.psi.impl.source.tree.CompositeElement;
16 import com.intellij.psi.impl.source.tree.JavaSharedImplUtil;
17 import com.intellij.psi.infos.MethodCandidateInfo;
18 import com.intellij.psi.search.LocalSearchScope;
19 import com.intellij.psi.search.SearchScope;
20 import com.intellij.psi.stubs.IStubElementType;
21 import com.intellij.psi.util.PsiTreeUtil;
22 import com.intellij.reference.SoftReference;
23 import com.intellij.ui.IconManager;
24 import com.intellij.ui.icons.RowIcon;
25 import com.intellij.util.IncorrectOperationException;
26 import com.intellij.util.PlatformIcons;
27 import org.jetbrains.annotations.NotNull;
28
29 import javax.swing.*;
30 import java.lang.ref.Reference;
31 import java.util.Arrays;
32
33 public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> implements PsiParameter {
34   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiParameterImpl");
35
36   private volatile Reference<PsiType> myCachedType;
37
38   public PsiParameterImpl(@NotNull PsiParameterStub stub) {
39     this(stub, JavaStubElementTypes.PARAMETER);
40   }
41
42   protected PsiParameterImpl(@NotNull PsiParameterStub stub, @NotNull IStubElementType type) {
43     super(stub, type);
44   }
45
46   public PsiParameterImpl(@NotNull ASTNode node) {
47     super(node);
48   }
49
50   public static PsiType getLambdaParameterType(PsiParameter param) {
51     final PsiElement paramParent = param.getParent();
52     if (paramParent instanceof PsiParameterList) {
53       final int parameterIndex = ((PsiParameterList)paramParent).getParameterIndex(param);
54       if (parameterIndex > -1) {
55         final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
56         if (lambdaExpression != null) {
57           final PsiType functionalInterfaceType = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(param, false,
58                                                                                                               () -> LambdaUtil.getFunctionalInterfaceType(lambdaExpression, true));
59           PsiType type = lambdaExpression.getGroundTargetType(functionalInterfaceType);
60           if (type instanceof PsiIntersectionType) {
61             final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
62             for (PsiType conjunct : conjuncts) {
63               final PsiType lambdaParameterFromType = LambdaUtil.getLambdaParameterFromType(conjunct, parameterIndex);
64               if (lambdaParameterFromType != null) {
65                 return lambdaParameterFromType;
66               }
67             }
68           } else {
69             final PsiType lambdaParameterFromType = LambdaUtil.getLambdaParameterFromType(type, parameterIndex);
70             if (lambdaParameterFromType != null) {
71               return lambdaParameterFromType;
72             }
73           }
74         }
75       }
76     }
77     return new PsiLambdaParameterType(param);
78   }
79
80   @Override
81   public void subtreeChanged() {
82     super.subtreeChanged();
83     myCachedType = null;
84   }
85
86   @Override
87   protected Object clone() {
88     PsiParameterImpl clone = (PsiParameterImpl)super.clone();
89     clone.myCachedType = null;
90
91     return clone;
92   }
93
94   @Override
95   @NotNull
96   public final String getName() {
97     PsiParameterStub stub = getGreenStub();
98     if (stub != null) {
99       return stub.getName();
100     }
101
102     return getNameIdentifier().getText();
103   }
104
105   @Override
106   public final PsiElement setName(@NotNull String name) throws IncorrectOperationException {
107     PsiImplUtil.setName(getNameIdentifier(), name);
108     return this;
109   }
110
111   @Override
112   @NotNull
113   public final PsiIdentifier getNameIdentifier() {
114     return PsiTreeUtil.getRequiredChildOfType(this, PsiIdentifier.class);
115   }
116
117   @Override
118   @NotNull
119   public CompositeElement getNode() {
120     return (CompositeElement)super.getNode();
121   }
122
123   @Override
124   @NotNull
125   public PsiType getType() {
126     PsiParameterStub stub = getStub();
127     if (stub != null) {
128       PsiType type = SoftReference.dereference(myCachedType);
129       if (type == null) {
130         String typeText = TypeInfo.createTypeText(stub.getType(false));
131         assert typeText != null : stub;
132         type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this);
133         type = JavaSharedImplUtil.applyAnnotations(type, getModifierList());
134         myCachedType = new SoftReference<>(type);
135       }
136       return type;
137     }
138
139     myCachedType = null;
140
141     PsiTypeElement typeElement = getTypeElement();
142     if (typeElement == null || isLambdaParameter() && typeElement.isInferredType()) {
143       assert isLambdaParameter() : this;
144       return getLambdaParameterType(this);
145     }
146     else {
147       return JavaSharedImplUtil.getType(typeElement, getNameIdentifier());
148     }
149   }
150
151   private boolean isLambdaParameter() {
152     final PsiElement parent = getParent();
153     return parent instanceof PsiParameterList && parent.getParent() instanceof PsiLambdaExpression;
154   }
155
156   @Override
157   public PsiTypeElement getTypeElement() {
158     for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
159       if (child instanceof PsiTypeElement) {
160         return (PsiTypeElement)child;
161       }
162     }
163     return null;
164   }
165
166   @Override
167   @NotNull
168   public PsiModifierList getModifierList() {
169     PsiModifierList modifierList = getStubOrPsiChild(JavaStubElementTypes.MODIFIER_LIST);
170     assert modifierList != null : this;
171     return modifierList;
172   }
173
174   @Override
175   public boolean hasModifierProperty(@NotNull String name) {
176     return getModifierList().hasModifierProperty(name);
177   }
178
179   @Override
180   public PsiExpression getInitializer() {
181     return null;
182   }
183
184   @Override
185   public boolean hasInitializer() {
186     return false;
187   }
188
189   @Override
190   public Object computeConstantValue() {
191     return null;
192   }
193
194   @Override
195   public void normalizeDeclaration() throws IncorrectOperationException {
196     CheckUtil.checkWritable(this);
197     JavaSharedImplUtil.normalizeBrackets(this);
198   }
199
200   @Override
201   public void accept(@NotNull PsiElementVisitor visitor) {
202     if (visitor instanceof JavaElementVisitor) {
203       ((JavaElementVisitor)visitor).visitParameter(this);
204     }
205     else {
206       visitor.visitElement(this);
207     }
208   }
209
210   @Override
211   public String toString() {
212     return "PsiParameter:" + getName();
213   }
214
215   @Override
216   @NotNull
217   public PsiElement getDeclarationScope() {
218     final PsiElement parent = getParent();
219     if (parent == null) return this;
220
221     if (parent instanceof PsiParameterList) {
222       return parent.getParent();
223     }
224     if (parent instanceof PsiForeachStatement) {
225       return parent;
226     }
227     if (parent instanceof PsiCatchSection) {
228       return parent;
229     }
230
231     PsiElement[] children = parent.getChildren();
232     //noinspection ConstantConditions
233     if (children != null) {
234       ext:
235       for (int i = 0; i < children.length; i++) {
236         if (children[i].equals(this)) {
237           for (int j = i + 1; j < children.length; j++) {
238             if (children[j] instanceof PsiCodeBlock) return children[j];
239           }
240           break ext;
241         }
242       }
243     }
244
245     LOG.error("Code block not found among parameter' (" + this + ") parent' (" + parent + ") children: " + Arrays.asList(children));
246     return null;
247   }
248
249   @Override
250   public boolean isVarArgs() {
251     final PsiParameterStub stub = getGreenStub();
252     if (stub != null) {
253       return stub.isParameterTypeEllipsis();
254     }
255
256     myCachedType = null;
257     final PsiTypeElement typeElement = getTypeElement();
258     return typeElement != null && SourceTreeToPsiMap.psiToTreeNotNull(typeElement).findChildByType(JavaTokenType.ELLIPSIS) != null;
259   }
260
261   @Override
262   public ItemPresentation getPresentation() {
263     return ItemPresentationProviders.getItemPresentation(this);
264   }
265
266   @Override
267   public Icon getElementIcon(final int flags) {
268     final RowIcon baseIcon = IconManager.getInstance().createLayeredIcon(this, PlatformIcons.PARAMETER_ICON, 0);
269     return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
270   }
271   @Override
272   protected boolean isVisibilitySupported() {
273     return true;
274   }
275
276   @Override
277   @NotNull
278   public SearchScope getUseScope() {
279     final PsiElement declarationScope = getDeclarationScope();
280     return new LocalSearchScope(declarationScope);
281   }
282
283   @Override
284   public PsiElement getOriginalElement() {
285     PsiElement parent = getParent();
286     if (parent instanceof PsiParameterList) {
287       PsiElement gParent = parent.getParent();
288       if (gParent instanceof PsiMethod) {
289         PsiElement originalMethod = gParent.getOriginalElement();
290         if (originalMethod instanceof PsiMethod && originalMethod != gParent) {
291           int index = ((PsiParameterList)parent).getParameterIndex(this);
292           PsiParameter[] originalParameters = ((PsiMethod)originalMethod).getParameterList().getParameters();
293           if (index < originalParameters.length) {
294             return originalParameters[index];
295           }
296         }
297       }
298     }
299     return this;
300   }
301 }