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
.search
;
18 import com
.intellij
.find
.findUsages
.FindUsagesOptions
;
19 import com
.intellij
.openapi
.diagnostic
.Logger
;
20 import com
.intellij
.openapi
.util
.Key
;
21 import com
.intellij
.psi
.*;
22 import com
.intellij
.psi
.search
.PsiSearchHelper
;
23 import com
.intellij
.psi
.search
.searches
.MethodReferencesSearch
;
24 import com
.intellij
.psi
.util
.PsiFormatUtil
;
25 import com
.intellij
.usageView
.UsageInfo
;
26 import com
.intellij
.util
.Processor
;
27 import com
.intellij
.util
.containers
.HashSet
;
28 import org
.jetbrains
.annotations
.Nullable
;
35 public class ThrowSearchUtil
{
37 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.search.ThrowSearchUtil");
39 private ThrowSearchUtil() {
42 public static class Root
{
43 final PsiElement myElement
;
45 final boolean isExact
;
47 public Root(final PsiElement root
, final PsiType type
, final boolean exact
) {
53 public String
toString() {
54 return PsiFormatUtil
.formatType (myType
, PsiFormatUtil
.SHOW_FQ_CLASS_NAMES
, PsiSubstitutor
.EMPTY
);
58 public static Key
<Root
> THROW_SEARCH_ROOT_KEY
= Key
.create("ThrowSearchUtil.root");
61 * @return true, if we should continue processing
67 private static boolean processExn(final PsiParameter aCatch
, Processor
<UsageInfo
> processor
, Root root
) {
68 final PsiType type
= aCatch
.getType();
69 if (type
.isAssignableFrom(root
.myType
)) {
70 processor
.process (new UsageInfo (aCatch
));
73 else if (!root
.isExact
&& root
.myType
.isAssignableFrom (type
)) {
74 processor
.process (new UsageInfo (aCatch
));
80 private static void scanCatches(PsiElement elem
,
81 Processor
<UsageInfo
> processor
,
83 FindUsagesOptions options
,
84 Set
<PsiMethod
> processed
)
86 while (elem
!= null) {
87 final PsiElement parent
= elem
.getParent();
88 if (elem
instanceof PsiMethod
) {
89 final PsiMethod deepestSuperMethod
= ((PsiMethod
) elem
).findDeepestSuperMethod();
90 final PsiMethod method
= deepestSuperMethod
!= null ? deepestSuperMethod
: (PsiMethod
)elem
;
91 if (!processed
.contains(method
)) {
92 processed
.add(method
);
93 PsiSearchHelper helper
= method
.getManager().getSearchHelper();
94 final PsiReference
[] refs
= MethodReferencesSearch
.search(method
, options
.searchScope
, true).toArray(PsiReference
.EMPTY_ARRAY
);
95 for (int i
= 0; i
!= refs
.length
; ++i
) {
96 scanCatches(refs
[i
].getElement(), processor
, root
, options
, processed
);
101 else if (elem
instanceof PsiTryStatement
) {
102 final PsiTryStatement aTry
= (PsiTryStatement
) elem
;
103 final PsiParameter
[] catches
= aTry
.getCatchBlockParameters();
104 for (int i
= 0; i
!= catches
.length
; ++ i
) {
105 if (!processExn(catches
[i
], processor
, root
)) {
110 else if (parent
instanceof PsiTryStatement
) {
111 final PsiTryStatement tryStmt
= (PsiTryStatement
) parent
;
112 if (elem
!= tryStmt
.getTryBlock()) {
113 elem
= parent
.getParent();
121 public static void addThrowUsages(Processor
<UsageInfo
> processor
, Root root
, FindUsagesOptions options
) {
122 Set
<PsiMethod
> processed
= new HashSet
<PsiMethod
>();
123 scanCatches (root
.myElement
, processor
, root
, options
, processed
);
129 * @return is type of exn exactly known
132 private static boolean isExactExnType(final PsiExpression exn
) {
133 return exn
instanceof PsiNewExpression
;
137 public static Root
[] getSearchRoots (final PsiElement element
) {
138 if (element
instanceof PsiThrowStatement
) {
139 final PsiThrowStatement aThrow
= (PsiThrowStatement
) element
;
140 final PsiExpression exn
= aThrow
.getException();
141 return new Root
[]{new Root (aThrow
.getParent(), exn
.getType(), isExactExnType(exn
))};
143 if (element
instanceof PsiKeyword
) {
144 final PsiKeyword kwd
= (PsiKeyword
) element
;
145 if (PsiKeyword
.THROWS
.equals (kwd
.getText())) {
146 final PsiElement parent
= kwd
.getParent();
147 if (parent
!= null && parent
.getParent() instanceof PsiMethod
) {
148 final PsiMethod method
= (PsiMethod
) parent
.getParent();
149 final PsiReferenceList throwsList
= method
.getThrowsList();
150 final PsiClassType
[] exns
= throwsList
.getReferencedTypes();
151 final Root
[] roots
= new Root
[exns
.length
];
152 for (int i
= 0; i
!= roots
.length
; ++ i
) {
153 final PsiClassType exn
= exns
[i
];
154 roots
[i
] = new Root (method
, exn
, false); // TODO: test for final
163 public static boolean isSearchable(final PsiElement element
) {
164 return getSearchRoots(element
) != null;
167 public static String
getSearchableTypeName(final PsiElement e
) {
168 if (e
instanceof PsiThrowStatement
) {
169 final PsiThrowStatement aThrow
= (PsiThrowStatement
) e
;
170 final PsiType type
= aThrow
.getException ().getType ();
171 return PsiFormatUtil
.formatType (type
, PsiFormatUtil
.SHOW_FQ_CLASS_NAMES
, PsiSubstitutor
.EMPTY
);
173 if (e
instanceof PsiKeyword
&& PsiKeyword
.THROWS
.equals (e
.getText())) {
174 return e
.getParent().getText ();
176 LOG
.error ("invalid searchable element");