/*
* 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;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.filters.ElementFilter;
import com.intellij.psi.impl.light.LightClassReference;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.scope.ElementClassHint;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.scope.processor.FilterScopeProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.search.SearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PairFunction;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static com.intellij.psi.PsiAnnotation.TargetType;
public class PsiImplUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiImplUtil");
private static final Set<TargetType> DEFAULT_TARGETS = Collections.unmodifiableSet(ContainerUtil.newHashSet(
TargetType.PACKAGE, TargetType.TYPE, TargetType.ANNOTATION_TYPE,
TargetType.FIELD, TargetType.METHOD, TargetType.CONSTRUCTOR,
TargetType.PARAMETER, TargetType.LOCAL_VARIABLE));
private static final TargetType[] PACKAGE_TARGETS = {TargetType.PACKAGE};
private static final TargetType[] TYPE_USE_TARGETS = {TargetType.TYPE_USE};
private static final TargetType[] ANNOTATION_TARGETS = {TargetType.ANNOTATION_TYPE, TargetType.TYPE, TargetType.TYPE_USE};
private static final TargetType[] TYPE_TARGETS = {TargetType.TYPE, TargetType.TYPE_USE};
private static final TargetType[] TYPE_PARAMETER_TARGETS = {TargetType.TYPE_PARAMETER, TargetType.TYPE_USE};
private static final TargetType[] CONSTRUCTOR_TARGETS = {TargetType.CONSTRUCTOR, TargetType.TYPE_USE};
private static final TargetType[] METHOD_TARGETS = {TargetType.METHOD, TargetType.TYPE_USE};
private static final TargetType[] FIELD_TARGETS = {TargetType.FIELD, TargetType.TYPE_USE};
private static final TargetType[] PARAMETER_TARGETS = {TargetType.PARAMETER, TargetType.TYPE_USE};
private static final TargetType[] LOCAL_VARIABLE_TARGETS ={TargetType.LOCAL_VARIABLE, TargetType.TYPE_USE};
private PsiImplUtil() { }
@NotNull
public static PsiMethod[] getConstructors(@NotNull PsiClass aClass) {
final List<PsiMethod> constructorsList = new SmartList<PsiMethod>();
final PsiMethod[] methods = aClass.getMethods();
for (final PsiMethod method : methods) {
if (method.isConstructor()) constructorsList.add(method);
}
return constructorsList.toArray(new PsiMethod[constructorsList.size()]);
}
@Nullable
public static PsiAnnotationMemberValue findDeclaredAttributeValue(@NotNull PsiAnnotation annotation, @NonNls String attributeName) {
if ("value".equals(attributeName)) attributeName = null;
PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
for (PsiNameValuePair attribute : attributes) {
@NonNls final String name = attribute.getName();
if (Comparing.equal(name, attributeName) || attributeName == null && PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(name)) {
return attribute.getValue();
}
}
return null;
}
@Nullable
public static PsiAnnotationMemberValue findAttributeValue(@NotNull PsiAnnotation annotation, @Nullable @NonNls String attributeName) {
final PsiAnnotationMemberValue value = findDeclaredAttributeValue(annotation, attributeName);
if (value != null) return value;
if (attributeName == null) attributeName = "value";
final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement != null) {
PsiElement resolved = referenceElement.resolve();
if (resolved != null) {
PsiMethod[] methods = ((PsiClass)resolved).getMethods();
for (PsiMethod method : methods) {
if (PsiUtil.isAnnotationMethod(method) && Comparing.equal(method.getName(), attributeName)) {
return ((PsiAnnotationMethod)method).getDefaultValue();
}
}
}
}
return null;
}
@NotNull
public static PsiTypeParameter[] getTypeParameters(@NotNull PsiTypeParameterListOwner owner) {
final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
if (typeParameterList != null) {
return typeParameterList.getTypeParameters();
}
return PsiTypeParameter.EMPTY_ARRAY;
}
@NotNull
public static PsiJavaCodeReferenceElement[] namesToPackageReferences(@NotNull PsiManager manager, @NotNull String[] names) {
PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[names.length];
for (int i = 0; i < names.length; i++) {
String name = names[i];
try {
refs[i] = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createPackageReferenceElement(name);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
return refs;
}
public static int getParameterIndex(@NotNull PsiParameter parameter, @NotNull PsiParameterList parameterList) {
PsiElement parameterParent = parameter.getParent();
assert parameterParent == parameterList : parameterList +"; "+parameterParent;
PsiParameter[] parameters = parameterList.getParameters();
for (int i = 0; i < parameters.length; i++) {
PsiParameter paramInList = parameters[i];
if (parameter.equals(paramInList)) return i;
}
String name = parameter.getName();
PsiParameter suspect = null;
int i;
for (i = parameters.length - 1; i >= 0; i--) {
PsiParameter paramInList = parameters[i];
if (Comparing.equal(name, paramInList.getName())) {
suspect = paramInList;
break;
}
}
String message = parameter + ":" + parameter.getClass() + " not found among parameters: " + Arrays.asList(parameters) + "." +
" parameterList' parent: " + parameterList.getParent() + ";" +
" parameter.isValid()=" + parameter.isValid() + ";" +
" parameterList.isValid()= " + parameterList.isValid() + ";" +
" parameterList stub: " + (parameterList instanceof StubBasedPsiElement ? ((StubBasedPsiElement)parameterList).getStub() : "---") + "; " +
" parameter stub: "+(parameter instanceof StubBasedPsiElement ? ((StubBasedPsiElement)parameter).getStub() : "---") + ";" +
" suspect: " + suspect +" (index="+i+"); " + (suspect==null?null:suspect.getClass()) +
" suspect stub: "+(suspect instanceof StubBasedPsiElement ? ((StubBasedPsiElement)suspect).getStub() : suspect == null ? "-null-" : "---"+suspect.getClass()) + ";" +
" parameter.equals(suspect) = " + parameter.equals(suspect) + "; " +
" parameter.getNode() == suspect.getNode(): " + (parameter.getNode() == (suspect==null ? null : suspect.getNode())) + "; " +
"."
;
LOG.error(message);
return i;
}
public static int getTypeParameterIndex(@NotNull PsiTypeParameter typeParameter, @NotNull PsiTypeParameterList typeParameterList) {
PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters();
for (int i = 0; i < typeParameters.length; i++) {
if (typeParameter.equals(typeParameters[i])) return i;
}
LOG.assertTrue(false);
return -1;
}
@NotNull
public static Object[] getReferenceVariantsByFilter(@NotNull PsiJavaCodeReferenceElement reference, @NotNull ElementFilter filter) {
FilterScopeProcessor processor = new FilterScopeProcessor(filter);
PsiScopesUtil.resolveAndWalk(processor, reference, null, true);
return processor.getResults().toArray();
}
public static boolean processDeclarationsInMethod(@NotNull final PsiMethod method,
@NotNull final PsiScopeProcessor processor,
@NotNull final ResolveState state,
final PsiElement lastParent,
@NotNull final PsiElement place) {
final boolean fromBody = lastParent instanceof PsiCodeBlock;
final PsiTypeParameterList typeParameterList = method.getTypeParameterList();
final PsiParameterList parameterList = method.getParameterList();
return processDeclarationsInMethodLike(method, processor, state, place, fromBody, typeParameterList, parameterList);
}
public static boolean processDeclarationsInLambda(@NotNull final PsiLambdaExpression lambda,
@NotNull final PsiScopeProcessor processor,
@NotNull final ResolveState state,
final PsiElement lastParent,
@NotNull final PsiElement place) {
final boolean fromBody = lastParent != null && lastParent == lambda.getBody();
final PsiParameterList parameterList = lambda.getParameterList();
return processDeclarationsInMethodLike(lambda, processor, state, place, fromBody, null, parameterList);
}
private static boolean processDeclarationsInMethodLike(@NotNull final PsiElement element,
@NotNull final PsiScopeProcessor processor,
@NotNull final ResolveState state,
@NotNull final PsiElement place,
final boolean fromBody,
@Nullable final PsiTypeParameterList typeParameterList,
@NotNull final PsiParameterList parameterList) {
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, element);
if (typeParameterList != null) {
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
if (hint == null || hint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
if (!typeParameterList.processDeclarations(processor, state, null, place)) return false;
}
}
if (fromBody) {
final PsiParameter[] parameters = parameterList.getParameters();
for (PsiParameter parameter : parameters) {
if (!processor.execute(parameter, state)) return false;
}
}
return true;
}
public static boolean processDeclarationsInResourceList(@NotNull final PsiResourceList resourceList,
@NotNull final PsiScopeProcessor processor,
@NotNull final ResolveState state,
final PsiElement lastParent) {
final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
if (hint != null && !hint.shouldProcess(ElementClassHint.DeclarationKind.VARIABLE)) return true;
final List<PsiResourceVariable> resources = resourceList.getResourceVariables();
@SuppressWarnings({"SuspiciousMethodCalls"})
final int lastIdx = lastParent instanceof PsiResourceVariable ? resources.indexOf(lastParent) : resources.size();
for (int i = 0; i < lastIdx; i++) {
if (!processor.execute(resources.get(i), state)) return false;
}
return true;
}
public static boolean hasTypeParameters(@NotNull PsiTypeParameterListOwner owner) {
final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
return typeParameterList != null && typeParameterList.getTypeParameters().length != 0;
}
@NotNull
public static PsiType[] typesByReferenceParameterList(@NotNull PsiReferenceParameterList parameterList) {
PsiTypeElement[] typeElements = parameterList.getTypeParameterElements();
return typesByTypeElements(typeElements);
}
@NotNull
public static PsiType[] typesByTypeElements(@NotNull PsiTypeElement[] typeElements) {
PsiType[] types = new PsiType[typeElements.length];
for (int i = 0; i < types.length; i++) {
types[i] = typeElements[i].getType();
}
if (types.length == 1 && types[0] instanceof PsiDiamondType) {
return ((PsiDiamondType)types[0]).resolveInferredTypes().getTypes();
}
return types;
}
public static PsiType getType(@NotNull PsiClassObjectAccessExpression classAccessExpression) {
GlobalSearchScope resolveScope = classAccessExpression.getResolveScope();
PsiManager manager = classAccessExpression.getManager();
final PsiClass classClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Class", resolveScope);
if (classClass == null) {
return new PsiClassReferenceType(new LightClassReference(manager, "Class", "java.lang.Class", resolveScope), null);
}
if (!PsiUtil.isLanguageLevel5OrHigher(classAccessExpression)) {
//Raw java.lang.Class
return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(classClass);
}
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
PsiType operandType = classAccessExpression.getOperand().getType();
if (operandType instanceof PsiPrimitiveType && !PsiType.NULL.equals(operandType)) {
if (PsiType.VOID.equals(operandType)) {
operandType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory()
.createTypeByFQClassName("java.lang.Void", classAccessExpression.getResolveScope());
}
else {
operandType = ((PsiPrimitiveType)operandType).getBoxedType(classAccessExpression);
}
}
final PsiTypeParameter[] typeParameters = classClass.getTypeParameters();
if (typeParameters.length == 1) {
substitutor = substitutor.put(typeParameters[0], operandType);
}
return new PsiImmediateClassType(classClass, substitutor);
}
@Nullable
public static PsiAnnotation findAnnotation(@Nullable PsiAnnotationOwner annotationOwner, @NotNull String qualifiedName) {
if (annotationOwner == null) return null;
PsiAnnotation[] annotations = annotationOwner.getAnnotations();
if (annotations.length == 0) return null;
String shortName = StringUtil.getShortName(qualifiedName);
for (PsiAnnotation annotation : annotations) {
PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement != null && shortName.equals(referenceElement.getReferenceName())) {
if (qualifiedName.equals(annotation.getQualifiedName())) {
return annotation;
}
}
}
return null;
}
@Nullable
public static TargetType findApplicableTarget(@NotNull PsiAnnotation annotation, @NotNull TargetType... types) {
if (types.length != 0) {
PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
if (ref != null) {
PsiElement annotationType = ref.resolve();
if (annotationType instanceof PsiClass) {
return findApplicableTarget((PsiClass)annotationType, types);
}
}
}
return TargetType.UNKNOWN;
}
@Nullable
public static TargetType findApplicableTarget(@NotNull PsiClass annotationType, @NotNull TargetType... types) {
if (types.length != 0) {
Set<TargetType> targets = getAnnotationTargets(annotationType);
if (targets != null) {
for (TargetType type : types) {
if (type != TargetType.UNKNOWN && targets.contains(type)) {
return type;
}
}
return null;
}
}
return TargetType.UNKNOWN;
}
// todo[r.sh] cache?
@Nullable
public static Set<TargetType> getAnnotationTargets(PsiClass annotationType) {
if (!annotationType.isAnnotationType()) return null;
PsiModifierList modifierList = annotationType.getModifierList();
if (modifierList == null) return null;
PsiAnnotation target = modifierList.findAnnotation(CommonClassNames.JAVA_LANG_ANNOTATION_TARGET);
if (target == null) return DEFAULT_TARGETS; // if omitted it is applicable to all but Java 8 TYPE_USE/TYPE_PARAMETERS targets
PsiAnnotationMemberValue value = target.findAttributeValue(null);
if (value instanceof PsiReference) {
TargetType targetType = translateTargetRef((PsiReference)value);
if (targetType != null) {
return Collections.singleton(targetType);
}
}
else if (value instanceof PsiArrayInitializerMemberValue) {
Set <TargetType> targets = ContainerUtil.newHashSet();
for (PsiAnnotationMemberValue initializer : ((PsiArrayInitializerMemberValue)value).getInitializers()) {
if (initializer instanceof PsiReference) {
TargetType targetType = translateTargetRef((PsiReference)initializer);
if (targetType != null) {
targets.add(targetType);
}
}
}
return targets;
}
return null;
}
@Nullable
private static TargetType translateTargetRef(PsiReference reference) {
PsiElement field = reference.resolve();
if (field instanceof PsiEnumConstant) {
String name = ((PsiEnumConstant)field).getName();
try {
return TargetType.valueOf(name);
}
catch (IllegalArgumentException e) {
LOG.warn("Unknown target: " + name);
}
}
return null;
}
@NotNull
public static TargetType[] getTargetsForLocation(@Nullable PsiAnnotationOwner owner) {
if (owner == null) {
return TargetType.EMPTY_ARRAY;
}
if (owner instanceof PsiType || owner instanceof PsiTypeElement) {
return TYPE_USE_TARGETS;
}
if (owner instanceof PsiTypeParameter) {
return TYPE_PARAMETER_TARGETS;
}
if (owner instanceof PsiModifierList) {
PsiElement element = ((PsiModifierList)owner).getParent();
if (element instanceof PsiPackageStatement) {
return PACKAGE_TARGETS;
}
if (element instanceof PsiClass) {
if (((PsiClass)element).isAnnotationType()) {
return ANNOTATION_TARGETS;
}
else {
return TYPE_TARGETS;
}
}
if (element instanceof PsiMethod) {
if (((PsiMethod)element).isConstructor()) {
return CONSTRUCTOR_TARGETS;
}
else {
return METHOD_TARGETS;
}
}
if (element instanceof PsiField) {
return FIELD_TARGETS;
}
if (element instanceof PsiParameter) {
return PARAMETER_TARGETS;
}
if (element instanceof PsiLocalVariable) {
return LOCAL_VARIABLE_TARGETS;
}
}
return TargetType.EMPTY_ARRAY;
}
@Nullable
public static ASTNode findDocComment(@NotNull CompositeElement element) {
TreeElement node = element.getFirstChildNode();
while (node != null && (isWhitespaceOrComment(node) && !(node.getPsi() instanceof PsiDocComment))) {
node = node.getTreeNext();
}
if (node != null && node.getElementType() == JavaDocElementType.DOC_COMMENT) {
return node;
}
else {
return null;
}
}
public static PsiType normalizeWildcardTypeByPosition(@NotNull PsiType type, @NotNull PsiExpression expression) {
LOG.assertTrue(expression.isValid());
LOG.assertTrue(type.isValid());
PsiExpression toplevel = expression;
while (toplevel.getParent() instanceof PsiArrayAccessExpression &&
((PsiArrayAccessExpression)toplevel.getParent()).getArrayExpression() == toplevel) {
toplevel = (PsiExpression)toplevel.getParent();
}
if (toplevel instanceof PsiArrayAccessExpression && !PsiUtil.isAccessedForWriting(toplevel)) {
return PsiUtil.captureToplevelWildcards(type, expression);
}
final PsiType normalized = doNormalizeWildcardByPosition(type, expression, toplevel);
LOG.assertTrue(normalized.isValid(), type);
if (normalized instanceof PsiClassType && !PsiUtil.isAccessedForWriting(toplevel)) {
return PsiUtil.captureToplevelWildcards(normalized, expression);
}
return normalized;
}
private static PsiType doNormalizeWildcardByPosition(final PsiType type, @NotNull PsiExpression expression, final PsiExpression toplevel) {
if (type instanceof PsiCapturedWildcardType) {
return doNormalizeWildcardByPosition(((PsiCapturedWildcardType)type).getWildcard(), expression, toplevel);
}
if (type instanceof PsiWildcardType) {
final PsiWildcardType wildcardType = (PsiWildcardType)type;
if (PsiUtil.isAccessedForWriting(toplevel)) {
return wildcardType.isSuper() ? wildcardType.getBound() : PsiCapturedWildcardType.create(wildcardType, expression);
}
else {
if (wildcardType.isExtends()) {
return wildcardType.getBound();
}
else {
return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope());
}
}
}
else if (type instanceof PsiArrayType) {
final PsiType componentType = ((PsiArrayType)type).getComponentType();
final PsiType normalizedComponentType = doNormalizeWildcardByPosition(componentType, expression, toplevel);
if (normalizedComponentType != componentType) {
return normalizedComponentType.createArrayType();
}
}
return type;
}
@NotNull
public static SearchScope getMemberUseScope(@NotNull PsiMember member) {
final GlobalSearchScope maximalUseScope = ResolveScopeManager.getElementUseScope(member);
PsiFile file = member.getContainingFile();
if (isInServerPage(file)) return maximalUseScope;
PsiClass aClass = member.getContainingClass();
if (aClass instanceof PsiAnonymousClass) {
//member from anonymous class can be called from outside the class
PsiElement methodCallExpr = PsiTreeUtil.getParentOfType(aClass, PsiMethodCallExpression.class);
return new LocalSearchScope(methodCallExpr != null ? methodCallExpr : aClass);
}
if (member.hasModifierProperty(PsiModifier.PUBLIC)) {
return maximalUseScope; // class use scope doesn't matter, since another very visible class can inherit from aClass
}
else if (member.hasModifierProperty(PsiModifier.PROTECTED)) {
return maximalUseScope; // class use scope doesn't matter, since another very visible class can inherit from aClass
}
else if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
PsiClass topClass = PsiUtil.getTopLevelClass(member);
return topClass != null ? new LocalSearchScope(topClass) : file != null ? new LocalSearchScope(file) : maximalUseScope;
}
else {
if (file instanceof PsiJavaFile) {
PsiPackage aPackage = JavaPsiFacade.getInstance(member.getProject()).findPackage(((PsiJavaFile)file).getPackageName());
if (aPackage != null) {
SearchScope scope = PackageScope.packageScope(aPackage, false);
scope = scope.intersectWith(maximalUseScope);
return scope;
}
}
return maximalUseScope;
}
}
public static boolean isInServerPage(@Nullable final PsiElement element) {
return getServerPageFile(element) != null;
}
@Nullable public static ServerPageFile getServerPageFile(final PsiElement element) {
final PsiFile psiFile = PsiUtilCore.getTemplateLanguageFile(element);
return psiFile instanceof ServerPageFile ? (ServerPageFile)psiFile : null;
}
public static PsiElement setName(@NotNull PsiElement element, @NotNull String name) throws IncorrectOperationException {
PsiManager manager = element.getManager();
PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
PsiIdentifier newNameIdentifier = factory.createIdentifier(name);
return element.replace(newNameIdentifier);
}
public static boolean isDeprecatedByAnnotation(@NotNull PsiModifierListOwner owner) {
PsiModifierList modifierList = owner.getModifierList();
return modifierList != null && modifierList.findAnnotation("java.lang.Deprecated") != null;
}
public static boolean isDeprecatedByDocTag(@NotNull PsiDocCommentOwner owner) {
PsiDocComment docComment = owner.getDocComment();
return docComment != null && docComment.findTagByName("deprecated") != null;
}
@Nullable
public static PsiAnnotationMemberValue setDeclaredAttributeValue(@NotNull PsiAnnotation psiAnnotation,
@Nullable String attributeName,
@Nullable PsiAnnotationMemberValue value,
@NotNull PairFunction<Project, String, PsiAnnotation> annotationCreator) {
final PsiAnnotationMemberValue existing = psiAnnotation.findDeclaredAttributeValue(attributeName);
if (value == null) {
if (existing == null) {
return null;
}
existing.getParent().delete();
} else {
if (existing != null) {
((PsiNameValuePair)existing.getParent()).setValue(value);
} else {
final PsiNameValuePair[] attributes = psiAnnotation.getParameterList().getAttributes();
if (attributes.length == 1 && attributes[0].getName() == null) {
attributes[0].replace(createNameValuePair(attributes[0].getValue(), PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME + "=", annotationCreator));
}
boolean allowNoName = attributes.length == 0 && ("value".equals(attributeName) || null == attributeName);
final String namePrefix;
if (allowNoName) {
namePrefix = "";
} else {
namePrefix = attributeName + "=";
}
psiAnnotation.getParameterList().addBefore(createNameValuePair(value, namePrefix, annotationCreator), null);
}
}
return psiAnnotation.findDeclaredAttributeValue(attributeName);
}
private static PsiNameValuePair createNameValuePair(@NotNull PsiAnnotationMemberValue value,
@NotNull String namePrefix,
@NotNull PairFunction<Project, String, PsiAnnotation> annotationCreator) {
return annotationCreator.fun(value.getProject(), "@A(" + namePrefix + value.getText() + ")").getParameterList().getAttributes()[0];
}
@Nullable
public static ASTNode skipWhitespaceAndComments(final ASTNode node) {
return skipWhitespaceCommentsAndTokens(node, TokenSet.EMPTY);
}
@Nullable
public static ASTNode skipWhitespaceCommentsAndTokens(final ASTNode node, TokenSet alsoSkip) {
ASTNode element = node;
while (true) {
if (element == null) return null;
if (!isWhitespaceOrComment(element) && !alsoSkip.contains(element.getElementType())) break;
element = element.getTreeNext();
}
return element;
}
public static boolean isWhitespaceOrComment(ASTNode element) {
return element.getPsi() instanceof PsiWhiteSpace || element.getPsi() instanceof PsiComment;
}
@Nullable
public static ASTNode skipWhitespaceAndCommentsBack(final ASTNode node) {
if (node == null) return null;
if (!isWhitespaceOrComment(node)) return node;
ASTNode parent = node.getTreeParent();
ASTNode prev = node;
while (prev instanceof CompositeElement) {
if (!isWhitespaceOrComment(prev)) return prev;
prev = prev.getTreePrev();
}
if (prev == null) return null;
ASTNode firstChildNode = parent.getFirstChildNode();
ASTNode lastRelevant = null;
while (firstChildNode != prev) {
if (!isWhitespaceOrComment(firstChildNode)) lastRelevant = firstChildNode;
firstChildNode = firstChildNode.getTreeNext();
}
return lastRelevant;
}
@Nullable
public static ASTNode findStatementChild(CompositePsiElement statement) {
if (DebugUtil.CHECK_INSIDE_ATOMIC_ACTION_ENABLED) {
ApplicationManager.getApplication().assertReadAccessAllowed();
}
for (ASTNode element = statement.getFirstChildNode(); element != null; element = element.getTreeNext()) {
if (element.getPsi() instanceof PsiStatement) return element;
}
return null;
}
public static PsiStatement[] getChildStatements(CompositeElement psiCodeBlock) {
ApplicationManager.getApplication().assertReadAccessAllowed();
// no lock is needed because all chameleons are expanded already
int count = 0;
for (ASTNode child1 = psiCodeBlock.getFirstChildNode(); child1 != null; child1 = child1.getTreeNext()) {
if (child1.getPsi() instanceof PsiStatement) {
count++;
}
}
PsiStatement[] result = PsiStatement.ARRAY_FACTORY.create(count);
if (count == 0) return result;
int idx = 0;
for (ASTNode child = psiCodeBlock.getFirstChildNode(); child != null && idx < count; child = child.getTreeNext()) {
if (child.getPsi() instanceof PsiStatement) {
PsiStatement element = (PsiStatement)child.getPsi();
LOG.assertTrue(element != null, child);
result[idx++] = element;
}
}
return result;
}
public static boolean isVarArgs(@NotNull PsiMethod method) {
PsiParameter[] parameters = method.getParameterList().getParameters();
return parameters.length > 0 && parameters[parameters.length - 1].isVarArgs();
}
public static PsiElement handleMirror(PsiElement element) {
return element instanceof PsiMirrorElement ? ((PsiMirrorElement)element).getPrototype() : element;
}
@Nullable
public static PsiModifierList findNeighbourModifierList(@NotNull PsiJavaCodeReferenceElement ref) {
PsiElement parent = PsiTreeUtil.skipParentsOfType(ref, PsiJavaCodeReferenceElement.class);
if (parent instanceof PsiTypeElement) {
PsiElement grandParent = parent.getParent();
if (grandParent instanceof PsiModifierListOwner) {
return ((PsiModifierListOwner)grandParent).getModifierList();
}
}
return null;
}
@Nullable
public static List<PsiAnnotation> getTypeUseAnnotations(@NotNull PsiModifierList modifierList) {
SmartList<PsiAnnotation> result = null;
for (PsiAnnotation annotation : modifierList.getAnnotations()) {
if (findApplicableTarget(annotation, TargetType.TYPE_USE) == TargetType.TYPE_USE) {
if (result == null) result = new SmartList<PsiAnnotation>();
result.add(annotation);
}
}
return result;
}
public static boolean isLeafElementOfType(@Nullable PsiElement element, IElementType type) {
return element instanceof LeafElement && ((LeafElement)element).getElementType() == type;
}
public static boolean isLeafElementOfType(PsiElement element, TokenSet tokenSet) {
return element instanceof LeafElement && tokenSet.contains(((LeafElement)element).getElementType());
}
}