Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
OUNSAFEADD: "unsafe.Add",
1// Copyright 2011 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package ir67import (8 "bytes"9 "fmt"10 "go/constant"11 "io"12 "os"13 "path/filepath"14 "reflect"15 "strings"1617 "unicode/utf8"1819 "cmd/compile/internal/base"20 "cmd/compile/internal/types"21 "cmd/internal/src"22)2324// Op2526var OpNames = []string{27 OADDR: "&",28 OADD: "+",29 OADDSTR: "+",30 OANDAND: "&&",31 OANDNOT: "&^",32 OAND: "&",33 OAPPEND: "append",34 OAS: "=",35 OAS2: "=",36 OBREAK: "break",37 OCALL: "function call", // not actual syntax38 OCAP: "cap",39 OCASE: "case",40 OCLEAR: "clear",41 OCLOSE: "close",42 OCOMPLEX: "complex",43 OBITNOT: "^",44 OCONTINUE: "continue",45 OCOPY: "copy",46 ODELETE: "delete",47 ODEFER: "defer",48 ODIV: "/",49 OEQ: "==",50 OFALL: "fallthrough",51 OFOR: "for",52 OGE: ">=",53 OGOTO: "goto",54 OGT: ">",55 OIF: "if",56 OIMAG: "imag",57 OINLMARK: "inlmark",58 ODEREF: "*",59 OLEN: "len",60 OLE: "<=",61 OLSH: "<<",62 OLT: "<",63 OMAKE: "make",64 ONEG: "-",65 OMAX: "max",66 OMIN: "min",67 OMOD: "%",68 OMUL: "*",69 ONEW: "new",70 ONE: "!=",71 ONOT: "!",72 OOROR: "||",73 OOR: "|",74 OPANIC: "panic",75 OPLUS: "+",76 OPRINTLN: "println",77 OPRINT: "print",78 ORANGE: "range",79 OREAL: "real",80 ORECV: "<-",81 ORECOVER: "recover",82 ORETURN: "return",83 ORSH: ">>",84 OSELECT: "select",85 OSEND: "<-",86 OSUB: "-",87 OSWITCH: "switch",88 OUNSAFEADD: "unsafe.Add",89 OUNSAFESLICE: "unsafe.Slice",90 OUNSAFESLICEDATA: "unsafe.SliceData",91 OUNSAFESTRING: "unsafe.String",92 OUNSAFESTRINGDATA: "unsafe.StringData",93 OXOR: "^",94}9596// GoString returns the Go syntax for the Op, or else its name.97func (o Op) GoString() string {98 if int(o) < len(OpNames) && OpNames[o] != "" {99 return OpNames[o]100 }101 return o.String()102}103104// Format implements formatting for an Op.105// The valid formats are:106//107// %v Go syntax ("+", "<-", "print")108// %+v Debug syntax ("ADD", "RECV", "PRINT")109func (o Op) Format(s fmt.State, verb rune) {110 switch verb {111 default:112 fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))113 case 'v':114 if s.Flag('+') {115 // %+v is OMUL instead of "*"116 io.WriteString(s, o.String())117 return118 }119 io.WriteString(s, o.GoString())120 }121}122123// Node124125// fmtNode implements formatting for a Node n.126// Every Node implementation must define a Format method that calls fmtNode.127// The valid formats are:128//129// %v Go syntax130// %L Go syntax followed by " (type T)" if type is known.131// %+v Debug syntax, as in Dump.132func fmtNode(n Node, s fmt.State, verb rune) {133 // %+v prints Dump.134 // Otherwise we print Go syntax.135 if s.Flag('+') && verb == 'v' {136 dumpNode(s, n, 1)137 return138 }139140 if verb != 'v' && verb != 'S' && verb != 'L' {141 fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)142 return143 }144145 if n == nil {146 fmt.Fprint(s, "<nil>")147 return148 }149150 t := n.Type()151 if verb == 'L' && t != nil {152 if t.Kind() == types.TNIL {153 fmt.Fprint(s, "nil")154 } else if n.Op() == ONAME && n.Name().AutoTemp() {155 fmt.Fprintf(s, "%v value", t)156 } else {157 fmt.Fprintf(s, "%v (type %v)", n, t)158 }159 return160 }161162 // TODO inlining produces expressions with ninits. we can't print these yet.163164 if OpPrec[n.Op()] < 0 {165 stmtFmt(n, s)166 return167 }168169 exprFmt(n, s, 0)170}171172var OpPrec = []int{173 OAPPEND: 8,174 OBYTES2STR: 8,175 OARRAYLIT: 8,176 OSLICELIT: 8,177 ORUNES2STR: 8,178 OCALLFUNC: 8,179 OCALLINTER: 8,180 OCALLMETH: 8,181 OCALL: 8,182 OCAP: 8,183 OCLEAR: 8,184 OCLOSE: 8,185 OCOMPLIT: 8,186 OCONVIFACE: 8,187 OCONVNOP: 8,188 OCONV: 8,189 OCOPY: 8,190 ODELETE: 8,191 OGETG: 8,192 OLEN: 8,193 OLITERAL: 8,194 OMAKESLICE: 8,195 OMAKESLICECOPY: 8,196 OMAKE: 8,197 OMAPLIT: 8,198 OMAX: 8,199 OMIN: 8,200 ONAME: 8,201 ONEW: 8,202 ONIL: 8,203 ONONAME: 8,204 OPANIC: 8,205 OPAREN: 8,206 OPRINTLN: 8,207 OPRINT: 8,208 ORUNESTR: 8,209 OSLICE2ARR: 8,210 OSLICE2ARRPTR: 8,211 OSTR2BYTES: 8,212 OSTR2RUNES: 8,213 OSTRUCTLIT: 8,214 OTYPE: 8,215 OUNSAFEADD: 8,216 OUNSAFESLICE: 8,217 OUNSAFESLICEDATA: 8,218 OUNSAFESTRING: 8,219 OUNSAFESTRINGDATA: 8,220 OINDEXMAP: 8,221 OINDEX: 8,222 OSLICE: 8,223 OSLICESTR: 8,224 OSLICEARR: 8,225 OSLICE3: 8,226 OSLICE3ARR: 8,227 OSLICEHEADER: 8,228 OSTRINGHEADER: 8,229 ODOTINTER: 8,230 ODOTMETH: 8,231 ODOTPTR: 8,232 ODOTTYPE2: 8,233 ODOTTYPE: 8,234 ODOT: 8,235 OXDOT: 8,236 OMETHVALUE: 8,237 OMETHEXPR: 8,238 OPLUS: 7,239 ONOT: 7,240 OBITNOT: 7,241 ONEG: 7,242 OADDR: 7,243 ODEREF: 7,244 ORECV: 7,245 OMUL: 6,246 ODIV: 6,247 OMOD: 6,248 OLSH: 6,249 ORSH: 6,250 OAND: 6,251 OANDNOT: 6,252 OADD: 5,253 OSUB: 5,254 OOR: 5,255 OXOR: 5,256 OEQ: 4,257 OLT: 4,258 OLE: 4,259 OGE: 4,260 OGT: 4,261 ONE: 4,262 OSEND: 3,263 OANDAND: 2,264 OOROR: 1,265266 // Statements handled by stmtfmt267 OAS: -1,268 OAS2: -1,269 OAS2DOTTYPE: -1,270 OAS2FUNC: -1,271 OAS2MAPR: -1,272 OAS2RECV: -1,273 OASOP: -1,274 OBLOCK: -1,275 OBREAK: -1,276 OCASE: -1,277 OCONTINUE: -1,278 ODCL: -1,279 ODEFER: -1,280 OFALL: -1,281 OFOR: -1,282 OGOTO: -1,283 OIF: -1,284 OLABEL: -1,285 OGO: -1,286 ORANGE: -1,287 ORETURN: -1,288 OSELECT: -1,289 OSWITCH: -1,290291 OEND: 0,292}293294// StmtWithInit reports whether op is a statement with an explicit init list.295func StmtWithInit(op Op) bool {296 switch op {297 case OIF, OFOR, OSWITCH:298 return true299 }300 return false301}302303func stmtFmt(n Node, s fmt.State) {304 // NOTE(rsc): This code used to support the text-based305 // which was more aggressive about printing full Go syntax306 // (for example, an actual loop instead of "for loop").307 // The code is preserved for now in case we want to expand308 // any of those shortenings later. Or maybe we will delete309 // the code. But for now, keep it.310 const exportFormat = false311312 // some statements allow for an init, but at most one,313 // but we may have an arbitrary number added, eg by typecheck314 // and inlining. If it doesn't fit the syntax, emit an enclosing315 // block starting with the init statements.316317 // if we can just say "for" n->ninit; ... then do so318 simpleinit := len(n.Init()) == 1 && len(n.Init()[0].Init()) == 0 && StmtWithInit(n.Op())319320 // otherwise, print the inits as separate statements321 complexinit := len(n.Init()) != 0 && !simpleinit && exportFormat322323 // but if it was for if/for/switch, put in an extra surrounding block to limit the scope324 extrablock := complexinit && StmtWithInit(n.Op())325326 if extrablock {327 fmt.Fprint(s, "{")328 }329330 if complexinit {331 fmt.Fprintf(s, " %v; ", n.Init())332 }333334 switch n.Op() {335 case ODCL:336 n := n.(*Decl)337 fmt.Fprintf(s, "var %v %v", n.X.Sym(), n.X.Type())338339 // Don't export "v = <N>" initializing statements, hope they're always340 // preceded by the DCL which will be re-parsed and typechecked to reproduce341 // the "v = <N>" again.342 case OAS:343 n := n.(*AssignStmt)344 if n.Def && !complexinit {345 fmt.Fprintf(s, "%v := %v", n.X, n.Y)346 } else {347 fmt.Fprintf(s, "%v = %v", n.X, n.Y)348 }349350 case OASOP:351 n := n.(*AssignOpStmt)352 if n.IncDec {353 if n.AsOp == OADD {354 fmt.Fprintf(s, "%v++", n.X)355 } else {356 fmt.Fprintf(s, "%v--", n.X)357 }358 break359 }360361 fmt.Fprintf(s, "%v %v= %v", n.X, n.AsOp, n.Y)362363 case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:364 n := n.(*AssignListStmt)365 if n.Def && !complexinit {366 fmt.Fprintf(s, "%.v := %.v", n.Lhs, n.Rhs)367 } else {368 fmt.Fprintf(s, "%.v = %.v", n.Lhs, n.Rhs)369 }370371 case OBLOCK:372 n := n.(*BlockStmt)373 if len(n.List) != 0 {374 fmt.Fprintf(s, "%v", n.List)375 }376377 case ORETURN:378 n := n.(*ReturnStmt)379 fmt.Fprintf(s, "return %.v", n.Results)380381 case OTAILCALL:382 n := n.(*TailCallStmt)383 fmt.Fprintf(s, "tailcall %v", n.Call)384385 case OINLMARK:386 n := n.(*InlineMarkStmt)387 fmt.Fprintf(s, "inlmark %d", n.Index)388389 case OGO:390 n := n.(*GoDeferStmt)391 fmt.Fprintf(s, "go %v", n.Call)392393 case ODEFER:394 n := n.(*GoDeferStmt)395 fmt.Fprintf(s, "defer %v", n.Call)396397 case OIF:398 n := n.(*IfStmt)399 if simpleinit {400 fmt.Fprintf(s, "if %v; %v { %v }", n.Init()[0], n.Cond, n.Body)401 } else {402 fmt.Fprintf(s, "if %v { %v }", n.Cond, n.Body)403 }404 if len(n.Else) != 0 {405 fmt.Fprintf(s, " else { %v }", n.Else)406 }407408 case OFOR:409 n := n.(*ForStmt)410 if !exportFormat { // TODO maybe only if FmtShort, same below411 fmt.Fprintf(s, "for loop")412 break413 }414415 fmt.Fprint(s, "for")416 if n.DistinctVars {417 fmt.Fprint(s, " /* distinct */")418 }419 if simpleinit {420 fmt.Fprintf(s, " %v;", n.Init()[0])421 } else if n.Post != nil {422 fmt.Fprint(s, " ;")423 }424425 if n.Cond != nil {426 fmt.Fprintf(s, " %v", n.Cond)427 }428429 if n.Post != nil {430 fmt.Fprintf(s, "; %v", n.Post)431 } else if simpleinit {432 fmt.Fprint(s, ";")433 }434435 fmt.Fprintf(s, " { %v }", n.Body)436437 case ORANGE:438 n := n.(*RangeStmt)439 if !exportFormat {440 fmt.Fprint(s, "for loop")441 break442 }443444 fmt.Fprint(s, "for")445 if n.Key != nil {446 fmt.Fprintf(s, " %v", n.Key)447 if n.Value != nil {448 fmt.Fprintf(s, ", %v", n.Value)449 }450 fmt.Fprint(s, " =")451 }452 fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)453 if n.DistinctVars {454 fmt.Fprint(s, " /* distinct vars */")455 }456457 case OSELECT:458 n := n.(*SelectStmt)459 if !exportFormat {460 fmt.Fprintf(s, "%v statement", n.Op())461 break462 }463 fmt.Fprintf(s, "select { %v }", n.Cases)464465 case OSWITCH:466 n := n.(*SwitchStmt)467 if !exportFormat {468 fmt.Fprintf(s, "%v statement", n.Op())469 break470 }471 fmt.Fprintf(s, "switch")472 if simpleinit {473 fmt.Fprintf(s, " %v;", n.Init()[0])474 }475 if n.Tag != nil {476 fmt.Fprintf(s, " %v ", n.Tag)477 }478 fmt.Fprintf(s, " { %v }", n.Cases)479480 case OCASE:481 n := n.(*CaseClause)482 if len(n.List) != 0 {483 fmt.Fprintf(s, "case %.v", n.List)484 } else {485 fmt.Fprint(s, "default")486 }487 fmt.Fprintf(s, ": %v", n.Body)488489 case OBREAK, OCONTINUE, OGOTO, OFALL:490 n := n.(*BranchStmt)491 if n.Label != nil {492 fmt.Fprintf(s, "%v %v", n.Op(), n.Label)493 } else {494 fmt.Fprintf(s, "%v", n.Op())495 }496497 case OLABEL:498 n := n.(*LabelStmt)499 fmt.Fprintf(s, "%v: ", n.Label)500 }501502 if extrablock {503 fmt.Fprint(s, "}")504 }505}506507func exprFmt(n Node, s fmt.State, prec int) {508 // NOTE(rsc): This code used to support the text-based509 // which was more aggressive about printing full Go syntax510 // (for example, an actual loop instead of "for loop").511 // The code is preserved for now in case we want to expand512 // any of those shortenings later. Or maybe we will delete513 // the code. But for now, keep it.514 const exportFormat = false515516 for {517 if n == nil {518 fmt.Fprint(s, "<nil>")519 return520 }521522 // Skip implicit operations introduced during typechecking.523 switch nn := n; nn.Op() {524 case OADDR:525 nn := nn.(*AddrExpr)526 if nn.Implicit() {527 n = nn.X528 continue529 }530 case ODEREF:531 nn := nn.(*StarExpr)532 if nn.Implicit() {533 n = nn.X534 continue535 }536 case OCONV, OCONVNOP, OCONVIFACE:537 nn := nn.(*ConvExpr)538 if nn.Implicit() {539 n = nn.X540 continue541 }542 }543544 break545 }546547 nprec := OpPrec[n.Op()]548 if n.Op() == OTYPE && n.Type() != nil && n.Type().IsPtr() {549 nprec = OpPrec[ODEREF]550 }551552 if prec > nprec {553 fmt.Fprintf(s, "(%v)", n)554 return555 }556557 switch n.Op() {558 case OPAREN:559 n := n.(*ParenExpr)560 fmt.Fprintf(s, "(%v)", n.X)561562 case ONIL:563 fmt.Fprint(s, "nil")564565 case OLITERAL:566 if n.Sym() != nil {567 fmt.Fprint(s, n.Sym())568 return569 }570571 typ := n.Type()572 val := n.Val()573574 // Special case for rune constants.575 if typ == types.RuneType || typ == types.UntypedRune {576 if x, ok := constant.Uint64Val(val); ok && x <= utf8.MaxRune {577 fmt.Fprintf(s, "%q", rune(x))578 return579 }580 }581582 // Only include typ if it's neither the default nor untyped type583 // for the constant value.584 if k := val.Kind(); typ == types.Types[types.DefaultKinds[k]] || typ == types.UntypedTypes[k] {585 fmt.Fprint(s, val)586 } else {587 fmt.Fprintf(s, "%v(%v)", typ, val)588 }589590 case ODCLFUNC:591 n := n.(*Func)592 if sym := n.Sym(); sym != nil {593 fmt.Fprint(s, sym)594 return595 }596 fmt.Fprintf(s, "<unnamed Func>")597598 case ONAME:599 n := n.(*Name)600 // Special case: name used as local variable in export.601 // _ becomes ~b%d internally; print as _ for export602 if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' {603 fmt.Fprint(s, "_")604 return605 }606 fallthrough607 case ONONAME:608 fmt.Fprint(s, n.Sym())609610 case OLINKSYMOFFSET:611 n := n.(*LinksymOffsetExpr)612 fmt.Fprintf(s, "(%v)(%s@%d)", n.Type(), n.Linksym.Name, n.Offset_)613614 case OTYPE:615 if n.Type() == nil && n.Sym() != nil {616 fmt.Fprint(s, n.Sym())617 return618 }619 fmt.Fprintf(s, "%v", n.Type())620621 case OCLOSURE:622 n := n.(*ClosureExpr)623 if !exportFormat {624 fmt.Fprint(s, "func literal")625 return626 }627 fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func.Body)628629 case OPTRLIT:630 n := n.(*AddrExpr)631 fmt.Fprintf(s, "&%v", n.X)632633 case OCOMPLIT, OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:634 n := n.(*CompLitExpr)635 if n.Implicit() {636 fmt.Fprintf(s, "... argument")637 return638 }639 fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(len(n.List) != 0))640641 case OKEY:642 n := n.(*KeyExpr)643 if n.Key != nil && n.Value != nil {644 fmt.Fprintf(s, "%v:%v", n.Key, n.Value)645 return646 }647648 if n.Key == nil && n.Value != nil {649 fmt.Fprintf(s, ":%v", n.Value)650 return651 }652 if n.Key != nil && n.Value == nil {653 fmt.Fprintf(s, "%v:", n.Key)654 return655 }656 fmt.Fprint(s, ":")657658 case OSTRUCTKEY:659 n := n.(*StructKeyExpr)660 fmt.Fprintf(s, "%v:%v", n.Field, n.Value)661662 case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OMETHVALUE, OMETHEXPR:663 n := n.(*SelectorExpr)664 exprFmt(n.X, s, nprec)665 if n.Sel == nil {666 fmt.Fprint(s, ".<nil>")667 return668 }669 fmt.Fprintf(s, ".%s", n.Sel.Name)670671 case ODOTTYPE, ODOTTYPE2:672 n := n.(*TypeAssertExpr)673 exprFmt(n.X, s, nprec)674 fmt.Fprintf(s, ".(%v)", n.Type())675676 case OINDEX, OINDEXMAP:677 n := n.(*IndexExpr)678 exprFmt(n.X, s, nprec)679 fmt.Fprintf(s, "[%v]", n.Index)680681 case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:682 n := n.(*SliceExpr)683 exprFmt(n.X, s, nprec)684 fmt.Fprint(s, "[")685 if n.Low != nil {686 fmt.Fprint(s, n.Low)687 }688 fmt.Fprint(s, ":")689 if n.High != nil {690 fmt.Fprint(s, n.High)691 }692 if n.Op().IsSlice3() {693 fmt.Fprint(s, ":")694 if n.Max != nil {695 fmt.Fprint(s, n.Max)696 }697 }698 fmt.Fprint(s, "]")699700 case OSLICEHEADER:701 n := n.(*SliceHeaderExpr)702 fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap)703704 case OCOMPLEX, OCOPY, OUNSAFEADD, OUNSAFESLICE:705 n := n.(*BinaryExpr)706 fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.X, n.Y)707708 case OCONV,709 OCONVIFACE,710 OCONVNOP,711 OBYTES2STR,712 ORUNES2STR,713 OSTR2BYTES,714 OSTR2RUNES,715 ORUNESTR,716 OSLICE2ARR,717 OSLICE2ARRPTR:718 n := n.(*ConvExpr)719 if n.Type() == nil || n.Type().Sym() == nil {720 fmt.Fprintf(s, "(%v)", n.Type())721 } else {722 fmt.Fprintf(s, "%v", n.Type())723 }724 fmt.Fprintf(s, "(%v)", n.X)725726 case OREAL,727 OIMAG,728 OCAP,729 OCLEAR,730 OCLOSE,731 OLEN,732 ONEW,733 OPANIC:734 n := n.(*UnaryExpr)735 fmt.Fprintf(s, "%v(%v)", n.Op(), n.X)736737 case OAPPEND,738 ODELETE,739 OMAKE,740 OMAX,741 OMIN,742 ORECOVER,743 OPRINT,744 OPRINTLN:745 n := n.(*CallExpr)746 if n.IsDDD {747 fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.Args)748 return749 }750 fmt.Fprintf(s, "%v(%.v)", n.Op(), n.Args)751752 case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:753 n := n.(*CallExpr)754 exprFmt(n.Fun, s, nprec)755 if n.IsDDD {756 fmt.Fprintf(s, "(%.v...)", n.Args)757 return758 }759 fmt.Fprintf(s, "(%.v)", n.Args)760761 case OINLCALL:762 n := n.(*InlinedCallExpr)763 // TODO(mdempsky): Print Init and/or Body?764 if len(n.ReturnVars) == 1 {765 fmt.Fprintf(s, "%v", n.ReturnVars[0])766 return767 }768 fmt.Fprintf(s, "(.%v)", n.ReturnVars)769770 case OMAKEMAP, OMAKECHAN, OMAKESLICE:771 n := n.(*MakeExpr)772 if n.Cap != nil {773 fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Len, n.Cap)774 return775 }776 if n.Len != nil && (n.Op() == OMAKESLICE || !n.Len.Type().IsUntyped()) {777 fmt.Fprintf(s, "make(%v, %v)", n.Type(), n.Len)778 return779 }780 fmt.Fprintf(s, "make(%v)", n.Type())781782 case OMAKESLICECOPY:783 n := n.(*MakeExpr)784 fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Len, n.Cap)785786 case OPLUS, ONEG, OBITNOT, ONOT, ORECV:787 // Unary788 n := n.(*UnaryExpr)789 fmt.Fprintf(s, "%v", n.Op())790 if n.X != nil && n.X.Op() == n.Op() {791 fmt.Fprint(s, " ")792 }793 exprFmt(n.X, s, nprec+1)794795 case OADDR:796 n := n.(*AddrExpr)797 fmt.Fprintf(s, "%v", n.Op())798 if n.X != nil && n.X.Op() == n.Op() {799 fmt.Fprint(s, " ")800 }801 exprFmt(n.X, s, nprec+1)802803 case ODEREF:804 n := n.(*StarExpr)805 fmt.Fprintf(s, "%v", n.Op())806 exprFmt(n.X, s, nprec+1)807808 // Binary809 case OADD,810 OAND,811 OANDNOT,812 ODIV,813 OEQ,814 OGE,815 OGT,816 OLE,817 OLT,818 OLSH,819 OMOD,820 OMUL,821 ONE,822 OOR,823 ORSH,824 OSUB,825 OXOR:826 n := n.(*BinaryExpr)827 exprFmt(n.X, s, nprec)828 fmt.Fprintf(s, " %v ", n.Op())829 exprFmt(n.Y, s, nprec+1)830831 case OANDAND,832 OOROR:833 n := n.(*LogicalExpr)834 exprFmt(n.X, s, nprec)835 fmt.Fprintf(s, " %v ", n.Op())836 exprFmt(n.Y, s, nprec+1)837838 case OSEND:839 n := n.(*SendStmt)840 exprFmt(n.Chan, s, nprec)841 fmt.Fprintf(s, " <- ")842 exprFmt(n.Value, s, nprec+1)843844 case OADDSTR:845 n := n.(*AddStringExpr)846 for i, n1 := range n.List {847 if i != 0 {848 fmt.Fprint(s, " + ")849 }850 exprFmt(n1, s, nprec)851 }852 default:853 fmt.Fprintf(s, "<node %v>", n.Op())854 }855}856857func ellipsisIf(b bool) string {858 if b {859 return "..."860 }861 return ""862}863864// Nodes865866// Format implements formatting for a Nodes.867// The valid formats are:868//869// %v Go syntax, semicolon-separated870// %.v Go syntax, comma-separated871// %+v Debug syntax, as in DumpList.872func (l Nodes) Format(s fmt.State, verb rune) {873 if s.Flag('+') && verb == 'v' {874 // %+v is DumpList output875 dumpNodes(s, l, 1)876 return877 }878879 if verb != 'v' {880 fmt.Fprintf(s, "%%!%c(Nodes)", verb)881 return882 }883884 sep := "; "885 if _, ok := s.Precision(); ok { // %.v is expr list886 sep = ", "887 }888889 for i, n := range l {890 fmt.Fprint(s, n)891 if i+1 < len(l) {892 fmt.Fprint(s, sep)893 }894 }895}896897// Dump898899// Dump prints the message s followed by a debug dump of n.900// This includes all the recursive structure under n.901func Dump(s string, n Node) {902 fmt.Printf("%s%+v\n", s, n)903}904905// FDump prints to w the message s followed by a debug dump of n.906// This includes all the recursive structure under n.907func FDump(w io.Writer, s string, n Node) {908 fmt.Fprintf(w, "%s%+v\n", s, n)909}910911// DumpList prints the message s followed by a debug dump of each node in the list.912// This includes all the recursive structure under each node in the list.913func DumpList(s string, list Nodes) {914 var buf bytes.Buffer915 FDumpList(&buf, s, list)916 os.Stdout.Write(buf.Bytes())917}918919// FDumpList prints to w the message s followed by a debug dump of each node in the list.920// This includes all the recursive structure under each node in the list.921func FDumpList(w io.Writer, s string, list Nodes) {922 io.WriteString(w, s)923 dumpNodes(w, list, 1)924 io.WriteString(w, "\n")925}926927// indent prints indentation to w.928func indent(w io.Writer, depth int) {929 fmt.Fprint(w, "\n")930 for i := 0; i < depth; i++ {931 fmt.Fprint(w, ". ")932 }933}934935// EscFmt is set by the escape analysis code to add escape analysis details to the node print.936var EscFmt func(n Node) string937938// dumpNodeHeader prints the debug-format node header line to w.939func dumpNodeHeader(w io.Writer, n Node) {940 // Useful to see which nodes in an AST printout are actually identical941 if base.Debug.DumpPtrs != 0 {942 fmt.Fprintf(w, " p(%p)", n)943 }944945 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {946 // Useful to see where Defn is set and what node it points to947 fmt.Fprintf(w, " defn(%p)", n.Name().Defn)948 }949950 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Curfn != nil {951 // Useful to see where Defn is set and what node it points to952 fmt.Fprintf(w, " curfn(%p)", n.Name().Curfn)953 }954 if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Outer != nil {955 // Useful to see where Defn is set and what node it points to956 fmt.Fprintf(w, " outer(%p)", n.Name().Outer)957 }958959 if EscFmt != nil {960 if esc := EscFmt(n); esc != "" {961 fmt.Fprintf(w, " %s", esc)962 }963 }964965 if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE {966 fmt.Fprintf(w, " %+v", n.Sym())967 }968969 // Print Node-specific fields of basic type in header line.970 v := reflect.ValueOf(n).Elem()971 t := v.Type()972 nf := t.NumField()973 for i := 0; i < nf; i++ {974 tf := t.Field(i)975 if tf.PkgPath != "" {976 // skip unexported field - Interface will fail977 continue978 }979 k := tf.Type.Kind()980 if reflect.Bool <= k && k <= reflect.Complex128 {981 name := strings.TrimSuffix(tf.Name, "_")982 vf := v.Field(i)983 vfi := vf.Interface()984 if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && vf.IsZero() {985 continue986 }987 if vfi == true {988 fmt.Fprintf(w, " %s", name)989 } else {990 fmt.Fprintf(w, " %s:%+v", name, vf.Interface())991 }992 }993 }994995 // Print Node-specific booleans by looking for methods.996 // Different v, t from above - want *Struct not Struct, for methods.997 v = reflect.ValueOf(n)998 t = v.Type()999 nm := t.NumMethod()1000 for i := 0; i < nm; i++ {1001 tm := t.Method(i)1002 if tm.PkgPath != "" {1003 // skip unexported method - call will fail1004 continue1005 }1006 m := v.Method(i)1007 mt := m.Type()1008 if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {1009 // TODO(rsc): Remove the func/defer/recover wrapping,1010 // which is guarding against panics in miniExpr,1011 // once we get down to the simpler state in which1012 // nodes have no getter methods that aren't allowed to be called.1013 func() {1014 defer func() { recover() }()1015 if m.Call(nil)[0].Bool() {1016 name := strings.TrimSuffix(tm.Name, "_")1017 fmt.Fprintf(w, " %s", name)1018 }1019 }()1020 }1021 }10221023 if n.Op() == OCLOSURE {1024 n := n.(*ClosureExpr)1025 if fn := n.Func; fn != nil && fn.Nname.Sym() != nil {1026 fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())1027 }1028 }10291030 if n.Type() != nil {1031 if n.Op() == OTYPE {1032 fmt.Fprintf(w, " type")1033 }1034 fmt.Fprintf(w, " %+v", n.Type())1035 }1036 if n.Typecheck() != 0 {1037 fmt.Fprintf(w, " tc(%d)", n.Typecheck())1038 }10391040 if n.Pos().IsKnown() {1041 fmt.Fprint(w, " # ")1042 switch n.Pos().IsStmt() {1043 case src.PosNotStmt:1044 fmt.Fprint(w, "_") // "-" would be confusing1045 case src.PosIsStmt:1046 fmt.Fprint(w, "+")1047 }1048 sep := ""1049 base.Ctxt.AllPos(n.Pos(), func(pos src.Pos) {1050 fmt.Fprint(w, sep)1051 sep = " "1052 // TODO(mdempsky): Print line pragma details too.1053 file := filepath.Base(pos.Filename())1054 // Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync.1055 fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col())1056 })1057 }1058}10591060func dumpNode(w io.Writer, n Node, depth int) {1061 indent(w, depth)1062 if depth > 40 {1063 fmt.Fprint(w, "...")1064 return1065 }10661067 if n == nil {1068 fmt.Fprint(w, "NilIrNode")1069 return1070 }10711072 if len(n.Init()) != 0 {1073 fmt.Fprintf(w, "%+v-init", n.Op())1074 dumpNodes(w, n.Init(), depth+1)1075 indent(w, depth)1076 }10771078 switch n.Op() {1079 default:1080 fmt.Fprintf(w, "%+v", n.Op())1081 dumpNodeHeader(w, n)10821083 case OLITERAL:1084 fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val())1085 dumpNodeHeader(w, n)1086 return10871088 case ONAME, ONONAME:1089 if n.Sym() != nil {1090 fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym())1091 } else {1092 fmt.Fprintf(w, "%+v", n.Op())1093 }1094 dumpNodeHeader(w, n)1095 return10961097 case OLINKSYMOFFSET:1098 n := n.(*LinksymOffsetExpr)1099 fmt.Fprintf(w, "%+v-%v", n.Op(), n.Linksym)1100 // Offset is almost always 0, so only print when it's interesting.1101 if n.Offset_ != 0 {1102 fmt.Fprintf(w, "%+v", n.Offset_)1103 }1104 dumpNodeHeader(w, n)11051106 case OASOP:1107 n := n.(*AssignOpStmt)1108 fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)1109 dumpNodeHeader(w, n)11101111 case OTYPE:1112 fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym())1113 dumpNodeHeader(w, n)1114 return11151116 case OCLOSURE:1117 fmt.Fprintf(w, "%+v", n.Op())1118 dumpNodeHeader(w, n)11191120 case ODCLFUNC:1121 // Func has many fields we don't want to print.1122 // Bypass reflection and just print what we want.1123 n := n.(*Func)1124 fmt.Fprintf(w, "%+v", n.Op())1125 dumpNodeHeader(w, n)1126 fn := n1127 if len(fn.Dcl) > 0 {1128 indent(w, depth)1129 fmt.Fprintf(w, "%+v-Dcl", n.Op())1130 for _, dcl := range n.Dcl {1131 dumpNode(w, dcl, depth+1)1132 }1133 }1134 if len(fn.ClosureVars) > 0 {1135 indent(w, depth)1136 fmt.Fprintf(w, "%+v-ClosureVars", n.Op())1137 for _, cv := range fn.ClosureVars {1138 dumpNode(w, cv, depth+1)1139 }1140 }1141 if len(fn.Body) > 0 {1142 indent(w, depth)1143 fmt.Fprintf(w, "%+v-body", n.Op())1144 dumpNodes(w, fn.Body, depth+1)1145 }1146 return1147 }11481149 v := reflect.ValueOf(n).Elem()1150 t := reflect.TypeOf(n).Elem()1151 nf := t.NumField()1152 for i := 0; i < nf; i++ {1153 tf := t.Field(i)1154 vf := v.Field(i)1155 if tf.PkgPath != "" {1156 // skip unexported field - Interface will fail1157 continue1158 }1159 switch tf.Type.Kind() {1160 case reflect.Interface, reflect.Ptr, reflect.Slice:1161 if vf.IsNil() {1162 continue1163 }1164 }1165 name := strings.TrimSuffix(tf.Name, "_")1166 // Do not bother with field name header lines for the1167 // most common positional arguments: unary, binary expr,1168 // index expr, send stmt, go and defer call expression.1169 switch name {1170 case "X", "Y", "Index", "Chan", "Value", "Call":1171 name = ""1172 }1173 switch val := vf.Interface().(type) {1174 case Node:1175 if name != "" {1176 indent(w, depth)1177 fmt.Fprintf(w, "%+v-%s", n.Op(), name)1178 }1179 dumpNode(w, val, depth+1)1180 case Nodes:1181 if len(val) == 0 {1182 continue1183 }1184 if name != "" {1185 indent(w, depth)1186 fmt.Fprintf(w, "%+v-%s", n.Op(), name)1187 }1188 dumpNodes(w, val, depth+1)1189 default:1190 if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {1191 if vf.Len() == 0 {1192 continue1193 }1194 if name != "" {1195 indent(w, depth)1196 fmt.Fprintf(w, "%+v-%s", n.Op(), name)1197 }1198 for i, n := 0, vf.Len(); i < n; i++ {1199 dumpNode(w, vf.Index(i).Interface().(Node), depth+1)1200 }1201 }1202 }1203 }1204}12051206var nodeType = reflect.TypeFor[Node]()12071208func dumpNodes(w io.Writer, list Nodes, depth int) {1209 if len(list) == 0 {1210 fmt.Fprintf(w, " <nil>")1211 return1212 }12131214 for _, n := range list {1215 dumpNode(w, n, depth)1216 }1217}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.