FAQ
I have a large program written in Go, and I need to find all occurences of
'=' operator with both operands being of type *A:

     (expression of type *A) = (expression of type *A)

because I want to replace all these occurences by:

     (expression of type *A).Equal(expression of type *A)

Does someone has some idea how to do that, by any chance ?


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Milan P. Stanic at Jan 4, 2015 at 11:15 pm

    On Sun, 2015-01-04 at 13:27, nicolas riesch wrote:
    I have a large program written in Go, and I need to find all occurences of
    '=' operator with both operands being of type *A:

    (expression of type *A) = (expression of type *A)

    because I want to replace all these occurences by:

    (expression of type *A).Equal(expression of type *A)

    Does someone has some idea how to do that, by any chance ?
    vim and:
    :%s/\((expression of type \*A)\)\( = \).*/\1\.Equal\1/g

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Val at Jan 5, 2015 at 1:42 pm
    Nicolas,
    are you trying to refactor some equality tests (which use == , not = ) ?
    Or are you trying to refactor assignments?

    Text editors and command-line regex matchers of course won't find exactly
    the occurrences you want, because when seeing
    a := b
    or
    if a == b {
    they don't know whether a and b have type *A .

    You may try :
    - walking the AST <https://en.wikipedia.org/wiki/Abstract_syntax_tree> in
    some go code, see package go/ast <http://golang.org/pkg/go/ast/>
    - gofix <http://blog.golang.org/introducing-gofix> is designed specifically
    to update/refactor existing code.

    Best regards
    On Sunday, January 4, 2015 10:27:31 PM UTC+1, nicolas riesch wrote:

    I have a large program written in Go, and I need to find all occurences of
    '=' operator with both operands being of type *A:

    (expression of type *A) = (expression of type *A)

    because I want to replace all these occurences by:

    (expression of type *A).Equal(expression of type *A)

    Does someone has some idea how to do that, by any chance ?

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Sebastien Binet at Jan 5, 2015 at 2:00 pm

    On Mon, Jan 5, 2015 at 2:42 PM, Val wrote:
    Nicolas,
    are you trying to refactor some equality tests (which use == , not = ) ?
    Or are you trying to refactor assignments?

    Text editors and command-line regex matchers of course won't find exactly
    the occurrences you want, because when seeing
    a := b
    or
    if a == b {
    they don't know whether a and b have type *A .

    You may try :
    - walking the AST in some go code, see package go/ast
    - gofix is designed specifically to update/refactor existing code.
    if it's the assignment(s) you are after, you may be out of luck. (or,
    at least, out of pre-packaged luck.)
    OTH, if it's the equality operand, then "eg" may be of some help:
    http://godoc.org/golang.org/x/tools/cmd/eg

    $ go get -u golang.org/x/tools/cmd/eg
    $ eg -help
    This tool implements example-based refactoring of expressions.

    The transformation is specified as a Go file defining two functions,
    'before' and 'after', of identical types. Each function body consists
    of a single statement: either a return statement with a single
    (possibly multi-valued) expression, or an expression statement. The
    'before' expression specifies a pattern and the 'after' expression its
    replacement.

    package P
       import ( "errors"; "fmt" )
       func before(s string) error { return fmt.Errorf("%s", s) }
       func after(s string) error { return errors.New(s) }
    [...]

    So, the transform above would change this input:
    err := fmt.Errorf("%s", "error: " + msg)
    to this output:
    err := errors.New("error: " + msg)
    [...]

    hth,
    -s

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Adonovan at Jan 5, 2015 at 2:50 pm

    On Sunday, 4 January 2015 16:27:31 UTC-5, nicolas riesch wrote:
    I have a large program written in Go, and I need to find all occurences of
    '=' operator with both operands being of type *A:

    (expression of type *A) = (expression of type *A)

    because I want to replace all these occurences by:

    (expression of type *A).Equal(expression of type *A)

    Does someone has some idea how to do that, by any chance ?
    This problem requires type information (as computed by
    golang.org/x/tools/go/types) and a more explicit representation of the
    source code in which implicit comparisons (such as in a switch statement)
    are explicit; the SSA form (golang.org/x/tools/go/ssa) provides both.

    Add the following lines to the golang.org/x/tools/cmd/ssadump program and
    run it on your application. It will report the source location of all
    equality comparisons of type A:

    A := types.NewPointer(types.Typ[types.String]) // A is *string in this
    example
    for fn := range ssautil.AllFunctions(prog) {
    for _, b := range fn.Blocks {
    for _, instr := range b.Instrs {
    if binop, ok := instr.(*ssa.BinOp); ok && binop.Op == token.EQL {
    if types.Identical(binop.X.Type(), A) {
    fmt.Println(prog.Fset.Position(binop.Pos()))
    }
    }
    }
    }
    }

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Adonovan at Jan 5, 2015 at 3:00 pm

    On Monday, 5 January 2015 09:50:43 UTC-5, adon...@google.com wrote:
    On Sunday, 4 January 2015 16:27:31 UTC-5, nicolas riesch wrote:

    I have a large program written in Go, and I need to find all occurences
    of '=' operator with both operands being of type *A:

    (expression of type *A) = (expression of type *A)

    because I want to replace all these occurences by:

    (expression of type *A).Equal(expression of type *A)

    Does someone has some idea how to do that, by any chance ?
    This problem requires type information (as computed by
    golang.org/x/tools/go/types) and a more explicit representation of the
    source code in which implicit comparisons (such as in a switch statement)
    are explicit; the SSA form (golang.org/x/tools/go/ssa) provides both.

    Add the following lines to the golang.org/x/tools/cmd/ssadump program and
    run it on your application. It will report the source location of all
    equality comparisons of type A:

    A := types.NewPointer(types.Typ[types.String]) // A is *string in this
    example
    for fn := range ssautil.AllFunctions(prog) {
    for _, b := range fn.Blocks {
    for _, instr := range b.Instrs {
    if binop, ok := instr.(*ssa.BinOp); ok && binop.Op == token.EQL {
    if types.Identical(binop.X.Type(), A) {
    fmt.Println(prog.Fset.Position(binop.Pos()))
    }
    }
    }
    }
    }
    I nearly forgot: the golang.org/x/tools/cmd/eg tool should be able to do
    exactly what you want for explicit assignments (i.e., it won't catch
    switches), like so:

    % cat template.go
    package p
    func before(x, y *A) { return x == y }
    func after(x, y *A) { return x.Equals(y) }
    % eg -t template.go myprog

    (If switches are important, you could use the ssadump code above to find
    places that eg doesn't catch.)

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nicolas riesch at Jan 5, 2015 at 9:58 pm
    Thank you very much for all your answers.
    Sorry, there was a typo in my question, I was looking for '==' equality
    operators, and not assignments.

    ssadump works like a charm, analyzing 80,000 lines in 15 seconds and
    printing the exact line position of all the expressions I was looking for.
    That's quite amazing !
    Really a great and invaluable tool ;-))))))

    For those who wants to try, I rewrite herebelow the code from
    adon...@google.com's answer, with the code to look for equality of
    *foo.Bar type.
    Recompile with:
             go install golang.org/x/tools/cmd/ssadump
    And run:
             ssadump myprogram

    -------------- add this at he end of the doMain() function in the file
    main.go of golang.org/x/tools/cmd/ssadump program --------------------

    // Also add these two packages in the import statement.
    // "go/token"
    // "golang.org/x/tools/go/ssa/ssautil"

         var (
             my_package_name string = "foo" // <------- the package in which
    your type is declared (only last element of package path)
             my_type_name string = "Bar" // <------- the name of the type
    you are looking for
             my_package *ssa.Package
             my_ssa_type *ssa.Type
             my_type types.Type
         )

         pkgs := prog.AllPackages()

         for _, pkg := range pkgs {
             if pkg.Object.Name() == my_package_name {
                 my_package = pkg

                 if my_ssa_type = my_package.Type(my_type_name); my_ssa_type ==
    nil {
                     return fmt.Errorf("type %s not found in package %s",
    my_type_name, my_package_name)
                 }
                 my_type = my_ssa_type.Type()
                 break
             }
         }

         // A := types.NewPointer(types.Typ[types.String]) // A is *string in
    this example
         // A := my_type // if i am looking
    for my_type (foo.Bar)
         A := types.NewPointer(my_type) // if I am looking
    for *my_type (*foo.Bar)

         for fn := range ssautil.AllFunctions(prog) {
             for _, b := range fn.Blocks {
                 for _, instr := range b.Instrs {
                     if binop, ok := instr.(*ssa.BinOp); ok && binop.Op ==
    token.EQL {
                         if types.Identical(binop.X.Type(), A) {
                             fmt.Println(prog.Fset.Position(binop.Pos()))
                         }
                     }
                 }
             }
         }
    ------------------------

    I have just a last question.
    The program also prints expressions of the kind a == nil (where a is of
    type *foo.Bar)
    It is correct, but I would like to filter them out.
    I haven't found the proper method in ssa or types package that returns
    whether an operand is the nil value.
    Can you give me a pointer ?


    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Alan Donovan at Jan 5, 2015 at 10:28 pm

    On 5 January 2015 at 16:58, nicolas riesch wrote:

    Thank you very much for all your answers.
    Sorry, there was a typo in my question, I was looking for '==' equality
    operators, and not assignments.
    Yes, I meant equality too; assignments was a typo.


    The program also prints expressions of the kind a == nil (where a is of
    type *foo.Bar)
    It is correct, but I would like to filter them out.
    I haven't found the proper method in ssa or types package that returns
    whether an operand is the nil value.
    Can you give me a pointer ?
    nil is an *ssa.Const, and in fact it's the only possible ssa.Const since
    this is a comparison of pointers.
    So if you change the predicate to:

             if types.Identical(binop.X.Type(), A) && !isConst(binop.X) &&
    !isConst(binop.Y) {

    and add this utility:

             func isConst(x ssa.Value) bool {
                     _, ok := x.(*ssa.Const)
                     return !ok
             }

    it should do what you want.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJan 4, '15 at 9:27p
activeJan 5, '15 at 10:28p
posts8
users5
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase