2 * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
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.siyeh.ig.psiutils;
18 import com.intellij.psi.*;
19 import com.intellij.psi.search.searches.MethodReferencesSearch;
20 import com.intellij.util.Processor;
21 import com.intellij.util.Query;
22 import org.jetbrains.annotations.NotNull;
24 public class SingletonUtil {
26 private SingletonUtil() {}
28 public static boolean isSingleton(@NotNull PsiClass aClass) {
29 if (aClass.isInterface() || aClass.isEnum() ||
30 aClass.isAnnotationType()) {
33 if(aClass instanceof PsiTypeParameter ||
34 aClass instanceof PsiAnonymousClass){
37 final PsiMethod[] constructors = getIfOnlyInvisibleConstructors(aClass);
38 if (constructors.length == 0) {
41 final PsiField selfInstance = getIfOneStaticSelfInstance(aClass);
42 if (selfInstance == null) {
45 return newOnlyAssignsToStaticSelfInstance(constructors[0], selfInstance);
48 private static PsiField getIfOneStaticSelfInstance(PsiClass aClass) {
49 final PsiField[] fields = aClass.getFields();
50 PsiField result = null;
51 for(final PsiField field : fields){
52 final String className = aClass.getQualifiedName();
53 if (!field.hasModifierProperty(PsiModifier.STATIC)) {
56 final PsiType type = field.getType();
57 final String fieldTypeName = type.getCanonicalText();
58 if (!fieldTypeName.equals(className)) {
69 private static PsiMethod[] getIfOnlyInvisibleConstructors(PsiClass aClass) {
70 final PsiMethod[] constructors = aClass.getConstructors();
71 if (constructors.length == 0) {
72 return PsiMethod.EMPTY_ARRAY;
74 for(final PsiMethod constructor : constructors){
75 if(constructor.hasModifierProperty(PsiModifier.PUBLIC)){
76 return PsiMethod.EMPTY_ARRAY;
78 if(!constructor.hasModifierProperty(PsiModifier.PRIVATE) &&
79 !constructor.hasModifierProperty(PsiModifier.PROTECTED)){
80 return PsiMethod.EMPTY_ARRAY;
86 private static boolean newOnlyAssignsToStaticSelfInstance(
87 PsiMethod method, final PsiField field) {
88 final Query<PsiReference> search =
89 MethodReferencesSearch.search(method, field.getUseScope(),
91 final NewOnlyAssignedToFieldProcessor processor =
92 new NewOnlyAssignedToFieldProcessor(field);
93 search.forEach(processor);
94 return processor.isNewOnlyAssignedToField();
97 private static class NewOnlyAssignedToFieldProcessor
98 implements Processor<PsiReference> {
100 private boolean newOnlyAssignedToField = true;
101 private final PsiField field;
103 public NewOnlyAssignedToFieldProcessor(PsiField field) {
107 public boolean process(PsiReference reference) {
108 final PsiElement element = reference.getElement();
109 final PsiElement parent = element.getParent();
110 if (!(parent instanceof PsiNewExpression)) {
111 newOnlyAssignedToField = false;
114 final PsiElement grandParent = parent.getParent();
115 if (field.equals(grandParent)) {
118 if (!(grandParent instanceof PsiAssignmentExpression)) {
119 newOnlyAssignedToField = false;
122 final PsiAssignmentExpression assignmentExpression =
123 (PsiAssignmentExpression) grandParent;
124 final PsiExpression lhs = assignmentExpression.getLExpression();
125 if (!(lhs instanceof PsiReferenceExpression)) {
126 newOnlyAssignedToField = false;
129 final PsiReferenceExpression referenceExpression =
130 (PsiReferenceExpression) lhs;
131 final PsiElement target = referenceExpression.resolve();
132 if (!field.equals(target)) {
133 newOnlyAssignedToField = false;
139 public boolean isNewOnlyAssignedToField() {
140 return newOnlyAssignedToField;