Пример #1
0
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)
}
Пример #2
0
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
}
Пример #3
0
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
}
Пример #4
0
// 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
}
Пример #5
0
// 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
}
Пример #6
0
// 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
}
Пример #7
0
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*/)
}
Пример #8
0
func getTypeString(expr ast.Expr, source []byte) string {
	return string(source[expr.Pos()-1 : expr.End()-1])
}