Files
codeql/csharp/autobuilder/Semmle.Autobuild.Shared/DiagnosticClassifier.cs
2023-03-03 13:05:27 +00:00

97 lines
3.5 KiB
C#

using System.Collections.Generic;
using System.Text.RegularExpressions;
using Semmle.Util;
namespace Semmle.Autobuild.Shared
{
/// <summary>
/// Direct results result from the successful application of a <see cref="DiagnosticRule" />,
/// which can later be converted to a corresponding <see cref="DiagnosticMessage" />.
/// </summary>
public interface IDiagnosticsResult
{
/// <summary>
/// Produces a <see cref="DiagnosticMessage" /> corresponding to this result.
/// </summary>
/// <param name="builder">
/// The autobuilder to use for constructing the base <see cref="DiagnosticMessage" />.
/// </param>
/// <param name="severity">
/// An optional severity value which overrides the default severity of the diagnostic.
/// </param>
/// <returns>The <see cref="DiagnosticMessage" /> corresponding to this result.</returns>
DiagnosticMessage ToDiagnosticMessage<T>(Autobuilder<T> builder, DiagnosticMessage.TspSeverity? severity = null) where T : AutobuildOptionsShared;
}
public class DiagnosticRule
{
/// <summary>
/// The pattern against which this rule matches build output.
/// </summary>
public Regex Pattern { get; }
/// <summary>
/// Constructs a diagnostic rule for the given <paramref name="pattern" />.
/// </summary>
/// <param name="pattern"></param>
public DiagnosticRule(Regex pattern)
{
this.Pattern = pattern;
}
/// <summary>
/// Constructs a diagnostic rule for the given regular expression <paramref name="pattern" />.
/// </summary>
/// <param name="pattern"></param>
public DiagnosticRule(string pattern)
{
this.Pattern = new Regex(pattern, RegexOptions.Compiled);
}
/// <summary>
/// Used by a <see cref="DiagnosticClassifier" /> <paramref name="classifier" /> to
/// signal that the rule has matched some build output with <paramref name="match" />.
/// </summary>
/// <param name="classifier">The classifier which is firing the rule.</param>
/// <param name="match">The <see cref="Match" /> that resulted from applying the rule.</param>
public virtual void Fire(DiagnosticClassifier classifier, Match match) { }
}
public class DiagnosticClassifier
{
private readonly List<DiagnosticRule> rules;
public readonly List<IDiagnosticsResult> Results;
public DiagnosticClassifier()
{
this.rules = new List<DiagnosticRule>();
this.Results = new List<IDiagnosticsResult>();
}
/// <summary>
/// Adds <paramref name="rule" /> to this classifier.
/// </summary>
/// <param name="rule">The rule to add.</param>
protected void AddRule(DiagnosticRule rule)
{
this.rules.Add(rule);
}
/// <summary>
/// Applies all of this classifier's rules to <paramref name="line" /> to see which match.
/// </summary>
/// <param name="line">The line to which the rules should be applied to.</param>
public void ClassifyLine(string line)
{
this.rules.ForEach(rule =>
{
var match = rule.Pattern.Match(line);
if (match.Success)
{
rule.Fire(this, match);
}
});
}
}
}