func emitTraceExpr(f *Function, event TraceEvent, syntax ast.Expr) Value { t := &Trace{ Event: event, Start: syntax.Pos(), End: syntax.End(), Breakpoint: false, syntax: syntax, } return emitTraceCommon(f, t) }
func extractText(ctx *Context, t ast.Expr) (string, error) { pos := ctx.Fset.Position(t.Pos()) end := ctx.Fset.Position(t.End()) read, err := ioutil.ReadFile(pos.Filename) if err != nil { return "", err } return string(read[pos.Offset:end.Offset]), nil }
func hasType(pkg *grinder.Package, fn *ast.FuncDecl, edit *grinder.EditBuffer, x, v ast.Expr) bool { // Does x (by itself) default to v's type? // Find the scope in which x appears. xScope := pkg.Info.Scopes[fn.Type] ast.Inspect(fn.Body, func(z ast.Node) bool { if z == nil { return false } if x.Pos() < z.Pos() || z.End() <= x.Pos() { return false } scope := pkg.Info.Scopes[z] if scope != nil { xScope = scope } return true }) xs := edit.TextAt(x.Pos(), x.End()) xt, err := types.Eval(pkg.FileSet, pkg.Types, xScope.Pos(), xs) if err != nil { return false } vt := pkg.Info.Types[v] if types.Identical(xt.Type, vt.Type) { return true } // Might be untyped. vb, ok1 := vt.Type.(*types.Basic) xb, ok2 := xt.Type.(*types.Basic) if ok1 && ok2 { switch xb.Kind() { case types.UntypedInt: return vb.Kind() == types.Int case types.UntypedBool: return vb.Kind() == types.Bool case types.UntypedRune: return vb.Kind() == types.Rune case types.UntypedFloat: return vb.Kind() == types.Float64 case types.UntypedComplex: return vb.Kind() == types.Complex128 case types.UntypedString: return vb.Kind() == types.String } } return false }
// checkExprOrType checks that x is an expression or a type // (and not a raw type such as [...]T). // func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { switch t := unparen(x).(type) { case *ast.ParenExpr: panic("unreachable") case *ast.UnaryExpr: if t.Op == token.RANGE { // the range operator is only allowed at the top of a for statement p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } case *ast.ArrayType: if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis { p.error(len.Pos(), "expected array length, found '...'") x = &ast.BadExpr{x.Pos(), x.End()} } } // all other nodes are expressions or types return x }
// checkExpr checks that x is an expression (and not a type). func (p *parser) checkExpr(x ast.Expr) ast.Expr { switch t := unparen(x).(type) { case *ast.BadExpr: case *ast.Ident: case *ast.BasicLit: case *ast.FuncLit: case *ast.CompositeLit: case *ast.ParenExpr: panic("unreachable") case *ast.SelectorExpr: case *ast.IndexExpr: case *ast.SliceExpr: case *ast.TypeAssertExpr: if t.Type == nil { // the form X.(type) is only allowed in type switch expressions p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } case *ast.CallExpr: case *ast.StarExpr: case *ast.UnaryExpr: if t.Op == token.RANGE { // the range operator is only allowed at the top of a for statement p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } case *ast.BinaryExpr: default: // all other nodes are not proper expressions p.errorExpected(x.Pos(), "expression") x = &ast.BadExpr{x.Pos(), x.End()} } return x }
// reflectFixSwitch rewrites *n (if n is an *ast.Stmt) corresponding // to a type switch. func reflectFixSwitch(n interface{}) bool { ptr, ok := n.(*ast.Stmt) if !ok { return false } n = *ptr ts, ok := n.(*ast.TypeSwitchStmt) if !ok { return false } // Are any switch cases referring to reflect types? // (That is, is this an old reflect type switch?) for _, cas := range ts.Body.List { for _, typ := range cas.(*ast.CaseClause).List { if reflectType(typ) != "" { goto haveReflect } } } return false haveReflect: // Now we know it's an old reflect type switch. Prepare the new version, // but don't replace or edit the original until we're sure of success. // Figure out the initializer statement, if any, and the receiver for the Kind call. var init ast.Stmt var rcvr ast.Expr init = ts.Init switch n := ts.Assign.(type) { default: warn(ts.Pos(), "unexpected form in type switch") return false case *ast.AssignStmt: as := n ta := as.Rhs[0].(*ast.TypeAssertExpr) x := isIdent(as.Lhs[0]) z := isIdent(ta.X) if isBlank(x) || x != nil && z != nil && x.Name == z.Name && !assignsTo(x, ts.Body.List) { // Can drop the variable creation. rcvr = ta.X } else { // Need to use initialization statement. if init != nil { warn(ts.Pos(), "cannot rewrite reflect type switch with initializing statement") return false } init = &ast.AssignStmt{ Lhs: []ast.Expr{as.Lhs[0]}, TokPos: as.TokPos, Tok: token.DEFINE, Rhs: []ast.Expr{ta.X}, } rcvr = as.Lhs[0] } case *ast.ExprStmt: rcvr = n.X.(*ast.TypeAssertExpr).X } // Prepare rewritten type switch (see large comment above for form). sw := &ast.SwitchStmt{ Switch: ts.Switch, Init: init, Tag: &ast.CallExpr{ Fun: &ast.SelectorExpr{ X: rcvr, Sel: &ast.Ident{ NamePos: rcvr.End(), Name: "Kind", Obj: nil, }, }, Lparen: rcvr.End(), Rparen: rcvr.End(), }, Body: &ast.BlockStmt{ Lbrace: ts.Body.Lbrace, List: nil, // to be filled in Rbrace: ts.Body.Rbrace, }, } // Translate cases. for _, tcas := range ts.Body.List { tcas := tcas.(*ast.CaseClause) cas := &ast.CaseClause{ Case: tcas.Case, Colon: tcas.Colon, Body: tcas.Body, } for _, t := range tcas.List { if isTopName(t, "nil") { cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", "Invalid")) continue } typ := reflectType(t) if typ == "" { warn(t.Pos(), "cannot rewrite reflect type switch case with non-reflect type %s", gofmt(t)) cas.List = append(cas.List, t) continue } for _, k := range reflectKind[typ] { cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", k)) } } sw.Body.List = append(sw.Body.List, cas) } // Everything worked. Rewrite AST. *ptr = sw return true }
func extractExpressionAsFunc( astFile *ast.File, fileSet *token.FileSet, expr ast.Expr, parent ast.Node, extractedFuncName string) { params := varIdentsUsedIn([]ast.Node{expr}) util.MapStringAstIdentRemoveKeys(params, namesOf(globalVarIdents(astFile))) newExpr := CopyNode(callExprWith(extractedFuncName, params)).(ast.Expr) RecalcPoses(newExpr, expr.Pos(), nil, 0) switch typedNode := parent.(type) { case *ast.AssignStmt: for i, rhs := range typedNode.Rhs { if rhs == expr { typedNode.Rhs[i] = newExpr } } for i, lhs := range typedNode.Lhs { if lhs == expr { typedNode.Lhs[i] = newExpr } } case *ast.CallExpr: for i, arg := range typedNode.Args { if arg == expr { typedNode.Args[i] = newExpr } } case *ast.ExprStmt: typedNode.X = newExpr case *ast.ReturnStmt: for i, result := range typedNode.Results { if result == expr { typedNode.Results[i] = newExpr } } case *ast.IfStmt: if typedNode.Cond == expr { typedNode.Cond = newExpr } case *ast.CaseClause: for i, caseExpr := range typedNode.List { if caseExpr == expr { typedNode.List[i] = newExpr } } case *ast.SwitchStmt: if typedNode.Tag == expr { typedNode.Tag = newExpr } case *ast.ForStmt: if typedNode.Cond == expr { typedNode.Cond = newExpr } case *ast.RangeStmt: if typedNode.Key == expr { typedNode.Key = newExpr } else if typedNode.Value == expr { typedNode.Value = newExpr } else if typedNode.X == expr { typedNode.X = newExpr } case *ast.SendStmt: if typedNode.Chan == expr { typedNode.Chan = newExpr } else if typedNode.Value == expr { typedNode.Value = newExpr } case *ast.IncDecStmt: if typedNode.X == expr { typedNode.X = newExpr } case *ast.ValueSpec: for i, value := range typedNode.Values { if value == expr { typedNode.Values[i] = newExpr } } default: panic(fmt.Sprintf("Type %v not supported yet", reflect.TypeOf(parent))) } areaRemoved := areaRemoved(fileSet, expr.Pos(), expr.End()) lineLengths := lineLengthsFrom(fileSet) lineNum, numLinesToCut, newLineLength := replacementModifications(fileSet, expr.Pos(), expr.End(), newExpr.End(), lineLengths, areaRemoved) shiftPosesAfterPos(astFile, newExpr, expr.End(), newExpr.End()-expr.End()) singleExprStmtFuncDeclWith := CopyNode(singleExprStmtFuncDeclWith(extractedFuncName, fieldsFrom(params), expr)).(*ast.FuncDecl) var moveOffset token.Pos RecalcPoses(singleExprStmtFuncDeclWith, astFile.End()+2, &moveOffset, 0) astFile.Decls = append(astFile.Decls, singleExprStmtFuncDeclWith) areaToBeAppended := insertionModifications(astFile, singleExprStmtFuncDeclWith, areaRemoved) lineLengths = append( lineLengths[:lineNum+1], lineLengths[lineNum+1+numLinesToCut:]...) lineLengths[lineNum] = newLineLength lineLengths = append(lineLengths, areaToBeAppended...) newFileSet := token.NewFileSet() newFileSet.AddFile(fileSet.File(1).Name(), 1, int(astFile.End())) success := newFileSet.File(1).SetLines(ConvertLineLengthsToLineOffsets(lineLengths)) if !success { panic("Could not SetLines on File.") } *fileSet = *newFileSet moveComments(astFile, moveOffset /*, needs a range to restict which comments to move*/) }
func getTypeString(expr ast.Expr, source []byte) string { return string(source[expr.Pos()-1 : expr.End()-1]) }