blob: b25f033e74b932dd3299c878b715f4df370f2755 [file] [log] [blame]
/*
* 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.psi.*;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.source.tree.ChildRole;
import com.intellij.psi.impl.source.tree.SharedImplUtil;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.reference.SoftReference;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
public class PsiAnonymousClassImpl extends PsiClassImpl implements PsiAnonymousClass {
private SoftReference<PsiClassType> myCachedBaseType = null;
public PsiAnonymousClassImpl(final PsiClassStub stub) {
super(stub, JavaStubElementTypes.ANONYMOUS_CLASS);
}
public PsiAnonymousClassImpl(final ASTNode node) {
super(node);
}
@Override
protected Object clone() {
PsiAnonymousClassImpl clone = (PsiAnonymousClassImpl)super.clone();
clone.myCachedBaseType = null;
return clone;
}
@Override
public void subtreeChanged() {
super.subtreeChanged();
myCachedBaseType = null;
}
@Override
public PsiExpressionList getArgumentList() {
return (PsiExpressionList)getNode().findChildByRoleAsPsiElement(ChildRole.ARGUMENT_LIST);
}
@Override
@NotNull
public PsiJavaCodeReferenceElement getBaseClassReference() {
final PsiElement baseRef = getFirstChild();
assert baseRef instanceof PsiJavaCodeReferenceElement : getText();
return (PsiJavaCodeReferenceElement)baseRef;
}
@Override
@NotNull
public PsiClassType getBaseClassType() {
final PsiClassStub stub = getStub();
if (stub == null) {
myCachedBaseType = null;
return getTypeByTree();
}
PsiClassType type = SoftReference.dereference(myCachedBaseType);
if (type != null) return type;
if (!isInQualifiedNew()) {
final String refText = stub.getBaseClassReferenceText();
assert refText != null : stub;
final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
final PsiElement context = calcBasesResolveContext(PsiNameHelper.getShortClassName(refText), getExtendsList());
try {
final PsiJavaCodeReferenceElement ref = factory.createReferenceFromText(refText, context);
((PsiJavaCodeReferenceElementImpl)ref).setKindWhenDummy(PsiJavaCodeReferenceElementImpl.CLASS_NAME_KIND);
type = factory.createType(ref);
}
catch (IncorrectOperationException e) {
type = PsiType.getJavaLangObject(getManager(), getResolveScope());
}
myCachedBaseType = new SoftReference<PsiClassType>(type);
return type;
}
else {
return getTypeByTree();
}
}
private PsiClassType getTypeByTree() {
return JavaPsiFacade.getInstance(getProject()).getElementFactory().createType(getBaseClassReference());
}
@Override
public PsiIdentifier getNameIdentifier() {
return null;
}
@Override
public String getQualifiedName() {
return null;
}
@Override
public PsiModifierList getModifierList() {
return null;
}
@Override
public boolean hasModifierProperty(@NotNull String name) {
return name.equals(PsiModifier.FINAL);
}
@Override
public PsiReferenceList getExtendsList() {
return null;
}
@Override
public PsiReferenceList getImplementsList() {
return null;
}
@Override
public PsiClass getContainingClass() {
return null;
}
@Override
public boolean isInterface() {
return false;
}
@Override
public boolean isAnnotationType() {
return false;
}
@Override
public boolean isEnum() {
return false;
}
@Override
public PsiTypeParameterList getTypeParameterList() {
return null;
}
@Override
public PsiElement getOriginalElement() {
return this;
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitAnonymousClass(this);
}
else {
visitor.visitElement(this);
}
}
public String toString() {
return "PsiAnonymousClass";
}
@Override
public boolean processDeclarations(@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
PsiElement lastParent,
@NotNull PsiElement place) {
if (lastParent instanceof PsiExpressionList) return true;
final PsiClassStub stub = getStub();
if (stub != null) {
// no tree is loaded
// that means we could not have come from resolving something inside anonymous class, we just resolving the base class reference
// so skip the (very expensive) getBaseClassReference() call which would load tree
return true;
}
if (lastParent != null/* IMPORTANT: do not call getBaseClassReference() for lastParent == null and lastParent which is not under our node - loads tree!*/
&& lastParent.getParent() == this && lastParent == getBaseClassReference()) {
return true;
}
return super.processDeclarations(processor, state, lastParent, place);
}
@Override
public boolean isInQualifiedNew() {
final PsiClassStub stub = getStub();
if (stub != null) {
return stub.isAnonymousInQualifiedNew();
}
final PsiElement parent = getParent();
return parent instanceof PsiNewExpression && ((PsiNewExpression)parent).getQualifier() != null;
}
@Override
public PsiElement getParent() {
return SharedImplUtil.getParent(getNode());
}
}