[][src]Module c2rust_refactor::rewrite

Module for rewriting source text to reflect changes in the AST.

Rewriting takes as input an old AST, a new AST, and source text that parses to the old AST, and transforms that source text into text that parses to the new AST. Rewriting is designed to preserve comments and whitespace whenever possible.

At a high level, rewriting is a recursive traversal on the old and new ASTs. Everywhere the two are equal, there is no work to do. But where they differ, it applies a number of "rewrite strategies" that attempt to turn the old text into new text. In cases where no strategy can perform the rewrite, it propagates the error upward, trying the available strategies to rewrite enclosing nodes of the ASTs.

The core of the actual implementation is the Rewrite::rewrite(old, new, rcx) -> bool method, which attempts to rewrite the old AST into the new AST. The implementation of this method for each node type simply tries each applicable strategy for the node type until either one of the strategies succeeds or it runs out of strategies to try. Rewrite::rewrite is not (directly) recursive - the recursive traversal is handled by the recursive strategy.

There are three core rewrite strategies:

  • equal: If the two nodes are equal, rewriting succeeds. If they aren't, it fails. In either case, this strategy performs no actual rewrites.

    For leaf nodes, this strategy is tried first.

  • recursive: If every child of the first can be rewritten to the corresponding child of the second, then rewriting succeeds. For nodes of enum type, the two nodes must be instances of the same variant (otherwise there would be no correspondence between the old and new nodes' children). If the variants are unequal or rewriting of any child fails, then the overall rewrite fails. This strategy performs no rewrites beyond those performed by its recursive calls.

    This is where the recursion happens in the actual implementation. Since it implements a superset of equal's functionality, it replaces equal as the first strategy to try for all non-leaf node types.

  • print: Pretty-prints the new node, and performs a rewrite to replace the old source with this new source text. This strategy always succeeds, but is only implemented for a few node types (mostly major ones such as Item, Expr, etc).

    Since pretty-printer's output is cosmetically quite bad (it includes no comments, prints macros in expanded form, and sometimes makes questionable decisions regarding whitespace), the print strategy tries to replace pretty-printer output with original (user-written) source text whenever possible. See the rewrite::strategy::print module docs for details.

    Since this strategy always succeeds, but often produces bad results, it is tried last for any node types that support it.

Since print and the more specialized (non-core) strategies only work for a small set of node types, for most nodes Rewrite::rewrite simply tries equal (leaf nodes) or recursive (non-leaf nodes), and fails if the strategy fails. This failure will cause a failure in the enclosing recursive, and will propagate upward until it reaches a node type that actually does support another strategy, such as Item. This is the point where rewriting actually happens: when recursive fails, Rewrite::rewrite will try the next strategy (such as print), which can perform rewrites to correct the error at this higher level.

Modules

files

Code for applying TextRewrites to the actual source files.

json

Structs

RewriteCtxt
RewriteCtxtRef
TextRewrite

Enums

ExprPrec

Precedence information about the context surrounding an expression. Used to determine whether an expr needs to be parenthesized.

SeqItemId

Common ID type for nodes and Attributes. Both are sequence items, but Attributes have their own custom ID type for some reason.

TextAdjust

Traits

Rewrite

Functions

rewrite