# 8.4.5 Unit Test

内联的 UT 可以参考IR Tree, 因为内联操作修改的便是 IR Tree. 例如如果我们想要测试如下代码：

```go
package p

func C() {
    println("C")
    D()
}

func D() {
    println("D")
    C()
}

func main() {
    C()
}
```

为了方便，这里我们将所有的测试代码拷贝到测试文件 `cmd/compile/internal/noder/inl_test.go`, 完整内容如下：

```go
package noder

import (
    "bufio"
    "cmd/compile/internal/amd64"
    "cmd/compile/internal/base"
    "cmd/compile/internal/deadcode"
    "cmd/compile/internal/escape"
    "cmd/compile/internal/inline"
    "cmd/compile/internal/ir"
    "cmd/compile/internal/reflectdata"
    "cmd/compile/internal/ssa"
    "cmd/compile/internal/ssagen"
    "cmd/compile/internal/syntax"
    "cmd/compile/internal/typecheck"
    "cmd/compile/internal/types"
    "cmd/compile/internal/types2"
    "cmd/internal/obj"
    "cmd/internal/objabi"
    "cmd/internal/src"
    "fmt"
    "os"
    "strings"
    "testing"
)

func parseSrc(path, src string) (*syntax.File, error) {
    var mode syntax.Mode
    mode = syntax.AllowGenerics | syntax.CheckBranches
    errh := func(error) {} // dummy error handler so that parsing continues in presence of errors
    return syntax.Parse(syntax.NewFileBase(path), strings.NewReader(src), errh, nil, mode)
}

func defaultImporter() *gcimports {
    return &gcimports{
        packages: map[string]*types2.Package{},
    }
}

func init() {
    amd64.Init(&ssagen.Arch)

    base.Ctxt = obj.Linknew(ssagen.Arch.LinkArch)
    base.Ctxt.DiagFunc = base.Errorf
    base.Ctxt.DiagFlush = base.FlushErrors
    base.Ctxt.Bso = bufio.NewWriter(os.Stdout)

    base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin

    types.LocalPkg = types.NewPkg("", "")
    types.LocalPkg.Prefix = "\"\""

    types.LocalPkg.Height = types.MaxPkgHeight

    types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
    types.BuiltinPkg.Prefix = "go.builtin"            // not go%2ebuiltin

    // pseudo-package, accessed by import "unsafe"
    ir.Pkgs.Unsafe = types.NewPkg("unsafe", "unsafe")

    ir.Pkgs.Runtime = types.NewPkg("go.runtime", "runtime")
    ir.Pkgs.Runtime.Prefix = "runtime"

    // pseudo-packages used in symbol tables
    ir.Pkgs.Itab = types.NewPkg("go.itab", "go.itab")
    ir.Pkgs.Itab.Prefix = "go.itab" // not go%2eitab

    // pseudo-package used for methods with anonymous receivers
    ir.Pkgs.Go = types.NewPkg("go", "")

    base.DebugSSA = ssa.PhaseOption

    ssagen.Arch.LinkArch.Init(base.Ctxt)
    ir.EscFmt = escape.Fmt
    ir.IsIntrinsicCall = ssagen.IsIntrinsicCall
    inline.SSADumpInline = ssagen.DumpInline
    ssagen.InitEnv()
    ssagen.InitTables()

    types.PtrSize = ssagen.Arch.LinkArch.PtrSize
    types.RegSize = ssagen.Arch.LinkArch.RegSize
    types.MaxWidth = ssagen.Arch.MAXWIDTH

    typecheck.Target = new(ir.Package)

    typecheck.NeedITab = func(t, iface *types.Type) { reflectdata.ITabAddr(t, iface) }
    typecheck.NeedRuntimeType = reflectdata.NeedRuntimeType // TODO(rsc): TypeSym for lock?

    base.AutogeneratedPos = base.Ctxt.PosTable.XPos(src.MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0))

    typecheck.InitUniverse()
}

func dumpIrTree(nodes []ir.Node) {
    for _, n := range nodes {
        s := fmt.Sprintf("\nafter noder2 %v", n)
        ir.Dump(s, n)
    }
}

func TestIrTree(t *testing.T) {
    code := `
package p

func C( )  {
    println("C")
D()
}

func D( )  {
    println("D")
C()
}


func main() {
C()
}
`
    base.Flag.LowerM = 2
    f, err := parseSrc("Inline", code)

    if err != nil {
        panic(err)
    }

    var conf types2.Config
    conf.Trace = false
    conf.Importer = defaultImporter()
    conf.Error = func(err error) {
        fmt.Printf("Typecheck Error: %v\n", err)
    }

    info := types2.Info{
        Types:      make(map[syntax.Expr]types2.TypeAndValue),
        Defs:       make(map[*syntax.Name]types2.Object),
        Uses:       make(map[*syntax.Name]types2.Object),
        Selections: make(map[*syntax.SelectorExpr]*types2.Selection),
        Implicits:  make(map[syntax.Node]types2.Object),
        Scopes:     make(map[syntax.Node]*types2.Scope),
        Inferred:   make(map[syntax.Expr]types2.Inferred),
    }

    pkg, err := conf.Check("<no package>", []*syntax.File{f}, &info)
    if err != nil {
        panic(err)
    }

    var m posMap
    g := irgen{
        target: typecheck.Target,
        self:   pkg,
        info:   &info,
        posMap: m,
        objs:   make(map[types2.Object]*ir.Name),
        typs:   make(map[types2.Type]*types.Type),
    }

    p := &noder{
        err:         make(chan syntax.Error),
        trackScopes: base.Flag.Dwarf,
        file:        f,
    }
    g.generate([]*noder{p})

    println("Before Inline:")
    dumpIrTree(typecheck.Target.Decls)

    inline.InlinePackage()

    println("After Inline:")
    dumpIrTree(typecheck.Target.Decls)
}
```

运行该测试用例，内联后的函数 C 与 D 的结构与前文我们分析的一致：

> ```
> after noder2 C [0xc0001ec2c0]
> .   DCLFUNC tc(1) Iota:-1 ABI:ABIInternal InlinabilityChecked FUNC-func() # Inline:4
> .   DCLFUNC-body
> .   .   PRINTN tc(1) Use:3 # Inline:5
> .   .   PRINTN-Args
> .   .   .   LITERAL-“C” tc(1) string # Inline:5
> .   .   CALLFUNC tc(1) Use:3 # Inline:6
> .   .   .   NAME-p.D tc(1) Class:PFUNC Offset:0 FUNC-func() # Inline:9
>
> after noder2 D [0xc0001ec420]
> .   DCLFUNC tc(1) Iota:-1 Label:1 ABI:ABIInternal InlinabilityChecked FUNC-func() # Inline:9
> .   DCLFUNC-body
> .   .   PRINTN tc(1) Use:3 # Inline:10
> .   .   PRINTN-Args
> .   .   .   LITERAL-“D” tc(1) string # Inline:10
> .   .   BLOCK # Inline:11
> .   .   BLOCK-List
> .   .   .   INLMARK # +Inline:11
> .   .   .   PRINTN tc(1) Use:3 # Inline:5
> .   .   .   PRINTN-Args
> .   .   .   .   LITERAL-“C” tc(1) string # Inline:5
> .   .   .   CALLFUNC tc(1) Use:3 # Inline:6
> .   .   .   .   NAME-p.D tc(1) Class:PFUNC Offset:0 FUNC-func() # Inline:9
> .   .   .   LABEL # Inline:11 p..i0
> ```

读者可以尝试着调试更加复杂的代码，以便查看编译器在内联时如何处理参数以及返回值的，这里不再赘述。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gocompiler.shizhz.me/8.-golang-bian-yi-qi-inline/8.4.5-unit-test.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
