/*
 * Copyright 2003-2005 Dave Griffith
 *
 * 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.performance;

import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;

class MethodReferenceVisitor extends PsiRecursiveElementVisitor{

    private boolean m_referencesStaticallyAccessible = true;
    private PsiMethod m_method;

    MethodReferenceVisitor(PsiMethod method){
        super();
        m_method = method;
    }

    public boolean areReferencesStaticallyAccessible(){
        return m_referencesStaticallyAccessible;
    }

    public void visitElement(PsiElement element) {
        if(!m_referencesStaticallyAccessible){
            return;
        }
        super.visitElement(element);
    }

    public void visitReferenceElement(PsiJavaCodeReferenceElement reference){
        super.visitReferenceElement(reference);
        final PsiElement parent =
                PsiTreeUtil.getParentOfType(reference, PsiNewExpression.class);
        if(parent == null){
            return;
        }
        final PsiElement resolvedElement = reference.resolve();
        if(!(resolvedElement instanceof PsiClass)){
            return;
        }
        final PsiClass aClass = (PsiClass) resolvedElement;
        final PsiElement scope = aClass.getScope();
        if(!(scope instanceof PsiClass)){
            return;
        }
        if (aClass.hasModifierProperty(PsiModifier.STATIC)){
            return;
        }
        m_referencesStaticallyAccessible = false;
    }

    public void visitReferenceExpression(
            @NotNull PsiReferenceExpression expression){
        super.visitReferenceExpression(expression);
        final PsiElement qualifier = expression.getQualifierExpression();
        if (qualifier != null && !(qualifier instanceof PsiThisExpression) &&
                !(qualifier instanceof PsiSuperExpression)){
            return;
        }
        final PsiElement element = expression.resolve();
        if(element instanceof PsiField){
            if (isFieldStaticallyAccessible((PsiField) element)){
                return;
            }
        } else if(element instanceof PsiMethod){
            if (isMethodStaticallyAccessible((PsiMethod) element)){
                return;
            }
        } else {
            return;
        }
        m_referencesStaticallyAccessible = false;
    }

    public void visitThisExpression(@NotNull PsiThisExpression expression){
        super.visitThisExpression(expression);
        m_referencesStaticallyAccessible = false;
    }

    private boolean isMethodStaticallyAccessible(PsiMethod method){
        if(m_method.equals(method)){
            return true;
        }
        if(method.hasModifierProperty(PsiModifier.STATIC)){
            return true;
        }
        if(method.isConstructor()){
            return true;
        }
        final PsiClass referenceContainingClass = m_method.getContainingClass();
        final PsiClass methodContainingClass = method.getContainingClass();
        return !InheritanceUtil.isCorrectDescendant(referenceContainingClass,
                                                  methodContainingClass, true);
    }

    private boolean isFieldStaticallyAccessible(PsiField field){
        if(field.hasModifierProperty(PsiModifier.STATIC)){
            return true;
        }
        final PsiClass referenceContainingClass = m_method.getContainingClass();
        final PsiClass fieldContainingClass = field.getContainingClass();
        return !InheritanceUtil.isCorrectDescendant(referenceContainingClass,
                                                  fieldContainingClass, true);
    }
}
@@ -703,50 +703,8 @@
 il;%0A
-import com.intellij.psi.util.PsiTreeUtil;%0A
 impo
@@ -741,16 +741,16 @@
 otNull;%0A
+
 %0Aclass M
@@ -1413,180 +1413,9 @@
 e);%0A
-        final PsiElement parent =%0A                PsiTreeUtil.getParentOfType(reference, PsiNewExpression.class);%0A        if(parent == null)%7B%0A            return;%0A        %7D
 %0A
+
     
@@ -2376,166 +2376,14 @@
  Psi
-Field)%7B%0A            if (isFieldStaticallyAccessible((PsiField) element))%7B%0A                return;%0A            %7D%0A        %7D else if(element instanceof PsiMethod
+Member
 )%7B%0A 
@@ -2397,28 +2397,28 @@
     if (isMe
-thod
+mber
 StaticallyAc
@@ -2432,20 +2432,20 @@
 e((PsiMe
-thod
+mber
 ) elemen
@@ -3421,21 +3421,22 @@
 olean is
-Field
+Member
 Statical
@@ -3455,38 +3455,113 @@
 (Psi
-Field field)%7B%0A        if(field
+Member member)%7B%0A        if(m_method.equals(member))%7B%0A            return true;%0A        %7D%0A        if(member
 .has
@@ -3738,22 +3738,17 @@
 siClass 
-fieldC
+c
 ontainin
@@ -3756,21 +3756,22 @@
 Class = 
-field
+member
 .getCont
@@ -3917,14 +3917,9 @@
     
-fieldC
+c
 onta

incorrect warning for the following class: