func (v *treeVisitor) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		return v
	}
	switch t := node.(type) {
	case *ast.GenDecl:
		if !v.p.matchConstant {
			return v
		}
		if t.Tok != token.CONST {
			return v
		}
		for _, spec := range t.Specs {
			val := spec.(*ast.ValueSpec)
			for i, str := range val.Values {
				lit, ok := str.(*ast.BasicLit)
				if !ok || !v.isSupported(lit.Kind) {
					continue
				}
				v.addConst(val.Names[i].Name, lit.Value, val.Names[i].Pos())
			}
		}
	case *ast.AssignStmt:
		for _, rhs := range t.Rhs {
			lit, ok := rhs.(*ast.BasicLit)
			if !ok || !v.isSupported(lit.Kind) {
				continue
			}
			v.addString(lit.Value, rhs.(*ast.BasicLit).Pos(), Assignment)
		}
	case *ast.BinaryExpr:
		if t.Op != token.EQL && t.Op != token.NEQ {
			return v
		}
		var lit *ast.BasicLit
		var ok bool
		lit, ok = t.X.(*ast.BasicLit)
		if ok && v.isSupported(lit.Kind) {
			v.addString(lit.Value, lit.Pos(), Binary)
		}
		lit, ok = t.Y.(*ast.BasicLit)
		if ok && v.isSupported(lit.Kind) {
			v.addString(lit.Value, lit.Pos(), Binary)
		}
	case *ast.CaseClause:
		for _, item := range t.List {
			lit, ok := item.(*ast.BasicLit)
			if ok && v.isSupported(lit.Kind) {
				v.addString(lit.Value, lit.Pos(), Case)
			}
		}
	case *ast.ReturnStmt:
		for _, item := range t.Results {
			lit, ok := item.(*ast.BasicLit)
			if ok && v.isSupported(lit.Kind) {
				v.addString(lit.Value, lit.Pos(), Return)
			}
		}
	case *ast.CallExpr:
		for _, item := range t.Args {
			lit, ok := item.(*ast.BasicLit)
			if ok && v.isSupported(lit.Kind) {
				v.addString(lit.Value, lit.Pos(), Call)
			}
		}
	}
	return v
}
Visit browses the AST tree for strings that could be potentially
replaced by constants.
A map of existing constants is built as well (-match-constant).
package goconst
import (
	"go/ast"
	"go/token"
	"strconv"
	"strings"
)
type treeVisitor struct {
	p                     *Parser
	fileSet               *token.FileSet
	packageName, fileName string
}