blob: b4b3385239471f82356322f8c2e63a665be7d973 [file] [log] [blame]
/*
* 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 com.intellij.psi.impl.compiled;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.AtomicNotNullLazyValue;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.ElementPresentationUtil;
import com.intellij.psi.impl.cache.TypeInfo;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiParameterStub;
import com.intellij.psi.impl.java.stubs.impl.PsiParameterStubImpl;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.stubs.StubElement;
import com.intellij.ui.RowIcon;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class ClsParameterImpl extends ClsRepositoryPsiElement<PsiParameterStub> implements PsiParameter {
private final NotNullLazyValue<PsiTypeElement> myType;
private volatile String myName;
private volatile String myMirrorName;
public ClsParameterImpl(@NotNull PsiParameterStub stub) {
super(stub);
myType = new AtomicNotNullLazyValue<PsiTypeElement>() {
@NotNull
@Override
protected PsiTypeElement compute() {
PsiParameterStub stub = getStub();
String typeText = TypeInfo.createTypeText(stub.getType(false));
assert typeText != null : stub;
return new ClsTypeElementImpl(ClsParameterImpl.this, typeText, ClsTypeElementImpl.VARIANCE_NONE);
}
};
}
@Override
public PsiIdentifier getNameIdentifier() {
return null;
}
@Override
public String getName() {
String name = myName;
if (name == null) {
PsiParameterStubImpl parameterStub = (PsiParameterStubImpl)getStub();
if (!parameterStub.isAutoGeneratedName()) {
name = parameterStub.getName();
}
if (name == null) {
if (DumbService.getInstance(getProject()).isDumb()) {
return null;
}
ClsMethodImpl method = (ClsMethodImpl)getDeclarationScope();
PsiMethod sourceMethod = method.getSourceMirrorMethod();
if (sourceMethod != null) {
assert sourceMethod != method : method;
name = sourceMethod.getParameterList().getParameters()[getIndex()].getName();
}
else {
name = getMirrorName();
}
}
myName = name;
}
return name;
}
public boolean isAutoGeneratedName() {
return ((PsiParameterStubImpl)getStub()).isAutoGeneratedName() &&
!DumbService.getInstance(getProject()).isDumb() &&
((ClsMethodImpl)getDeclarationScope()).getSourceMirrorMethod() == null;
}
@Override
public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
throw new IncorrectOperationException(CAN_NOT_MODIFY_MESSAGE);
}
@Override
@NotNull
public PsiTypeElement getTypeElement() {
return myType.getValue();
}
@Override
@NotNull
public PsiType getType() {
return getTypeElement().getType();
}
@Override
@NotNull
public PsiModifierList getModifierList() {
final StubElement<PsiModifierList> child = getStub().findChildStubByType(JavaStubElementTypes.MODIFIER_LIST);
assert child != null;
return child.getPsi();
}
@Override
public boolean hasModifierProperty(@NotNull String name) {
return getModifierList().hasModifierProperty(name);
}
@Override
public PsiExpression getInitializer() {
return null;
}
@Override
public boolean hasInitializer() {
return false;
}
@Override
public Object computeConstantValue() {
return null;
}
@Override
public void normalizeDeclaration() throws IncorrectOperationException {
}
@Override
public void appendMirrorText(int indentLevel, @NotNull StringBuilder buffer) {
PsiAnnotation[] annotations = getModifierList().getAnnotations();
for (PsiAnnotation annotation : annotations) {
appendText(annotation, indentLevel, buffer);
buffer.append(' ');
}
appendText(getTypeElement(), indentLevel, buffer, " ");
buffer.append(getMirrorName());
}
private String getMirrorName() {
String mirrorName = myMirrorName;
if (mirrorName == null) {
// parameter name may depend on a name of a previous one in a same parameter list
synchronized (getParent()) {
mirrorName = myMirrorName;
if (mirrorName == null) {
myMirrorName = mirrorName = calcNiceParameterName();
}
}
}
return mirrorName;
}
private String calcNiceParameterName() {
String name = null;
PsiParameterStubImpl stub = (PsiParameterStubImpl)getStub();
if (!stub.isAutoGeneratedName() || DumbService.getInstance(getProject()).isDumb()) {
name = stub.getName();
}
if (name == null) {
name = "p";
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(getProject());
String[] nameSuggestions = codeStyleManager.suggestCompiledParameterName(getType()).names;
if (nameSuggestions.length > 0 && nameSuggestions[0] != null) {
name = nameSuggestions[0];
}
String base = name;
int n = 0;
AttemptsLoop:
while (true) {
for (PsiParameter parameter : ((PsiParameterList)getParent()).getParameters()) {
if (parameter == this) break AttemptsLoop;
String prevName = ((ClsParameterImpl)parameter).getMirrorName();
if (name.equals(prevName)) {
name = base + (++n);
continue AttemptsLoop;
}
}
}
}
return name;
}
@Override
public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException {
setMirrorCheckingType(element, null);
PsiParameter mirror = SourceTreeToPsiMap.treeToPsiNotNull(element);
setMirror(getModifierList(), mirror.getModifierList());
setMirror(getTypeElement(), mirror.getTypeElement());
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitParameter(this);
}
else {
visitor.visitElement(this);
}
}
@Override
@NotNull
public PsiElement getDeclarationScope() {
// only method parameters exist in compiled code
return getParent().getParent();
}
private int getIndex() {
final PsiParameterStub stub = getStub();
return stub.getParentStub().getChildrenStubs().indexOf(stub);
}
@Override
public boolean isVarArgs() {
final PsiParameterList paramList = (PsiParameterList)getParent();
final PsiMethod method = (PsiMethod)paramList.getParent();
return method.isVarArgs() && getIndex() == paramList.getParametersCount() - 1;
}
@Override
protected boolean isVisibilitySupported() {
return true;
}
@Override
public Icon getElementIcon(final int flags) {
final RowIcon baseIcon = createLayeredIcon(this, PlatformIcons.PARAMETER_ICON, 0);
return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
}
@Override
@NotNull
public SearchScope getUseScope() {
return new LocalSearchScope(getDeclarationScope());
}
@Override
public String toString() {
return "PsiParameter";
}
}