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() {
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()]);
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();
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();
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
;
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
];
117 refs
[i
] = JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createPackageReferenceElement(name
);
119 catch (IncorrectOperationException e
) {
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
));
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);
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
,
154 PsiElement lastParent
,
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;
172 public static boolean hasTypeParameters(PsiTypeParameterListOwner owner
) {
173 final PsiTypeParameterList typeParameterList
= owner
.getTypeParameterList();
174 return typeParameterList
!= null && typeParameterList
.getTypeParameters().length
!= 0;
178 public static PsiType
[] typesByReferenceParameterList(final PsiReferenceParameterList parameterList
) {
179 PsiTypeElement
[] typeElements
= parameterList
.getTypeParameterElements();
181 return typesByTypeElements(typeElements
);
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();
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());
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
;
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
) {
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
);
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
);
283 if (wildcardType
.isExtends()) {
284 return wildcardType
.getBound();
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();
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
);
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
);
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;
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
);
364 if (existing
== null) {
367 existing
.getParent().delete();
369 if (existing
!= null) {
370 ((PsiNameValuePair
)existing
.getParent()).setValue(value
);
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
;
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];