提交 cc4c8209 编写于 作者: N Nick Guerrera

Adjust ErrorLogger to conform to current SARIF draft

See https://github.com/sarif-standard/sarif-spec

* Change structure from:
   {
      "version": <version>,
      "toolInfo": <toolInfo>,
      "issues": [ <issue>* ]
   }

to:
    {
      "version": <version>,
      "runLogs": [
        {
          "toolInfo": <toolInfo>,
          "issues": [ <issue>* ]
        }
      ]
    }

* Flatten custom properties to conform to requirement for all issue
property values to be strings:

   "customProperties": { "a": "b", "c": "d" }
-> "customProperties.a": "b", "customProperties.c": "d"

* Rename toolName -> name

* Rename productVersion -> version

* Let original fileVersion through without trimming off 4th part

* Use actual URI syntax for "uri" elements

* Make region start/end line/column 1-based
上级 421121ce
......@@ -46,7 +46,9 @@ public static void Main(string[] args)
var expectedHeader = GetExpectedErrorLogHeader(actualOutput, cmd);
var expectedIssues = @"
""issues"": [
""issues"": [
]
}
]
}";
var expectedText = expectedHeader + expectedIssues;
......@@ -83,52 +85,54 @@ public class C
var expectedHeader = GetExpectedErrorLogHeader(actualOutput, cmd);
var expectedIssues = string.Format(@"
""issues"": [
{{
""ruleId"": ""CS0169"",
""locations"": [
""issues"": [
{{
""analysisTarget"": [
""ruleId"": ""CS0169"",
""locations"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 3,
""startColumn"": 16,
""endLine"": 3,
""endColumn"": 17
}}
""analysisTarget"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 4,
""startColumn"": 17,
""endLine"": 4,
""endColumn"": 18
}}
}}
]
}}
]
],
""fullMessage"": ""The field 'C.x' is never used"",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""3"",
""defaultSeverity"": ""Warning"",
""title"": ""Field is never used"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""CS5001"",
""locations"": [
],
""fullMessage"": ""Program does not contain a static 'Main' method suitable for an entry point"",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
}}
],
""fullMessage"": ""The field 'C.x' is never used"",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""3"",
""defaultSeverity"": ""Warning"",
""title"": ""Field is never used"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""CS5001"",
""locations"": [
],
""fullMessage"": ""Program does not contain a static 'Main' method suitable for an entry point"",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
]
}}
]
}}", AnalyzerForErrorLogTest.EscapeDirectorySeparatorChar(sourceFile));
}}", AnalyzerForErrorLogTest.GetEscapedUriForPath(sourceFile));
var expectedText = expectedHeader + expectedIssues;
Assert.Equal(expectedText, actualOutput);
......@@ -167,52 +171,54 @@ public class C
var expectedHeader = GetExpectedErrorLogHeader(actualOutput, cmd);
var expectedIssues = string.Format(@"
""issues"": [
{{
""ruleId"": ""CS0169"",
""locations"": [
""issues"": [
{{
""analysisTarget"": [
""ruleId"": ""CS0169"",
""locations"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 4,
""startColumn"": 16,
""endLine"": 4,
""endColumn"": 17
}}
""analysisTarget"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 5,
""startColumn"": 17,
""endLine"": 5,
""endColumn"": 18
}}
}}
]
}}
]
],
""fullMessage"": ""The field 'C.x' is never used"",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""3"",
""defaultSeverity"": ""Warning"",
""title"": ""Field is never used"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""True"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""CS5001"",
""locations"": [
],
""fullMessage"": ""Program does not contain a static 'Main' method suitable for an entry point"",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
}}
],
""fullMessage"": ""The field 'C.x' is never used"",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""3"",
""defaultSeverity"": ""Warning"",
""title"": ""Field is never used"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""True"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""CS5001"",
""locations"": [
],
""fullMessage"": ""Program does not contain a static 'Main' method suitable for an entry point"",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
]
}}
]
}}", AnalyzerForErrorLogTest.EscapeDirectorySeparatorChar(sourceFile));
}}", AnalyzerForErrorLogTest.GetEscapedUriForPath(sourceFile));
var expectedText = expectedHeader + expectedIssues;
Assert.Equal(expectedText, actualOutput);
......
......@@ -11,9 +11,10 @@ private static class WellKnownStrings
{
public const string OutputFormatVersion = "version";
public const string ToolFileVersion = "fileVersion";
public const string ToolAssemblyVersion = "productVersion";
public const string ToolAssemblyVersion = "version";
public const string ToolInfo = "toolInfo";
public const string ToolName = "toolName";
public const string ToolName = "name";
public const string RunLogs = "runLogs";
public const string Issues = "issues";
public const string DiagnosticId = "ruleId";
public const string Locations = "locations";
......@@ -22,7 +23,7 @@ private static class WellKnownStrings
public const string IsSuppressedInSource = "isSuppressedInSource";
public const string Properties = "properties";
public const string Location = "analysisTarget";
public const string LocationSyntaxTreePath = "uri";
public const string LocationSyntaxTreeUri = "uri";
public const string LocationSpanInfo = "region";
public const string LocationSpanStartLine = "startLine";
public const string LocationSpanStartColumn = "startColumn";
......
......@@ -14,6 +14,8 @@ namespace Microsoft.CodeAnalysis
/// <summary>
/// Used for logging all compiler diagnostics into a given <see cref="Stream"/>.
/// This logger is responsible for closing the given stream on <see cref="Dispose"/>.
/// The log format is SARIF (Static Analysis Results Interchange Format)
/// https://github.com/sarif-standard/sarif-spec
/// </summary>
internal partial class ErrorLogger : IDisposable
{
......@@ -51,8 +53,13 @@ private void WriteHeader(string toolName, string toolFileVersion, Version toolAs
WriteSimpleKeyValuePair(WellKnownStrings.OutputFormatVersion, OutputFormatVersion, isFirst: true);
WriteKey(WellKnownStrings.RunLogs, isFirst: false);
StartList();
StartNewEntry(isFirst: true);
StartGroup();
var toolInfo = GetToolInfo(toolName, toolFileVersion, toolAssemblyVersion);
WriteKeyValuePair(WellKnownStrings.ToolInfo, toolInfo, isFirst: false);
WriteKeyValuePair(WellKnownStrings.ToolInfo, toolInfo, isFirst: true);
WriteKey(WellKnownStrings.Issues, isFirst: false);
StartList();
......@@ -63,30 +70,10 @@ private Value GetToolInfo(string toolName, string toolFileVersion, Version toolA
var builder = ArrayBuilder<KeyValuePair<string, Value>>.GetInstance();
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.ToolName, toolName));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.ToolAssemblyVersion, toolAssemblyVersion.ToString(fieldCount: 3)));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.ToolFileVersion, GetToolFileVersionSubStr(toolFileVersion)));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.ToolFileVersion, toolFileVersion));
return Value.Create(builder.ToImmutableAndFree(), this);
}
private string GetToolFileVersionSubStr(string toolFileVersion)
{
// Our log format specifies that fileVersion can have at most 3 fields.
int count = 0;
for (int i = 0; i < toolFileVersion.Length; i++)
{
if (toolFileVersion[i] == '.')
{
if (count == 2)
{
return toolFileVersion.Substring(0, i);
}
count++;
}
}
return toolFileVersion;
}
internal static void LogDiagnostic(Diagnostic diagnostic, CultureInfo culture, ErrorLogger errorLogger)
{
......@@ -170,7 +157,7 @@ private Value GetLocationValue(Location location)
}
var builder = ArrayBuilder<KeyValuePair<string, Value>>.GetInstance();
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSyntaxTreePath, location.SourceTree.FilePath));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSyntaxTreeUri, GetUri(location.SourceTree)));
var spanInfoValue = GetSpanInfoValue(location.GetLineSpan());
builder.Add(KeyValuePair.Create(WellKnownStrings.LocationSpanInfo, spanInfoValue));
......@@ -183,13 +170,30 @@ private Value GetLocationValue(Location location)
return Value.Create(ImmutableArray.Create(wrapperKvp), this);
}
private static string GetUri(SyntaxTree syntaxTree)
{
Uri uri;
if (!Uri.TryCreate(syntaxTree.FilePath, UriKind.RelativeOrAbsolute, out uri))
{
// The only constraint on SyntaxTree.FilePath is that it can be interpreted by
// various resolvers so there is no guarantee we can turn the arbitrary string
// in to a URI. If our attempt to do so fails, use the original string as the
// "URI".
return syntaxTree.FilePath;
}
return uri.ToString();
}
private Value GetSpanInfoValue(FileLinePositionSpan lineSpan)
{
// Note that SARIF region lines and columns are specified to be 1-based, but FileLinePositionSpan.Line and Character are 0-based.
var builder = ArrayBuilder<KeyValuePair<string, Value>>.GetInstance();
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanStartLine, lineSpan.StartLinePosition.Line));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanStartColumn, lineSpan.StartLinePosition.Character));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanEndLine, lineSpan.EndLinePosition.Line));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanEndColumn, lineSpan.EndLinePosition.Character));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanStartLine, lineSpan.StartLinePosition.Line + 1));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanStartColumn, lineSpan.StartLinePosition.Character + 1));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanEndLine, lineSpan.EndLinePosition.Line + 1));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.LocationSpanEndColumn, lineSpan.EndLinePosition.Character + 1));
return Value.Create(builder.ToImmutableAndFree(), this);
}
......@@ -225,16 +229,9 @@ private Value GetPropertiesValue(Issue issue)
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.CustomTags, issue.CustomTags.WhereNotNull().Join(";")));
}
if (issue.CustomProperties.Length > 0)
foreach (var kvp in issue.CustomProperties)
{
var customPropertiesBuilder = ArrayBuilder<KeyValuePair<string, Value>>.GetInstance();
foreach (var kvp in issue.CustomProperties)
{
customPropertiesBuilder.Add(CreateSimpleKeyValuePair(kvp.Key, kvp.Value));
}
var customPropertiesValue = Value.Create(customPropertiesBuilder.ToImmutableAndFree(), this);
builder.Add(KeyValuePair.Create(WellKnownStrings.CustomProperties, customPropertiesValue));
builder.Add(CreateSimpleKeyValuePair(WellKnownStrings.CustomProperties + "." + kvp.Key, kvp.Value));
}
return Value.Create(builder.ToImmutableAndFree(), this);
......@@ -362,6 +359,12 @@ public void Dispose()
// End issues list.
EndList();
// End runLog entry.
EndGroup();
// End runLogs list.
EndList();
// End dictionary for log file key-value pairs.
EndGroup();
......
......@@ -46,7 +46,9 @@ End Class
Dim expectedHeader = GetExpectedErrorLogHeader(actualOutput, cmd)
Dim expectedIssues = "
""issues"": [
""issues"": [
]
}
]
}"
......@@ -89,52 +91,54 @@ End Class
Dim expectedHeader = GetExpectedErrorLogHeader(actualOutput, cmd)
Dim expectedIssues = String.Format("
""issues"": [
{{
""ruleId"": ""BC42024"",
""locations"": [
""issues"": [
{{
""analysisTarget"": [
""ruleId"": ""BC42024"",
""locations"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 3,
""startColumn"": 12,
""endLine"": 3,
""endColumn"": 13
}}
""analysisTarget"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 4,
""startColumn"": 13,
""endLine"": 4,
""endColumn"": 14
}}
}}
]
}}
]
],
""fullMessage"": ""Unused local variable: 'x'."",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""1"",
""defaultSeverity"": ""Warning"",
""title"": ""Unused local variable"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""BC30420"",
""locations"": [
],
""fullMessage"": ""'Sub Main' was not found in '{1}'."",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
}}
],
""fullMessage"": ""Unused local variable: 'x'."",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""1"",
""defaultSeverity"": ""Warning"",
""title"": ""Unused local variable"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""BC30420"",
""locations"": [
],
""fullMessage"": ""'Sub Main' was not found in '{1}'."",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
]
}}
]
}}", AnalyzerForErrorLogTest.EscapeDirectorySeparatorChar(sourceFilePath), Path.GetFileNameWithoutExtension(sourceFilePath))
}}", AnalyzerForErrorLogTest.GetEscapedUriForPath(sourceFilePath), Path.GetFileNameWithoutExtension(sourceFilePath))
Dim expectedText = expectedHeader + expectedIssues
Assert.Equal(expectedText, actualOutput)
......@@ -178,52 +182,54 @@ End Class
Dim expectedHeader = GetExpectedErrorLogHeader(actualOutput, cmd)
Dim expectedIssues = String.Format("
""issues"": [
{{
""ruleId"": ""BC42024"",
""locations"": [
""issues"": [
{{
""analysisTarget"": [
""ruleId"": ""BC42024"",
""locations"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 4,
""startColumn"": 12,
""endLine"": 4,
""endColumn"": 13
}}
""analysisTarget"": [
{{
""uri"": ""{0}"",
""region"": {{
""startLine"": 5,
""startColumn"": 13,
""endLine"": 5,
""endColumn"": 14
}}
}}
]
}}
]
],
""fullMessage"": ""Unused local variable: 'x'."",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""1"",
""defaultSeverity"": ""Warning"",
""title"": ""Unused local variable"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""True"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""BC30420"",
""locations"": [
],
""fullMessage"": ""'Sub Main' was not found in '{1}'."",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
}}
],
""fullMessage"": ""Unused local variable: 'x'."",
""properties"": {{
""severity"": ""Warning"",
""warningLevel"": ""1"",
""defaultSeverity"": ""Warning"",
""title"": ""Unused local variable"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""True"",
""customTags"": ""Compiler;Telemetry""
}}
}},
{{
""ruleId"": ""BC30420"",
""locations"": [
],
""fullMessage"": ""'Sub Main' was not found in '{1}'."",
""properties"": {{
""severity"": ""Error"",
""defaultSeverity"": ""Error"",
""category"": ""Compiler"",
""isEnabledByDefault"": ""True"",
""isSuppressedInSource"": ""False"",
""customTags"": ""Compiler;Telemetry;NotConfigurable""
}}
]
}}
]
}}", AnalyzerForErrorLogTest.EscapeDirectorySeparatorChar(sourceFilePath), Path.GetFileNameWithoutExtension(sourceFilePath))
}}", AnalyzerForErrorLogTest.GetEscapedUriForPath(sourceFilePath), Path.GetFileNameWithoutExtension(sourceFilePath))
Dim expectedText = expectedHeader + expectedIssues
Assert.Equal(expectedText, actualOutput)
......
......@@ -64,25 +64,15 @@ public override void Initialize(AnalysisContext context)
private static string GetExpectedPropertiesMapText()
{
var isFirst = true;
var expectedText = @",
""customProperties"": {";
var expectedText = "";
foreach (var kvp in s_properties.OrderBy(kvp => kvp.Key))
{
if (!isFirst)
{
expectedText += ",";
}
expectedText += ",";
expectedText += string.Format(@"
""{0}"": ""{1}""", kvp.Key, kvp.Value);
isFirst = false;
""customProperties.{0}"": ""{1}""", kvp.Key, kvp.Value);
}
expectedText += @"
}";
return expectedText;
}
......@@ -91,67 +81,69 @@ public static string GetExpectedErrorLogIssuesText(Compilation compilation)
var tree = compilation.SyntaxTrees.First();
var root = tree.GetRoot();
var expectedLineSpan = root.GetLocation().GetLineSpan();
var filePath = EscapeDirectorySeparatorChar(tree.FilePath);
var filePath = GetEscapedUriForPath(tree.FilePath);
return @"
""issues"": [
{
""ruleId"": """ + Descriptor1.Id + @""",
""locations"": [
""issues"": [
{
""analysisTarget"": [
""ruleId"": """ + Descriptor1.Id + @""",
""locations"": [
{
""uri"": """ + filePath + @""",
""region"": {
""startLine"": " + expectedLineSpan.StartLinePosition.Line + @",
""startColumn"": " + expectedLineSpan.StartLinePosition.Character + @",
""endLine"": " + expectedLineSpan.EndLinePosition.Line + @",
""endColumn"": " + expectedLineSpan.EndLinePosition.Character + @"
}
""analysisTarget"": [
{
""uri"": """ + filePath + @""",
""region"": {
""startLine"": " + (expectedLineSpan.StartLinePosition.Line + 1) + @",
""startColumn"": " + (expectedLineSpan.StartLinePosition.Character + 1) + @",
""endLine"": " + (expectedLineSpan.EndLinePosition.Line + 1) + @",
""endColumn"": " + (expectedLineSpan.EndLinePosition.Character + 1) + @"
}
}
]
}
]
],
""shortMessage"": """ + Descriptor1.MessageFormat + @""",
""fullMessage"": """ + Descriptor1.Description + @""",
""properties"": {
""severity"": """ + Descriptor1.DefaultSeverity + @""",
""warningLevel"": ""1"",
""defaultSeverity"": """ + Descriptor1.DefaultSeverity + @""",
""title"": """ + Descriptor1.Title + @""",
""category"": """ + Descriptor1.Category + @""",
""helpLink"": """ + Descriptor1.HelpLinkUri + @""",
""isEnabledByDefault"": """ + Descriptor1.IsEnabledByDefault + @""",
""isSuppressedInSource"": ""False"",
""customTags"": """ + Descriptor1.CustomTags.Join(";") + @"""" +
GetExpectedPropertiesMapText() + @"
}
},
{
""ruleId"": """ + Descriptor2.Id + @""",
""locations"": [
],
""shortMessage"": """ + Descriptor2.MessageFormat + @""",
""fullMessage"": """ + Descriptor2.Description + @""",
""properties"": {
""severity"": """ + Descriptor2.DefaultSeverity + @""",
""defaultSeverity"": """ + Descriptor2.DefaultSeverity + @""",
""title"": """ + Descriptor2.Title + @""",
""category"": """ + Descriptor2.Category + @""",
""helpLink"": """ + Descriptor2.HelpLinkUri + @""",
""isEnabledByDefault"": """ + Descriptor2.IsEnabledByDefault + @""",
""isSuppressedInSource"": ""False"",
""customTags"": """ + Descriptor2.CustomTags.Join(";") + @"""" +
GetExpectedPropertiesMapText() + @"
}
}
],
""shortMessage"": """ + Descriptor1.MessageFormat + @""",
""fullMessage"": """ + Descriptor1.Description + @""",
""properties"": {
""severity"": """ + Descriptor1.DefaultSeverity + @""",
""warningLevel"": ""1"",
""defaultSeverity"": """ + Descriptor1.DefaultSeverity + @""",
""title"": """ + Descriptor1.Title + @""",
""category"": """ + Descriptor1.Category + @""",
""helpLink"": """ + Descriptor1.HelpLinkUri + @""",
""isEnabledByDefault"": """ + Descriptor1.IsEnabledByDefault + @""",
""isSuppressedInSource"": ""False"",
""customTags"": """ + Descriptor1.CustomTags.Join(";") + @"""" +
GetExpectedPropertiesMapText() + @"
}
},
{
""ruleId"": """ + Descriptor2.Id + @""",
""locations"": [
],
""shortMessage"": """ + Descriptor2.MessageFormat + @""",
""fullMessage"": """ + Descriptor2.Description + @""",
""properties"": {
""severity"": """ + Descriptor2.DefaultSeverity + @""",
""defaultSeverity"": """ + Descriptor2.DefaultSeverity + @""",
""title"": """ + Descriptor2.Title + @""",
""category"": """ + Descriptor2.Category + @""",
""helpLink"": """ + Descriptor2.HelpLinkUri + @""",
""isEnabledByDefault"": """ + Descriptor2.IsEnabledByDefault + @""",
""isSuppressedInSource"": ""False"",
""customTags"": """ + Descriptor2.CustomTags.Join(";") + @"""" +
GetExpectedPropertiesMapText() + @"
}
]
}
]
}";
}
public static string EscapeDirectorySeparatorChar(string input)
public static string GetEscapedUriForPath(string path)
{
return input.Replace(Path.DirectorySeparatorChar.ToString(), @"\" + Path.DirectorySeparatorChar);
return new Uri(path, UriKind.RelativeOrAbsolute).ToString().Replace("/", "\\/");
}
}
......
......@@ -292,16 +292,17 @@ internal static string GetExpectedErrorLogHeader(string actualOutput, CommonComp
{
var expectedToolName = compiler.GetToolName();
var expectedProductVersion = compiler.GetAssemblyVersion().ToString(fieldCount: 3);
var fileVersion = compiler.GetAssemblyFileVersion();
var expectedFileVersion = fileVersion.Substring(0, fileVersion.LastIndexOf('.'));
var expectedFileVersion = compiler.GetAssemblyFileVersion();
return string.Format(@"{{
""version"": ""{0}"",
""toolInfo"": {{
""toolName"": ""{1}"",
""productVersion"": ""{2}"",
""fileVersion"": ""{3}""
}},", ErrorLogger.OutputFormatVersion, expectedToolName, expectedProductVersion, expectedFileVersion);
""runLogs"": [
{{
""toolInfo"": {{
""name"": ""{1}"",
""version"": ""{2}"",
""fileVersion"": ""{3}""
}},", ErrorLogger.OutputFormatVersion, expectedToolName, expectedProductVersion, expectedFileVersion);
}
public static string Stringize(this Diagnostic e)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册