static async Task Main(string[] args) { // Attempt to set the version of MSBuild. var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray(); var instance = visualStudioInstances.Length == 1 // If there is only one instance of MSBuild on this machine, set that as the one to use. ? visualStudioInstances[0] // Handle selecting the version of MSBuild you want to use. : SelectVisualStudioInstance(visualStudioInstances); Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects."); // NOTE: Be sure to register an instance with the MSBuildLocator // before calling MSBuildWorkspace.Create() // otherwise, MSBuildWorkspace won't MEF compose. MSBuildLocator.RegisterInstance(instance); using (var workspace = MSBuildWorkspace.Create()) { // Print message for WorkspaceFailed event to help diagnosing project load failures. workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message); var solutionPath = args[0]; Console.WriteLine($"Loading solution '{solutionPath}'"); // Attach progress reporter so we print projects as they are loaded. var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter()); var solutionName = Path.GetFileNameWithoutExtension(solutionPath); Console.WriteLine($"Finished loading solution '{solutionPath}'"); var nodes = new Dictionary <long, Node>(); var edges = new Dictionary <long, EdgeNode>(); foreach (var project in solution.Projects.Where(p => !p.Name.Contains("Test"))) { foreach (var document in project.Documents)//.Where(d=>!d.Name.Contains("Dummy"))) { var collector = new CodeWalker(document.FilePath, document.Name, nodes, edges); SyntaxTree tree = CSharpSyntaxTree.ParseText(await document.GetTextAsync()); var root = (CompilationUnitSyntax)tree.GetRoot(); collector.Visit(root); } } // Save Data files new Exporter(nodes, edges) //.ExportJson(solutionName) //.ExportNeo4J(solutionName) .ExportCsv(solutionName); } }
/// <summary> /// Renders the C# code text to the specified <see cref="TextWriter" />. /// </summary> /// <remarks> /// The version of the <c>Render</c> method does all of the work because the other versions ultimately call this one. The /// steps involved are: /// <list type="number"> /// <item><description> /// The code text is parsed to produce a <c>SyntaxTree</c> /// </description></item> /// <item><description> /// A compilation unit is created from the <c>SyntaxTree</c> and <c>MetadataReferences</c> properties and from that /// the <c>SemanticModel</c> is initialized. Note that renderers that are only interested in the syntax need not /// access the semantic mode, but the HTML renderer does need this information to determine if an identifier represents /// a symbol that should be (color) formatted. /// </description></item> /// <item><description> /// The <c>SyntaxVisiting</c> event is handled by invoking the <c>Callback</c> passing the <c>SyntaxTreeElement</c> /// object and <c>VisitingState</c> enumeration value encapsulated in the <c>SyntaxVisitingEventArgs</c> object. /// Concrete implementations due the actual rendering from the callback delegate. /// </description></item> /// <item><description> /// Any prefix text is recovered using the <c>GetPrefixText</c> method and is written to the <c>Writer</c>. /// </description></item> /// <item><description> /// The syntax tree root node is passed to the <c>SyntaxWalker.Visit</c> method (really the overridden /// <c>SyntaxVisitor.Visit</c> method. This causes the callback delegate to be called as the tree is traversed. From /// the callback delegate, concrete implementations can write to the <c>Writer</c> to render the nodes, tokens and /// trivia that make up the syntax tree. /// </description></item> /// <item><description> /// Finally, any postfix text is recovered using the <c>GetPostfixText</c> method and is written to the <c>Writer</c>. /// </description></item> /// </list> /// </remarks> /// <param name="writer">The <c>TextWriter</c> which contains the rendered code. It is the responsibility of the /// caller to dispose of the <paramref name="writer" /> when it is no longer needed. </param> /// <param name="codeText">The code text as a <see cref="string" /> instance.</param> /// <exception cref="ArgumentNullException">if <paramref name="writer"/> is null.</exception> public virtual void Render(TextWriter writer, string codeText) { if (writer == null) { throw new ArgumentNullException(nameof(writer), "A non-null TextWriter is required."); } Writer = writer; SyntaxTree = CSharpSyntaxTree.ParseText(codeText ?? string.Empty); // TODO: Formatting no longer provides a extension method on nodes. Move the entire functionality to another namespace. // if (FormatCode) // { // IFormattingResult formattingResult = SyntaxTree.GetRoot().Format(FormattingOptions.GetDefaultOptions()); // CompilationUnitSyntax formattedRoot = (CompilationUnitSyntax)formattingResult.GetFormattedRoot(); // SyntaxTree = SyntaxTree.Create(formattedRoot); // } Compilation compilation = CSharpCompilation.Create("CoreRenderer", syntaxTrees: new List <SyntaxTree> { SyntaxTree }, references: MetadataReferences); SemanticModel = compilation.GetSemanticModel(SyntaxTree); CodeWalker walker = new CodeWalker(); walker.SyntaxVisiting += (s, e) => { if (Callback != null) { Callback(e.SyntaxTreeElement, e.State); } }; Writer.Write(GetPrefixText()); walker.Visit(SyntaxTree.GetRoot()); Writer.Write(GetPostfixText()); }