update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / PsiImplUtil.java
blob288cff3236bef70850daa348a70dd0e36c38308f
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.psi.impl;
18 import com.intellij.lang.ASTNode;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.project.Project;
21 import com.intellij.openapi.util.Comparing;
22 import com.intellij.openapi.util.text.StringUtil;
23 import com.intellij.psi.*;
24 import com.intellij.psi.filters.ElementFilter;
25 import com.intellij.psi.impl.light.LightClassReference;
26 import com.intellij.psi.impl.source.PsiClassReferenceType;
27 import com.intellij.psi.impl.source.PsiImmediateClassType;
28 import com.intellij.psi.impl.source.tree.CompositeElement;
29 import com.intellij.psi.impl.source.tree.ElementType;
30 import com.intellij.psi.impl.source.tree.JavaDocElementType;
31 import com.intellij.psi.impl.source.tree.TreeElement;
32 import com.intellij.psi.javadoc.PsiDocComment;
33 import com.intellij.psi.scope.ElementClassHint;
34 import com.intellij.psi.scope.PsiScopeProcessor;
35 import com.intellij.psi.scope.processor.FilterScopeProcessor;
36 import com.intellij.psi.scope.util.PsiScopesUtil;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.search.LocalSearchScope;
39 import com.intellij.psi.search.PackageScope;
40 import com.intellij.psi.search.SearchScope;
41 import com.intellij.psi.util.PsiTreeUtil;
42 import com.intellij.psi.util.PsiUtil;
43 import com.intellij.util.IncorrectOperationException;
44 import com.intellij.util.PairFunction;
45 import com.intellij.util.SmartList;
46 import org.jetbrains.annotations.NonNls;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
50 import java.util.Arrays;
51 import java.util.List;
53 public class PsiImplUtil {
54 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiImplUtil");
56 private PsiImplUtil() {
59 @NotNull
60 public static PsiMethod[] getConstructors(PsiClass aClass) {
61 final List<PsiMethod> constructorsList = new SmartList<PsiMethod>();
62 final PsiMethod[] methods = aClass.getMethods();
63 for (final PsiMethod method : methods) {
64 if (method.isConstructor()) constructorsList.add(method);
66 return constructorsList.toArray(new PsiMethod[constructorsList.size()]);
69 @Nullable
70 public static PsiAnnotationMemberValue findDeclaredAttributeValue(PsiAnnotation annotation, @NonNls String attributeName) {
71 if ("value".equals(attributeName)) attributeName = null;
72 PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
73 for (PsiNameValuePair attribute : attributes) {
74 @NonNls final String name = attribute.getName();
75 if (Comparing.equal(name, attributeName) || attributeName == null && name.equals(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME)) {
76 return attribute.getValue();
79 return null;
82 @Nullable
83 public static PsiAnnotationMemberValue findAttributeValue(PsiAnnotation annotation, @NonNls String attributeName) {
84 final PsiAnnotationMemberValue value = findDeclaredAttributeValue(annotation, attributeName);
85 if (value != null) return value;
87 if (attributeName == null) attributeName = "value";
88 final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
89 if (referenceElement != null) {
90 PsiElement resolved = referenceElement.resolve();
91 if (resolved != null) {
92 PsiMethod[] methods = ((PsiClass)resolved).getMethods();
93 for (PsiMethod method : methods) {
94 if (method instanceof PsiAnnotationMethod && Comparing.equal(method.getName(), attributeName)) {
95 return ((PsiAnnotationMethod)method).getDefaultValue();
100 return null;
103 public static PsiTypeParameter[] getTypeParameters(PsiTypeParameterListOwner owner) {
104 final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
105 if (typeParameterList != null) {
106 return typeParameterList.getTypeParameters();
108 return PsiTypeParameter.EMPTY_ARRAY;
111 @NotNull
112 public static PsiJavaCodeReferenceElement[] namesToPackageReferences(PsiManager manager, String[] names) {
113 PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[names.length];
114 for (int i = 0; i < names.length; i++) {
115 String name = names[i];
116 try {
117 refs[i] = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createPackageReferenceElement(name);
119 catch (IncorrectOperationException e) {
120 LOG.error(e);
123 return refs;
126 public static int getParameterIndex(PsiParameter parameter, PsiParameterList parameterList) {
127 PsiParameter[] parameters = parameterList.getParameters();
128 for (int i = 0; i < parameters.length; i++) {
129 if (parameter.equals(parameters[i])) return i;
131 LOG.error("Parameter " + parameter + " not found among paramaters: " + Arrays.asList(parameters));
132 return -1;
135 public static int getTypeParameterIndex(PsiTypeParameter typeParameter, PsiTypeParameterList typeParameterList) {
136 PsiTypeParameter[] typeParameters = typeParameterList.getTypeParameters();
137 for (int i = 0; i < typeParameters.length; i++) {
138 if (typeParameter.equals(typeParameters[i])) return i;
140 LOG.assertTrue(false);
141 return -1;
144 @NotNull
145 public static Object[] getReferenceVariantsByFilter(PsiJavaCodeReferenceElement reference, ElementFilter filter) {
146 FilterScopeProcessor processor = new FilterScopeProcessor(filter);
147 PsiScopesUtil.resolveAndWalk(processor, reference, null, true);
148 return processor.getResults().toArray();
151 public static boolean processDeclarationsInMethod(PsiMethod method,
152 PsiScopeProcessor processor,
153 ResolveState state,
154 PsiElement lastParent,
155 PsiElement place) {
156 final ElementClassHint hint = processor.getHint(ElementClassHint.KEY);
157 processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, method);
158 if (hint == null || hint.shouldProcess(ElementClassHint.DeclaractionKind.CLASS)) {
159 final PsiTypeParameterList list = method.getTypeParameterList();
160 if (list != null && !list.processDeclarations(processor, state, null, place)) return false;
162 if (lastParent instanceof PsiCodeBlock) {
163 final PsiParameter[] parameters = method.getParameterList().getParameters();
164 for (PsiParameter parameter : parameters) {
165 if (!processor.execute(parameter, state)) return false;
169 return true;
172 public static boolean hasTypeParameters(PsiTypeParameterListOwner owner) {
173 final PsiTypeParameterList typeParameterList = owner.getTypeParameterList();
174 return typeParameterList != null && typeParameterList.getTypeParameters().length != 0;
177 @NotNull
178 public static PsiType[] typesByReferenceParameterList(final PsiReferenceParameterList parameterList) {
179 PsiTypeElement[] typeElements = parameterList.getTypeParameterElements();
181 return typesByTypeElements(typeElements);
184 @NotNull
185 public static PsiType[] typesByTypeElements(PsiTypeElement[] typeElements) {
186 PsiType[] types = new PsiType[typeElements.length];
187 for (int i = 0; i < types.length; i++) {
188 types[i] = typeElements[i].getType();
190 return types;
193 public static PsiType getType(PsiClassObjectAccessExpression classAccessExpression) {
194 GlobalSearchScope resolveScope = classAccessExpression.getResolveScope();
195 PsiManager manager = classAccessExpression.getManager();
196 final PsiClass classClass = JavaPsiFacade.getInstance(manager.getProject()).findClass("java.lang.Class", resolveScope);
197 if (classClass == null) {
198 return new PsiClassReferenceType(new LightClassReference(manager, "Class", "java.lang.Class", resolveScope), null);
200 if (!PsiUtil.isLanguageLevel5OrHigher(classAccessExpression)) {
201 //Raw java.lang.Class
202 return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(classClass);
205 PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
206 PsiType operandType = classAccessExpression.getOperand().getType();
207 if (operandType instanceof PsiPrimitiveType && !PsiType.NULL.equals(operandType)) {
208 if (PsiType.VOID.equals(operandType)) {
209 operandType = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory()
210 .createTypeByFQClassName("java.lang.Void", classAccessExpression.getResolveScope());
212 else {
213 operandType = ((PsiPrimitiveType)operandType).getBoxedType(classAccessExpression);
216 final PsiTypeParameter[] typeParameters = classClass.getTypeParameters();
217 if (typeParameters.length == 1) {
218 substitutor = substitutor.put(typeParameters[0], operandType);
221 return new PsiImmediateClassType(classClass, substitutor);
224 public static PsiAnnotation findAnnotation(PsiAnnotationOwner modifierList, @NotNull String qualifiedName) {
225 final String shortName = StringUtil.getShortName(qualifiedName);
226 PsiAnnotation[] annotations = modifierList.getAnnotations();
227 for (PsiAnnotation annotation : annotations) {
228 final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
229 if (referenceElement != null && shortName.equals(referenceElement.getReferenceName())) {
230 if (qualifiedName.equals(annotation.getQualifiedName())) return annotation;
234 return null;
237 @Nullable
238 public static ASTNode findDocComment(final CompositeElement element) {
239 TreeElement node = element.getFirstChildNode();
240 while (node != null &&
241 (ElementType.WHITE_SPACE_BIT_SET.contains(node.getElementType()) ||
242 node.getElementType() == JavaTokenType.C_STYLE_COMMENT ||
243 node.getElementType() == JavaTokenType.END_OF_LINE_COMMENT)) {
244 node = node.getTreeNext();
247 if (node != null && node.getElementType() == JavaDocElementType.DOC_COMMENT) {
248 return node;
250 else {
251 return null;
255 public static PsiType normalizeWildcardTypeByPosition(final PsiType type, final PsiExpression expression) {
256 PsiExpression toplevel = expression;
257 while (toplevel.getParent() instanceof PsiArrayAccessExpression &&
258 ((PsiArrayAccessExpression)toplevel.getParent()).getArrayExpression() == toplevel) {
259 toplevel = (PsiExpression)toplevel.getParent();
262 final PsiType normalized = doNormalizeWildcardByPosition(type, expression, toplevel);
263 if (normalized instanceof PsiClassType && !PsiUtil.isAccessedForWriting(toplevel)) {
264 return PsiUtil.captureToplevelWildcards(normalized, expression);
267 return normalized;
270 private static PsiType doNormalizeWildcardByPosition(final PsiType type, final PsiExpression expression, final PsiExpression toplevel) {
271 if (type instanceof PsiCapturedWildcardType) {
272 return doNormalizeWildcardByPosition(((PsiCapturedWildcardType)type).getWildcard(), expression, toplevel);
276 if (type instanceof PsiWildcardType) {
277 final PsiWildcardType wildcardType = (PsiWildcardType)type;
279 if (PsiUtil.isAccessedForWriting(toplevel)) {
280 return wildcardType.isSuper() ? wildcardType.getBound() : PsiCapturedWildcardType.create(wildcardType, expression);
282 else {
283 if (wildcardType.isExtends()) {
284 return wildcardType.getBound();
286 else {
287 return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope());
291 else if (type instanceof PsiArrayType) {
292 final PsiType componentType = ((PsiArrayType)type).getComponentType();
293 final PsiType normalizedComponentType = doNormalizeWildcardByPosition(componentType, expression, toplevel);
294 if (normalizedComponentType != componentType) {
295 return normalizedComponentType.createArrayType();
299 return type;
302 @NotNull
303 public static SearchScope getMemberUseScope(final PsiMember member) {
304 final PsiManagerEx psiManager = (PsiManagerEx)member.getManager();
305 final GlobalSearchScope maximalUseScope = psiManager.getFileManager().getUseScope(member);
306 PsiFile file = member.getContainingFile();
307 if (JspPsiUtil.isInJspFile(file)) return maximalUseScope;
309 PsiClass aClass = member.getContainingClass();
310 if (aClass instanceof PsiAnonymousClass) {
311 //member from anonymous class can be called from outside the class
312 PsiElement methodCallExpr = PsiTreeUtil.getParentOfType(aClass, PsiMethodCallExpression.class);
313 return new LocalSearchScope(methodCallExpr != null ? methodCallExpr : aClass);
316 if (member.hasModifierProperty(PsiModifier.PUBLIC)) {
317 return maximalUseScope; // class use scope doesn't matter, since another very visible class can inherit from aClass
319 else if (member.hasModifierProperty(PsiModifier.PROTECTED)) {
320 return maximalUseScope; // class use scope doesn't matter, since another very visible class can inherit from aClass
322 else if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
323 PsiClass topClass = PsiUtil.getTopLevelClass(member);
324 return topClass != null ? new LocalSearchScope(topClass) : new LocalSearchScope(file);
326 else {
327 if (file instanceof PsiJavaFile) {
328 PsiPackage aPackage = JavaPsiFacade.getInstance(psiManager.getProject()).findPackage(((PsiJavaFile)file).getPackageName());
329 if (aPackage != null) {
330 SearchScope scope = PackageScope.packageScope(aPackage, false);
331 scope = scope.intersectWith(maximalUseScope);
332 return scope;
336 return maximalUseScope;
340 public static PsiElement setName(PsiElement element, String name) throws IncorrectOperationException {
341 PsiManager manager = element.getManager();
342 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
343 PsiIdentifier newNameIdentifier = factory.createIdentifier(name);
344 return element.replace(newNameIdentifier);
347 public static boolean isDeprecatedByAnnotation(PsiModifierListOwner owner) {
348 PsiModifierList modifierList = owner.getModifierList();
349 return modifierList != null && modifierList.findAnnotation("java.lang.Deprecated") != null;
352 public static boolean isDeprecatedByDocTag(PsiDocCommentOwner owner) {
353 PsiDocComment docComment = owner.getDocComment();
354 return docComment != null && docComment.findTagByName("deprecated") != null;
357 @Nullable
358 public static PsiAnnotationMemberValue setDeclaredAttributeValue(@NotNull PsiAnnotation psiAnnotation,
359 @Nullable String attributeName,
360 @Nullable PsiAnnotationMemberValue value,
361 @NotNull PairFunction<Project, String, PsiAnnotation> annotationCreator) {
362 final PsiAnnotationMemberValue existing = psiAnnotation.findDeclaredAttributeValue(attributeName);
363 if (value == null) {
364 if (existing == null) {
365 return null;
367 existing.getParent().delete();
368 } else {
369 if (existing != null) {
370 ((PsiNameValuePair)existing.getParent()).setValue(value);
371 } else {
372 final PsiNameValuePair[] attributes = psiAnnotation.getParameterList().getAttributes();
373 if (attributes.length == 1 && attributes[0].getName() == null) {
374 attributes[0].replace(createNameValuePair(attributes[0].getValue(), PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME + "=", annotationCreator));
377 boolean allowNoName = attributes.length == 0 && ("value".equals(attributeName) || null == attributeName);
378 final String namePrefix;
379 if (allowNoName) {
380 namePrefix = "";
381 } else {
382 namePrefix = attributeName + "=";
384 psiAnnotation.getParameterList().addBefore(createNameValuePair(value, namePrefix, annotationCreator), null);
387 return psiAnnotation.findDeclaredAttributeValue(attributeName);
390 public static PsiNameValuePair createNameValuePair(PsiAnnotationMemberValue value, String namePrefix,
391 PairFunction<Project, String, PsiAnnotation> annotationCreator) {
392 return annotationCreator.fun(value.getProject(), "@A(" + namePrefix + value.getText() + ")").getParameterList().getAttributes()[0];