/* * 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.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) { 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(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(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() { return null; } @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(); } }