summaryrefslogtreecommitdiff
path: root/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java')
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java126
1 files changed, 126 insertions, 0 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java
new file mode 100644
index 000000000000..6f1f817a7735
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.memory;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.NotNull;
+
+class InnerClassReferenceVisitor extends JavaRecursiveElementVisitor {
+
+ private final PsiClass innerClass;
+ private boolean referencesStaticallyAccessible = true;
+
+ public InnerClassReferenceVisitor(@NotNull PsiClass innerClass) {
+ this.innerClass = innerClass;
+ }
+
+ public boolean canInnerClassBeStatic() {
+ final PsiClass superClass = innerClass.getSuperClass();
+ if (!isClassStaticallyAccessible(superClass)) {
+ return false;
+ }
+ return referencesStaticallyAccessible;
+ }
+
+ private boolean isClassStaticallyAccessible(PsiClass aClass) {
+ if (PsiTreeUtil.isAncestor(innerClass, aClass, false) || aClass.hasModifierProperty(PsiModifier.STATIC)) {
+ return true;
+ }
+ final PsiClass containingClass = aClass.getContainingClass();
+ return containingClass == null || InheritanceUtil.isInheritorOrSelf(innerClass, containingClass, true);
+ }
+
+ @Override
+ public void visitThisExpression(@NotNull PsiThisExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitThisExpression(expression);
+ if (hasContainingClassQualifier(expression)) {
+ referencesStaticallyAccessible = false;
+ }
+ }
+
+ @Override
+ public void visitSuperExpression(@NotNull PsiSuperExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitSuperExpression(expression);
+ if (hasContainingClassQualifier(expression)) {
+ referencesStaticallyAccessible = false;
+ }
+ }
+
+ private boolean hasContainingClassQualifier(PsiQualifiedExpression expression) {
+ final PsiJavaCodeReferenceElement qualifier = expression.getQualifier();
+ if (qualifier == null) {
+ return false;
+ }
+ return !innerClass.equals(qualifier.resolve());
+ }
+
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitReferenceExpression(expression);
+ final PsiExpression qualifierExpression = ParenthesesUtils.stripParentheses(expression.getQualifierExpression());
+ if (qualifierExpression != null) {
+ return;
+ }
+ final PsiElement target = expression.resolve();
+ if (target instanceof PsiLocalVariable || target instanceof PsiParameter) {
+ return;
+ }
+ if (target instanceof PsiMethod || target instanceof PsiField) {
+ final PsiMember member = (PsiMember)target;
+ if (member.hasModifierProperty(PsiModifier.STATIC) || PsiTreeUtil.isAncestor(innerClass, member, true)) {
+ return;
+ }
+ if (!member.hasModifierProperty(PsiModifier.PRIVATE)) {
+ final PsiClass containingClass = member.getContainingClass();
+ if (InheritanceUtil.isInheritorOrSelf(innerClass, containingClass, true)) {
+ return;
+ }
+ }
+ referencesStaticallyAccessible = false;
+ }
+ }
+
+ @Override
+ public void visitNewExpression(PsiNewExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitNewExpression(expression);
+ final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
+ if (classReference == null) {
+ return;
+ }
+ final PsiElement target = classReference.resolve();
+ if (!(target instanceof PsiClass)) {
+ return;
+ }
+ if (!isClassStaticallyAccessible((PsiClass)target)) {
+ referencesStaticallyAccessible = false;
+ }
+ }
+}