private void Verify(string analyzerPath, IEnumerable <string> expectedMessages, params string[] assemblyPaths) { var actualMessages = new List <string>(); var analyzer = ILDiagnosticsAnalyzer.Create(this.GetType().Assembly.Location); foreach (string assemblyPath in assemblyPaths) { analyzer.Analyze(assemblyPath, (d) => actualMessages.Add(d.GetMessage())); } try { actualMessages.ShouldBeEquivalentTo(expectedMessages); } catch { _testOutputHelper.WriteLine("Expected messages:"); foreach (string message in expectedMessages) { _testOutputHelper.WriteLine("\"" + message + "\","); } _testOutputHelper.WriteLine("Actual messages:"); foreach (string message in actualMessages) { _testOutputHelper.WriteLine("\"" + message + "\","); } throw; } }
private void AnalyzeManagedAssembly(string assemblyFilePath, IEnumerable <string> roslynAnalyzerFilePaths, BinaryAnalyzerContext context) { if (roslynAnalyzerFilePaths == null) { return; } if (_globalRoslynAnalysisContext == null) { _globalRoslynAnalysisContext = new RoslynAnalysisContext(); // We could use the ILDiagnosticsAnalyzer factory method that initializes // an object instance from an enumerable collection of analyzer paths. We // initialize a context object from each path one-by-one instead, in order // to make an attempt to load each specified analyzer. We will therefore // collect information on each analyzer that fails to load. We will also // proceed with performing as much analysis as possible. Ultimately, a // single analyzer load failure will return in BinSkim returning a non-zero // failure code from the run. foreach (string analyzerFilePath in roslynAnalyzerFilePaths) { InvokeCatchingRelevantIOExceptions ( action: () => { ILDiagnosticsAnalyzer.LoadAnalyzer(analyzerFilePath, _globalRoslynAnalysisContext); }, exceptionHandler: (ex) => { Errors.LogExceptionLoadingPlugin(analyzerFilePath, context, ex); } ); } } Debug.Assert(context.MimeType == Sarif.Writers.MimeType.Binary); ILDiagnosticsAnalyzer roslynAnalyzer = ILDiagnosticsAnalyzer.Create(_globalRoslynAnalysisContext); roslynAnalyzer.Analyze(assemblyFilePath, diagnostic => { // 0. Populate various members var result = new Result(); result.Level = diagnostic.Severity.ConvertToResultLevel(); result.Message = new Message { Text = diagnostic.GetMessage() }; if (diagnostic.IsSuppressed) { result.SuppressionStates = SuppressionStates.SuppressedInSource; } result.SetProperty("Severity", diagnostic.Severity.ToString()); result.SetProperty("IsWarningAsError", diagnostic.IsWarningAsError.ToString()); result.SetProperty("WarningLevel", diagnostic.WarningLevel.ToString()); foreach (string key in diagnostic.Properties.Keys) { string value; if (result.TryGetProperty(key, out value)) { // If the properties bag recapitulates one of the values set // previously, we'll retain the already set value continue; } result.SetProperty(key, diagnostic.Properties[key]); } result.Locations = new List <Sarif.Location>(); // 1. Record the assembly under analysis result.AnalysisTarget = new ArtifactLocation { Uri = new Uri(assemblyFilePath) }; // 2. Record the actual location associated with the result var region = diagnostic.Location.ConvertToRegion(); string filePath; PhysicalLocation resultFile = null; if (diagnostic.Location != Location.None) { filePath = diagnostic.Location.GetLineSpan().Path; resultFile = new PhysicalLocation { ArtifactLocation = { Uri = new Uri(filePath) }, Region = region }; } result.Locations.Add(new Sarif.Location() { PhysicalLocation = resultFile }); // 3. If present, emit additional locations associated with diagnostic. // According to docs, these locations typically reference related // locations (i.e., they are not locations that specify other // occurrences of a problem). if (diagnostic.AdditionalLocations != null && diagnostic.AdditionalLocations.Count > 0) { result.RelatedLocations = new List <Sarif.Location>(); foreach (Location location in diagnostic.AdditionalLocations) { filePath = location.GetLineSpan().Path; region = location.ConvertToRegion(); result.RelatedLocations.Add(new Sarif.Location { Message = new Message { Text = "Additional location" }, PhysicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri(filePath) }, Region = region } }); } } ReportingDescriptor rule = diagnostic.ConvertToRuleDescriptor(); context.Logger.Log(null, result); }); }
private void AnalyzeManagedAssembly(string assemblyFilePath, IEnumerable <string> roslynAnalyzerFilePaths, BinaryAnalyzerContext context) { if (roslynAnalyzerFilePaths == null) { return; } if (_globalRoslynAnalysisContext == null) { _globalRoslynAnalysisContext = new RoslynAnalysisContext(); // We could use the ILDiagnosticsAnalyzer factory method that initializes // an object instance from an enumerable collection of analyzer paths. We // initialize a context object from each path one-by-one instead, in order // to make an attempt to load each specified analyzer. We will therefore // collect information on each analyzer that fails to load. We will also // proceed with performing as much analysis as possible. Ultimately, a // single analyzer load failure will return in BinSkim returning a non-zero // failure code from the run. foreach (string analyzerFilePath in roslynAnalyzerFilePaths) { InvokeCatchingRelevantIOExceptions ( action: () => { ILDiagnosticsAnalyzer.LoadAnalyzer(analyzerFilePath, _globalRoslynAnalysisContext); }, exceptionHandler: (ex) => { Errors.LogExceptionLoadingPlugIn(analyzerFilePath, context, ex); } ); } } Debug.Assert(context.MimeType == Sarif.Writers.MimeType.Binary); ILDiagnosticsAnalyzer roslynAnalyzer = ILDiagnosticsAnalyzer.Create(_globalRoslynAnalysisContext); roslynAnalyzer.Analyze(assemblyFilePath, diagnostic => { // 0. Populate various members var result = new Result(); result.Kind = diagnostic.Severity.ConvertToMessageKind(); result.FullMessage = diagnostic.GetMessage(); // For Roslyn diagnostics, suppression information is always available (i.e., it // is not contingent on compilation with specific #define such as CODE_ANLAYSIS). // As a result, we always populate IsSuppressedInSource with this information. result.IsSuppressedInSource = diagnostic.IsSuppressed; result.Properties = new Dictionary <string, string>(); result.Properties["Severity"] = diagnostic.Severity.ToString(); result.Properties["IsWarningAsError"] = diagnostic.IsWarningAsError.ToString(); result.Properties["WarningLevel"] = diagnostic.WarningLevel.ToString(); foreach (string key in diagnostic.Properties.Keys) { result.Properties[key] = diagnostic.Properties[key]; } // 1. Record the assembly under analysis result.Locations = new[] { new Sarif.Sdk.Location { AnalysisTarget = new[] { new PhysicalLocationComponent { Uri = assemblyFilePath.CreateUriForJsonSerialization(), MimeType = context.MimeType, } } } }; // 2. Record the actual location associated with the result var region = diagnostic.Location.ConvertToRegion(); string filePath; if (diagnostic.Location != Location.None) { filePath = diagnostic.Location.GetLineSpan().Path; result.Locations[0].ResultFile = new[] { new PhysicalLocationComponent { Uri = filePath.CreateUriForJsonSerialization(), MimeType = Sarif.Writers.MimeType.DetermineFromFileExtension(filePath), Region = region } }; } // 3. If present, emit additional locations associated with diagnostic.\ // According to docs, these locations typically reference related // locations (i.e., they are not locations that specify other // occurrences of a problem). if (diagnostic.AdditionalLocations != null && diagnostic.AdditionalLocations.Count > 0) { result.RelatedLocations = new List <AnnotatedCodeLocation>(diagnostic.AdditionalLocations.Count); foreach (Location location in diagnostic.AdditionalLocations) { filePath = location.GetLineSpan().Path; region = location.ConvertToRegion(); result.RelatedLocations.Add(new AnnotatedCodeLocation { Message = "Additional location", PhysicalLocation = new[] { new PhysicalLocationComponent { Uri = filePath.CreateUriForJsonSerialization(), MimeType = Sarif.Writers.MimeType.DetermineFromFileExtension(filePath), Region = region } } }); } } IRuleDescriptor rule = diagnostic.ConvertToRuleDescriptor(); context.Logger.Log(null, result); }); }