Extract Method and Inline literals – How does it work?

If you recall in my previous post, I presented a new plugin "CR_ExtractMethodAndInlineLiterals

In this post I’ll walk you through exactly how it works.

Overview

This plugin does it’s job by automating the execution of existing Refactorings, moving the caret around and executing more Refactorings.

Broadly speaking there are 3 parts to this task.

  • Extract literals from selection.
  • Extract remaining code to new method.
  • Inline literals back into the call to the new method.
  • Extraction of the literals

    The first part of extracting the literals is to find them. For this we will use an instance of ElementEnumerable. The ElementEnumerable constructor requires a scope (in which to search) and a filter (to use for testing found items). We can’t pass the current selection as scope (Selection isn’t a LanguageElement). Instead we’ll pass the ActiveFileNode. For the Filter, we’ll pass a custom implementation of an IElementFilter. The bulk of our class (TypeInRangeFilter) is shown here:

    EMIL-TypeInRangeFilter

    IElementFilters are used to test IElements (or sequences of them) against specific criteria. The criteria will vary from implementation to implementation. In this case we have created an IElementFilter which passes elements if they are both of the required type, and their start is within the supplied range.

    We use this IElementFilter together with the ElementEnumerable in order to produce a list of PrimitiveExpressions (strings, numbers etc) )within the selected SourceRange.

    EMIL-GetPrimitivesMethod

    Having found these literals, we need to place our caret within their name, or better yet, select them entirely…

    EMIL-SelectRange

    Once selected, we need to call a refactoring.

    However calling a Refactoring from within another refactoring, is a little more complicated that just getting a reference and calling it:

    EMIL-ExecuteRefactoringMethod

    Using this helper method, we make the call to the ‘Introduce Local’ refactoring

    EMIL-CallIntroduceLocalRefactoring

    At this point it’s worth noting that the refactoring will have changed our code, and naturally enough the Active Document will have to be reparsed.

    For this, we need a call to…

    ReparseActiveDocument

    … which will cause CodeRush to update it’s internal representation of the code.

    Each call to Introduce Local will have caused the the introduction of a new Initialized variable. However each of these will have been placed immediately prior to it’s initial usage. This is less than ideal since since we’d like to exclude these initializations from the extraction. Not to worry, we can move these statements up above the original selection.

    Finding these InitializedVariables involves another custom implementation of IElementFilter (InitializedVarFilter).

    This time the internals look more like this:

    EMIL-InitializedVarFilter

    This IElementFilter looks for IElements whose type is InitializedVariable and also match a given name

    As before, we use our new IElementFilter like this

    EMIL-GetInitializedVarsMethod

    Iterating through our InitializedVars we can move each above the selection using:

    EMIL-MoveInitializedVar

    Extract Method

    Next we reselect our original selection. (Messing with code doesn’t always alter your selection, but it can be a good practice to ensure things are the way you want them anyway)

    EMIL-SelectSelectRange

    … and then Extract the Method using the helper function we created earlier.

    EMIL-CallExtractMethod

    Inline Variables

    Our final official step is to inline the Initialized Variables back into the method call.

    Once more we can iterate through our previously gathered list of InitializedVariables

    Select the range of each in turn

    EMIL-SelectInitializedVariable

    Then Execute the Inline Temp refactoring

    EMIL-CallInlineTempRefactoring

    Essentially that’s all there is to it.

    As usual the full code to this plugin can be found on github.com as well as the VSIX.

    Feel free to use these as a reference for your own plugins, or to extend them and contribute changes back again.

    no comments
    No Comments

    Please login or register to post comments.