customizable value calculation
[fedora-idea.git] / source / com / intellij / psi / impl / PsiImplUtil.java
blobe3b6c78a55735d6b321f75025f894318b0c3095a
1 package com.intellij.psi.impl;
3 import com.intellij.lang.ASTNode;
4 import com.intellij.openapi.diagnostic.Logger;
5 import com.intellij.openapi.util.text.StringUtil;
6 import com.intellij.psi.*;
7 import com.intellij.psi.filters.ElementFilter;
8 import com.intellij.psi.impl.light.LightClassReference;
9 import com.intellij.psi.impl.source.PsiClassReferenceType;
10 import com.intellij.psi.impl.source.PsiImmediateClassType;
11 import com.intellij.psi.impl.source.tree.CompositeElement;
12 import com.intellij.psi.impl.source.tree.ElementType;
13 import com.intellij.psi.impl.source.tree.JavaDocElementType;
14 import com.intellij.psi.impl.source.tree.TreeElement;
15 import com.intellij.psi.javadoc.PsiDocComment;
16 import com.intellij.psi.scope.ElementClassHint;
17 import com.intellij.psi.scope.PsiScopeProcessor;
18 import com.intellij.psi.scope.processor.FilterScopeProcessor;
19 import com.intellij.psi.scope.util.PsiScopesUtil;
20 import com.intellij.psi.search.GlobalSearchScope;
21 import com.intellij.psi.search.LocalSearchScope;
22 import com.intellij.psi.search.PackageScope;
23 import com.intellij.psi.search.SearchScope;
24 import com.intellij.psi.util.PsiTreeUtil;
25 import com.intellij.psi.util.PsiUtil;
26 import com.intellij.util.IncorrectOperationException;
27 import com.intellij.util.ObjectUtils;
28 import com.intellij.util.SmartList;
29 import org.jetbrains.annotations.NonNls;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
33 import java.util.List;
35 public class PsiImplUtil {
36 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiImplUtil");
38 private PsiImplUtil() {
41 @NotNull
42 public static PsiMethod[] getConstructors(PsiClass aClass) {
43 final List<PsiMethod> constructorsList = new SmartList<PsiMethod>();
44 final PsiMethod[] methods = aClass.getMethods();
45 for (final PsiMethod method : methods) {
46 if (method.isConstructor()) constructorsList.add(method);
48 return constructorsList.toArray(new PsiMethod[constructorsList.size()]);
51 @Nullable
52 public static PsiAnnotationMemberValue findDeclaredAttributeValue(PsiAnnotation annotation, @NonNls String attributeName) {
53 if ("value".equals(attributeName)) attributeName = null;
54 PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
55 for (PsiNameValuePair attribute : attributes) {
56 @NonNls final String name = attribute.getName();
57 if (ObjectUtils.equals(name, attributeName) || attributeName == null && name.equals(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME)) {
58 return attribute.getValue();
61 return null;
64 @Nullable
65 public static PsiAnnotationMemberValue findAttributeValue(PsiAnnotation annotation, @NonNls String attributeName) {
66 final PsiAnnotationMemberValue value = findDeclaredAttributeValue(annotation, attributeName);
67 if (value != null) return value;
69 if (attributeName == null) attributeName = "value";
70 final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
71 if (referenceElement != null) {
72 PsiElement resolved = referenceElement.resolve();
73 if (resolved != null) {
74 PsiMethod[] methods = ((PsiClass)resolved).getMethods();
75 for (PsiMethod method : methods) {
76 if (method instanceof PsiAnnotationMethod && ObjectUtils.equals(method.getName(), attributeName)) {
77 return ((PsiAnnotationMethod)method).getDefaultValue();
82 return null;
85 public static PsiTypeParameter[] getTypeParameters(PsiTypeParameterListOwner owner) {
86 final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
87 if (typeParameterList != null) {
88 return typeParameterList.getTypeParameters();
90 return PsiTypeParameter.EMPTY_ARRAY;
93 @NotNull
94 public static PsiJavaCodeReferenceElement[] namesToPackageReferences(PsiManager manager, String[] names) {
95 PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[names.length];
96 for (int i = 0; i < names.length; i++) {
97 String name = names[i];
98 try {
99 refs[i] = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createPackageReferenceElement(name);
101 catch (IncorrectOperationException e) {
102 LOG.error(e);
105 return refs;
108 public static int getParameterIndex(PsiParameter parameter, PsiParameterList parameterList) {
109 PsiParameter[] parameters = parameterList.getParameters();
110 for (int i = 0; i < parameters.length; i++) {
111 if (parameter.equals(parameters[i])) return i;
113 LOG.assertTrue(false);
114 return -1;
117 public static int getTypeParameterIndex(PsiTypeParameter typeParameter, PsiTypeParameterList typeParameterList) {
118 PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters();
119 for (int i = 0; i < typeParameters.length; i++) {
120 if (typeParameter.equals(typeParameters[i])) return i;
122 LOG.assertTrue(false);
123 return -1;
126 @NotNull
127 public static Object[] getReferenceVariantsByFilter(PsiJavaCodeReferenceElement reference, ElementFilter filter) {
128 FilterScopeProcessor processor = new FilterScopeProcessor(filter);
129 PsiScopesUtil.resolveAndWalk(processor, reference, null, true);
130 return processor.getResults().toArray();
133 public static boolean processDeclarationsInMethod(PsiMethod method,
134 PsiScopeProcessor processor,
135 ResolveState state,
136 PsiElement lastParent,
137 PsiElement place) {
138 final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
139 processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, method);
140 if (hint == null || hint.shouldProcess(ElementClassHint.DeclaractionKind.CLASS)) {
141 final PsiTypeParameterList list = method.getTypeParameterList();
142 if (list != null && !list.processDeclarations(processor, state, null, place)) return false;
144 if (lastParent instanceof PsiCodeBlock) {
145 final PsiParameter[] parameters = method.getParameterList().getParameters();
146 for (PsiParameter parameter : parameters) {
147 if (!processor.execute(parameter, state)) return false;
151 return true;
154 public static boolean hasTypeParameters(PsiTypeParameterListOwner owner) {
155 final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
156 return typeParameterList != null && typeParameterList.getTypeParameters().length != 0;
159 @NotNull
160 public static PsiType[] typesByReferenceParameterList(final PsiReferenceParameterList parameterList) {
161 PsiTypeElement[] typeElements = parameterList.getTypeParameterElements();
163 return typesByTypeElements(typeElements);
166 @NotNull
167 public static PsiType[] typesByTypeElements(PsiTypeElement[] typeElements) {
168 PsiType[] types = new PsiType[typeElements.length];
169 for (int i = 0; i < types.length; i++) {
170 types[i] = typeElements[i].getType();
172 return types;
175 public static PsiType getType(PsiClassObjectAccessExpression classAccessExpression) {
176 GlobalSearchScope resolveScope = classAccessExpression.getResolveScope();
177 PsiManager manager = classAccessExpression.getManager();
178 final PsiClass classClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Class", resolveScope);
179 if (classClass == null) {
180 return new PsiClassReferenceType(new LightClassReference(manager, "Class", "java.lang.Class", resolveScope), null);
182 if (!PsiUtil.isLanguageLevel5OrHigher(classAccessExpression)) {
183 //Raw java.lang.Class
184 return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(classClass);
187 PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
188 PsiType operandType = classAccessExpression.getOperand().getType();
189 if (operandType instanceof PsiPrimitiveType && !PsiType.NULL.equals(operandType)) {
190 if (PsiType.VOID.equals(operandType)) {
191 operandType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory()
192 .createTypeByFQClassName("java.lang.Void", classAccessExpression.getResolveScope());
194 else {
195 operandType = ((PsiPrimitiveType)operandType).getBoxedType(classAccessExpression);
198 final PsiTypeParameter[] typeParameters = classClass.getTypeParameters();
199 if (typeParameters.length == 1) {
200 substitutor = substitutor.put(typeParameters[0], operandType);
203 return new PsiImmediateClassType(classClass, substitutor);
206 public static PsiAnnotation findAnnotation(PsiAnnotationOwner modifierList, @NotNull String qualifiedName) {
207 final String shortName = StringUtil.getShortName(qualifiedName);
208 PsiAnnotation[] annotations = modifierList.getAnnotations();
209 for (PsiAnnotation annotation : annotations) {
210 final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
211 if (referenceElement != null && shortName.equals(referenceElement.getReferenceName())) {
212 if (qualifiedName.equals(annotation.getQualifiedName())) return annotation;
216 return null;
219 @Nullable
220 public static ASTNode findDocComment(final CompositeElement element) {
221 TreeElement node = element.getFirstChildNode();
222 while (node != null &&
223 (ElementType.WHITE_SPACE_BIT_SET.contains(node.getElementType()) ||
224 node.getElementType() == JavaTokenType.C_STYLE_COMMENT ||
225 node.getElementType() == JavaTokenType.END_OF_LINE_COMMENT)) {
226 node = node.getTreeNext();
229 if (node != null && node.getElementType() == JavaDocElementType.DOC_COMMENT) {
230 return node;
232 else {
233 return null;
237 public static PsiType normalizeWildcardTypeByPosition(final PsiType type, final PsiExpression expression) {
238 PsiExpression toplevel = expression;
239 while (toplevel.getParent() instanceof PsiArrayAccessExpression &&
240 ((PsiArrayAccessExpression)toplevel.getParent()).getArrayExpression() == toplevel) {
241 toplevel = (PsiExpression)toplevel.getParent();
244 final PsiType normalized = doNormalizeWildcardByPosition(type, expression, toplevel);
245 if (normalized instanceof PsiClassType && !PsiUtil.isAccessedForWriting(toplevel)) {
246 return PsiUtil.captureToplevelWildcards(normalized, expression);
249 return normalized;
252 private static PsiType doNormalizeWildcardByPosition(final PsiType type, final PsiExpression expression, final PsiExpression toplevel) {
253 if (type instanceof PsiCapturedWildcardType) {
254 return doNormalizeWildcardByPosition(((PsiCapturedWildcardType)type).getWildcard(), expression, toplevel);
258 if (type instanceof PsiWildcardType) {
259 final PsiWildcardType wildcardType = (PsiWildcardType)type;
261 if (PsiUtil.isAccessedForWriting(toplevel)) {
262 return wildcardType.isSuper() ? wildcardType.getBound() : PsiCapturedWildcardType.create(wildcardType, expression);
264 else {
265 if (wildcardType.isExtends()) {
266 return wildcardType.getBound();
268 else {
269 return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope());
273 else if (type instanceof PsiArrayType) {
274 final PsiType componentType = ((PsiArrayType)type).getComponentType();
275 final PsiType normalizedComponentType = doNormalizeWildcardByPosition(componentType, expression, toplevel);
276 if (normalizedComponentType != componentType) {
277 return normalizedComponentType.createArrayType();
281 return type;
284 @NotNull
285 public static SearchScope getMemberUseScope(final PsiMember member) {
286 final PsiManagerEx psiManager = (PsiManagerEx)member.getManager();
287 final GlobalSearchScope maximalUseScope = psiManager.getFileManager().getUseScope(member);
288 PsiFile file = member.getContainingFile();
289 if (PsiUtil.isInJspFile(file)) return maximalUseScope;
291 PsiClass aClass = member.getContainingClass();
292 if (aClass instanceof PsiAnonymousClass) {
293 //member from anonymous class can be called from outside the class
294 PsiElement methodCallExpr = PsiTreeUtil.getParentOfType(aClass, PsiMethodCallExpression.class);
295 return new LocalSearchScope(methodCallExpr != null ? methodCallExpr : aClass);
298 if (member.hasModifierProperty(PsiModifier.PUBLIC)) {
299 return maximalUseScope; // class use scope doesn't matter, since another very visible class can inherit from aClass
301 else if (member.hasModifierProperty(PsiModifier.PROTECTED)) {
302 return maximalUseScope; // class use scope doesn't matter, since another very visible class can inherit from aClass
304 else if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
305 PsiClass topClass = PsiUtil.getTopLevelClass(member);
306 return topClass != null ? new LocalSearchScope(topClass) : new LocalSearchScope(file);
308 else {
309 if (file instanceof PsiJavaFile) {
310 PsiPackage aPackage = JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(((PsiJavaFile)file).getPackageName());
311 if (aPackage != null) {
312 SearchScope scope = PackageScope.packageScope(aPackage, false);
313 scope = scope.intersectWith(maximalUseScope);
314 return scope;
318 return maximalUseScope;
322 public static PsiElement setName(PsiElement element, String name) throws IncorrectOperationException {
323 PsiManager manager = element.getManager();
324 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
325 PsiIdentifier newNameIdentifier = factory.createIdentifier(name);
326 return element.replace(newNameIdentifier);
329 public static boolean isDeprecatedByAnnotation(PsiModifierListOwner owner) {
330 PsiModifierList modifierList = owner.getModifierList();
331 return modifierList != null && modifierList.findAnnotation("java.lang.Deprecated") != null;
334 public static boolean isDeprecatedByDocTag(PsiDocCommentOwner owner) {
335 PsiDocComment docComment = owner.getDocComment();
336 return docComment != null && docComment.findTagByName("deprecated") != null;