Click here to Skip to main content
15,891,431 members
Articles / Programming Languages / C#

Resolving Symbolic References in a CodeDOM (Part 7)

Rate me:
Please Sign up or sign in to vote.
4.75/5 (6 votes)
2 Dec 2012CDDL12 min read 19.4K   509   14  
Resolving symbolic references in a CodeDOM.
// Nova.CLI - a command-line interface for Nova.CodeDOM.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;

using Nova.CodeDOM;
using Nova.Utilities;

namespace Nova.CLI
{
    /// <summary>
    /// This program is a command-line interface for the Nova.CodeDOM C# object model library.
    /// </summary>
    class Program
    {
        static void Main(string[] arguments)
        {
            int exitCode = 0;
            try
            {
                // Determine the application name and if we're running in VS
                string appName = AppDomain.CurrentDomain.FriendlyName;
                if (appName.EndsWith(".exe"))
                    appName = appName.Substring(0, appName.Length - 4);
                if (appName.EndsWith(".vshost"))
                    appName = appName.Substring(0, appName.Length - 7);
                bool waitBeforeExiting = Debugger.IsAttached;

                bool spawned = StringUtil.Contains(arguments, "/spawned");
                if (!spawned)
                {
                    Version appVersion = typeof(Program).Assembly.GetName().Version;
                    string appDescription = appName + " " + appVersion.Major + "." + appVersion.Minor;
                    Console.WriteLine(appDescription + "  -  C# CodeDOM command-line utility.\nCopyright (C) 2011-2012 Inevitable Software, all rights reserved.");
                }

                // Process the command-line arguments
                if (arguments == null || arguments.Length == 0 || (arguments.Length == 1 && arguments[0] == "/?"))
                {
                    Console.WriteLine("\nUsage: " + appName + " <file> [<file> ...] [<option> ...]\n"
                        + "                ('<file>' can be a solution, project, or source file)\n"
                        + "                A file can be optionally suffixed with a configuration\n"
                        + "                and platform, such as: <file>|Release\n"
                        + "                Or: <file>|Debug|\"Any CPU\"\n"
                        + "\n"
                        + "\tGeneral options:\n"
                        + "\t/donotresolve - Load and parse sources, but don't resolve\n"
                        + "\t/loadonly     - Load, but don't parse or resolve sources\n"
                        + "\t/save         - Save all files after loading is complete\n"
                        + "\t/detail       - Detailed log messages\n"
                        + "\t/minimal      - Minimal log messages, and no code messages\n"
                        + "\t/spawn        - Load each specified file using a child process\n"
                        + "\t/wait         - Wait for key press when done before exiting\n"
                        + "\t/waitfail     - Wait for key press when done if any check option failed\n"
                        + "\t/config:\"C|P\" - Apply the configuration (Debug, Release, etc) and\n"
                        + "\t                optional platform (Any CPU, Mixed Platforms, x86, etc)\n"
                        + "\t                to ALL files. Such as: /config:Release\n"
                        + "\t                Or: /config:\"Debug|Any CPU\"\n"
                        + "\t/donotparsebodies   - Don't parse method bodies\n"
                        + "\t/donotresolvebodies - Don't resolve method bodies\n"
                        + "\n"
                        + "\tOptions for the preceeding file only:\n"
                        + "\t/check:E,W,C  - Check message counts (E=errors, W=warnings, C=comments)\n"
                        );
                }
                else
                    exitCode = ProcessArguments(arguments, appName, ref waitBeforeExiting);

                // Wait for a key press before exiting if requested
                if (waitBeforeExiting)
                {
                    Console.WriteLine("\nPress any key to exit.");
                    Console.ReadKey();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("EXCEPTION: " + ex);
            }

            Environment.Exit(exitCode);
        }

        private static int ProcessArguments(string[] arguments, string appName, ref bool waitBeforeExiting)
        {
            bool spawn = false;
            bool spawned = false;
            string spawnArguments = null;
            bool save = false;
            bool waitIfChecksFail = false;
            LoadOptions loadOptions = LoadOptions.Complete;
            string configuration = null;
            string platform = null;

            // Process any options first
            foreach (string argument in arguments)
            {
                // Look only at options here
                if (argument.StartsWith("/config:"))
                    GetConfigurationAndPlatform(argument.Substring(8), out configuration, out platform);
                else if (argument.StartsWith("/") && !argument.StartsWith("/check:"))
                {
                    switch (argument.Substring(1).ToLower())
                    {
                        case "donotresolve": loadOptions &= ~LoadOptions.ResolveSources; break;
                        case "loadonly": loadOptions &= ~(LoadOptions.ParseSources | LoadOptions.ResolveSources); break;
                        case "donotparsebodies": loadOptions |= LoadOptions.DoNotParseBodies; break;
                        case "donotresolvebodies": loadOptions |= LoadOptions.DoNotResolveBodies; break;
                        case "save": save = true; break;
                        case "detail": Log.LogLevel = Log.Level.Detailed; break;
                        case "minimal": Log.LogLevel = Log.Level.Minimal; break;
                        case "spawn":
                            spawn = true;
                            spawnArguments = Enumerable.Aggregate(Enumerable.Where(arguments,
                                delegate(string arg) { return arg.StartsWith("/") && arg != "/spawn" && arg != "/wait" && !arg.StartsWith("/check:"); }), spawnArguments,
                                delegate(string current, string arg) { return current + (arg + " "); }) + "/spawned";
                            Log.WriteLine("Spawning each load in a separate child process...");
                            break;
                        case "wait": waitBeforeExiting = true; break;
                        case "waitfail": waitIfChecksFail = true; break;
                        case "spawned": spawned = true; Configuration.LogSettings = false; break;
                        default:
                            Log.WriteLine("Option '" + argument + "' not recognized (use no arguments to get a list of valid ones)."); break;
                    }
                }
            }

            // Process any specified solution, project, or source files
            int fileCount = 0, checkCount = 0, failCount = 0;
            int errorCount = 0, warningCount = 0, commentCount = 0;
            for (int index = 0; index < arguments.Length; ++index)
            {
                string argument = arguments[index];
                if (!argument.StartsWith("/"))  // Ignore options at this point
                {
                    if (spawn)
                    {
                        // If so requested, run each file load in a separate child process
                        Log.WriteLine("");
                        string spawnArgs = "\"" + argument + "\" ";
                        bool checkMessageCounts = false;
                        if (arguments[index + 1].StartsWith("/check:"))
                        {
                            ++index;
                            spawnArgs += arguments[index] + " ";
                            checkMessageCounts = true;
                        }
                        spawnArgs += spawnArguments;
                        Process process = new Process { StartInfo = { FileName = appName + ".exe", Arguments = spawnArgs, UseShellExecute = false } };
                        process.Start();
                        process.WaitForExit();
                        if (checkMessageCounts)
                        {
                            ++checkCount;
                            if (process.ExitCode != 0)
                                ++failCount;
                        }
                    }
                    else
                    {
                        if (!spawned)
                            Log.WriteLine("");
                        if (Log.LogLevel == Log.Level.Detailed)
                        {
                            GC.Collect();
                            Log.DetailWriteLine("Before Heap Size = " + (int)(GC.GetTotalMemory(true) / (1024 * 1024)) + " MBs");
                        }

                        // Strip any trailing config
                        string[] parts = argument.Split('|');
                        string fileConfiguration = configuration;
                        string filePlatform = platform;
                        if (parts.Length > 1)
                        {
                            fileConfiguration = parts[1];
                            filePlatform = (parts.Length > 2 ? parts[2] : null);
                        }

                        // Get the file extension, defaulting to ".sln" if none
                        string fileName = parts[0];
                        string fileExtension = Path.GetExtension(fileName);
                        if (string.IsNullOrEmpty(fileExtension))
                        {
                            fileExtension = Solution.SolutionFileExtension;
                            fileName += fileExtension;
                        }

                        // Load the specified solution, project, or file
                        loadOptions |= LoadOptions.LogMessages;
                        if (fileExtension == Solution.SolutionFileExtension)
                        {
                            Solution solution = Solution.Load(fileName, fileConfiguration, filePlatform, loadOptions);
                            if (solution != null)
                            {
                                solution.GetMessageCounts(out errorCount, out warningCount, out commentCount);
                                if (save)
                                    solution.SaveAll();
                                solution.Unload();
                            }
                        }
                        else if (fileExtension == Project.CSharpProjectFileExtension)
                        {
                            Project project = Project.Load(fileName, fileConfiguration, filePlatform, loadOptions);
                            if (project != null)
                            {
                                project.Solution.GetMessageCounts(out errorCount, out warningCount, out commentCount);
                                if (save)
                                    project.SaveAll();
                                project.Unload();
                            }
                        }
                        else if (fileExtension == Project.CSharpFileExtension)
                        {
                            CodeUnit codeUnit = CodeUnit.Load(fileName, loadOptions);
                            if (codeUnit != null)
                            {
                                codeUnit.GetMessageCounts(out errorCount, out warningCount, out commentCount);
                                if (save)
                                    codeUnit.Save();
                            }
                        }

                        if (Log.LogLevel == Log.Level.Detailed)
                        {
                            GC.Collect();
                            Log.DetailWriteLine("After Heap Size = " + (int)(GC.GetTotalMemory(true) / (1024 * 1024)) + " MBs");
                        }
                    }
                    ++fileCount;
                }
                else if (argument.StartsWith("/check:"))
                {
                    ++checkCount;
                    bool pass = false;
                    int[] counts = StringUtil.ParseArray<int>(argument.Substring(7), null);
                    if (counts != null && counts.Length > 0)
                    {
                        pass = ((counts[0] == errorCount) && (counts.Length < 2 || counts[1] == warningCount)
                            && (counts.Length < 3 || counts[2] == commentCount));
                    }
                    if (!pass)
                        ++failCount;
                    Log.WriteLine("Check message counts: " + (pass ? "PASS" : "FAIL"));
                }
            }

            Log.WriteLine("");
            if (fileCount > 1)
            {
                GC.Collect();
                Log.WriteLine("DONE!  " + fileCount + " files loaded.  Heap size = " + (int)(GC.GetTotalMemory(true) / (1024 * 1024)) + " MBs");

                if (checkCount > 0)
                {
                    if (!spawned)
                        Log.WriteLine("Checked " + checkCount + ", " + (failCount == 0 ? "all PASSED" : "FAILED " + failCount));
                    if (waitIfChecksFail && failCount > 0)
                        waitBeforeExiting = true;
                }
            }

            return -failCount;
        }

        private static void GetConfigurationAndPlatform(string input, out string configuration, out string platform)
        {
            string[] parts = input.Split('|');
            configuration = parts[0];
            platform = (parts.Length > 1 ? parts[1] : null);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer (Senior)
United States United States
I've been writing software since the late 70's, currently focusing mainly on C#.NET. I also like to travel around the world, and I own a Chocolate Factory (sadly, none of my employees are oompa loompas).

Comments and Discussions