Пример #1
0
        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 <CodeFlowLocation>();
            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 codeFlowLocation = new CodeFlowLocation
                {
                    Location = new Location
                    {
                        PhysicalLocation = fileLocation
                    },
                    Step = ++step
                };

                if (pathUsesKeyEvents)
                {
                    if (string.IsNullOrWhiteSpace(sfa.KeyEvent?.Id))
                    {
                        codeFlowLocation.Importance = CodeFlowLocationImportance.Unimportant;
                    }
                    else
                    {
                        codeFlowLocation.SetProperty("keyEventId", sfa.KeyEvent.Id);

                        if (Enum.TryParse(sfa.KeyEvent.Importance, true, out CodeFlowLocationImportance importance))
                        {
                            codeFlowLocation.Importance = importance;
                        }

                        if (!string.IsNullOrWhiteSpace(sfa.KeyEvent.Message) &&
                            codeFlowLocation.Location?.Message != null)
                        {
                            codeFlowLocation.Location.Message.Text = sfa.KeyEvent.Message;
                        }
                    }
                }

                locations.Add(codeFlowLocation);
            }

            result.CodeFlows = new List <CodeFlow>()
            {
                SarifUtilities.CreateSingleThreadedCodeFlow(locations)
            };
        }
        private void ProcessLine(string logFileLine, ref int nestingLevel, 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];
                }

                sdvKind = sdvKind.Trim();

                var codeFlowLocation = new CodeFlowLocation
                {
                    Step       = step + 1,
                    Importance = CodeFlowLocationImportance.Unimportant,
                    Location   = new Location
                    {
                        Message = new Message()
                    }
                };

                if (uri != null)
                {
                    codeFlowLocation.Location.PhysicalLocation = new PhysicalLocation
                    {
                        FileLocation = new FileLocation
                        {
                            Uri = uri
                        },
                        Region = new Region
                        {
                            StartLine = line
                        }
                    };
                }

                if (sdvKind == "Call")
                {
                    string extraMsg = $"{tokens[KIND1]} {tokens[CALLER]} {tokens[CALLEE]}";

                    string caller, callee;

                    if (ExtractCallerAndCallee(extraMsg.Trim(), out caller, out callee))
                    {
                        codeFlowLocation.Location.FullyQualifiedLogicalName = caller;
                        codeFlowLocation.Location.Message.Text = callee;
                        codeFlowLocation.SetProperty("target", callee);
                        _callers.Push(caller);
                    }
                    else
                    {
                        Debug.Assert(false);
                    }

                    codeFlowLocation.NestingLevel = nestingLevel++;

                    if (uri == null)
                    {
                        codeFlowLocation.Importance = CodeFlowLocationImportance.Unimportant;
                    }
                    else if (IsHarnessOrRulesFiles(uriText))
                    {
                        codeFlowLocation.Importance = CodeFlowLocationImportance.Important;
                    }
                    else
                    {
                        codeFlowLocation.Importance = CodeFlowLocationImportance.Essential;
                    }
                }
                else if (sdvKind == "Return")
                {
                    Debug.Assert(_callers.Count > 0);

                    codeFlowLocation.NestingLevel = nestingLevel--;
                    codeFlowLocation.Location.FullyQualifiedLogicalName = _callers.Pop();
                }
                else
                {
                    codeFlowLocation.NestingLevel          = nestingLevel;
                    codeFlowLocation.Location.Message.Text = sdvKind;
                }

                string   separatorText = "^====Auto=====";
                string   state         = tokens[STATE];
                string[] stateTokens   = state.Split(new string[] { separatorText }, StringSplitOptions.RemoveEmptyEntries);

                if (stateTokens.Length > 0)
                {
                    if (stateTokens.Length == 2)
                    {
                        codeFlowLocation.SetProperty("currentDataValues", stateTokens[0]);
                        codeFlowLocation.SetProperty("permanentDataValues", stateTokens[1]);
                    }
                    else
                    {
                        Debug.Assert(stateTokens.Length == 1);
                        if (stateTokens[0].StartsWith(separatorText))
                        {
                            codeFlowLocation.SetProperty("permanentDataValues", stateTokens[0]);
                        }
                        else
                        {
                            codeFlowLocation.SetProperty("currentDataValues", stateTokens[0]);
                        }
                    }
                }

                codeFlow.ThreadFlows[0].Locations.Add(codeFlowLocation);
            }
            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 = new Message {
                    Text = 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.Text.Contains("is satisfied"))
                {
                    result.Level = ResultLevel.Pass;
                }

                // Finally, populate this result location with the
                // last observed location in the code flow.

                IList <CodeFlowLocation> locations = result.CodeFlows[0].ThreadFlows[0].Locations;

                for (int i = locations.Count - 1; i >= 0; --i)
                {
                    if (locations[i].Location?.PhysicalLocation != null)
                    {
                        result.Locations.Add(new Location
                        {
                            PhysicalLocation = locations[i].Location.PhysicalLocation
                        });
                        break;
                    }
                }
            }
        }