update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / search / ThrowSearchUtil.java
blobed38b7d69558f23f59d9f3185c95844bf8468109
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.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;
30 import java.util.Set;
32 /**
33 * Author: msk
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;
44 final PsiType myType;
45 final boolean isExact;
47 public Root(final PsiElement root, final PsiType type, final boolean exact) {
48 myElement = root;
49 myType = type;
50 isExact = 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");
60 /**
61 * @return true, if we should continue processing
62 * @param aCatch
63 * @param processor
64 * @param root
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));
71 return false;
73 else if (!root.isExact && root.myType.isAssignableFrom (type)) {
74 processor.process (new UsageInfo (aCatch));
75 return true;
77 return true;
80 private static void scanCatches(PsiElement elem,
81 Processor<UsageInfo> processor,
82 Root root,
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);
99 return;
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)) {
106 return;
110 else if (parent instanceof PsiTryStatement) {
111 final PsiTryStatement tryStmt = (PsiTryStatement) parent;
112 if (elem != tryStmt.getTryBlock()) {
113 elem = parent.getParent();
114 continue;
117 elem = parent;
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);
128 * @param exn
129 * @return is type of exn exactly known
132 private static boolean isExactExnType(final PsiExpression exn) {
133 return exn instanceof PsiNewExpression;
136 @Nullable
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
156 return roots;
160 return null;
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");
177 return e.getText();