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 void ProcessLine(string logFileLine, Result result) { var codeFlow = result.CodeFlows[0]; const int STEP = 0; const int URI = 1; const int LINE = 2; // const int IMPORTANCE = 3; This value not persisted to SARIF const int STATE = 4; const int KIND1 = 5; // When KIND1 == "Atomic" the 6th slot is the // the remainder of the kind id, e.g., Atomic Assigment const int KIND2 = 6; // When KIND1 == "Call" the 6th and 7th slots are: const int CALLER = 6; const int CALLEE = 7; int step; string[] tokens = logFileLine.Split(' '); if (int.TryParse(tokens[STEP], out step)) { // If we find a numeric value as the first token, // this is a general step. Uri uri = null; string uriText = tokens[URI].Trim('"'); if (!uriText.Equals("?", StringComparison.Ordinal)) { if (File.Exists(uriText)) { uriText = Path.GetFullPath(uriText); } uri = new Uri(uriText, UriKind.RelativeOrAbsolute); } // We assume a valid line here. This code will throw if not. int line = int.Parse(tokens[LINE]); string sdvKind = tokens[KIND1]; if (sdvKind.Equals("Atomic", StringComparison.Ordinal)) { // For multipart SDV kinds 'Atomic XXX', we // map using the second value only, e.g, // 'Assignment' or 'Conditional' sdvKind = tokens[KIND2]; } AnnotatedCodeLocationKind kind = ConvertToAnnotatedCodeLocationKind(sdvKind.Trim()); var annotatedCodeLocation = new AnnotatedCodeLocation { Kind = kind, Step = step, Importance = AnnotatedCodeLocationImportance.Unimportant, PhysicalLocation = (uri != null) ? new PhysicalLocation { Uri = uri, Region = new Region { StartLine = line } } : null, }; if (kind == AnnotatedCodeLocationKind.Call) { string extraMsg = tokens[KIND1] + " " + tokens[CALLER] + " " + tokens[CALLEE]; string caller, callee; if (ExtractCallerAndCallee(extraMsg.Trim(), out caller, out callee)) { annotatedCodeLocation.FullyQualifiedLogicalName = caller; annotatedCodeLocation.Target = callee; _callers.Push(caller); } else { Debug.Assert(false); } if (uri == null) { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Unimportant; } else if (IsHarnessOrRulesFiles(uriText)) { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Important; } else { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Essential; } } if (kind == AnnotatedCodeLocationKind.CallReturn) { Debug.Assert(_callers.Count > 0); annotatedCodeLocation.FullyQualifiedLogicalName = _callers.Pop(); } string separatorText = "^====Auto====="; string state = tokens[STATE]; string[] stateTokens = state.Split(new string[] { separatorText }, StringSplitOptions.RemoveEmptyEntries); if (stateTokens.Length > 0) { if (stateTokens.Length == 2) { annotatedCodeLocation.SetProperty("currentDataValues", stateTokens[0]); annotatedCodeLocation.SetProperty("permanentDataValues", stateTokens[1]); } else { Debug.Assert(stateTokens.Length == 1); if (stateTokens[0].StartsWith(separatorText)) { annotatedCodeLocation.SetProperty("permanentDataValues", stateTokens[0]); } else { annotatedCodeLocation.SetProperty("currentDataValues", stateTokens[0]); } } } codeFlow.Locations.Add(annotatedCodeLocation); } else { // This is the defect message. const int LEVEL = 0; string levelText = tokens[LEVEL]; result.Level = ConvertToResultLevel(levelText); // Everything on the line following defect level comprises the message result.Message = logFileLine.Substring(levelText.Length).Trim(); // SDV currently produces 'pass' notifications when // the final line is prefixed with 'Error'. We'll examine // the message text to detect this condition if (result.Message.Contains("is satisfied")) { result.Level = ResultLevel.Pass; } // Finally, populate this result location with the // last observed location in the code flow. IList<AnnotatedCodeLocation> locations = result.CodeFlows[0].Locations; for (int i = locations.Count - 1; i >= 0; --i) { if (locations[i].PhysicalLocation != null) { result.Locations.Add(new Location { ResultFile = locations[i].PhysicalLocation }); break; } } } }
private void ProcessLine(string logFileLine, Result result) { var codeFlow = result.CodeFlows[0]; const int STEP = 0; const int URI = 1; const int LINE = 2; // const int IMPORTANCE = 3; This value not persisted to SARIF const int STATE = 4; const int KIND1 = 5; // When KIND1 == "Atomic" the 6th slot is the // the remainder of the kind id, e.g., Atomic Assigment const int KIND2 = 6; // When KIND1 == "Call" the 6th and 7th slots are: const int CALLER = 6; const int CALLEE = 7; int step; string[] tokens = logFileLine.Split(' '); if (int.TryParse(tokens[STEP], out step)) { // If we find a numeric value as the first token, // this is a general step. Uri uri = null; string uriText = tokens[URI].Trim('"'); if (!uriText.Equals("?", StringComparison.Ordinal)) { if (File.Exists(uriText)) { uriText = Path.GetFullPath(uriText); } uri = new Uri(uriText, UriKind.RelativeOrAbsolute); } // We assume a valid line here. This code will throw if not. int line = int.Parse(tokens[LINE]); string sdvKind = tokens[KIND1]; if (sdvKind.Equals("Atomic", StringComparison.Ordinal)) { // For multipart SDV kinds 'Atomic XXX', we // map using the second value only, e.g, // 'Assignment' or 'Conditional' sdvKind = tokens[KIND2]; } AnnotatedCodeLocationKind kind = ConvertToAnnotatedCodeLocationKind(sdvKind.Trim()); var annotatedCodeLocation = new AnnotatedCodeLocation { Kind = kind, Step = step, Importance = AnnotatedCodeLocationImportance.Unimportant, PhysicalLocation = (uri != null) ? new PhysicalLocation { Uri = uri, Region = new Region { StartLine = line } } : null, }; if (kind == AnnotatedCodeLocationKind.Call) { string extraMsg = tokens[KIND1] + " " + tokens[CALLER] + " " + tokens[CALLEE]; string caller, callee; if (ExtractCallerAndCallee(extraMsg.Trim(), out caller, out callee)) { annotatedCodeLocation.FullyQualifiedLogicalName = caller; annotatedCodeLocation.Target = callee; _callers.Push(caller); } else { Debug.Assert(false); } if (uri == null) { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Unimportant; } else if (IsHarnessOrRulesFiles(uriText)) { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Important; } else { annotatedCodeLocation.Importance = AnnotatedCodeLocationImportance.Essential; } } if (kind == AnnotatedCodeLocationKind.CallReturn) { Debug.Assert(_callers.Count > 0); annotatedCodeLocation.FullyQualifiedLogicalName = _callers.Pop(); } string separatorText = "^====Auto====="; string state = tokens[STATE]; string[] stateTokens = state.Split(new string[] { separatorText }, StringSplitOptions.RemoveEmptyEntries); if (stateTokens.Length > 0) { if (stateTokens.Length == 2) { annotatedCodeLocation.SetProperty("currentDataValues", stateTokens[0]); annotatedCodeLocation.SetProperty("permanentDataValues", stateTokens[1]); } else { Debug.Assert(stateTokens.Length == 1); if (stateTokens[0].StartsWith(separatorText)) { annotatedCodeLocation.SetProperty("permanentDataValues", stateTokens[0]); } else { annotatedCodeLocation.SetProperty("currentDataValues", stateTokens[0]); } } } codeFlow.Locations.Add(annotatedCodeLocation); } else { // This is the defect message. const int LEVEL = 0; string levelText = tokens[LEVEL]; result.Level = ConvertToResultLevel(levelText); // Everything on the line following defect level comprises the message result.Message = logFileLine.Substring(levelText.Length).Trim(); // SDV currently produces 'pass' notifications when // the final line is prefixed with 'Error'. We'll examine // the message text to detect this condition if (result.Message.Contains("is satisfied")) { result.Level = ResultLevel.Pass; } // Finally, populate this result location with the // last observed location in the code flow. IList <AnnotatedCodeLocation> locations = result.CodeFlows[0].Locations; for (int i = locations.Count - 1; i >= 0; --i) { if (locations[i].PhysicalLocation != null) { result.Locations.Add(new Location { ResultFile = locations[i].PhysicalLocation }); break; } } } }