Generating from Source Code

One of the awesome features of CodeSmith Generator is that you can generate from any kind of metadata. A new feature to CodeSmith Generator is the CodeFileParser which allows you to generate off of existing source code. The CodeSmith.CodeFileParser class can parse any string or file and return an easy to use DOM object.

Requirements

In order for the CodeFileParser requires that the passed in string or file contents contain valid CSharp or VisualBasic code. The CodeFileParser uses the public NRefactory libraries under the hood to create the DOM object.

The CodeFileParser Object

It is very easy to create a new CodeFileParser Instance in code by using the overloaded constructors below. Also, you can use the CodeFileParser by creating a template property. All you need to do is add a new Property Directive with the type CodeSmith.CodeFileParser to your template.

// There are overloads that don't require basePath or parseMethodBodies.
public CodeFileParser(string fileName, string basePath, bool parseMethodBodies)

 // There are overloads that don't require parseMethodBodies.
public CodeFileParser(string source, SupportedLanguage language, bool parseMethodBodies)

The Selection Methods

Most of the methods in NRefactory return position information in the form of Location objects, which, while very descriptive, are not the easiest thing to use when trying to take substrings or selections from the existing code.
Because this can be very important when using the object DOM to assist with code generation, we have added several methods to assist with getting substrings and selections; these methods take in Location objects and return strings.

public string GetSectionFromStart(Location end)
public string GetSectionToEnd(Location start)
public string GetSection(Location start, Location end)

The CodeDomCompilationUnit

To quick and easily walk the DOM, the CodeFileParser exposes a (lazy loaded) property that returns System.CodeDom.CodeCompileUnit object.
This is a standard .NET object that contains a complete code graph; this object is the quickest and easiest way to traverse your metadata.
For more information about the CodeCompileUnit, please check out MSDN article.

The Visitor

When more advanced or customized information is required, the CodeFileParser exposes the CompilationUnit object, which is capable of taking in a visitor object to traverse the DOM and bring back specific data.
This is an NRefactory feature, and it only requires that your visitor object implement the AbstractAstVisitor class.

Example

We are already using the CodeFileParser in CodeSmith Generator and our Plinqo templates! In CodeSmith Generator we have implemented the CodeFileParser in our InsertClassMergeStrategy; it allows us to parse the existing code file and determine where we need to insert our new content. In PLINQO for Linq-to-SQL we use the CodeFileParser to assist with our MetaData class merge; it allows us to make a map of all the properties in that class and then preserve their attributes during regeneration.

 

<%@ CodeTemplate Language="C#" TargetLanguage="Text" Debug="False" CompilerVersion="v3.5" %>
<%@ Property Category="2.Class" Name="TheFile" Type="CodeFileParser" Optional="False" %>
<%@ Assembly Name="CodeSmith.CodeParser" %>
<%@ Import Namespace="System.CodeDom" %>

<% foreach(CodeNamespace n in TheFile.CodeDomCompilationUnit.Namespaces) { %>
    Namespace: <%= n.Name %>
    <% foreach(CodeTypeDeclaration t in n.Types) { %>
        Type: <%= t.Name %>
        <% foreach(CodeMemberProperty m in t.Members) { %>
            Property Name: <%= m.Name %> Property Type <%= m.Type.BaseType %>
        <% } %>
    <% } %>
<% } %>