public IssueMatch(IssueMatch runningMatch, IssuePattern pattern, GroupCollection groups, string defaultSeverity = null)
        {
            File     = runningMatch?.File ?? GetValue(groups, pattern.File);
            Line     = runningMatch?.Line ?? GetValue(groups, pattern.Line);
            Column   = runningMatch?.Column ?? GetValue(groups, pattern.Column);
            Severity = runningMatch?.Severity ?? GetValue(groups, pattern.Severity);
            Code     = runningMatch?.Code ?? GetValue(groups, pattern.Code);
            Message  = runningMatch?.Message ?? GetValue(groups, pattern.Message);
            FromPath = runningMatch?.FromPath ?? GetValue(groups, pattern.FromPath);

            if (string.IsNullOrEmpty(Severity) && !string.IsNullOrEmpty(defaultSeverity))
            {
                Severity = defaultSeverity;
            }
        }
        public IssueMatch Match(string line)
        {
            // Single pattern
            if (_patterns.Length == 1)
            {
                var pattern    = _patterns[0];
                var regexMatch = pattern.Regex.Match(line);

                if (regexMatch.Success)
                {
                    return(new IssueMatch(null, pattern, regexMatch.Groups, DefaultSeverity));
                }

                return(null);
            }
            // Multiple patterns
            else
            {
                // Each pattern (iterate in reverse)
                for (int i = _patterns.Length - 1; i >= 0; i--)
                {
                    var runningMatch = i > 0 ? _state[i - 1] : null;

                    // First pattern or a running match
                    if (i == 0 || runningMatch != null)
                    {
                        var pattern    = _patterns[i];
                        var isLast     = i == _patterns.Length - 1;
                        var regexMatch = pattern.Regex.Match(line);

                        // Matched
                        if (regexMatch.Success)
                        {
                            // Last pattern
                            if (isLast)
                            {
                                // Loop
                                if (pattern.Loop)
                                {
                                    // Clear most state, but preserve the running match
                                    Reset();
                                    _state[i - 1] = runningMatch;
                                }
                                // Not loop
                                else
                                {
                                    // Clear the state
                                    Reset();
                                }

                                // Return
                                return(new IssueMatch(runningMatch, pattern, regexMatch.Groups, DefaultSeverity));
                            }
                            // Not the last pattern
                            else
                            {
                                // Store the match
                                _state[i] = new IssueMatch(runningMatch, pattern, regexMatch.Groups);
                            }
                        }
                        // Not matched
                        else
                        {
                            // Last pattern
                            if (isLast)
                            {
                                // Break the running match
                                _state[i - 1] = null;
                            }
                            // Not the last pattern
                            else
                            {
                                // Record not matched
                                _state[i] = null;
                            }
                        }
                    }
                }

                return(null);
            }
        }