protected override void Analyze( PhysicalLocation physicalLocation, string physicalLocationPointer) { EnsureRelativeUriWithUriBaseId( physicalLocation.Uri, physicalLocation.UriBaseId, physicalLocationPointer); }
private Result GetResultFrom(string fullMessage) { Match match = s_errorLineRegex.Match(fullMessage); if (!match.Success) { return(null); } // MSBuild logs can contain duplicate error report lines. Take only one of them. if (!_verbose) { if (_fullMessageHashes.Contains(fullMessage)) { return(null); } _fullMessageHashes.Add(fullMessage); } string fileName = match.Groups["fileName"].Value; string region = match.Groups["region"].Value; string buildTool = match.Groups["buildTool"].Value; string levelQualification = match.Groups["levelQualification"].Value; string level = match.Groups["level"].Value; string ruleId = match.Groups["ruleId"].Value; string message = match.Groups["message"].Value; var result = new Result { RuleId = ruleId, Level = GetFailureLevelFrom(level, out ResultKind resultKind), Kind = resultKind, Message = new Message { Text = message } }; if (!string.IsNullOrWhiteSpace(fileName)) { var physicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri(fileName, UriKind.RelativeOrAbsolute) } }; if (!string.IsNullOrWhiteSpace(region)) { physicalLocation.Region = GetRegionFrom(region); } result.Locations = new Location[] { new Location { PhysicalLocation = physicalLocation } }; } return(result); }
private Result CreateTestResult() { Result testResult = new Result() { RuleId = "ruleName.test.value", Message = new Message { Text = "failure.test.value" }, Level = FailureLevel.Warning, Kind = ResultKind.Fail }; Region region = new Region() { StartLine = 3, StartColumn = 2, EndLine = 13, EndColumn = 12, CharOffset = 3, CharLength = 10 }; PhysicalLocation physLoc = new PhysicalLocation() { ArtifactLocation = new ArtifactLocation { Uri = new Uri("name.test.value", UriKind.Relative) }, Region = region }; Location location = new Location() { PhysicalLocation = physLoc }; testResult.Locations = new List <Location>() { location }; Replacement replacement = new Replacement() { DeletedRegion = new Region { CharLength = 5, CharOffset = 10 }, InsertedContent = new ArtifactContent { Text = "fix.innerText.test.value" } }; testResult.Fixes = new List <Fix>() { new Fix() { ArtifactChanges = new List <ArtifactChange>() { new ArtifactChange() { ArtifactLocation = new ArtifactLocation { Uri = new Uri("name.test.value", UriKind.Relative) }, Replacements = new List <Replacement>() { replacement } } } } }; return(testResult); }
private void ParseLocationFromTrace(Result result) { CodeFlow codeFlow = result.CodeFlows.First(); int step = 0; string nodeLabel = null; string lastNodeId = null; _reader.Read(); while (!AtEndOf(_strings.Trace)) { if (AtStartOf(_strings.NodeRef)) { string nodeId = _reader.GetAttribute(_strings.IdAttribute); if (!string.IsNullOrWhiteSpace(nodeId)) { var tfl = new ThreadFlowLocation { Step = ++step }; _tflToNodeIdDictionary.Add(tfl, nodeId); codeFlow.ThreadFlows[0].Locations.Add(tfl); } _reader.Read(); } else if (AtStartOf(_strings.Node)) { nodeLabel = _reader.GetAttribute(_strings.LabelAttribute); _reader.Read(); } else if (AtStartOf(_strings.SourceLocation)) { // Note: SourceLocation is an empty element (it has only attributes), // so we can't call AtStartOfNonEmpty here. string snippetId = _reader.GetAttribute(_strings.SnippetAttribute); PhysicalLocation physicalLocation = ParsePhysicalLocationFromSourceInfo(); // Step past the empty SourceLocation element. _reader.Read(); // If we don't have a label, get the <Action> value if (string.IsNullOrWhiteSpace(nodeLabel)) { nodeLabel = _reader.ReadElementContentAsString(); } var tfl = new ThreadFlowLocation { Step = ++step, Location = new Location { Message = new Message { Text = nodeLabel }, PhysicalLocation = physicalLocation } }; // Remember the id of the snippet associated with this location. // We'll use it to fill the snippet text when we read the Snippets element later on. if (!string.IsNullOrEmpty(snippetId)) { _tflToSnippetIdDictionary.Add(tfl, snippetId); } codeFlow.ThreadFlows[0].Locations.Add(tfl); // Keep track of the snippet associated with the last location in the // CodeFlow; that's the snippet that we'll associate with the Result // as a whole. lastNodeId = snippetId; } else { _reader.Read(); } } if (codeFlow.ThreadFlows[0].Locations.Any()) { result.Locations.Add(new Location { // TODO: Confirm that the traces are ordered chronologically // (so that we really do want to use the last one as the // overall result location). PhysicalLocation = codeFlow.ThreadFlows[0].Locations.Last().Location?.PhysicalLocation.DeepClone() }); result.RelatedLocations.Add(new Location { // Links embedded in the result message refer to related physicalLocation.id PhysicalLocation = codeFlow.ThreadFlows[0].Locations.Last().Location?.PhysicalLocation.DeepClone() }); result.RelatedLocations.Last().PhysicalLocation.Id = 1; if (!string.IsNullOrEmpty(lastNodeId)) { _resultToSnippetIdDictionary.Add(result, lastNodeId); } } }
protected virtual void Analyze(PhysicalLocation physicalLocation, string physicalLocationPointer) { }
internal Result CreateResult(TSLintLogEntry entry) { entry = entry ?? throw new ArgumentNullException(nameof(entry)); Result result = new Result() { RuleId = entry.RuleName, Message = new Message { Text = entry.Failure } }; switch (entry.RuleSeverity) { case "ERROR": result.Level = ResultLevel.Error; break; case "WARN": case "WARNING": result.Level = ResultLevel.Warning; break; case "DEFAULT": default: result.Level = ResultLevel.Note; break; } Region region = new Region() { // The TSLint logs have line and column start at 0, Sarif has them starting at 1, so add 1 to each StartLine = entry.StartPosition.Line + 1, StartColumn = entry.StartPosition.Character + 1, EndLine = entry.EndPosition.Line + 1, EndColumn = entry.EndPosition.Character + 1, CharOffset = entry.StartPosition.Position }; int length = entry.EndPosition.Position - entry.StartPosition.Position; region.CharLength = length > 0 ? length : 0; Uri analysisTargetUri = new Uri(entry.Name, UriKind.Relative); var physicalLocation = new PhysicalLocation(id: 0, fileLocation: new FileLocation(uri: analysisTargetUri, uriBaseId: null), region: region, contextRegion: null); Location location = new Location() { PhysicalLocation = physicalLocation }; result.Locations = new List <Location>() { location }; if (entry.Fixes?.Any() == true) { IList <Replacement> replacements = new List <Replacement>(); foreach (TSLintLogFix fix in entry.Fixes) { Replacement replacement = new Replacement(); replacement.DeletedRegion = new Region { CharLength = fix.InnerLength, CharOffset = fix.InnerStart }; if (!string.IsNullOrEmpty(fix.InnerText)) { replacement.InsertedContent = new FileContent { Text = fix.InnerText }; } replacements.Add(replacement); } FileChange sarifFileChange = new FileChange(fileLocation: new FileLocation(uri: analysisTargetUri, uriBaseId: null), replacements: replacements); Fix sarifFix = new Fix(description: null, fileChanges: new List <FileChange>() { sarifFileChange }); result.Fixes = new List <Fix> { sarifFix }; } return(result); }
private void ParseLocationsFromTraces(Result result) { CodeFlow codeFlow = null; string nodeLabel = null; string lastNodeId = null; bool? isDefault = null; while (!AtEndOf(_strings.Unified)) { if (AtStartOf(_strings.Trace)) { codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(); result.CodeFlows.Add(codeFlow); while (!AtEndOf(_strings.Trace)) { if (AtStartOf(_strings.NodeRef)) { string nodeId = _reader.GetAttribute(_strings.IdAttribute); if (!string.IsNullOrWhiteSpace(nodeId)) { var tfl = new ThreadFlowLocation(); _tflToNodeIdDictionary.Add(tfl, nodeId); codeFlow.ThreadFlows[0].Locations.Add(tfl); } _reader.Read(); } else if (AtStartOf(_strings.Node)) { if (isDefault == null) { // We haven't found the default node yet, so check this one. string isDefaultValue = _reader.GetAttribute(_strings.IsDefaultAttribute); if (!string.IsNullOrWhiteSpace(isDefaultValue) && bool.TryParse(isDefaultValue, out bool val) && val == true) { // This is the default, set the flag so we know to add a result location. isDefault = val; } } nodeLabel = _reader.GetAttribute(_strings.LabelAttribute); _reader.Read(); } else if (AtStartOf(_strings.SourceLocation)) { // Note: SourceLocation is an empty element (it has only attributes), // so we can't call AtStartOfNonEmpty here. string snippetId = _reader.GetAttribute(_strings.SnippetAttribute); PhysicalLocation physicalLocation = ParsePhysicalLocationFromSourceInfo(); // Step past the empty SourceLocation element. _reader.Read(); string actionType = null; if (AtStartOf(_strings.Action)) { actionType = _reader.GetAttribute(_strings.TypeAttribute); actionType = actionType ?? string.Empty; // We use empty string to indicates there is an // Action element without a type attribute. // If we don't have a label, get the <Action> value. if (string.IsNullOrWhiteSpace(nodeLabel)) { nodeLabel = _reader.ReadElementContentAsString(); } } if (actionType == string.Empty) { if (codeFlow.ThreadFlows[0].Locations.Count > 0) { // If there is no type attribute on the Action element, we treat // it as a note about the prior node. ThreadFlowLocation tfl = codeFlow.ThreadFlows[0].Locations.Last(); // Annotate the location with the Action text. if (tfl?.Location != null) { tfl.Location.Annotations = new List <Region>(); Region region = physicalLocation.Region; region.Message = new Message { Text = nodeLabel }; tfl.Location.Annotations.Add(region); } } } else { var location = new Location { PhysicalLocation = physicalLocation }; if (isDefault == true) { result.Locations = new List <Location>(); result.Locations.Add(location.DeepClone()); result.RelatedLocations.Add(location.DeepClone()); // Keep track of the snippet associated with the default location. // That's the snippet that we'll associate with the result. lastNodeId = snippetId; isDefault = false; // This indicates we have already found the default node. } var tfl = new ThreadFlowLocation { Kinds = ConvertActionTypeToLocationKinds(actionType), Location = location }; if (!string.IsNullOrWhiteSpace(nodeLabel)) { tfl.Location.Message = new Message { Text = nodeLabel }; } // Remember the id of the snippet associated with this location. // We'll use it to fill the snippet text when we read the Snippets element later on. if (!string.IsNullOrEmpty(snippetId)) { _tflToSnippetIdDictionary.Add(tfl, snippetId); } codeFlow.ThreadFlows[0].Locations.Add(tfl); } } else { _reader.Read(); } } } else { _reader.Read(); } } if (result.RelatedLocations.Any()) { Location relatedLocation = result.RelatedLocations.Last(); if (relatedLocation != null) { relatedLocation.Id = 1; } } if (!string.IsNullOrEmpty(lastNodeId)) { _resultToSnippetIdDictionary.Add(result, lastNodeId); } }
private void GenerateCodeFlows(Defect defect, Result result) { List <SFA> sfas = defect?.Path?.SFAs; if (sfas == null || sfas.Count == 0) { return; } int step = 0; var locations = new List <ThreadFlowLocation>(); bool pathUsesKeyEvents = defect.Path.SFAs.Any(x => !string.IsNullOrWhiteSpace(x?.KeyEvent?.Id)); foreach (var sfa in defect.Path.SFAs) { var region = new Region() { StartColumn = sfa.Column + 1, StartLine = sfa.Line }; var uri = new Uri($"{sfa.FilePath}{sfa.FileName}", UriKind.Relative); var fileLocation = new PhysicalLocation(id: 0, fileLocation: new FileLocation(uri: uri, uriBaseId: null), region: region, contextRegion: null); var threadFlowLocation = new ThreadFlowLocation { Location = new Location { PhysicalLocation = fileLocation }, Step = ++step }; if (pathUsesKeyEvents) { if (string.IsNullOrWhiteSpace(sfa.KeyEvent?.Id)) { threadFlowLocation.Importance = ThreadFlowLocationImportance.Unimportant; } else { threadFlowLocation.SetProperty("keyEventId", sfa.KeyEvent.Id); if (Enum.TryParse(sfa.KeyEvent.Importance, true, out ThreadFlowLocationImportance importance)) { threadFlowLocation.Importance = importance; } if (!string.IsNullOrWhiteSpace(sfa.KeyEvent.Message) && threadFlowLocation.Location?.Message != null) { threadFlowLocation.Location.Message.Text = sfa.KeyEvent.Message; } } } locations.Add(threadFlowLocation); } result.CodeFlows = new List <CodeFlow>() { SarifUtilities.CreateSingleThreadedCodeFlow(locations) }; }
/// <summary>Converts a Fortify result to a static analysis results interchange format result.</summary> /// <param name="fortify">The Fortify result convert.</param> /// <returns> /// A SARIF result <see cref="Result"/> containing the same content as the supplied /// <see cref="FortifyIssue"/>. /// </returns> public static Result ConvertFortifyIssueToSarifIssue(FortifyIssue fortify) { var result = new Result(); result.RuleId = fortify.Category; if (!string.IsNullOrWhiteSpace(fortify.InstanceId)) { if (result.PartialFingerprints == null) { result.PartialFingerprints = new Dictionary <string, string>(); } SarifUtilities.AddOrUpdateDictionaryEntry(result.PartialFingerprints, "InstanceId", fortify.InstanceId); } List <string> messageComponents = new List <string>(); if (fortify.Abstract != null) { messageComponents.Add(fortify.Abstract); } if (fortify.AbstractCustom != null) { messageComponents.Add(fortify.AbstractCustom); } if (messageComponents.Count == 0) { result.Message = new Message { Text = String.Format(CultureInfo.InvariantCulture, ConverterResources.FortifyFallbackMessage, result.RuleId) }; } else { result.Message = new Message { Text = String.Join(Environment.NewLine, messageComponents) }; } result.SetProperty("kingdom", fortify.Kingdom); if (fortify.Priority != null) { result.SetProperty("priority", fortify.Priority); } if (!fortify.CweIds.IsDefaultOrEmpty) { result.SetProperty("cwe", String.Join(", ", fortify.CweIds.Select(id => id.ToString(CultureInfo.InvariantCulture)))); } if (fortify.RuleId != null) { result.SetProperty("fortifyRuleId", fortify.RuleId); } PhysicalLocation primaryOrSink = ConvertFortifyLocationToPhysicalLocation(fortify.PrimaryOrSink); result.Locations = new List <Location> { new Location { PhysicalLocation = primaryOrSink } }; if (fortify.Source != null) { PhysicalLocation source = ConvertFortifyLocationToPhysicalLocation(fortify.Source); var locations = new List <ThreadFlowLocation>() { new ThreadFlowLocation { Location = new Location { PhysicalLocation = source } }, new ThreadFlowLocation { Location = new Location { PhysicalLocation = primaryOrSink } } }; result.CodeFlows = new List <CodeFlow>() { SarifUtilities.CreateSingleThreadedCodeFlow(locations) }; } return(result); }
private void WriteRunToErrorList(Run runLog) { List <SarifError> sarifErrors = new List <SarifError>(); // Prefer optional fullName, fall back to required Name property string toolName = runLog.Tool.FullName ?? runLog.Tool.Name; foreach (Result result in runLog.Results) { string category, document, shortMessage, fullMessage; Region region; NewLineIndex newLineIndex; IRule rule = null; category = null; if (result.Properties != null) { result.Properties.TryGetValue("category", out category); } foreach (Location location in result.Locations) { region = null; PhysicalLocation physicalLocation = null; if (location.ResultFile != null) { physicalLocation = location.ResultFile; document = physicalLocation.Uri.LocalPath; region = physicalLocation.Region; } else if (location.AnalysisTarget != null) { physicalLocation = location.AnalysisTarget; document = physicalLocation.Uri.LocalPath; region = physicalLocation.Region; } else { document = location.FullyQualifiedLogicalName; } rule = GetRule(runLog, result.RuleId); shortMessage = result.GetMessageText(rule, concise: true); fullMessage = result.GetMessageText(rule, concise: false); if (shortMessage == fullMessage) { fullMessage = null; } SarifError sarifError = new SarifError(document) { Region = region, RuleId = result.RuleId, RuleName = rule?.Name, Kind = result.Kind, Category = category, ShortMessage = shortMessage, FullMessage = fullMessage, Tool = toolName, HelpLink = rule?.HelpUri?.ToString() }; CaptureAnnotatedCodeLocationCollections(result.Stacks, AnnotatedCodeLocationKind.Stack, sarifError); CaptureAnnotatedCodeLocationCollections(result.CodeFlows, AnnotatedCodeLocationKind.CodeFlow, sarifError); CaptureAnnotatedCodeLocations(result.RelatedLocations, AnnotatedCodeLocationKind.Stack, sarifError); if (region != null) { sarifError.ColumnNumber = region.StartColumn - 1; sarifError.LineNumber = region.StartLine - 1; } sarifErrors.Add(sarifError); } // TODO zap this on implementing todo above if (result.RelatedLocations != null) { foreach (AnnotatedCodeLocation annotation in result.RelatedLocations) { PhysicalLocation physicalLocation = annotation.PhysicalLocation; region = physicalLocation.Region; shortMessage = annotation.Message; document = annotation.PhysicalLocation.Uri.LocalPath; if (!this.documentToLineIndexMap.TryGetValue(document, out newLineIndex)) { this.documentToLineIndexMap[document] = newLineIndex = new NewLineIndex(File.ReadAllText(document)); } if (region != null) { region.Populate(newLineIndex); } SarifError sarifError = new SarifError(document) { Region = region, RuleId = result.RuleId, RuleName = rule?.Name, Kind = ResultKind.Note, Category = "Related Location", // or should we prefer original result category? ShortMessage = shortMessage, FullMessage = null, Tool = toolName }; if (region != null) { sarifError.ColumnNumber = region.StartColumn - 1; sarifError.LineNumber = region.StartLine - 1; } sarifErrors.Add(sarifError); } } CodeAnalysisResultManager.Instance.SarifErrors = sarifErrors; SarifTableDataSource.Instance.AddErrors(sarifErrors); } }
private Result MakeResultFromError(JsonError error) { var result = new Result(); string analysisTargetFilePath; NewLineIndex index = null; switch (error.Location) { case JsonErrorLocation.InstanceDocument: analysisTargetFilePath = _instanceFilePath; index = InstanceFileIndex; break; case JsonErrorLocation.Schema: analysisTargetFilePath = _schemaFilePath; index = SchemaFileIndex; break; default: analysisTargetFilePath = "unknown_file"; break; } Uri analysisTargetUri = new Uri(analysisTargetFilePath); switch (error.Kind) { case JsonErrorKind.Syntax: result.RuleId = JsonSyntaxErrorRule.Id; result.Kind = ResultKind.Error; result.FormattedMessage = new FormattedMessage( JsonSyntaxErrorFormatSpecifier, new string[] { error.Message }); break; case JsonErrorKind.Validation: result.RuleId = JsonSchemaValidationErrorRule.Id; result.Kind = ResultKind.Error; result.FormattedMessage = new FormattedMessage( JsonSchemaValidationErrorFormatSpecifier, new string[] { error.Message }); break; default: result.RuleId = UnknownErrorRule.Id; result.Kind = ResultKind.InternalError; result.FormattedMessage = new FormattedMessage( UnknownErrorFormatSpecifier, new string[] { error.Kind.ToString() }); break; } Region region; if (index != null) { region = new Region { Offset = error.Start, Length = error.Length }; region.Populate(index); } else { region = new Region(); } var plc = new PhysicalLocation { Uri = analysisTargetUri, Region = region }; var location = new Location { AnalysisTarget = new PhysicalLocation(plc) }; result.Locations = new List <Location> { location }; return(result); }
public async Task <IActionResult> AddHardwareItem(HardwareItem hardwareItem) { if (ModelState.IsValid) { var user = await _userManager.GetUserAsync(User); var category = new Category() { Name = hardwareItem.Category.Name, User = user, LastUsed = DateTime.Now.Date }; var model = new ItemModel() { Name = hardwareItem.Model.Name, User = user, LastUsed = DateTime.Now.Date }; var manufacturer = new Manufacturer() { Name = hardwareItem.Manufacturer.Name, User = user, LastUsed = DateTime.Now.Date }; var physicalLocation = new PhysicalLocation() { Name = hardwareItem.PhysicalLocation.Name, User = user, LastUsed = DateTime.Now.Date }; var dbCategory = await _applicationDbContext.Categories .ToAsyncEnumerable() .SingleOrDefaultAsync(c => c.Name == category.Name && c.User == category.User); var dbModel = await _applicationDbContext.ItemModels .ToAsyncEnumerable() .SingleOrDefaultAsync(c => c.Name == model.Name && c.User == model.User); var dbManufacturer = await _applicationDbContext.Manufacturers .ToAsyncEnumerable() .SingleOrDefaultAsync(c => c.Name == manufacturer.Name && c.User == manufacturer.User); var dbPhysicalLocation = await _applicationDbContext.PhysicalLocations .ToAsyncEnumerable() .SingleOrDefaultAsync(c => c.Name == physicalLocation.Name && c.User == physicalLocation.User); if (dbCategory == null) { dbCategory = (await _applicationDbContext.Categories.AddAsync(category)).Entity; } else { dbCategory.Update(category); dbCategory.Uses++; _applicationDbContext.Entry(dbCategory).State = EntityState.Modified; } if (dbModel == null) { dbModel = (await _applicationDbContext.ItemModels.AddAsync(model)).Entity; } else { dbModel.Update(model); dbModel.Uses++; _applicationDbContext.Entry(dbModel).State = EntityState.Modified; } if (dbManufacturer == null) { dbManufacturer = (await _applicationDbContext.Manufacturers.AddAsync(manufacturer)).Entity; } else { dbManufacturer.Update(manufacturer); dbManufacturer.Uses++; _applicationDbContext.Entry(dbManufacturer).State = EntityState.Modified; } if (dbPhysicalLocation == null) { dbPhysicalLocation = (await _applicationDbContext.PhysicalLocations.AddAsync(physicalLocation)).Entity; } else { dbPhysicalLocation.Update(physicalLocation); dbPhysicalLocation.Uses++; _applicationDbContext.Entry(dbPhysicalLocation).State = EntityState.Modified; } await _applicationDbContext.SaveChangesAsync(); if (hardwareItem.ReceiptFiles != null && hardwareItem.ReceiptFiles.Count() > 0) { var receipts = await hardwareItem.ReceiptFiles .ToAsyncEnumerable() .SelectAwait(async h => await GetReceiptAsBytes(h)) .ToListAsync(); hardwareItem.Receipts = receipts; } hardwareItem.Category = null; hardwareItem.Model = null; hardwareItem.Manufacturer = null; hardwareItem.PhysicalLocation = null; var inventoryItems = _applicationDbContext.HardwareItems; hardwareItem = (await inventoryItems.AddAsync(hardwareItem)).Entity; //await _applicationDbContext.SaveChangesAsync(); hardwareItem.Category = dbCategory; hardwareItem.Model = dbModel; hardwareItem.Manufacturer = dbManufacturer; hardwareItem.PhysicalLocation = dbPhysicalLocation; await _applicationDbContext.SaveChangesAsync(); } hardwareItem = (await PrepareComboBoxesAsync(hardwareItem)) as HardwareItem; return(View(hardwareItem)); //return RedirectToAction("EditHardwareItem", new { hardwareItem = hardwareItem }); }
public void Should_Generate_Report() { // Given var fixture = new SarifIssueReportFixture(); var issues = new List <IIssue> { IssueBuilder .NewIssue("Message Foo.", "ProviderType Foo", "ProviderName Foo") .InFile(@"src\Cake.Issues.Reporting.Sarif.Tests\SarifIssueReportGeneratorTests.cs", 10) .InProjectFile(@"src\Cake.Issues.Reporting.Sarif.Tests\Cake.Issues.Reporting.Sarif.Tests.csproj") .OfRule("Rule Foo") .WithPriority(IssuePriority.Error) .Create(), // Issue to exercise creation of rule metadata with helpUri, and messages // in Markdown format. IssueBuilder .NewIssue("Message Bar.", "ProviderType Bar", "ProviderName Bar") .InFile(@"src\Cake.Issues.Reporting.Sarif.Tests\SarifIssueReportGeneratorTests.cs", 12, 5) .OfRule("Rule Bar", new Uri("https://www.example.come/rules/bar.html")) .WithPriority(IssuePriority.Warning) .WithMessageInMarkdownFormat("Message Bar -- now in **Markdown**!") .Create(), // Issue to exercise the corner case where ruleId is absent (so no rule // metadata is created) but helpUri is present (so it is stored in the // result's property bag. IssueBuilder .NewIssue("Message Bar 2.", "ProviderType Bar", "ProviderName Bar") .InFile(@"src\Cake.Issues.Reporting.Sarif.Tests\SarifIssueReportGeneratorTests.cs", 23, 42, 5, 10) .OfRule(null, new Uri("https://www.example.come/rules/bar2.html")) .WithPriority(IssuePriority.Warning) .Create(), }; // When var logContents = fixture.CreateReport(issues); // Then var sarifLog = JsonConvert.DeserializeObject <SarifLog>(logContents); // There are two runs because there are two issue providers. sarifLog.Runs.Count.ShouldBe(2); Run run = sarifLog.Runs[0]; run.Tool.Driver.Name.ShouldBe("ProviderType Foo"); // This run doesn't have any rules that specify a help URI, so we didn't bother // adding rule metadata. run.Tool.Driver.Rules.ShouldBeNull(); run.Results.Count.ShouldBe(1); Result result = run.Results[0]; result.RuleId.ShouldBe("Rule Foo"); result.RuleIndex.ShouldBe(-1); // because there's no rule metadata to point to. result.Message.Text.ShouldBe("Message Foo."); result.Message.Markdown.ShouldBeNull(); result.Level.ShouldBe(FailureLevel.Error); result.Kind.ShouldBe(ResultKind.Fail); result.Locations.Count.ShouldBe(1); PhysicalLocation physicalLocation = result.Locations[0].PhysicalLocation; physicalLocation.ArtifactLocation.Uri.OriginalString.ShouldBe("src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs"); physicalLocation.Region.StartLine.ShouldBe(10); run.OriginalUriBaseIds.Count.ShouldBe(1); run.OriginalUriBaseIds[SarifIssueReportGenerator.RepoRootUriBaseId].Uri.LocalPath.ShouldBe(SarifIssueReportFixture.RepositoryRootPath); run = sarifLog.Runs[1]; run.Tool.Driver.Name.ShouldBe("ProviderType Bar"); // This run has a rule that specifies a help URI, so we added rule metadata. IList <ReportingDescriptor> rules = run.Tool.Driver.Rules; rules.Count.ShouldBe(1); ReportingDescriptor rule = rules[0]; rule.Id.ShouldBe("Rule Bar"); rule.HelpUri.OriginalString.ShouldBe("https://www.example.come/rules/bar.html"); run.Results.Count.ShouldBe(2); result = run.Results[0]; result.RuleId.ShouldBe("Rule Bar"); result.RuleIndex.ShouldBe(0); // The index of the metadata for this rule in the rules array. result.Message.Text.ShouldBe("Message Bar."); result.Message.Markdown.ShouldBe("Message Bar -- now in **Markdown**!"); result.Level.ShouldBe(FailureLevel.Warning); result.Kind.ShouldBe(ResultKind.Fail); result.Locations.Count.ShouldBe(1); physicalLocation = result.Locations[0].PhysicalLocation; physicalLocation.ArtifactLocation.Uri.OriginalString.ShouldBe("src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs"); physicalLocation.Region.StartLine.ShouldBe(12); physicalLocation.Region.StartColumn.ShouldBe(5); // This run also includes an issue with a rule URL but no rule name, so we'll find // the rule URL in the result's property bag. result = run.Results[1]; result.RuleId.ShouldBeNull(); result.RuleIndex.ShouldBe(-1); result.GetProperty(SarifIssueReportGenerator.RuleUrlPropertyName).ShouldBe("https://www.example.come/rules/bar2.html"); result.Message.Text.ShouldBe("Message Bar 2."); result.Level.ShouldBe(FailureLevel.Warning); result.Kind.ShouldBe(ResultKind.Fail); result.Locations.Count.ShouldBe(1); physicalLocation = result.Locations[0].PhysicalLocation; physicalLocation.ArtifactLocation.Uri.OriginalString.ShouldBe("src/Cake.Issues.Reporting.Sarif.Tests/SarifIssueReportGeneratorTests.cs"); physicalLocation.Region.StartLine.ShouldBe(23); physicalLocation.Region.EndLine.ShouldBe(42); physicalLocation.Region.StartColumn.ShouldBe(5); physicalLocation.Region.EndColumn.ShouldBe(10); run.OriginalUriBaseIds.Count.ShouldBe(1); run.OriginalUriBaseIds[SarifIssueReportGenerator.RepoRootUriBaseId].Uri.LocalPath.ShouldBe(SarifIssueReportFixture.RepositoryRootPath); }
private void GenerateCodeFlows(Defect defect, Result result) { List <SFA> sfas = defect?.Path?.SFAs; if (sfas == null || sfas.Count == 0) { return; } int step = 0; var locations = new List <AnnotatedCodeLocation>(); bool pathUsesKeyEvents = defect.Path.SFAs.Any(x => !string.IsNullOrWhiteSpace(x?.KeyEvent?.Id)); foreach (var sfa in defect.Path.SFAs) { var region = new Region() { StartColumn = sfa.Column + 1, StartLine = sfa.Line }; var uri = new Uri($"{sfa.FilePath}{sfa.FileName}", UriKind.Relative); var fileLocation = new PhysicalLocation(uri: uri, uriBaseId: null, region: region); var annotatedCodeLocation = new AnnotatedCodeLocation { PhysicalLocation = fileLocation, Step = ++step }; if (pathUsesKeyEvents) { if (string.IsNullOrWhiteSpace(sfa.KeyEvent?.Id)) { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Unimportant; } else { annotatedCodeLocation.SetProperty("keyEventId", sfa.KeyEvent.Id); if (Enum.TryParse(sfa.KeyEvent.Kind, true, out AnnotatedCodeLocationKind kind)) { annotatedCodeLocation.Kind = kind; } if (Enum.TryParse(sfa.KeyEvent.Importance, true, out AnnotatedCodeLocationImportance importance)) { annotatedCodeLocation.Importance = importance; } if (!string.IsNullOrWhiteSpace(sfa.KeyEvent.Message)) { annotatedCodeLocation.Message = sfa.KeyEvent.Message; } } } locations.Add(annotatedCodeLocation); } result.CodeFlows = new List <CodeFlow>() { new CodeFlow { Locations = locations } }; }
private IList <AnnotatedCodeLocation> NormalizeRawMessage(string rawMessage, out string normalizedMessage) { // The rawMessage contains embedded related locations. We need to extract the related locations and reformat the rawMessage embedded links wrapped in [brackets]. // Example rawMessage // po (coming from [["hbm"|"relative://windows/Core/ntgdi/gre/brushapi.cxx:176:4882:3"],["hbm"|"relative://windows/Core/ntgdi/gre/windows/ntgdi.c:1873:50899:3"],["hbm"|"relative://windows/Core/ntgdi/gre/windows/ntgdi.c:5783:154466:3"]]) may not have been checked for validity before call to vSync. // Example normalizedMessage // po (coming from [hbm]) may not have been checked for validity before call to vSync. // Example relatedLocations // relative://windows/Core/ntgdi/gre/brushapi.cxx:176:4882:3 // relative://windows/Core/ntgdi/gre/windows/ntgdi.c:1873:50899:3 // relative://windows/Core/ntgdi/gre/windows/ntgdi.c:5783:154466:3 List <AnnotatedCodeLocation> relatedLocations = null; normalizedMessage = String.Empty; var sb = new StringBuilder(); int index = rawMessage.IndexOf("[["); while (index > -1) { sb.Append(rawMessage.Substring(0, index)); rawMessage = rawMessage.Substring(index + 2); index = rawMessage.IndexOf("]]"); // embeddedLinksText contains the text for one set of embedded links except for the leading '[[' and trailing ']]' // "hbm"|"relative://windows/Core/ntgdi/gre/brushapi.cxx:176:4882:3"],["hbm"|"relative://windows/Core/ntgdi/gre/windows/ntgdi.c:1873:50899:3"],["hbm"|"relative://windows/Core/ntgdi/gre/windows/ntgdi.c:5783:154466:3" string embeddedLinksText = rawMessage.Substring(0, index - 1); // embeddedLinks splits the set of embedded links into invividual links // 1. "hbm"|"relative://windows/Core/ntgdi/gre/brushapi.cxx:176:4882:3" // 2. "hbm"|"relative://windows/Core/ntgdi/gre/windows/ntgdi.c:1873:50899:3" // 3. "hbm"|"relative://windows/Core/ntgdi/gre/windows/ntgdi.c:5783:154466:3" string[] embeddedLinks = embeddedLinksText.Split(new string[] { "],[" }, StringSplitOptions.None); foreach (string embeddedLink in embeddedLinks) { string[] tokens = embeddedLink.Split(new char[] { '\"' }, StringSplitOptions.RemoveEmptyEntries); // save the text portion of the link embeddedLinksText = tokens[0]; string location = tokens[2]; string[] locationTokens = location.Split(':'); relatedLocations = relatedLocations ?? new List <AnnotatedCodeLocation>(); PhysicalLocation physicalLocation; if (locationTokens[0].Equals("file", StringComparison.OrdinalIgnoreCase)) { // Special case for file paths, e.g.: // "IComparable"|"file://C:/Windows/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll:0:0:0:0" physicalLocation = new PhysicalLocation { Uri = new Uri($"{locationTokens[0]}:{locationTokens[1]}:{locationTokens[2]}", UriKind.Absolute), Region = new Region { StartLine = Int32.Parse(locationTokens[3]), Offset = Int32.Parse(locationTokens[4]), Length = Int32.Parse(locationTokens[5]) } }; } else { physicalLocation = new PhysicalLocation { Uri = new Uri(locationTokens[1].Substring(1), UriKind.Relative), UriBaseId = "$srcroot", Region = new Region { StartLine = Int32.Parse(locationTokens[2]), Offset = Int32.Parse(locationTokens[3]), Length = Int32.Parse(locationTokens[4]) } }; } var relatedLocation = new AnnotatedCodeLocation { PhysicalLocation = physicalLocation }; relatedLocations.Add(relatedLocation); } // Re-add the text portion of the link in brackets. sb.Append($"[{embeddedLinksText}]"); rawMessage = rawMessage.Substring(index + "]]".Length); index = rawMessage.IndexOf("[["); } sb.Append(rawMessage); normalizedMessage = sb.ToString(); return(relatedLocations); }
private void ParseLocationFromAnalysisInfo(Result result) { CodeFlow codeFlow = result.CodeFlows.First(); int step = 0; _reader.Read(); string lastSnippetId = null; while (!AtEndOf(_strings.AnalysisInfo)) { // Note: SourceLocation is an empty element (it has only attributes), // so we can't call AtStartOfNonEmpty here. if (AtStartOf(_strings.SourceLocation)) { string snippetId = _reader.GetAttribute(_strings.SnippetAttribute); PhysicalLocation physLoc = ParsePhysicalLocationFromSourceInfo(); var acl = new AnnotatedCodeLocation { Step = step++, PhysicalLocation = physLoc }; // Remember the id of the snippet associated with this location. // We'll use it to fill the snippet text when we read the Snippets element later on. if (!String.IsNullOrEmpty(snippetId)) { _aclToSnippetIdDictionary.Add(acl, snippetId); } codeFlow.Locations.Add(acl); // Keep track of the snippet associated with the last location in the // CodeFlow; that's the snippet that we'll associate with the Result // as a whole. lastSnippetId = snippetId; // Step past the empty element. _reader.Read(); } else { _reader.Read(); } } if (codeFlow.Locations.Any()) { result.Locations.Add(new Location { // TODO: Confirm that the traces are ordered chronologically // (so that we really do want to use the last one as the // overall result location). ResultFile = codeFlow.Locations.Last().PhysicalLocation }); if (!String.IsNullOrEmpty(lastSnippetId)) { _resultToSnippetIdDictionary.Add(result, lastSnippetId); } } }
protected override void Analyze(PhysicalLocation physicalLocation, string physicalLocationPointer) { AnalyzeUri(physicalLocation.Uri, physicalLocationPointer); }
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); }); }
public static Uri FileUri(this PhysicalLocation physicalLocation, Run run) { return(FileUri(physicalLocation?.ArtifactLocation, run)); }
private void AddFile(PhysicalLocation physicalLocation) { if (physicalLocation == null) { return; } Uri uri = physicalLocation.Uri; string key = UriHelper.MakeValidUri(uri.OriginalString); string filePath = key; if (uri.IsAbsoluteUri && uri.IsFile) { filePath = uri.LocalPath; } if (!_fileInfoDictionary.ContainsKey(key)) { _fileInfoDictionary.Add( key, new FileData { MimeType = _mimeTypeClassifier(filePath) }); } }
private IList <Location> NormalizeRawMessage(string rawMessage, out string normalizedMessage) { // The rawMessage contains embedded related locations. We need to extract the related locations and reformat the rawMessage embedded links wrapped in [brackets]. // Example rawMessage // po (coming from [["hbm"|"relative://code/.../file1.cxx:176:4882:3"],["hbm"|"relative://code/.../file2.c:1873:50899:3"],["hbm"|"relative://code/.../file2.c:5783:154466:3"]]) may not have been checked for validity before call to vSync. // Example normalizedMessage, where 'id' is the related location id to link to // Note: the first link in the message links to the first related location in the list, the second link to the second, etc. // po (coming from [hbm](id)) may not have been checked for validity before call to vSync. // Example relatedLocations // relative://code/.../file1.cxx:176:4882:3 // relative://code/.../file2.c:1873:50899:3 // relative://code/.../file2.c:5783:154466:3 List <Location> relatedLocations = null; var sb = new StringBuilder(); int count = 0; int linkIndex = 0; int index = rawMessage.IndexOf("[["); while (index > -1) { sb.Append(rawMessage.Substring(0, index)); rawMessage = rawMessage.Substring(index + 2); index = rawMessage.IndexOf("]]"); // embeddedLinksText contains the text for one set of embedded links except for the leading '[[' and trailing ']]' // "hbm"|"relative:/code/.../file1.cxx:176:4882:3"],["hbm"|"relative://code/.../file2.c:1873:50899:3"],["hbm"|"relative://code/.../file2.c:5783:154466:3" string embeddedLinksText = rawMessage.Substring(0, index - 1); // embeddedLinks splits the set of embedded links into invividual links // 1. "hbm"|"relative://code/.../file1.cxx:176:4882:3" // 2. "hbm"|"relative://code/.../file2.c:1873:50899:3" // 3. "hbm"|"relative://code/.../file2.c:5783:154466:3" string[] embeddedLinks = embeddedLinksText.Split(new string[] { "],[" }, StringSplitOptions.None); foreach (string embeddedLink in embeddedLinks) { string[] tokens = embeddedLink.Split(new char[] { '\"' }, StringSplitOptions.RemoveEmptyEntries); // save the text portion of the link embeddedLinksText = tokens[0]; string location = tokens[2]; string[] locationTokens = location.Split(':'); relatedLocations = relatedLocations ?? new List <Location>(); PhysicalLocation physicalLocation; if (locationTokens[0].Equals("file", StringComparison.OrdinalIgnoreCase)) { // Special case for file paths, e.g.: // "IComparable"|"file://C:/Windows/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll:0:0:0:0" physicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri($"{locationTokens[0]}:{locationTokens[1]}:{locationTokens[2]}", UriKind.Absolute) }, Region = new Region { StartLine = Int32.Parse(locationTokens[3]), ByteOffset = Int32.Parse(locationTokens[4]), ByteLength = Int32.Parse(locationTokens[5]) } }; } else { physicalLocation = new PhysicalLocation { ArtifactLocation = new ArtifactLocation { Uri = new Uri(locationTokens[1].Substring(1), UriKind.Relative), UriBaseId = "$srcroot" }, Region = new Region { StartLine = Int32.Parse(locationTokens[2]), ByteOffset = Int32.Parse(locationTokens[3]), ByteLength = Int32.Parse(locationTokens[4]) } }; } // TODO: Region.ByteOffset is not being handled correctly in SemmleQlConverter. Fix this! // https://github.com/Microsoft/sarif-sdk/issues/1458 if (physicalLocation.Region.ByteLength == 0) { physicalLocation.Region.ByteOffset = -1; } var relatedLocation = new Location { Id = ++count, PhysicalLocation = physicalLocation }; relatedLocations.Add(relatedLocation); } // Re-add the text portion of the link in brackets with the location id in parens, e.g. [link text](id) sb.Append($"[{embeddedLinksText}]({relatedLocations[linkIndex++].Id})"); rawMessage = rawMessage.Substring(index + "]]".Length); index = rawMessage.IndexOf("[["); } sb.Append(rawMessage); normalizedMessage = sb.ToString(); return(relatedLocations); }
/// <summary>Converts a Fortify result to a static analysis results interchange format result.</summary> /// <param name="fortify">The Fortify result convert.</param> /// <returns> /// A SARIF result <see cref="Result"/> containing the same content as the supplied /// <see cref="FortifyIssue"/>. /// </returns> public static Result ConvertFortifyIssueToSarifIssue(FortifyIssue fortify) { var result = new Result(); result.RuleId = fortify.Category; result.ToolFingerprint = fortify.InstanceId; List <string> messageComponents = new List <string>(); if (fortify.Abstract != null) { messageComponents.Add(fortify.Abstract); } if (fortify.AbstractCustom != null) { messageComponents.Add(fortify.AbstractCustom); } if (messageComponents.Count == 0) { result.Message = String.Format(CultureInfo.InvariantCulture, SarifResources.FortifyFallbackMessage, result.RuleId); } else { result.Message = String.Join(Environment.NewLine, messageComponents); } var extraProperties = new Dictionary <string, string>(); extraProperties.Add("kingdom", fortify.Kingdom); if (fortify.Priority != null) { extraProperties.Add("priority", fortify.Priority); } if (!fortify.CweIds.IsDefaultOrEmpty) { extraProperties.Add("cwe", String.Join(", ", fortify.CweIds.Select(id => id.ToString(CultureInfo.InvariantCulture)))); } if (fortify.RuleId != null) { extraProperties.Add("fortifyRuleId", fortify.RuleId); } result.Properties = extraProperties; PhysicalLocation primaryOrSink = ConvertFortifyLocationToPhysicalLocation(fortify.PrimaryOrSink); result.Locations = new HashSet <Location> { new Location { ResultFile = primaryOrSink } }; if (fortify.Source != null) { PhysicalLocation source = ConvertFortifyLocationToPhysicalLocation(fortify.Source); result.CodeFlows = new HashSet <CodeFlow> { new CodeFlow { Locations = new List <AnnotatedCodeLocation> { new AnnotatedCodeLocation { PhysicalLocation = source }, new AnnotatedCodeLocation { PhysicalLocation = primaryOrSink } } } }; } return(result); }
public override PhysicalLocation VisitPhysicalLocation(PhysicalLocation node) { if (node.Region == null || node.Region.IsBinaryRegion) { goto Exit; } bool insertRegionSnippets = _dataToInsert.HasFlag(OptionallyEmittedData.RegionSnippets); bool overwriteExistingData = _dataToInsert.HasFlag(OptionallyEmittedData.OverwriteExistingData); bool insertContextCodeSnippets = _dataToInsert.HasFlag(OptionallyEmittedData.ContextRegionSnippets); bool populateRegionProperties = _dataToInsert.HasFlag(OptionallyEmittedData.ComprehensiveRegionProperties); if (insertRegionSnippets || populateRegionProperties || insertContextCodeSnippets) { Region expandedRegion; ArtifactLocation artifactLocation = node.ArtifactLocation; _fileRegionsCache = _fileRegionsCache ?? new FileRegionsCache(_run); if (artifactLocation.Uri == null && artifactLocation.Index >= 0) { // Uri is not stored at result level, but we have an index to go look in run.Artifacts // we must pick the ArtifactLocation details from run.artifacts array Artifact artifactFromRun = _run.Artifacts[artifactLocation.Index]; artifactLocation = artifactFromRun.Location; } // If we can resolve a file location to a newly constructed // absolute URI, we will prefer that if (!artifactLocation.TryReconstructAbsoluteUri(_run.OriginalUriBaseIds, out Uri resolvedUri)) { resolvedUri = artifactLocation.Uri; } if (!resolvedUri.IsAbsoluteUri) { goto Exit; } expandedRegion = _fileRegionsCache.PopulateTextRegionProperties(node.Region, resolvedUri, populateSnippet: insertRegionSnippets); ArtifactContent originalSnippet = node.Region.Snippet; if (populateRegionProperties) { node.Region = expandedRegion; } if (originalSnippet == null || overwriteExistingData) { node.Region.Snippet = expandedRegion.Snippet; } else { node.Region.Snippet = originalSnippet; } if (insertContextCodeSnippets && (node.ContextRegion == null || overwriteExistingData)) { node.ContextRegion = _fileRegionsCache.ConstructMultilineContextSnippet(expandedRegion, resolvedUri); } } Exit: return(base.VisitPhysicalLocation(node)); }
public void ApplyTo(PhysicalLocation physicalLocation) { physicalLocation.Region = this.Region; physicalLocation.ContextRegion = this.ContextRegion; }