/*
 * 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.confusing;

import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiSuperMethodUtil;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.MethodInspection;
import org.jetbrains.annotations.NotNull;

public class RefusedBequestInspection extends MethodInspection{
    public String getDisplayName(){
        return "Refused bequest";
    }

    public String getGroupDisplayName(){
        return GroupNames.INHERITANCE_GROUP_NAME;
    }

    public String buildErrorString(PsiElement location){
        return "Method #ref ignores defined method in superclass #loc";
    }

    public BaseInspectionVisitor buildVisitor(){
        return new RefusedBequestVisitor();
    }

    private static class RefusedBequestVisitor extends BaseInspectionVisitor{


        public void visitMethod(@NotNull PsiMethod method){
            super.visitMethod(method);
            final PsiCodeBlock body = method.getBody();
            if(body == null){
                return;
            }
            PsiMethod leastConcreteSuperMethod = null;
            final PsiMethod[] superMethods =
                    PsiSuperMethodUtil.findSuperMethods(method, true);
            for(final PsiMethod superMethod : superMethods){
                final PsiClass containingClass =
                        superMethod.getContainingClass();
                if(!superMethod.hasModifierProperty(PsiModifier.ABSTRACT) &&
                        !containingClass.isInterface()){
                    leastConcreteSuperMethod = superMethod;
                    break;
                }
            }
            if(leastConcreteSuperMethod == null){
                return;
            }
            final PsiClass containingClass =
                    leastConcreteSuperMethod.getContainingClass();
            final String className = containingClass.getQualifiedName();
            if("java.lang.Object".equals(className)){
                return;
            }
            if(containsSuperCall(body, leastConcreteSuperMethod)){
                return;
            }

            registerMethodError(method);
        }
    }

    private static boolean containsSuperCall(PsiCodeBlock body,
                                             PsiMethod method){
        final SuperCallVisitor visitor = new SuperCallVisitor(method);
        body.accept(visitor);
        return visitor.hasSuperCall();
    }

    private static class SuperCallVisitor extends PsiRecursiveElementVisitor{
        private PsiMethod methodToSearchFor;
        private boolean hasSuperCall = false;

        SuperCallVisitor(PsiMethod methodToSearchFor){
            super();
            this.methodToSearchFor = methodToSearchFor;
        }

        public void visitElement(@NotNull PsiElement element){
            if(!hasSuperCall){
                super.visitElement(element);
            }
        }

        public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression){
            if(hasSuperCall){
                return;
            }
            super.visitMethodCallExpression(expression);
            final PsiReferenceExpression methodExpression =
                    expression.getMethodExpression();
            if(methodExpression == null){
                return;
            }
            final PsiExpression qualifier =
                    methodExpression.getQualifierExpression();
            if(qualifier == null){
                return;
            }
            final String text = qualifier.getText();
            if(!"super".equals(text)){
                return;
            }
            final PsiMethod method = expression.resolveMethod();
            if(method == null){
                return;
            }
            if(method.equals(methodToSearchFor)){
                hasSuperCall = true;
            }
        }

        public boolean hasSuperCall(){
            return hasSuperCall;
        }
    }
}

@@ -832,16 +832,109 @@
 ection;%0A
+import com.siyeh.ig.psiutils.MethodUtils;%0Aimport com.siyeh.ig.ui.SingleCheckboxOptionsPanel;%0A
 import o
@@ -968,16 +968,48 @@
 tNull;%0A%0A
+import javax.swing.JComponent;%0A%0A
 public c
@@ -1064,16 +1064,106 @@
 ection%7B%0A
+%0A    /** @noinspection PublicField*/%0A    public boolean ignoreEmptySuperMethods = false;%0A%0A
     publ
@@ -1457,32 +1457,287 @@
 s #loc%22;%0A    %7D%0A%0A
+    public JComponent createOptionsPanel() %7B%0A        return new SingleCheckboxOptionsPanel(%0A                %22%3Chtml%3EIgnore empty super methods (degrades performance of %22 +%0A                %22this inspection)%3C/html%3E%22, this, %22ignoreEmptySuperMethods%22);%0A    %7D%0A%0A
     public BaseI
@@ -1828,31 +1828,24 @@
     private 
-static 
 class Refuse
@@ -1892,17 +1892,16 @@
 sitor%7B%0A%0A
-%0A
         
@@ -2550,21 +2550,16 @@
         
-     
 !contain
@@ -3059,32 +3059,334 @@
 ;%0A            %7D%0A
+            if (ignoreEmptySuperMethods) %7B%0A                final PsiMethod navigationElement = (PsiMethod)%0A                        leastConcreteSuperMethod.getNavigationElement();%0A                if (MethodUtils.isEmpty(navigationElement)) %7B%0A                    return;%0A                %7D%0A            %7D%0A
             if(c
@@ -3526,23 +3526,21 @@
       %7D%0A
+%0A
     
-%7D%0A%0A
     priv
@@ -3543,23 +3543,16 @@
 private 
-static 
 boolean 
@@ -3622,35 +3622,32 @@
                 
-   
 PsiMethod method
@@ -3653,24 +3653,28 @@
 d)%7B%0A        
+   
+ 
 final SuperC
@@ -3732,16 +3732,20 @@
         
+    
 body.acc
@@ -3758,16 +3758,20 @@
 sitor);%0A
+    
         
@@ -3797,24 +3797,36 @@
 uperCall();%0A
+        %7D%0A%0A%0A
     %7D%0A%0A    p
@@ -5354,9 +5354,8 @@
 %0A    %7D%0A%7D
-%0A

fix for IDEADEV-2317