Beispiel #1
0
func constDecl(kind token.Token, args ...string) *ast.GenDecl {
	decl := ast.GenDecl{Tok: token.CONST}

	if len(args)%3 != 0 {
		panic("Number of values passed to ConstString must be a multiple of 3")
	}
	for i := 0; i < len(args); i += 3 {
		name, typ, val := args[i], args[i+1], args[i+2]
		lit := &ast.BasicLit{Kind: kind}
		if kind == token.STRING {
			lit.Value = strconv.Quote(val)
		} else {
			lit.Value = val
		}
		a := &ast.ValueSpec{
			Names:  []*ast.Ident{ast.NewIdent(name)},
			Values: []ast.Expr{lit},
		}
		if typ != "" {
			a.Type = ast.NewIdent(typ)
		}
		decl.Specs = append(decl.Specs, a)
	}

	if len(decl.Specs) > 1 {
		decl.Lparen = 1
	}

	return &decl
}
Beispiel #2
0
Datei: fix.go Projekt: ssrl/go
// addImport adds the import path to the file f, if absent.
func addImport(f *ast.File, path string) {
	if imports(f, path) {
		return
	}

	newImport := &ast.ImportSpec{
		Path: &ast.BasicLit{
			Kind:  token.STRING,
			Value: strconv.Quote(path),
		},
	}

	var impdecl *ast.GenDecl

	// Find an import decl to add to.
	for _, decl := range f.Decls {
		gen, ok := decl.(*ast.GenDecl)

		if ok && gen.Tok == token.IMPORT {
			impdecl = gen
			break
		}
	}

	// No import decl found.  Add one.
	if impdecl == nil {
		impdecl = &ast.GenDecl{
			Tok: token.IMPORT,
		}
		f.Decls = append(f.Decls, nil)
		copy(f.Decls[1:], f.Decls)
		f.Decls[0] = impdecl
	}

	// Ensure the import decl has parentheses, if needed.
	if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
		impdecl.Lparen = impdecl.Pos()
	}

	// Assume the import paths are alphabetically ordered.
	// If they are not, the result is ugly, but legal.
	insertAt := len(impdecl.Specs) // default to end of specs
	for i, spec := range impdecl.Specs {
		impspec := spec.(*ast.ImportSpec)
		if importPath(impspec) > path {
			insertAt = i
			break
		}
	}

	impdecl.Specs = append(impdecl.Specs, nil)
	copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
	impdecl.Specs[insertAt] = newImport

	f.Imports = append(f.Imports, newImport)
}
Beispiel #3
0
func ast_decl_split(d ast.Decl) []ast.Decl {
	var decls []ast.Decl
	if t, ok := d.(*ast.GenDecl); ok {
		decls = make([]ast.Decl, len(t.Specs))
		for i, s := range t.Specs {
			decl := new(ast.GenDecl)
			*decl = *t
			decl.Specs = make([]ast.Spec, 1)
			decl.Specs[0] = s
			decls[i] = decl
		}
	} else {
		decls = make([]ast.Decl, 1)
		decls[0] = d
	}
	return decls
}
Beispiel #4
0
// AddNamedImport adds the import path to the file f, if absent.
// If name is not empty, it is used to rename the import.
//
// For example, calling
//	AddNamedImport(fset, f, "pathpkg", "path")
// adds
//	import pathpkg "path"
func AddNamedImport(fset *token.FileSet, f *ast.File, name, ipath string) (added bool) {
	if imports(f, ipath) {
		return false
	}

	newImport := &ast.ImportSpec{
		Path: &ast.BasicLit{
			Kind:  token.STRING,
			Value: strconv.Quote(ipath),
		},
	}
	if name != "" {
		newImport.Name = &ast.Ident{Name: name}
	}

	// Find an import decl to add to.
	// The goal is to find an existing import
	// whose import path has the longest shared
	// prefix with ipath.
	var (
		bestMatch  = -1         // length of longest shared prefix
		lastImport = -1         // index in f.Decls of the file's final import decl
		impDecl    *ast.GenDecl // import decl containing the best match
		impIndex   = -1         // spec index in impDecl containing the best match
	)
	for i, decl := range f.Decls {
		gen, ok := decl.(*ast.GenDecl)
		if ok && gen.Tok == token.IMPORT {
			lastImport = i
			// Do not add to import "C", to avoid disrupting the
			// association with its doc comment, breaking cgo.
			if declImports(gen, "C") {
				continue
			}

			// Match an empty import decl if that's all that is available.
			if len(gen.Specs) == 0 && bestMatch == -1 {
				impDecl = gen
			}

			// Compute longest shared prefix with imports in this group.
			for j, spec := range gen.Specs {
				impspec := spec.(*ast.ImportSpec)
				n := matchLen(importPath(impspec), ipath)
				if n > bestMatch {
					bestMatch = n
					impDecl = gen
					impIndex = j
				}
			}
		}
	}

	// If no import decl found, add one after the last import.
	if impDecl == nil {
		impDecl = &ast.GenDecl{
			Tok: token.IMPORT,
		}
		if lastImport >= 0 {
			impDecl.TokPos = f.Decls[lastImport].End()
		} else {
			// There are no existing imports.
			// Our new import goes after the package declaration and after
			// the comment, if any, that starts on the same line as the
			// package declaration.
			impDecl.TokPos = f.Package

			file := fset.File(f.Package)
			pkgLine := file.Line(f.Package)
			for _, c := range f.Comments {
				if file.Line(c.Pos()) > pkgLine {
					break
				}
				impDecl.TokPos = c.End()
			}
		}
		f.Decls = append(f.Decls, nil)
		copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
		f.Decls[lastImport+1] = impDecl
	}

	// Insert new import at insertAt.
	insertAt := 0
	if impIndex >= 0 {
		// insert after the found import
		insertAt = impIndex + 1
	}
	impDecl.Specs = append(impDecl.Specs, nil)
	copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
	impDecl.Specs[insertAt] = newImport
	pos := impDecl.Pos()
	if insertAt > 0 {
		// If there is a comment after an existing import, preserve the comment
		// position by adding the new import after the comment.
		if spec, ok := impDecl.Specs[insertAt-1].(*ast.ImportSpec); ok && spec.Comment != nil {
			pos = spec.Comment.End()
		} else {
			// Assign same position as the previous import,
			// so that the sorter sees it as being in the same block.
			pos = impDecl.Specs[insertAt-1].Pos()
		}
	}
	if newImport.Name != nil {
		newImport.Name.NamePos = pos
	}
	newImport.Path.ValuePos = pos
	newImport.EndPos = pos

	// Clean up parens. impDecl contains at least one spec.
	if len(impDecl.Specs) == 1 {
		// Remove unneeded parens.
		impDecl.Lparen = token.NoPos
	} else if !impDecl.Lparen.IsValid() {
		// impDecl needs parens added.
		impDecl.Lparen = impDecl.Specs[0].Pos()
	}

	f.Imports = append(f.Imports, newImport)

	if len(f.Decls) <= 1 {
		return true
	}

	// Merge all the import declarations into the first one.
	var first *ast.GenDecl
	for i := 0; i < len(f.Decls); i++ {
		decl := f.Decls[i]
		gen, ok := decl.(*ast.GenDecl)
		if !ok || gen.Tok != token.IMPORT || declImports(gen, "C") {
			continue
		}
		if first == nil {
			first = gen
			continue // Don't touch the first one.
		}
		// We now know there is more than one package in this import
		// declaration. Ensure that it ends up parenthesized.
		first.Lparen = first.Pos()
		// Move the imports of the other import declaration to the first one.
		for _, spec := range gen.Specs {
			spec.(*ast.ImportSpec).Path.ValuePos = first.Pos()
			first.Specs = append(first.Specs, spec)
		}
		f.Decls = append(f.Decls[:i], f.Decls[i+1:]...)
		i--
	}

	return true
}
Beispiel #5
0
func imp(fset *token.FileSet, af *ast.File, toggle []ImportDeclArg) *ast.File {
	add := map[ImportDecl]bool{}
	del := map[ImportDecl]bool{}
	for _, sda := range toggle {
		sd := ImportDecl{
			Path: sda.Path,
			Name: sda.Name,
		}
		if sda.Add {
			add[sd] = true
		} else {
			del[sd] = true
		}
	}

	var firstDecl *ast.GenDecl
	imports := map[ImportDecl]bool{}
	for _, decl := range af.Decls {
		if gdecl, ok := decl.(*ast.GenDecl); ok && len(gdecl.Specs) > 0 {
			hasC := false
			sj := 0
			for _, spec := range gdecl.Specs {
				if ispec, ok := spec.(*ast.ImportSpec); ok {
					sd := ImportDecl{
						Path: unquote(ispec.Path.Value),
					}
					if ispec.Name != nil {
						sd.Name = ispec.Name.String()
					}

					if sd.Path == "C" {
						hasC = true
					} else if del[sd] {
						if sj > 0 {
							if lspec, ok := gdecl.Specs[sj-1].(*ast.ImportSpec); ok {
								lspec.EndPos = ispec.Pos()
							}
						}
						continue
					} else {
						imports[sd] = true
					}
				}

				gdecl.Specs[sj] = spec
				sj += 1
			}
			gdecl.Specs = gdecl.Specs[:sj]

			if !hasC && firstDecl == nil {
				firstDecl = gdecl
			}
		}
	}

	if len(add) > 0 {
		if firstDecl == nil {
			firstDecl = &ast.GenDecl{
				Tok:    token.IMPORT,
				Lparen: 1,
			}
			af.Decls = append(af.Decls, firstDecl)
		} else if firstDecl.Lparen == token.NoPos {
			firstDecl.Lparen = 1
		}

		for sd, _ := range add {
			if !imports[sd] {
				ispec := &ast.ImportSpec{
					Path: &ast.BasicLit{
						Value: quote(sd.Path),
						Kind:  token.STRING,
					},
				}
				if sd.Name != "" {
					ispec.Name = &ast.Ident{
						Name: sd.Name,
					}
				}
				firstDecl.Specs = append(firstDecl.Specs, ispec)
				imports[sd] = true
			}
		}
	}

	dj := 0
	for _, decl := range af.Decls {
		if gdecl, ok := decl.(*ast.GenDecl); ok {
			if len(gdecl.Specs) == 0 {
				continue
			}
		}
		af.Decls[dj] = decl
		dj += 1
	}
	af.Decls = af.Decls[:dj]

	ast.SortImports(fset, af)
	return af
}
Beispiel #6
0
// AddNamedImport adds the import path to the file f, if absent.
// If name is not empty, it is used to rename the import.
//
// For example, calling
//	AddNamedImport(fset, f, "pathpkg", "path")
// adds
//	import pathpkg "path"
func AddNamedImport(fset *token.FileSet, f *ast.File, name, ipath string) (added bool) {
	if imports(f, ipath) {
		return false
	}

	newImport := &ast.ImportSpec{
		Path: &ast.BasicLit{
			Kind:  token.STRING,
			Value: strconv.Quote(ipath),
		},
	}
	if name != "" {
		newImport.Name = &ast.Ident{Name: name}
	}

	// Find an import decl to add to.
	var (
		bestMatch  = -1
		lastImport = -1
		impDecl    *ast.GenDecl
		impIndex   = -1
		hasImports = false
	)
	for i, decl := range f.Decls {
		gen, ok := decl.(*ast.GenDecl)
		if ok && gen.Tok == token.IMPORT {
			hasImports = true
			lastImport = i
			// Do not add to import "C", to avoid disrupting the
			// association with its doc comment, breaking cgo.
			if declImports(gen, "C") {
				continue
			}

			// Compute longest shared prefix with imports in this block.
			for j, spec := range gen.Specs {
				impspec := spec.(*ast.ImportSpec)
				n := matchLen(importPath(impspec), ipath)
				if n > bestMatch {
					bestMatch = n
					impDecl = gen
					impIndex = j
				}
			}
		}
	}

	// If no import decl found, add one after the last import.
	if impDecl == nil {
		// TODO(bradfitz): remove this hack. See comment below on
		// addImportViaSourceModification.
		if !hasImports {
			f2, err := addImportViaSourceModification(fset, f, name, ipath)
			if err == nil {
				*f = *f2
				return true
			}
			log.Printf("addImportViaSourceModification error: %v", err)
		}

		// TODO(bradfitz): fix above and resume using this old code:
		impDecl = &ast.GenDecl{
			Tok: token.IMPORT,
		}
		f.Decls = append(f.Decls, nil)
		copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
		f.Decls[lastImport+1] = impDecl
	}

	// Ensure the import decl has parentheses, if needed.
	if len(impDecl.Specs) > 0 && !impDecl.Lparen.IsValid() {
		impDecl.Lparen = impDecl.Pos()
	}

	insertAt := impIndex + 1
	if insertAt == 0 {
		insertAt = len(impDecl.Specs)
	}
	impDecl.Specs = append(impDecl.Specs, nil)
	copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
	impDecl.Specs[insertAt] = newImport
	if insertAt > 0 {
		// Assign same position as the previous import,
		// so that the sorter sees it as being in the same block.
		prev := impDecl.Specs[insertAt-1]
		newImport.Path.ValuePos = prev.Pos()
		newImport.EndPos = prev.Pos()
	}
	if len(impDecl.Specs) > 1 && impDecl.Lparen == 0 {
		// set Lparen to something not zero, so the printer prints
		// the full block rather just the first ImportSpec.
		impDecl.Lparen = 1
	}

	f.Imports = append(f.Imports, newImport)
	return true
}
Beispiel #7
0
// addImport adds the import path to the file f, if absent.
func addImport(f *ast.File, ipath string) (added bool) {
	if imports(f, ipath) {
		return false
	}

	// Determine name of import.
	// Assume added imports follow convention of using last element.
	_, name := path.Split(ipath)

	// Rename any conflicting top-level references from name to name_.
	renameTop(f, name, name+"_")

	newImport := &ast.ImportSpec{
		Path: &ast.BasicLit{
			Kind:  token.STRING,
			Value: strconv.Quote(ipath),
		},
	}

	// Find an import decl to add to.
	var (
		bestMatch  = -1
		lastImport = -1
		impDecl    *ast.GenDecl
		impIndex   = -1
	)
	for i, decl := range f.Decls {
		gen, ok := decl.(*ast.GenDecl)
		if ok && gen.Tok == token.IMPORT {
			lastImport = i
			// Do not add to import "C", to avoid disrupting the
			// association with its doc comment, breaking cgo.
			if declImports(gen, "C") {
				continue
			}

			// Compute longest shared prefix with imports in this block.
			for j, spec := range gen.Specs {
				impspec := spec.(*ast.ImportSpec)
				n := matchLen(importPath(impspec), ipath)
				if n > bestMatch {
					bestMatch = n
					impDecl = gen
					impIndex = j
				}
			}
		}
	}

	// If no import decl found, add one after the last import.
	if impDecl == nil {
		impDecl = &ast.GenDecl{
			Tok: token.IMPORT,
		}
		f.Decls = append(f.Decls, nil)
		copy(f.Decls[lastImport+2:], f.Decls[lastImport+1:])
		f.Decls[lastImport+1] = impDecl
	}

	// Ensure the import decl has parentheses, if needed.
	if len(impDecl.Specs) > 0 && !impDecl.Lparen.IsValid() {
		impDecl.Lparen = impDecl.Pos()
	}

	insertAt := impIndex + 1
	if insertAt == 0 {
		insertAt = len(impDecl.Specs)
	}
	impDecl.Specs = append(impDecl.Specs, nil)
	copy(impDecl.Specs[insertAt+1:], impDecl.Specs[insertAt:])
	impDecl.Specs[insertAt] = newImport
	if insertAt > 0 {
		// Assign same position as the previous import,
		// so that the sorter sees it as being in the same block.
		prev := impDecl.Specs[insertAt-1]
		newImport.Path.ValuePos = prev.Pos()
		newImport.EndPos = prev.Pos()
	}

	f.Imports = append(f.Imports, newImport)
	return true
}
Beispiel #8
0
// TODO(bradfitz): delete this function (and whole file) once
// http://golang.org/issue/4380 is fixed.
func clone(i interface{}) (cloned interface{}) {
	if debugClone {
		defer func() {
			if !reflect.DeepEqual(i, cloned) {
				log.Printf("cloned %T doesn't match: in=%#v out=%#v", i, i, cloned)
			}
		}()
	}
	switch v := i.(type) {
	case nil:
		return nil
	case *ast.File:
		o := &ast.File{
			Doc:      v.Doc, // shallow
			Package:  v.Package,
			Comments: v.Comments, // shallow
			Name:     v.Name,
			Scope:    v.Scope,
		}
		for _, x := range v.Decls {
			o.Decls = append(o.Decls, clone(x).(ast.Decl))
		}
		for _, x := range v.Imports {
			o.Imports = append(o.Imports, clone(x).(*ast.ImportSpec))
		}
		for _, x := range v.Unresolved {
			o.Unresolved = append(o.Unresolved, x)
		}
		return o
	case *ast.GenDecl:
		o := new(ast.GenDecl)
		*o = *v
		o.Specs = nil
		for _, x := range v.Specs {
			o.Specs = append(o.Specs, clone(x).(ast.Spec))
		}
		return o
	case *ast.TypeSpec:
		o := new(ast.TypeSpec)
		*o = *v
		o.Type = cloneExpr(v.Type)
		return o
	case *ast.InterfaceType:
		o := new(ast.InterfaceType)
		*o = *v
		o.Methods = clone(v.Methods).(*ast.FieldList)
		return o
	case *ast.FieldList:
		if v == nil {
			return v
		}
		o := new(ast.FieldList)
		*o = *v
		o.List = nil
		for _, x := range v.List {
			o.List = append(o.List, clone(x).(*ast.Field))
		}
		return o
	case *ast.Field:
		o := &ast.Field{
			Doc:     v.Doc, // shallow
			Type:    cloneExpr(v.Type),
			Tag:     clone(v.Tag).(*ast.BasicLit),
			Comment: v.Comment, // shallow
		}
		for _, x := range v.Names {
			o.Names = append(o.Names, clone(x).(*ast.Ident))
		}
		return o
	case *ast.FuncType:
		if v == nil {
			return v
		}
		return &ast.FuncType{
			Func:    v.Func,
			Params:  clone(v.Params).(*ast.FieldList),
			Results: clone(v.Results).(*ast.FieldList),
		}
	case *ast.FuncDecl:
		if v == nil {
			return v
		}
		return &ast.FuncDecl{
			Recv: clone(v.Recv).(*ast.FieldList),
			Name: v.Name,
			Type: clone(v.Type).(*ast.FuncType),
			Body: v.Body, // shallow
		}
	case *ast.ValueSpec:
		if v == nil {
			return v
		}
		o := &ast.ValueSpec{
			Type: cloneExpr(v.Type),
		}
		for _, x := range v.Names {
			o.Names = append(o.Names, x)
		}
		for _, x := range v.Values {
			o.Values = append(o.Values, cloneExpr(x))
		}
		return o
	case *ast.CallExpr:
		if v == nil {
			return v
		}
		o := &ast.CallExpr{}
		*o = *v
		o.Args = cloneExprs(v.Args)
		o.Fun = cloneExpr(v.Fun)
		return o
	case *ast.SelectorExpr:
		if v == nil {
			return nil
		}
		return &ast.SelectorExpr{
			X:   cloneExpr(v.X),
			Sel: v.Sel,
		}
	case *ast.ArrayType:
		return &ast.ArrayType{
			Lbrack: v.Lbrack,
			Len:    cloneExpr(v.Len),
			Elt:    cloneExpr(v.Elt),
		}
	case *ast.StructType:
		return &ast.StructType{
			Struct:     v.Struct,
			Fields:     clone(v.Fields).(*ast.FieldList),
			Incomplete: v.Incomplete,
		}
	case *ast.StarExpr:
		return &ast.StarExpr{
			Star: v.Star,
			X:    cloneExpr(v.X),
		}
	case *ast.CompositeLit:
		return &ast.CompositeLit{
			Type:   cloneExpr(v.Type),
			Lbrace: v.Lbrace,
			Elts:   cloneExprs(v.Elts),
			Rbrace: v.Rbrace,
		}
	case *ast.UnaryExpr:
		return &ast.UnaryExpr{
			OpPos: v.OpPos,
			Op:    v.Op,
			X:     cloneExpr(v.X),
		}
	case *ast.BinaryExpr:
		return &ast.BinaryExpr{
			OpPos: v.OpPos,
			Op:    v.Op,
			X:     cloneExpr(v.X),
			Y:     cloneExpr(v.Y),
		}
	case *ast.Ellipsis:
		return &ast.Ellipsis{
			Ellipsis: v.Ellipsis,
			Elt:      cloneExpr(v.Elt),
		}
	case *ast.KeyValueExpr:
		return &ast.KeyValueExpr{
			Key:   cloneExpr(v.Key),
			Colon: v.Colon,
			Value: cloneExpr(v.Value),
		}
	case *ast.FuncLit:
		return &ast.FuncLit{
			Type: clone(v.Type).(*ast.FuncType),
			Body: v.Body, // shallow
		}
	case *ast.MapType:
		return &ast.MapType{
			Map:   v.Map,
			Key:   cloneExpr(v.Key),
			Value: cloneExpr(v.Value),
		}
	case *ast.ParenExpr:
		return &ast.ParenExpr{
			Lparen: v.Lparen,
			X:      cloneExpr(v.X),
			Rparen: v.Rparen,
		}
	case *ast.Ident, *ast.BasicLit:
		return v
	case *ast.ImportSpec:
		return &ast.ImportSpec{
			Doc:     v.Doc, // shallow
			Name:    v.Name,
			Path:    clone(v.Path).(*ast.BasicLit),
			Comment: v.Comment, // shallow
			EndPos:  v.EndPos,
		}
	case *ast.ChanType:
		return &ast.ChanType{
			Begin: v.Begin,
			Arrow: v.Arrow,
			Dir:   v.Dir,
			Value: cloneExpr(v.Value),
		}
	case *ast.TypeAssertExpr:
		return &ast.TypeAssertExpr{
			X:    cloneExpr(v.X),
			Type: cloneExpr(v.Type),
		}
	case *ast.IndexExpr:
		return &ast.IndexExpr{
			X:      cloneExpr(v.X),
			Index:  cloneExpr(v.Index),
			Lbrack: v.Lbrack,
			Rbrack: v.Rbrack,
		}
	}
	panic(fmt.Sprintf("Uncloneable type %T", i))
}