/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */
package net.sourceforge.pmd.lang.java.rule.strings;

import net.sourceforge.pmd.lang.java.ast.ASTMethodReference;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.AbstractJavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
import net.sourceforge.pmd.lang.symboltable.ScopedNode;

public class StringToStringRule extends AbstractJavaRule {

    public Object visit(ASTVariableDeclaratorId node, Object data) {
        if (!TypeHelper.isA(node.getNameDeclaration(), String.class)) {
            return data;
        }
        boolean isArray = node.isArray();
        for (NameOccurrence occ: node.getUsages()) {
            JavaNameOccurrence jocc = (JavaNameOccurrence)occ;
            NameOccurrence qualifier = jocc.getNameForWhichThisIsAQualifier();
            if (qualifier != null) {
                if (!isArray && isNotAMethodReference(qualifier) && qualifier.getImage().indexOf("toString") != -1) {
                    addViolation(data, jocc.getLocation());
                } else if (isArray && isNotAName(qualifier) && qualifier.getImage().equals("toString")) {
                    addViolation(data, jocc.getLocation());
                }
            }
        }
        return data;
    }

    private boolean isNotAMethodReference(NameOccurrence qualifier) {
        return isNotA(qualifier, ASTMethodReference.class);
    }

    private boolean isNotAName(NameOccurrence qualifier) {
        return isNotA(qualifier, ASTName.class);
    }

    private boolean isNotA(NameOccurrence qualifier, Class<? extends AbstractJavaNode> type) {
        ScopedNode location = qualifier.getLocation();
        return location == null || !(type.isAssignableFrom(location.getClass()));
    }
}
