Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

x/tools/gopls/internal/analysis/modernize: replace a string += string loop by strings.Builder #75190

Open
Assignees
Labels
AnalysisIssues related to static analysis (vet, x/tools/go/analysis) ToolsThis label describes issues relating to any tools in the x/tools repository. goplsIssues related to the Go language server, gopls.
Milestone
@adonovan

Description

@jakebailey's GopherCon talk mentioned the fact that string += string in TypeScript is a constant-time operation; this is not the case in Go, and it is a mistake to build a string by invoking this operation in a loop, as it allocates a quadratic amount of memory.

We should define a modernizer that replaces such loops by uses of strings.Builder, which is efficient. For example:

var s = "initial"
for ... {
 s += expr
}
use(s)

could be replaced by:

var s strings.Builder
s.WriteString("initial")
for ... {
 s.WriteString(expr)
}
use(s.String())

The general approach should be to search for a += statement within a loop, whose LHS s is a local string variable; find s's types.Var object; then use typeindex.{Def,Uses} to iterate over the other uses of s to see if they conform to the pattern.

The safety conditions are:

  • s must be a local variable. It may not be a global variable or some other expression such as expr.field that may have aliases.
  • s must not be a parameter, since this would change the function's type. (One could introduce a new variable for the strings.Builder rather than turning s into a Builder, but I don't think it's worth it.)
  • All but one uses of s must be of the form s += expr, and must be within a loop.
  • Exactly one (rvalue) use of s must be after the loop.
  • The final use of s must not itself be within a loop. This subtle condition is needed because the transformation moves the expensive allocation step from the += operation to the use(s) operation. We must not degrade performance if the use(s) operation is executed much more often, as in this example when m is much larger than n:
for range n { s += expr }
for range m { use(s) }

Metadata

Metadata

Labels

AnalysisIssues related to static analysis (vet, x/tools/go/analysis) ToolsThis label describes issues relating to any tools in the x/tools repository. goplsIssues related to the Go language server, gopls.

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions

    AltStyle によって変換されたページ (->オリジナル) /