update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInspection / reference / RefClassImpl.java
blob801e7c06ee4c867332f81c3b43056fc55ebd0ea4
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.
18 * Created by IntelliJ IDEA.
19 * User: max
20 * Date: Oct 21, 2001
21 * Time: 4:29:19 PM
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com.intellij.codeInspection.reference;
27 import com.intellij.codeInsight.TestUtil;
28 import com.intellij.openapi.application.ApplicationManager;
29 import com.intellij.openapi.module.Module;
30 import com.intellij.openapi.module.ModuleUtil;
31 import com.intellij.psi.*;
32 import com.intellij.psi.util.ClassUtil;
33 import com.intellij.psi.util.PsiFormatUtil;
34 import gnu.trove.THashSet;
35 import org.jetbrains.annotations.NotNull;
36 import org.jetbrains.annotations.Nullable;
38 import java.util.ArrayList;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Set;
43 public class RefClassImpl extends RefJavaElementImpl implements RefClass {
44 private static final HashSet<RefElement> EMPTY_SET = new HashSet<RefElement>(0);
45 private static final HashSet<RefClass> EMPTY_CLASS_SET = new HashSet<RefClass>(0);
46 private static final ArrayList<RefMethod> EMPTY_METHOD_LIST = new ArrayList<RefMethod>(0);
47 private static final int IS_ANONYMOUS_MASK = 0x10000;
48 private static final int IS_INTERFACE_MASK = 0x20000;
49 private static final int IS_UTILITY_MASK = 0x40000;
50 private static final int IS_ABSTRACT_MASK = 0x80000;
52 private static final int IS_APPLET_MASK = 0x200000;
53 private static final int IS_SERVLET_MASK = 0x400000;
54 private static final int IS_TESTCASE_MASK = 0x800000;
55 private static final int IS_LOCAL_MASK = 0x1000000;
57 private HashSet<RefClass> myBases;
58 private HashSet<RefClass> mySubClasses;
59 private ArrayList<RefMethod> myConstructors;
60 private RefMethodImpl myDefaultConstructor;
61 private ArrayList<RefMethod> myOverridingMethods;
62 private THashSet<RefElement> myInTypeReferences;
63 private THashSet<RefElement> myInstanceReferences;
64 private ArrayList<RefJavaElement> myClassExporters;
66 RefClassImpl(PsiClass psiClass, RefManager manager) {
67 super(psiClass, manager);
70 protected void initialize() {
71 myDefaultConstructor = null;
73 final PsiClass psiClass = getElement();
75 LOG.assertTrue(psiClass != null);
77 PsiElement psiParent = psiClass.getParent();
78 if (psiParent instanceof PsiFile) {
79 if (isSyntheticJSP()) {
80 final RefFileImpl refFile = (RefFileImpl)getRefManager().getReference(JspPsiUtil.getJspFile(psiClass));
81 LOG.assertTrue(refFile != null);
82 refFile.add(this);
83 } else if (psiParent instanceof PsiJavaFile) {
84 PsiJavaFile psiFile = (PsiJavaFile) psiParent;
85 String packageName = psiFile.getPackageName();
86 if (!"".equals(packageName)) {
87 ((RefPackageImpl)getRefJavaManager().getPackage(packageName)).add(this);
88 } else {
89 ((RefPackageImpl)getRefJavaManager().getDefaultPackage()).add(this);
92 final Module module = ModuleUtil.findModuleForPsiElement(psiClass);
93 LOG.assertTrue(module != null);
94 final RefModuleImpl refModule = ((RefModuleImpl)getRefManager().getRefModule(module));
95 LOG.assertTrue(refModule != null);
96 refModule.add(this);
97 } else {
98 while (!(psiParent instanceof PsiClass || psiParent instanceof PsiMethod || psiParent instanceof PsiField)) {
99 psiParent = psiParent.getParent();
101 RefElement refParent = getRefManager().getReference(psiParent);
102 LOG.assertTrue (refParent != null);
103 ((RefElementImpl)refParent).add(this);
107 setAbstract(psiClass.hasModifierProperty(PsiModifier.ABSTRACT));
109 setAnonymous(psiClass instanceof PsiAnonymousClass);
110 setIsLocal(!(isAnonymous() || psiParent instanceof PsiClass || psiParent instanceof PsiFile));
111 setInterface(psiClass.isInterface());
113 initializeSuperReferences(psiClass);
115 PsiMethod[] psiMethods = psiClass.getMethods();
116 PsiField[] psiFields = psiClass.getFields();
118 setUtilityClass(psiMethods.length > 0 || psiFields.length > 0);
120 for (PsiField psiField : psiFields) {
121 getRefManager().getReference(psiField);
124 if (!isApplet()) {
125 final PsiClass servlet = getRefJavaManager().getServlet();
126 setServlet(servlet != null && psiClass.isInheritor(servlet, true));
128 if (!isApplet() && !isServlet()) {
129 setTestCase(TestUtil.isTestClass(psiClass));
130 for (RefClass refBase : getBaseClasses()) {
131 ((RefClassImpl)refBase).setTestCase(true);
135 for (PsiMethod psiMethod : psiMethods) {
136 RefMethod refMethod = (RefMethod)getRefManager().getReference(psiMethod);
138 if (refMethod != null) {
139 if (psiMethod.isConstructor()) {
140 if (psiMethod.getParameterList().getParametersCount() > 0 || !psiMethod.hasModifierProperty(PsiModifier.PRIVATE)) {
141 setUtilityClass(false);
144 addConstructor(refMethod);
145 if (psiMethod.getParameterList().getParametersCount() == 0) {
146 setDefaultConstructor((RefMethodImpl)refMethod);
149 else {
150 if (!psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
151 setUtilityClass(false);
157 if (getConstructors().size() == 0 && !isInterface() && !isAnonymous()) {
158 RefImplicitConstructorImpl refImplicitConstructor = new RefImplicitConstructorImpl(this);
159 setDefaultConstructor(refImplicitConstructor);
160 addConstructor(refImplicitConstructor);
163 if (isInterface()) {
164 for (int i = 0; i < psiFields.length && isUtilityClass(); i++) {
165 PsiField psiField = psiFields[i];
166 if (!psiField.hasModifierProperty(PsiModifier.STATIC)) {
167 setUtilityClass(false);
173 final PsiClass applet = getRefJavaManager().getApplet();
174 setApplet(applet != null && psiClass.isInheritor(applet, true));
175 getRefManager().fireNodeInitialized(this);
178 private void initializeSuperReferences(PsiClass psiClass) {
179 if (!isSelfInheritor(psiClass)) {
180 for (PsiClass psiSuperClass : psiClass.getSupers()) {
181 if (getRefManager().belongsToScope(psiSuperClass)) {
182 RefClassImpl refClass = (RefClassImpl)getRefManager().getReference(psiSuperClass);
183 if (refClass != null) {
184 addBaseClass(refClass);
185 refClass.addSubClass(this);
192 public boolean isSelfInheritor(PsiClass psiClass) {
193 return isSelfInheritor(psiClass, new ArrayList<PsiClass>());
196 public PsiClass getElement() {
197 return (PsiClass)super.getElement();
200 private static boolean isSelfInheritor(PsiClass psiClass, ArrayList<PsiClass> visited) {
201 if (visited.contains(psiClass)) return true;
203 visited.add(psiClass);
204 for (PsiClass aSuper : psiClass.getSupers()) {
205 if (isSelfInheritor(aSuper, visited)) return true;
207 visited.remove(psiClass);
209 return false;
212 private void setDefaultConstructor(RefMethodImpl defaultConstructor) {
213 if (defaultConstructor != null) {
214 for (RefClass superClass : getBaseClasses()) {
215 RefMethodImpl superDefaultConstructor = (RefMethodImpl)superClass.getDefaultConstructor();
217 if (superDefaultConstructor != null) {
218 superDefaultConstructor.addInReference(defaultConstructor);
219 defaultConstructor.addOutReference(superDefaultConstructor);
224 myDefaultConstructor = defaultConstructor;
227 public void buildReferences() {
228 PsiClass psiClass = getElement();
230 if (psiClass != null) {
231 for (PsiClassInitializer classInitializer : psiClass.getInitializers()) {
232 RefJavaUtil.getInstance().addReferences(psiClass, this, classInitializer.getBody());
235 RefJavaUtil.getInstance().addReferences(psiClass, this, psiClass.getModifierList());
237 PsiField[] psiFields = psiClass.getFields();
238 for (PsiField psiField : psiFields) {
239 getRefManager().getReference(psiField);
240 final PsiExpression initializer = psiField.getInitializer();
241 if (initializer != null) {
242 RefJavaUtil.getInstance().addReferences(psiClass, this, initializer);
246 PsiMethod[] psiMethods = psiClass.getMethods();
247 for (PsiMethod psiMethod : psiMethods) {
248 getRefManager().getReference(psiMethod);
250 getRefManager().fireBuildReferences(this);
254 public void accept(final RefVisitor visitor) {
255 if (visitor instanceof RefJavaVisitor) {
256 ApplicationManager.getApplication().runReadAction(new Runnable() {
257 public void run() {
258 ((RefJavaVisitor)visitor).visitClass(RefClassImpl.this);
261 } else {
262 super.accept(visitor);
266 @NotNull
267 public HashSet<RefClass> getBaseClasses() {
268 if (myBases == null) return EMPTY_CLASS_SET;
269 return myBases;
272 private void addBaseClass(RefClass refClass){
273 if (myBases == null){
274 myBases = new HashSet<RefClass>(1);
276 myBases.add(refClass);
279 @NotNull
280 public HashSet<RefClass> getSubClasses() {
281 if (mySubClasses == null) return EMPTY_CLASS_SET;
282 return mySubClasses;
285 private void addSubClass(RefClass refClass){
286 if (mySubClasses == null){
287 mySubClasses = new HashSet<RefClass>(1);
289 mySubClasses.add(refClass);
292 @NotNull
293 public ArrayList<RefMethod> getConstructors() {
294 if (myConstructors == null) return EMPTY_METHOD_LIST;
295 return myConstructors;
298 @NotNull
299 public Set<RefElement> getInTypeReferences() {
300 if (myInTypeReferences == null) return EMPTY_SET;
301 return myInTypeReferences;
304 public void addTypeReference(RefJavaElement from) {
305 if (from != null) {
306 if (myInTypeReferences == null){
307 myInTypeReferences = new THashSet<RefElement>(1);
309 myInTypeReferences.add(from);
310 ((RefJavaElementImpl)from).addOutTypeRefernce(this);
311 getRefManager().fireNodeMarkedReferenced(this, from, false, false, false);
315 @NotNull
316 public Set<RefElement> getInstanceReferences() {
317 if (myInstanceReferences == null) return EMPTY_SET;
318 return myInstanceReferences;
321 public void addInstanceReference(RefElement from) {
322 if (myInstanceReferences == null){
323 myInstanceReferences = new THashSet<RefElement>(1);
325 myInstanceReferences.add(from);
328 public RefMethod getDefaultConstructor() {
329 return myDefaultConstructor;
332 private void addConstructor(RefMethod refConstructor) {
333 if (myConstructors == null){
334 myConstructors = new ArrayList<RefMethod>(1);
336 myConstructors.add(refConstructor);
339 public void addLibraryOverrideMethod(RefMethod refMethod) {
340 if (myOverridingMethods == null){
341 myOverridingMethods = new ArrayList<RefMethod>(2);
343 myOverridingMethods.add(refMethod);
346 @NotNull
347 public List<RefMethod> getLibraryMethods() {
348 if (myOverridingMethods == null) return EMPTY_METHOD_LIST;
349 return myOverridingMethods;
352 public boolean isAnonymous() {
353 return checkFlag(IS_ANONYMOUS_MASK);
356 public boolean isInterface() {
357 return checkFlag(IS_INTERFACE_MASK);
360 public boolean isSuspicious() {
361 return !(isUtilityClass() && getOutReferences().isEmpty()) && super.isSuspicious();
364 public boolean isUtilityClass() {
365 return checkFlag(IS_UTILITY_MASK);
368 public String getExternalName() {
369 final String[] result = new String[1];
370 ApplicationManager.getApplication().runReadAction(new Runnable() {
371 public void run() {//todo synthetic JSP
372 final PsiClass psiClass = getElement();
373 LOG.assertTrue(psiClass != null);
374 result[0] = PsiFormatUtil.getExternalName(psiClass);
377 return result[0];
381 @Nullable
382 public static RefClass classFromExternalName(RefManager manager, String externalName) {
383 return (RefClass) manager.getReference(ClassUtil.findPsiClass(PsiManager.getInstance(manager.getProject()), externalName));
386 public void referenceRemoved() {
387 super.referenceRemoved();
389 for (RefClass subClass : getSubClasses()) {
390 ((RefClassImpl)subClass).removeBase(this);
393 for (RefClass superClass : getBaseClasses()) {
394 superClass.getSubClasses().remove(this);
398 private void removeBase(RefClass superClass) {
399 getBaseClasses().remove(superClass);
402 protected void methodRemoved(RefMethod method) {
403 getConstructors().remove(method);
404 getLibraryMethods().remove(method);
406 if (getDefaultConstructor() == method) {
407 setDefaultConstructor(null);
411 public boolean isAbstract() {
412 return checkFlag(IS_ABSTRACT_MASK);
415 public boolean isApplet() {
416 return checkFlag(IS_APPLET_MASK);
419 public boolean isServlet() {
420 return checkFlag(IS_SERVLET_MASK);
423 public boolean isTestCase() {
424 return checkFlag(IS_TESTCASE_MASK);
427 public boolean isLocalClass() {
428 return checkFlag(IS_LOCAL_MASK);
432 public boolean isReferenced() {
433 if (super.isReferenced()) return true;
435 if (isInterface() || isAbstract()) {
436 if (getSubClasses().size() > 0) return true;
439 return false;
442 public boolean hasSuspiciousCallers() {
443 if (super.hasSuspiciousCallers()) return true;
445 if (isInterface() || isAbstract()) {
446 if (getSubClasses().size() > 0) return true;
449 return false;
452 public void addClassExporter(RefJavaElement exporter) {
453 if (myClassExporters == null) myClassExporters = new ArrayList<RefJavaElement>(1);
454 if (myClassExporters.contains(exporter)) return;
455 myClassExporters.add(exporter);
458 public List<RefJavaElement> getClassExporters() {
459 return myClassExporters;
462 private void setAnonymous(boolean anonymous) {
463 setFlag(anonymous, IS_ANONYMOUS_MASK);
466 private void setInterface(boolean anInterface) {
467 setFlag(anInterface, IS_INTERFACE_MASK);
470 private void setUtilityClass(boolean utilityClass) {
471 setFlag(utilityClass, IS_UTILITY_MASK);
474 private void setAbstract(boolean anAbstract) {
475 setFlag(anAbstract, IS_ABSTRACT_MASK);
478 private void setApplet(boolean applet) {
479 setFlag(applet, IS_APPLET_MASK);
482 private void setServlet(boolean servlet) {
483 setFlag(servlet, IS_SERVLET_MASK);
486 private void setTestCase(boolean testCase) {
487 setFlag(testCase, IS_TESTCASE_MASK);
490 private void setIsLocal(boolean isLocal) {
491 setFlag(isLocal, IS_LOCAL_MASK);
494 @NotNull
495 public RefElement getContainingEntry() {
496 RefElement defaultConstructor = getDefaultConstructor();
497 if (defaultConstructor != null) return defaultConstructor;
498 return super.getContainingEntry();