/* * Copyright 2000-2013 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.source; import com.intellij.lang.ASTNode; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.CheckUtil; import com.intellij.psi.impl.ElementPresentationUtil; import com.intellij.psi.impl.PsiImplUtil; 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.source.tree.CompositeElement; import com.intellij.psi.impl.source.tree.JavaSharedImplUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.reference.SoftReference; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.util.Arrays; public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> implements PsiParameter { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiParameterImpl"); private volatile SoftReference<PsiType> myCachedType = null; public PsiParameterImpl(@NotNull PsiParameterStub stub) { this(stub, JavaStubElementTypes.PARAMETER); } protected PsiParameterImpl(@NotNull PsiParameterStub stub, @NotNull IStubElementType type) { super(stub, type); } public PsiParameterImpl(@NotNull ASTNode node) { super(node); } @Override public void subtreeChanged() { super.subtreeChanged(); myCachedType = null; } @Override protected Object clone() { PsiParameterImpl clone = (PsiParameterImpl)super.clone(); clone.myCachedType = null; return clone; } @Override @NotNull public final String getName() { PsiParameterStub stub = getStub(); if (stub != null) { return stub.getName(); } return getParameterIdentifier().getText(); } @Override public final PsiElement setName(@NotNull String name) throws IncorrectOperationException { if (this instanceof PsiReceiverParameter) { throw new IncorrectOperationException("Cannot rename receiver parameter"); } PsiImplUtil.setName(getParameterIdentifier(), name); return this; } @Override public final PsiIdentifier getNameIdentifier() { return PsiTreeUtil.getChildOfType(this, PsiIdentifier.class); } @NotNull private PsiElement getParameterIdentifier() { PsiJavaToken identifier = PsiTreeUtil.getChildOfAnyType(this, PsiIdentifier.class, PsiKeyword.class); assert identifier != null : getClass() + ":" + getText(); return identifier; } @Override @NotNull public CompositeElement getNode() { return (CompositeElement)super.getNode(); } @Override @NotNull public PsiType getType() { PsiParameterStub stub = getStub(); if (stub != null) { SoftReference<PsiType> cachedType = myCachedType; if (cachedType != null) { PsiType type = cachedType.get(); if (type != null) return type; } String typeText = TypeInfo.createTypeText(stub.getType(true)); assert typeText != null : stub; try { PsiType type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); myCachedType = new SoftReference<PsiType>(type); return type; } catch (IncorrectOperationException e) { LOG.error(e); return null; } } myCachedType = null; PsiTypeElement typeElement = getTypeElement(); if (typeElement == null) { assert isLambdaParameter() : this; return LambdaUtil.getLambdaParameterType(this); } else { return JavaSharedImplUtil.getType(typeElement, getParameterIdentifier()); } } @Override public PsiType getTypeNoResolve() { return getType(); } private boolean isLambdaParameter() { final PsiElement parent = getParent(); return parent instanceof PsiParameterList && parent.getParent() instanceof PsiLambdaExpression; } @Override public PsiTypeElement getTypeElement() { for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof PsiTypeElement) { //noinspection unchecked return (PsiTypeElement)child; } } return null; } @Override @NotNull public PsiModifierList getModifierList() { PsiModifierList modifierList = getStubOrPsiChild(JavaStubElementTypes.MODIFIER_LIST); assert modifierList != null : this; return modifierList; } @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 { CheckUtil.checkWritable(this); JavaSharedImplUtil.normalizeBrackets(this); } @Override public void accept(@NotNull PsiElementVisitor visitor) { if (visitor instanceof JavaElementVisitor) { ((JavaElementVisitor)visitor).visitParameter(this); } else { visitor.visitElement(this); } } public String toString() { return "PsiParameter:" + getName(); } @Override @NotNull public PsiElement getDeclarationScope() { final PsiElement parent = getParent(); if (parent == null) return this; if (parent instanceof PsiParameterList) { return parent.getParent(); } if (parent instanceof PsiForeachStatement) { return parent; } if (parent instanceof PsiCatchSection) { return parent; } PsiElement[] children = parent.getChildren(); //noinspection ConstantConditions if (children != null) { ext: for (int i = 0; i < children.length; i++) { if (children[i].equals(this)) { for (int j = i + 1; j < children.length; j++) { if (children[j] instanceof PsiCodeBlock) return children[j]; } break ext; } } } LOG.error("Code block not found among parameter' (" + this + ") parent' (" + parent + ") children: " + Arrays.asList(children)); return null; } @Override public boolean isVarArgs() { final PsiParameterStub stub = getStub(); if (stub != null) { return stub.isParameterTypeEllipsis(); } myCachedType = null; final PsiTypeElement typeElement = getTypeElement(); return typeElement != null && SourceTreeToPsiMap.psiToTreeNotNull(typeElement).findChildByType(JavaTokenType.ELLIPSIS) != null; } @Override public ItemPresentation getPresentation() { return ItemPresentationProviders.getItemPresentation(this); } @Override protected boolean isVisibilitySupported() { return true; } @Override @NotNull public SearchScope getUseScope() { final PsiElement declarationScope = getDeclarationScope(); return new LocalSearchScope(declarationScope); } }