/// <summary>
        /// Initializes a new instance of the <see cref="CompilerCommandLine"/> struct from a raw PDB-supplied command line.
        /// </summary>
        /// <param name="commandLine">The raw command line from the PDB.</param>
        public CompilerCommandLine(string commandLine)
        {
            //
            // https://msdn.microsoft.com/en-us/library/thxezb7y.aspx
            //

            this.Raw              = commandLine ?? "";
            this.WarningLevel     = 0;
            this.WarningsAsErrors = false;
            var explicitWarnings = new Dictionary <int, WarningState>();

            foreach (string argument in ArgumentSplitter.CommandLineToArgvW(commandLine))
            {
                if (!IsSwitch(argument))
                {
                    continue;
                }

                switch (argument.Length)
                {
                case 2:
                    // /w Disables all compiler warnings.
                    if (argument[1] == 'w')
                    {
                        this.WarningLevel = 0;
                    }
                    break;

                case 3:
                    if (argument[1] == 'W')
                    {
                        char wChar = argument[2];
                        if (wChar == 'X')
                        {
                            // Treats all compiler warnings as errors.
                            this.WarningsAsErrors = true;
                        }
                        else if (wChar >= '0' && wChar <= '4')
                        {
                            // Specifies the level of warning to be generated by the compiler.
                            this.WarningLevel = wChar - '0';
                        }
                    }
                    break;

                case 4:
                    if (argument.EndsWith("WX-"))
                    {
                        // (inverse of) Treats all compiler warnings as errors.
                        this.WarningsAsErrors = false;
                    }
                    break;

                case 5:
                    if (argument.EndsWith("Wall"))
                    {
                        // Displays all /W4 warnings and any other warnings that are not included in /W4
                        this.WarningLevel = 4;
                    }
                    break;

                case 7:
                    if (argument[1] != 'w')
                    {
                        break;
                    }

                    WarningState state;
                    char         mode = argument[2];
                    if (mode == 'd')
                    {
                        // Disables the compiler warning that is specified
                        state = WarningState.Disabled;
                    }
                    else if (mode == 'e')
                    {
                        // Treats as an error the compiler warning that is specified
                        state = WarningState.AsError;
                    }
                    else if (mode == 'o')
                    {
                        // Reports the error only once for the compiler warning that is specified
                        state = WarningState.Once;
                    }
                    else if (mode >= '1' && mode <= '4')
                    {
                        // Specifies the level for a particular warning.
                        // e.g. /w14996 sets 4996 to level 1
                        state = (WarningState)(mode - '1' + (int)WarningState.Level1);
                    }
                    else
                    {
                        break;
                    }

                    int warningNumber;
                    if (!int.TryParse(argument.Remove(0, 3), 0, CultureInfo.InvariantCulture, out warningNumber))
                    {
                        break;
                    }

                    explicitWarnings[warningNumber] = state;
                    break;
                }
            }

            ImmutableArray <int> .Builder explicitlyDisabledBuilder = ImmutableArray.CreateBuilder <int>();
            foreach (KeyValuePair <int, WarningState> entry in explicitWarnings)
            {
                bool isEnabled;
                switch (entry.Value)
                {
                case WarningState.AsError:
                case WarningState.Once:
                    isEnabled = true;
                    break;

                case WarningState.Disabled:
                    isEnabled = false;
                    break;

                case WarningState.Level1:
                    isEnabled = this.WarningLevel >= 1;
                    break;

                case WarningState.Level2:
                    isEnabled = this.WarningLevel >= 2;
                    break;

                case WarningState.Level3:
                    isEnabled = this.WarningLevel >= 3;
                    break;

                case WarningState.Level4:
                    isEnabled = this.WarningLevel >= 4;
                    break;

                default:
                    isEnabled = true;
                    Debug.Fail("Unexpected WarningState");
                    break;
                }

                if (!isEnabled)
                {
                    explicitlyDisabledBuilder.Add(entry.Key);
                }
            }

            explicitlyDisabledBuilder.Sort();
            this.WarningsExplicitlyDisabled = explicitlyDisabledBuilder.ToImmutable();
        }
        /// <summary>
        /// Determine if a switch is set,unset or not present on the command-line.
        /// </summary>
        /// <param name="switchNames">Array of switches that alias each other and all set the same compiler state.</param>
        /// <param name="overrideNames">Array of switches that invalidate the state of the switches in switchNames.</param>
        /// <param name="defaultState">The default state of the switch should no instance of the switch or its overrides be found.</param>
        /// <param name="precedence">The precedence rules for this set of switches.</param>
        public SwitchState GetSwitchState(string[] switchNames, string[] overrideNames, SwitchState defaultState, OrderOfPrecedence precedence)
        {
            // TODO-paddymcd-MSFT - This is an OK first pass.
            // Unfortunately composite switches get tricky and not all switches support the '-' semantics
            // e.g. /O1- gets translated to /O1 /O-, the second of which is not supported.
            // Additionally, currently /d2guardspecload is translated into /guardspecload, which may be a bug for ENC
            SwitchState namedswitchesState = SwitchState.SwitchNotFound;

            if (switchNames != null && switchNames.Length > 0)
            {
                // array of strings for the switch name without the preceding switchPrefix to make comparison easier
                string[] switchArray    = new string[switchNames.Length];
                string[] overridesArray = null;

                SwitchState namedoverridesState = SwitchState.SwitchNotFound;

                for (int index = 0; index < switchNames.Length; index++)
                {
                    // if present remove the slash or minus
                    switchArray[index] = switchNames[index].TrimStart(switchPrefix);
                }

                if (overrideNames != null && overrideNames.Length > 0)
                {
                    overridesArray = new string[overrideNames.Length];

                    for (int index = 0; index < overrideNames.Length; index++)
                    {
                        // if present remove the slash or minus
                        overridesArray[index] = overrideNames[index].TrimStart(switchPrefix);
                    }
                }

                foreach (string arg in ArgumentSplitter.CommandLineToArgvW(this.Raw))
                {
                    if (IsSwitch(arg))
                    {
                        string realArg = arg.TrimStart(switchPrefix);

                        // Check if this matches one of the names switches
                        for (int index = 0; index < switchArray.Length; index++)
                        {
                            if (realArg.StartsWith(switchArray[index]))
                            {
                                // partial stem match - now check if this is a full match or a match with a "-" on the end
                                if (realArg.Equals(switchArray[index]))
                                {
                                    namedswitchesState = SwitchState.SwitchEnabled;
                                    // not necessary at this time, but here for completeness...
                                    namedoverridesState = SwitchState.SwitchDisabled;
                                }
                                else if (realArg[switchArray[index].Length] == '-')
                                {
                                    namedswitchesState = SwitchState.SwitchDisabled;
                                }
                                // Else we have a stem match - do nothing
                            }
                        }

                        // check if this matches one of the named overrides
                        if (overridesArray != null)
                        {
                            for (int index = 0; index < overridesArray.Length; index++)
                            {
                                if (realArg.StartsWith(overridesArray[index]))
                                {
                                    // partial stem match - now check if this is a full match or a match with a "-" on the end
                                    if (realArg.Equals(overridesArray[index]))
                                    {
                                        namedoverridesState = SwitchState.SwitchEnabled;
                                        namedswitchesState  = SwitchState.SwitchDisabled;
                                    }
                                    else if (realArg[overridesArray[index].Length] == '-')
                                    {
                                        namedoverridesState = SwitchState.SwitchDisabled;
                                        // Unsetting an override has no impact upon the named switches
                                    }
                                    // Else we have a stem match - do nothing
                                }
                            }
                        }

                        if (namedswitchesState != SwitchState.SwitchNotFound &&
                            namedoverridesState != SwitchState.SwitchNotFound &&
                            precedence == OrderOfPrecedence.FirstWins)
                        {
                            // we found a switch that impacts the desired state and FirstWins is set
                            break;
                        }
                    }
                }

                if (namedswitchesState == SwitchState.SwitchNotFound)
                {
                    if (namedoverridesState == SwitchState.SwitchEnabled)
                    {
                        namedswitchesState = SwitchState.SwitchDisabled;
                    }
                    else
                    {
                        namedswitchesState = defaultState;
                    }
                }
            }

            return(namedswitchesState);
        }