blob: 7862a7381011b83daa1ca7ee3e99f677cdd49802 [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.source.tree.java;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.resolve.reference.impl.PsiPolyVariantCachingReference;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PsiNewExpressionImpl extends ExpressionPsiElement implements PsiNewExpression {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiNewExpressionImpl");
public PsiNewExpressionImpl() {
super(JavaElementType.NEW_EXPRESSION);
}
@Override
public PsiType getType() {
return doGetType(null);
}
@Override
public PsiType getOwner(@NotNull PsiAnnotation annotation) {
assert annotation.getParent() == this : annotation.getParent() + " != " + this;
return doGetType(annotation);
}
@Nullable
private PsiType doGetType(@Nullable PsiAnnotation stopAt) {
PsiType type = null;
SmartList<PsiAnnotation> annotations = new SmartList<PsiAnnotation>();
boolean stop = false;
for (ASTNode child = getFirstChildNode(); child != null; child = child.getTreeNext()) {
IElementType elementType = child.getElementType();
if (elementType == JavaElementType.ANNOTATION) {
PsiAnnotation annotation = (PsiAnnotation)child.getPsi();
annotations.add(annotation);
if (annotation == stopAt) stop = true;
}
else if (elementType == JavaElementType.JAVA_CODE_REFERENCE) {
assert type == null : this;
type = new PsiClassReferenceType((PsiJavaCodeReferenceElement)child.getPsi(), null);
if (stop) return type;
}
else if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(elementType)) {
assert type == null : this;
PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
type = factory.createPrimitiveType(child.getText(), ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true));
if (stop) return type;
}
else if (elementType == JavaTokenType.LBRACKET) {
assert type != null : this;
type = type.createArrayType(ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true));
if (stop) return type;
}
else if (elementType == JavaElementType.ANONYMOUS_CLASS) {
PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
PsiClass aClass = (PsiClass)child.getPsi();
PsiSubstitutor substitutor = aClass instanceof PsiTypeParameter ? PsiSubstitutor.EMPTY : factory.createRawSubstitutor(aClass);
type = factory.createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass),
ContainerUtil.copyAndClear(annotations, PsiAnnotation.ARRAY_FACTORY, true));
if (stop) return type;
}
}
// stop == true means annotation is misplaced
return stop ? null : type;
}
@Override
public PsiExpressionList getArgumentList() {
PsiExpressionList list = (PsiExpressionList)findChildByRoleAsPsiElement(ChildRole.ARGUMENT_LIST);
if (list != null) return list;
CompositeElement anonymousClass = (CompositeElement)SourceTreeToPsiMap.psiElementToTree(findChildByRoleAsPsiElement(ChildRole.ANONYMOUS_CLASS));
if (anonymousClass != null){
return (PsiExpressionList)anonymousClass.findChildByRoleAsPsiElement(ChildRole.ARGUMENT_LIST);
}
return null;
}
@Override
@NotNull
public PsiExpression[] getArrayDimensions() {
PsiExpression[] expressions = getChildrenAsPsiElements(ElementType.ARRAY_DIMENSION_BIT_SET, PsiExpression.ARRAY_FACTORY);
PsiExpression qualifier = getQualifier();
if (qualifier == null) {
return expressions;
}
else {
LOG.assertTrue(expressions[0] == qualifier);
PsiExpression[] expressions1 = new PsiExpression[expressions.length - 1];
System.arraycopy(expressions, 1, expressions1, 0, expressions1.length);
return expressions1;
}
}
@Override
public PsiArrayInitializerExpression getArrayInitializer() {
return (PsiArrayInitializerExpression)findChildByRoleAsPsiElement(ChildRole.ARRAY_INITIALIZER);
}
@Override
public PsiMethod resolveMethod() {
return resolveConstructor();
}
private PsiPolyVariantCachingReference getConstructorFakeReference() {
return new PsiPolyVariantCachingReference() {
@Override
@NotNull
public JavaResolveResult[] resolveInner(boolean incompleteCode, @NotNull PsiFile containingFile) {
ASTNode classRef = findChildByRole(ChildRole.TYPE_REFERENCE);
if (classRef != null) {
ASTNode argumentList = PsiImplUtil.skipWhitespaceAndComments(classRef.getTreeNext());
if (argumentList != null && argumentList.getElementType() == JavaElementType.EXPRESSION_LIST) {
final JavaPsiFacade facade = JavaPsiFacade.getInstance(containingFile.getProject());
PsiType aClass = facade.getElementFactory().createType((PsiJavaCodeReferenceElement)SourceTreeToPsiMap.treeElementToPsi(classRef));
return facade.getResolveHelper().multiResolveConstructor((PsiClassType)aClass,
(PsiExpressionList)SourceTreeToPsiMap.treeElementToPsi(argumentList),
PsiNewExpressionImpl.this);
}
}
else{
ASTNode anonymousClassElement = findChildByType(JavaElementType.ANONYMOUS_CLASS);
if (anonymousClassElement != null) {
final JavaPsiFacade facade = JavaPsiFacade.getInstance(containingFile.getProject());
final PsiAnonymousClass anonymousClass = (PsiAnonymousClass)SourceTreeToPsiMap.treeElementToPsi(anonymousClassElement);
PsiType aClass = anonymousClass.getBaseClassType();
ASTNode argumentList = anonymousClassElement.findChildByType(JavaElementType.EXPRESSION_LIST);
return facade.getResolveHelper().multiResolveConstructor((PsiClassType)aClass,
(PsiExpressionList)SourceTreeToPsiMap.treeElementToPsi(argumentList),
anonymousClass);
}
}
return JavaResolveResult.EMPTY_ARRAY;
}
@Override
public PsiElement getElement() {
return PsiNewExpressionImpl.this;
}
@Override
public TextRange getRangeInElement() {
return null;
}
@Override
@NotNull
public String getCanonicalText() {
throw new UnsupportedOperationException();
}
@Override
public PsiElement handleElementRename(String newElementName) {
return null;
}
@Override
public PsiElement bindToElement(@NotNull PsiElement element) {
return null;
}
@Override
@NotNull
public Object[] getVariants() {
return ArrayUtil.EMPTY_OBJECT_ARRAY;
}
@Override
public int hashCode() {
return getElement().hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof PsiPolyVariantCachingReference && getElement() == ((PsiReference)obj).getElement();
}
};
}
@Override
@NotNull
public JavaResolveResult resolveMethodGenerics() {
ResolveResult[] results = getConstructorFakeReference().multiResolve(false);
return results.length == 1 ? (JavaResolveResult)results[0] : JavaResolveResult.EMPTY;
}
@Override
public PsiExpression getQualifier() {
return (PsiExpression)findChildByRoleAsPsiElement(ChildRole.QUALIFIER);
}
@Override
@NotNull
public PsiReferenceParameterList getTypeArgumentList() {
return (PsiReferenceParameterList) findChildByRoleAsPsiElement(ChildRole.REFERENCE_PARAMETER_LIST);
}
@Override
@NotNull
public PsiType[] getTypeArguments() {
return getTypeArgumentList().getTypeArguments();
}
@Override
public PsiMethod resolveConstructor(){
return (PsiMethod)resolveMethodGenerics().getElement();
}
@Override
public PsiJavaCodeReferenceElement getClassReference() {
return (PsiJavaCodeReferenceElement)findChildByRoleAsPsiElement(ChildRole.TYPE_REFERENCE);
}
@Override
public PsiAnonymousClass getAnonymousClass() {
ASTNode anonymousClass = findChildByType(JavaElementType.ANONYMOUS_CLASS);
if (anonymousClass == null) return null;
return (PsiAnonymousClass)SourceTreeToPsiMap.treeElementToPsi(anonymousClass);
}
private static final TokenSet CLASS_REF = TokenSet.create(JavaElementType.JAVA_CODE_REFERENCE, JavaElementType.ANONYMOUS_CLASS);
@Override
@Nullable
public PsiJavaCodeReferenceElement getClassOrAnonymousClassReference() {
ASTNode ref = findChildByType(CLASS_REF);
if (ref == null) return null;
if (ref instanceof PsiJavaCodeReferenceElement) return (PsiJavaCodeReferenceElement)ref;
PsiAnonymousClass anonymousClass = (PsiAnonymousClass)ref.getPsi();
return anonymousClass.getBaseClassReference();
}
@Override
public void deleteChildInternal(@NotNull ASTNode child) {
if (getChildRole(child) == ChildRole.QUALIFIER){
ASTNode dot = findChildByRole(ChildRole.DOT);
super.deleteChildInternal(child);
deleteChildInternal(dot);
}
else{
super.deleteChildInternal(child);
}
}
@Override
public ASTNode findChildByRole(int role){
LOG.assertTrue(ChildRole.isUnique(role));
switch(role){
default:
return null;
case ChildRole.REFERENCE_PARAMETER_LIST:
return findChildByType(JavaElementType.REFERENCE_PARAMETER_LIST);
case ChildRole.QUALIFIER:
TreeElement firstChild = getFirstChildNode();
if (firstChild != null && firstChild.getElementType() != JavaTokenType.NEW_KEYWORD) {
return firstChild;
}
else {
return null;
}
case ChildRole.DOT:
return findChildByType(JavaTokenType.DOT);
case ChildRole.NEW_KEYWORD:
return findChildByType(JavaTokenType.NEW_KEYWORD);
case ChildRole.ANONYMOUS_CLASS:
return findChildByType(JavaElementType.ANONYMOUS_CLASS);
case ChildRole.TYPE_REFERENCE:
return findChildByType(JavaElementType.JAVA_CODE_REFERENCE);
case ChildRole.TYPE_KEYWORD:
return findChildByType(ElementType.PRIMITIVE_TYPE_BIT_SET);
case ChildRole.ARGUMENT_LIST:
return findChildByType(JavaElementType.EXPRESSION_LIST);
case ChildRole.LBRACKET:
return findChildByType(JavaTokenType.LBRACKET);
case ChildRole.RBRACKET:
return findChildByType(JavaTokenType.RBRACKET);
case ChildRole.ARRAY_INITIALIZER:
if (getLastChildNode().getElementType() == JavaElementType.ARRAY_INITIALIZER_EXPRESSION){
return getLastChildNode();
}
else{
return null;
}
}
}
@Override
public int getChildRole(ASTNode child) {
LOG.assertTrue(child.getTreeParent() == this);
IElementType i = child.getElementType();
if (i == JavaElementType.REFERENCE_PARAMETER_LIST) {
return ChildRole.REFERENCE_PARAMETER_LIST;
}
else if (i == JavaTokenType.NEW_KEYWORD) {
return ChildRole.NEW_KEYWORD;
}
else if (i == JavaTokenType.DOT) {
return ChildRole.DOT;
}
else if (i == JavaElementType.JAVA_CODE_REFERENCE) {
return ChildRole.TYPE_REFERENCE;
}
else if (i == JavaElementType.EXPRESSION_LIST) {
return ChildRole.ARGUMENT_LIST;
}
else if (i == JavaTokenType.LBRACKET) {
return ChildRole.LBRACKET;
}
else if (i == JavaTokenType.RBRACKET) {
return ChildRole.RBRACKET;
}
else if (i == JavaElementType.ARRAY_INITIALIZER_EXPRESSION) {
if (child == getLastChildNode()) {
return ChildRole.ARRAY_INITIALIZER;
}
else if (child == getFirstChildNode()) {
return ChildRole.QUALIFIER;
}
else {
return ChildRole.ARRAY_DIMENSION;
}
}
else if (i == JavaElementType.ANONYMOUS_CLASS) {
return ChildRole.ANONYMOUS_CLASS;
}
else {
if (ElementType.PRIMITIVE_TYPE_BIT_SET.contains(child.getElementType())) {
return ChildRole.TYPE_KEYWORD;
}
else if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) {
return child == getFirstChildNode() ? ChildRole.QUALIFIER : ChildRole.ARRAY_DIMENSION;
}
else {
return ChildRoleBase.NONE;
}
}
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitNewExpression(this);
}
else {
visitor.visitElement(this);
}
}
public String toString() {
return "PsiNewExpression:" + getText();
}
}