func (pkg *GoPackage) Patch(vendorPkgRegex []string, patchCmds ...PatchCmd) (updatedFiles int, patchCount int, err error) {
	parsedFiles, err := parsePackageSources(pkg.pathToPackage, vendorPkgRegex)
	if err != nil {
		return 0, 0, err
	}
	visitors := make([]*funcVisitor, len(patchCmds))
	for cmdIndex, cmd := range patchCmds {
		visitors[cmdIndex] = newFuncVisitor(uniqueTargetMap(cmd.Targets), cmd.PatchFn)
	}
	totalPatchCount := 0
	visitorPatchCount := 0
	visitorModifiedAST := false
	for _, parsedFile := range parsedFiles {
		modifiedAST := false
		for _, visitor := range visitors {
			visitorModifiedAST, visitorPatchCount = visitor.Process(parsedFile)
			modifiedAST = visitorModifiedAST || modifiedAST
			totalPatchCount += visitorPatchCount
		}
		if modifiedAST {
			f, err := os.Create(parsedFile.filePath)
			if err != nil {
				return 0, 0, err
			}
			printer.Fprint(f, parsedFile.fset, parsedFile.astFile)
			f.Close()
			updatedFiles++
		}
	}
	return updatedFiles, totalPatchCount, err
}
Patch iterates the list of go source files that comprise this package and any folder
defined inside it and applies the patch function to AST entries matching the given
list of targets.

This function will automatically overwrite any files that are modified by the
given patch function.
package tools
import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/token"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"golang.org/x/tools/go/ssa"
)
var (
	stripCharRegex = regexp.MustCompile(`[()*]`)
)
type PatchFunc func(cgNode *CallGraphNode, fnDeclNode *ast.BlockStmt) (modifiedAST bool, extraImports []string)
type PatchCmd struct {
	Targets []ProfileTarget
	PatchFn PatchFunc
}
type parsedGoFile struct {
	filePath string
	pkgName string
	fset    *token.FileSet
	astFile *ast.File
}
type GoPackage struct {
	pathToPackage string
	PkgPrefix string
	ssaFuncCandidates map[string]*ssa.Function
	GOPATH string
}
func NewGoPackage(pathToPackage string) (*GoPackage, error) {
	fqPkgPrefix, err := qualifiedPkgName(pathToPackage)
	if err != nil {
		return nil, err
	}
	adjustedGoPath, err := adjustGoPath(pathToPackage)
	if err != nil {
		return nil, err
	}
	candidates, err := ssaCandidates(pathToPackage, fqPkgPrefix, adjustedGoPath)
	if err != nil {
		return nil, err
	}
	return &GoPackage{
		pathToPackage:     pathToPackage,
		PkgPrefix:         fqPkgPrefix,
		ssaFuncCandidates: candidates,
		GOPATH:            adjustedGoPath,
	}, nil
}
func (pkg *GoPackage) Find(targetList ...string) ([]ProfileTarget, error) {
	profileTargets := make([]ProfileTarget, len(targetList))
	var entrypointSSA *ssa.Function
	for targetIndex, target := range targetList {
		entrypointSSA = nil
		for candidate, ssaFn := range pkg.ssaFuncCandidates {
			if candidate == target {
				entrypointSSA = ssaFn
				break
			}
		}
		if entrypointSSA == nil {
			return nil, fmt.Errorf("GoPackage.Find: no match for profile target %q", target)
		}
		profileTargets[targetIndex] = ProfileTarget{
			QualifiedName: target,
			PkgPrefix:     pkg.PkgPrefix,
			ssaFunc:       entrypointSSA,
		}
	}
	return profileTargets, nil
}