Cleanup: NotNull/Nullable
[idea/community.git] / java / java-psi-impl / src / com / intellij / psi / impl / compiled / ClsParameterImpl.java
1 /*
2  * Copyright 2000-2016 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 com.intellij.psi.impl.compiled;
17
18 import com.intellij.openapi.project.DumbService;
19 import com.intellij.openapi.roots.FileIndexFacade;
20 import com.intellij.openapi.util.AtomicNotNullLazyValue;
21 import com.intellij.openapi.util.NotNullLazyValue;
22 import com.intellij.psi.*;
23 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
24 import com.intellij.psi.impl.ElementPresentationUtil;
25 import com.intellij.psi.impl.cache.TypeInfo;
26 import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
27 import com.intellij.psi.impl.java.stubs.PsiParameterStub;
28 import com.intellij.psi.impl.java.stubs.impl.PsiParameterStubImpl;
29 import com.intellij.psi.impl.source.SourceTreeToPsiMap;
30 import com.intellij.psi.impl.source.tree.TreeElement;
31 import com.intellij.psi.search.LocalSearchScope;
32 import com.intellij.psi.search.SearchScope;
33 import com.intellij.psi.stubs.StubElement;
34 import com.intellij.psi.util.CachedValueProvider;
35 import com.intellij.psi.util.CachedValuesManager;
36 import com.intellij.ui.RowIcon;
37 import com.intellij.util.IncorrectOperationException;
38 import com.intellij.util.PlatformIcons;
39 import org.jetbrains.annotations.NotNull;
40 import org.jetbrains.annotations.Nullable;
41
42 import javax.swing.*;
43
44 public class ClsParameterImpl extends ClsRepositoryPsiElement<PsiParameterStub> implements PsiParameter {
45   private final NotNullLazyValue<PsiTypeElement> myType;
46   private volatile String myMirrorName;
47
48   public ClsParameterImpl(@NotNull PsiParameterStub stub) {
49     super(stub);
50     myType = new AtomicNotNullLazyValue<PsiTypeElement>() {
51       @NotNull
52       @Override
53       protected PsiTypeElement compute() {
54         PsiParameterStub stub = getStub();
55         String typeText = TypeInfo.createTypeText(stub.getType(false));
56         assert typeText != null : stub;
57         return new ClsTypeElementImpl(ClsParameterImpl.this, typeText, ClsTypeElementImpl.VARIANCE_NONE);
58       }
59     };
60   }
61
62   @Override
63   public PsiIdentifier getNameIdentifier() {
64     return null;
65   }
66
67   @Override
68   public String getName() {
69     return CachedValuesManager.getCachedValue(this, () -> CachedValueProvider.Result.create(calcName(),
70                                                                                             getContainingFile(),
71                                                                                             getContainingFile().getNavigationElement(),
72                                                                                             FileIndexFacade.getInstance(getProject()).getRootModificationTracker(),
73                                                                                             DumbService.getInstance(getProject()).getModificationTracker()));
74   }
75
76   @Nullable 
77   private String calcName() {
78     PsiParameterStubImpl parameterStub = (PsiParameterStubImpl)getStub();
79     if (!parameterStub.isAutoGeneratedName()) {
80       return parameterStub.getName();
81     }
82     
83     if (DumbService.getInstance(getProject()).isDumb()) {
84       return null;
85     }
86
87     ClsMethodImpl method = (ClsMethodImpl)getDeclarationScope();
88     PsiMethod sourceMethod = method.getSourceMirrorMethod();
89     if (sourceMethod != null) {
90       assert sourceMethod != method : method;
91       return sourceMethod.getParameterList().getParameters()[getIndex()].getName();
92     }
93     
94     return getMirrorName();
95   }
96
97   public boolean isAutoGeneratedName() {
98     return ((PsiParameterStubImpl)getStub()).isAutoGeneratedName() &&
99            !DumbService.getInstance(getProject()).isDumb() &&
100            ((ClsMethodImpl)getDeclarationScope()).getSourceMirrorMethod() == null;
101   }
102
103   @Override
104   public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
105     throw cannotModifyException(this);
106   }
107
108   @Override
109   @NotNull
110   public PsiTypeElement getTypeElement() {
111     return myType.getValue();
112   }
113
114   @Override
115   @NotNull
116   public PsiType getType() {
117     return getTypeElement().getType();
118   }
119
120   @Override
121   @NotNull
122   public PsiModifierList getModifierList() {
123     final StubElement<PsiModifierList> child = getStub().findChildStubByType(JavaStubElementTypes.MODIFIER_LIST);
124     assert child != null;
125     return child.getPsi();
126   }
127
128   @Override
129   public boolean hasModifierProperty(@NotNull String name) {
130     return getModifierList().hasModifierProperty(name);
131   }
132
133   @Override
134   public PsiExpression getInitializer() {
135     return null;
136   }
137
138   @Override
139   public boolean hasInitializer() {
140     return false;
141   }
142
143   @Override
144   public Object computeConstantValue() {
145     return null;
146   }
147
148   @Override
149   public void normalizeDeclaration() throws IncorrectOperationException {
150   }
151
152   @Override
153   public void appendMirrorText(int indentLevel, @NotNull StringBuilder buffer) {
154     PsiAnnotation[] annotations = getModifierList().getAnnotations();
155     for (PsiAnnotation annotation : annotations) {
156       appendText(annotation, indentLevel, buffer);
157       buffer.append(' ');
158     }
159     appendText(getTypeElement(), indentLevel, buffer, " ");
160     buffer.append(getMirrorName());
161   }
162
163   private String getMirrorName() {
164     String mirrorName = myMirrorName;
165     if (mirrorName == null) {
166       // parameter name may depend on a name of a previous one in a same parameter list
167       synchronized (getParent()) {
168         mirrorName = myMirrorName;
169         if (mirrorName == null) {
170           myMirrorName = mirrorName = calcNiceParameterName();
171         }
172       }
173     }
174     return mirrorName;
175   }
176
177   private String calcNiceParameterName() {
178     String name = null;
179
180     PsiParameterStubImpl stub = (PsiParameterStubImpl)getStub();
181     if (!stub.isAutoGeneratedName() || DumbService.getInstance(getProject()).isDumb()) {
182       name = stub.getName();
183     }
184
185     if (name == null) {
186       name = "p";
187
188       JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(getProject());
189       String[] nameSuggestions = codeStyleManager.suggestCompiledParameterName(getType()).names;
190       if (nameSuggestions.length > 0 && nameSuggestions[0] != null) {
191         name = nameSuggestions[0];
192       }
193
194       String base = name;
195       int n = 0;
196       AttemptsLoop:
197       while (true) {
198         for (PsiParameter parameter : ((PsiParameterList)getParent()).getParameters()) {
199           if (parameter == this) break AttemptsLoop;
200           String prevName = ((ClsParameterImpl)parameter).getMirrorName();
201           if (name.equals(prevName)) {
202             name = base + (++n);
203             continue AttemptsLoop;
204           }
205         }
206       }
207     }
208
209     return name;
210   }
211
212   @Override
213   public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException {
214     setMirrorCheckingType(element, null);
215
216     PsiParameter mirror = SourceTreeToPsiMap.treeToPsiNotNull(element);
217     setMirror(getModifierList(), mirror.getModifierList());
218     setMirror(getTypeElement(), mirror.getTypeElement());
219   }
220
221   @Override
222   public void accept(@NotNull PsiElementVisitor visitor) {
223     if (visitor instanceof JavaElementVisitor) {
224       ((JavaElementVisitor)visitor).visitParameter(this);
225     }
226     else {
227       visitor.visitElement(this);
228     }
229   }
230
231   @Override
232   @NotNull
233   public PsiElement getDeclarationScope() {
234     // only method parameters exist in compiled code
235     return getParent().getParent();
236   }
237
238   private int getIndex() {
239     final PsiParameterStub stub = getStub();
240     return stub.getParentStub().getChildrenStubs().indexOf(stub);
241   }
242
243   @Override
244   public boolean isVarArgs() {
245     final PsiParameterList paramList = (PsiParameterList)getParent();
246     final PsiMethod method = (PsiMethod)paramList.getParent();
247     return method.isVarArgs() && getIndex() == paramList.getParametersCount() - 1;
248   }
249
250   @Override
251   protected boolean isVisibilitySupported() {
252     return true;
253   }
254
255   @Override
256   public Icon getElementIcon(final int flags) {
257     final RowIcon baseIcon = createLayeredIcon(this, PlatformIcons.PARAMETER_ICON, 0);
258     return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
259   }
260
261   @Override
262   @NotNull
263   public SearchScope getUseScope() {
264     return new LocalSearchScope(getDeclarationScope());
265   }
266
267   @Override
268   public String toString() {
269     return "PsiParameter";
270   }
271 }