public Suppression(TextContainer text, int lineNumber) { if (text is null) { throw new ArgumentNullException("text"); } _text = text; _lineNumber = lineNumber; _lineText = _text.GetLineContent(_lineNumber); ParseLine(); }
/// <summary> /// Parse the line of code to find rule suppressors /// </summary> private void ParseLine() { if (_text != null) { _lineText = _text.GetLineContent(_lineNumber); // If the line with the issue doesn't contain a suppression check the lines above it if (!_lineText.Contains(KeywordPrefix)) { if (_lineNumber > 1) { var content = _text.GetLineContent(--_lineNumber); if (content.Contains(Language.GetCommentSuffix(_text.Language))) { while (_lineNumber >= 1) { if (reg.IsMatch(_text.GetLineContent(_lineNumber))) { _lineText = _text.GetLineContent(_lineNumber); break; } else if (_text.GetLineContent(_lineNumber).Contains(Language.GetCommentPrefix(_text.Language))) { break; } _lineNumber--; } } else if (content.Contains(Language.GetCommentInline(_text.Language))) { _lineText = content; } } } } Match match = reg.Match(_lineText); if (match.Success) { _suppressStart = match.Index; _suppressLength = match.Length; string idString = match.Groups[1].Value.Trim(); IssuesListIndex = match.Groups[1].Index; // Parse date if (match.Groups.Count > 2) { string date = match.Groups[2].Value; reg = new Regex(@"(\d{4}-\d{2}-\d{2})"); Match m = reg.Match(date); if (m.Success) { try { _expirationDate = DateTime.ParseExact(m.Value, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture); } catch (FormatException) { _expirationDate = DateTime.MinValue; } } } // parse Ids. if (idString == KeywordAll) { _issues.Add(new SuppressedIssue() { ID = KeywordAll, Boundary = new Boundary() { Index = IssuesListIndex, Length = KeywordAll.Length } }); } else { string[] ids = idString.Split(','); int index = IssuesListIndex; foreach (string id in ids) { _issues.Add(new SuppressedIssue() { ID = id, Boundary = new Boundary() { Index = index, Length = id.Length } }); index += id.Length + 1; } } } }
/// <summary> /// Analyzes given line of code /// </summary> /// <param name="text">Source code</param> /// <param name="languages">List of languages</param> /// <returns>Array of matches</returns> public Issue[] Analyze(string text, string[] languages) { // Get rules for the given content type IEnumerable <Rule> rules = GetRulesForLanguages(languages); List <Issue> resultsList = new List <Issue>(); TextContainer textContainer = new TextContainer(text, (languages.Length > 0) ? languages[0] : string.Empty); // Go through each rule foreach (Rule rule in rules) { List <Issue> matchList = new List <Issue>(); // Skip rules that don't apply based on settings if (rule.Disabled || !SeverityLevel.HasFlag(rule.Severity)) { continue; } // Go through each matching pattern of the rule foreach (SearchPattern pattern in rule.Patterns) { // Get all matches for the patttern List <Boundary> matches = textContainer.MatchPattern(pattern); if (matches.Count > 0) { foreach (Boundary match in matches) { bool passedConditions = true; foreach (SearchCondition condition in rule.Conditions) { bool res = textContainer.MatchPattern(condition.Pattern, match, condition); if (res && condition.NegateFinding) { passedConditions = false; break; } if (!res && condition.NegateFinding) { passedConditions = true; break; } if (!res) { passedConditions = false; break; } } if (passedConditions) { Issue issue = new Issue() { Boundary = match, StartLocation = textContainer.GetLocation(match.Index), EndLocation = textContainer.GetLocation(match.Index + match.Length), Rule = rule }; matchList.Add(issue); } } } } // We got matching rule and suppression are enabled, // let's see if we have a supression on the line if (EnableSuppressions && matchList.Count > 0) { Suppression supp; foreach (Issue result in matchList) { supp = new Suppression(textContainer.GetLineContent(result.StartLocation.Line)); // If rule is NOT being suppressed then report it SuppressedIssue supissue = supp.GetSuppressedIssue(result.Rule.Id); if (supissue == null) { resultsList.Add(result); } // Otherwise add the suppression info instead else { Boundary bound = textContainer.GetLineBoundary(result.Boundary.Index); bound.Index += supissue.Boundary.Index; bound.Length = supissue.Boundary.Length; //resultsList.Add(); Issue info = new Issue() { IsSuppressionInfo = true, Boundary = bound, StartLocation = textContainer.GetLocation(bound.Index), EndLocation = textContainer.GetLocation(bound.Index + bound.Length), Rule = result.Rule }; // Add info only if it's not exists on the same location if (resultsList.FirstOrDefault(x => x.Rule.Id == info.Rule.Id && x.Boundary.Index == info.Boundary.Index) == null) { resultsList.Add(info); } } } } // Otherwise put matchlist to resultlist else { resultsList.AddRange(matchList); } } // Deal with overrides List <Issue> removes = new List <Issue>(); foreach (Issue m in resultsList) { if (m.Rule.Overrides != null && m.Rule.Overrides.Length > 0) { foreach (string ovrd in m.Rule.Overrides) { // Find all overriden rules and mark them for removal from issues list foreach (Issue om in resultsList.FindAll(x => x.Rule.Id == ovrd)) { if (om.Boundary.Index >= m.Boundary.Index && om.Boundary.Index <= m.Boundary.Index + m.Boundary.Length) { removes.Add(om); } } } } } // Remove overriden rules resultsList.RemoveAll(x => removes.Contains(x)); return(resultsList.ToArray()); }