// removeParam computes a refactoring to remove the parameter indicated by the // given range. func removeParam(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, rng protocol.Range) ([]protocol.DocumentChange, error) { … } // ChangeSignature computes a refactoring to update the signature according to // the provided parameter transformation, for the signature definition // surrounding rng. // // newParams expresses the new parameters for the signature in terms of the old // parameters. Each entry in newParams is the index of the new parameter in the // original parameter list. For example, given func Foo(a, b, c int) and newParams // [2, 0, 1], the resulting changed signature is Foo(c, a, b int). If newParams // omits an index of the original signature, that parameter is removed. // // This operation is a work in progress. Remaining TODO: // - Handle adding parameters. // - Handle adding/removing/reordering results. // - Improve the extra newlines in output. // - Stream type checking via ForEachPackage. // - Avoid unnecessary additional type checking. func ChangeSignature(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Package, pgf *parsego.File, rng protocol.Range, newParams []int) ([]protocol.DocumentChange, error) { … } // rewriteSignature rewrites the signature of the declIdx'th declaration in src // to use the signature of newDecl (described by fset). // // TODO(rfindley): I think this operation could be generalized, for example by // using a concept of a 'nodepath' to correlate nodes between two related // files. // // Note that with its current application, rewriteSignature is expected to // succeed. Separate bug.Errorf calls are used below (rather than one call at // the callsite) in order to have greater precision. func rewriteSignature(fset *token.FileSet, declIdx int, src0 []byte, newDecl *ast.FuncDecl) ([]byte, error) { … } type paramInfo … // findParam finds the parameter information spanned by the given range. func findParam(pgf *parsego.File, rng protocol.Range) *paramInfo { … } type signatureRewrite … // rewriteCalls returns the document changes required to rewrite the // signature of origDecl to that of newDecl. // // This is a rather complicated factoring of the rewrite operation, but is able // to describe arbitrary rewrites. Specifically, rewriteCalls creates a // synthetic copy of pkg, where the original function declaration is changed to // be a trivial wrapper around the new declaration. params and callArgs are // used to perform this delegation: params must have the same type as origDecl, // but may have renamed parameters (such as is required for delegating blank // parameters). callArgs are the arguments of the delegated call (i.e. using // params). // // For example, consider removing the unused 'b' parameter below, rewriting // // func Foo(a, b, c, _ int) int { // return a+c // } // // To // // func Foo(a, c, _ int) int { // return a+c // } // // In this case, rewriteCalls is parameterized as follows: // - origDecl is the original declaration // - newDecl is the new declaration, which is a copy of origDecl less the 'b' // parameter. // - params is a new parameter list (a, b, c, blank0 int) to be used for the // new wrapper. // - callArgs is the argument list (a, c, blank0), to be used to call the new // delegate. // // rewriting is expressed this way so that rewriteCalls can own the details // of *how* this rewriting is performed. For example, as of writing it names // the synthetic delegate G_o_p_l_s_foo, but the caller need not know this. // // By passing an entirely new declaration, rewriteCalls may be used for // signature refactorings that may affect the function body, such as removing // or adding return values. func rewriteCalls(ctx context.Context, rw signatureRewrite) (map[protocol.DocumentURI][]byte, error) { … } // reTypeCheck re-type checks orig with new file contents defined by fileMask. // // It expects that any newly added imports are already present in the // transitive imports of orig. // // If expectErrors is true, reTypeCheck allows errors in the new package. // TODO(rfindley): perhaps this should be a filter to specify which errors are // acceptable. func reTypeCheck(logf func(string, ...any), orig *cache.Package, fileMask map[protocol.DocumentURI]*ast.File, expectErrors bool) (*types.Package, *types.Info, error) { … } var goVersionRx … func remove[T any](s []T, i int) []T { … } // selectElements returns a new array of elements of s indicated by the // provided list of indices. It returns false if any index was out of bounds. // // For example, given the slice []string{"a", "b", "c", "d"}, the // indices []int{3, 0, 1} results in the slice []string{"d", "a", "b"}. func selectElements[T any](s []T, indices []int) ([]T, bool) { … } // replaceFileDecl replaces old with new in the file described by pgf. // // TODO(rfindley): generalize, and combine with rewriteSignature. func replaceFileDecl(pgf *parsego.File, old, new ast.Decl) ([]byte, error) { … } // findDecl finds the index of decl in file.Decls. // // TODO: use slices.Index when it is available. func findDecl(file *ast.File, decl ast.Decl) int { … }