Example #1
0
        internal FileDataVersionOne CreateFileData(FileData v2FileData)
        {
            FileDataVersionOne fileData = null;

            if (v2FileData != null)
            {
                fileData = new FileDataVersionOne
                {
                    Hashes     = v2FileData.Hashes?.Select(CreateHash).ToList(),
                    Length     = v2FileData.Length,
                    MimeType   = v2FileData.MimeType,
                    Offset     = v2FileData.Offset,
                    ParentKey  = v2FileData.ParentKey,
                    Properties = v2FileData.Properties,
                    Uri        = v2FileData.FileLocation?.Uri,
                    UriBaseId  = v2FileData.FileLocation?.UriBaseId
                };

                if (v2FileData.Contents != null)
                {
                    fileData.Contents = MimeType.IsTextualMimeType(v2FileData.MimeType) ?
                                        SarifUtilities.GetUtf8Base64String(v2FileData.Contents.Text) :
                                        v2FileData.Contents.Binary;
                }
            }

            return(fileData);
        }
Example #2
0
        private void ParseVulnerability()
        {
            var result = new Result
            {
                Locations        = new List <Location>(),
                RelatedLocations = new List <Location>(),
                CodeFlows        = new []
                {
                    SarifUtilities.CreateSingleThreadedCodeFlow()
                }
            };

            _reader.Read();
            while (!AtEndOf(_strings.Vulnerability))
            {
                if (AtStartOfNonEmpty(_strings.ClassId))
                {
                    result.RuleId = _reader.ReadElementContentAsString();
                }
                else if (AtStartOfNonEmpty(_strings.ReplacementDefinitions))
                {
                    ParseReplacementDefinitions(result);
                }
                else if (AtStartOfNonEmpty(_strings.Trace))
                {
                    ParseLocationFromTrace(result);
                }

                _reader.Read();
            }

            _results.Add(result);
        }
        internal ReplacementVersionOne CreateReplacementVersionOne(Replacement v2Replacement, Encoding encoding)
        {
            ReplacementVersionOne replacement = null;

            if (v2Replacement != null)
            {
                replacement = new ReplacementVersionOne();
                ArtifactContent insertedContent = v2Replacement.InsertedContent;

                if (insertedContent != null)
                {
                    if (insertedContent.Binary != null)
                    {
                        replacement.InsertedBytes = insertedContent.Binary;
                    }
                    else if (insertedContent.Text != null)
                    {
                        if (encoding != null)
                        {
                            replacement.InsertedBytes = SarifUtilities.GetBase64String(insertedContent.Text, encoding);
                        }
                        else
                        {
                            // The encoding is null or not supported on the current platform
                            throw new UnknownEncodingException();
                        }
                    }
                }

                replacement.DeletedLength = v2Replacement.DeletedRegion.ByteLength;
                replacement.Offset        = v2Replacement.DeletedRegion.ByteOffset;
            }

            return(replacement);
        }
        public void CanConvertCodeFlowToTreeOnlyDeclarations()
        {
            var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Declaration
                },
            });

            List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null);

            topLevelNodes.Count.Should().Be(3);
            topLevelNodes[0].Children.Should().BeEmpty();
            topLevelNodes[1].Children.Should().BeEmpty();
            topLevelNodes[2].Children.Should().BeEmpty();

            topLevelNodes[1].Location.NestingLevel.Should().Be(0); // Declaration
            topLevelNodes[0].Location.NestingLevel.Should().Be(0); // Declaration
            topLevelNodes[2].Location.NestingLevel.Should().Be(0); // Declaration

            topLevelNodes[0].Parent.Should().Be(null);
            topLevelNodes[1].Parent.Should().Be(null);
            topLevelNodes[2].Parent.Should().Be(null);
        }
        private FileDataVersionOne CreateFileDataVersionOne(Artifact v2FileData)
        {
            FileDataVersionOne fileData = null;

            if (v2FileData != null)
            {
                int    parentIndex = v2FileData.ParentIndex;
                string parentKey   = parentIndex == -1
                    ? null
                    : _v2FileIndexToV1KeyMap?[parentIndex];

                fileData = new FileDataVersionOne
                {
                    Hashes     = CreateHashVersionOneListFromV2Hashes(v2FileData.Hashes),
                    Length     = v2FileData.Length,
                    MimeType   = v2FileData.MimeType,
                    Offset     = v2FileData.Offset,
                    ParentKey  = parentKey,
                    Properties = v2FileData.Properties,
                    Uri        = v2FileData.Location?.Uri,
                    UriBaseId  = v2FileData.Location?.UriBaseId
                };

                if (v2FileData.Contents != null)
                {
                    fileData.Contents = MimeType.IsTextualMimeType(v2FileData.MimeType) ?
                                        SarifUtilities.GetUtf8Base64String(v2FileData.Contents.Text) :
                                        v2FileData.Contents.Binary;
                }
            }

            return(fileData);
        }
Example #6
0
        public void SelectPreviousNextCommandsTest()
        {
            var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0
                }
            });

            var mockToolWindow = new Mock <IToolWindow>();

            mockToolWindow.Setup(s => s.UpdateSelectionList(It.IsAny <object[]>()));

            CallTree callTree = new CallTree(CodeFlowToTreeConverter.Convert(codeFlow, run: null), mockToolWindow.Object);

            callTree.FindPrevious().Should().Be(null);
            callTree.FindNext().Should().Be(null);

            callTree.SelectedItem = callTree.TopLevelNodes[0];
            callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0]);
            callTree.FindNext().Should().Be(callTree.TopLevelNodes[0].Children[0]);

            callTree.SelectedItem = callTree.TopLevelNodes[0].Children[0];
            callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0]);
            callTree.FindNext().Should().Be(callTree.TopLevelNodes[0].Children[1]);

            callTree.SelectedItem = callTree.TopLevelNodes[0].Children[2];
            callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0].Children[1]);
            callTree.FindNext().Should().Be(callTree.TopLevelNodes[1]);

            callTree.SelectedItem = callTree.TopLevelNodes[1];
            callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[0].Children[2]);
            callTree.FindNext().Should().Be(callTree.TopLevelNodes[2]);

            callTree.SelectedItem = callTree.TopLevelNodes[2];
            callTree.FindPrevious().Should().Be(callTree.TopLevelNodes[1]);
            callTree.FindNext().Should().Be(callTree.TopLevelNodes[2]);
        }
        public void SelectPreviousNextCommandsTest()
        {
            CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                },
            });

            var analysisStep = new AnalysisStep(CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0));

            analysisStep.FindPrevious().Should().Be(null);
            analysisStep.FindNext().Should().Be(null);

            analysisStep.SelectedItem = analysisStep.TopLevelNodes[0];
            analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0]);
            analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[0].Children[0]);

            analysisStep.SelectedItem = analysisStep.TopLevelNodes[0].Children[0];
            analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0]);
            analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[0].Children[1]);

            analysisStep.SelectedItem = analysisStep.TopLevelNodes[0].Children[2];
            analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0].Children[1]);
            analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[1]);

            analysisStep.SelectedItem = analysisStep.TopLevelNodes[1];
            analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[0].Children[2]);
            analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[2]);

            analysisStep.SelectedItem = analysisStep.TopLevelNodes[2];
            analysisStep.FindPrevious().Should().Be(analysisStep.TopLevelNodes[1]);
            analysisStep.FindNext().Should().Be(analysisStep.TopLevelNodes[2]);
        }
        internal Artifact CreateFileData(FileDataVersionOne v1FileData, string key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            Artifact fileData = null;

            if (v1FileData != null)
            {
                string parentKey   = v1FileData.ParentKey;
                int    parentIndex = parentKey == null
                    ? -1
                    : _v1FileKeytoV2IndexMap[parentKey];

                fileData = new Artifact
                {
                    Hashes      = v1FileData.Hashes?.Select(CreateHash).ToDictionary(p => p.Key, p => p.Value),
                    Length      = v1FileData.Length,
                    MimeType    = v1FileData.MimeType,
                    Offset      = v1FileData.Offset,
                    ParentIndex = parentIndex,
                    Properties  = v1FileData.Properties
                };

                fileData.Location           = ArtifactLocation.CreateFromFilesDictionaryKey(key, parentKey);
                fileData.Location.UriBaseId = v1FileData.UriBaseId;

                if (v1FileData.Contents != null)
                {
                    fileData.Contents = new ArtifactContent();

                    if (MimeType.IsTextualMimeType(v1FileData.MimeType))
                    {
                        fileData.Contents.Text = SarifUtilities.DecodeBase64String(v1FileData.Contents);
                    }
                    else
                    {
                        fileData.Contents.Binary = v1FileData.Contents;
                    }
                }
            }

            return(fileData);
        }
        private static void AddLocationToResult(IEnumerable <CppCheckLocation> cppCheckLocations, Result result)
        {
            PhysicalLocation lastLocationConverted;
            var locations = new List <ThreadFlowLocation>
            {
                Capacity = cppCheckLocations.Count()
            };

            if (locations.Capacity == 0)
            {
                return;
            }

            foreach (CppCheckLocation loc in cppCheckLocations)
            {
                locations.Add(new ThreadFlowLocation
                {
                    Location = new Location
                    {
                        PhysicalLocation = loc.ToSarifPhysicalLocation()
                    },
                    Importance = ThreadFlowLocationImportance.Essential
                });
            }

            // A codeflow doesn't make sense if you only have the result location, and nothing leading up to it.
            if (locations.Capacity > 1)
            {
                result.CodeFlows = new List <CodeFlow>()
                {
                    SarifUtilities.CreateSingleThreadedCodeFlow(locations)
                };
            }

            // Set the result's location to the last location in the code flow.
            lastLocationConverted = locations[locations.Count - 1].Location.PhysicalLocation;
            result.Locations      = new List <Location>
            {
                new Location
                {
                    PhysicalLocation = lastLocationConverted
                }
            };
        }
        private CallTree CreateCallTree()
        {
            var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Importance   = ThreadFlowLocationImportance.Unimportant,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Importance   = ThreadFlowLocationImportance.Important,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Importance   = ThreadFlowLocationImportance.Essential,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Importance   = ThreadFlowLocationImportance.Unimportant,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Importance   = ThreadFlowLocationImportance.Unimportant,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Importance   = ThreadFlowLocationImportance.Essential,
                }
            });

            var mockToolWindow = new Mock <IToolWindow>();

            mockToolWindow.Setup(s => s.UpdateSelectionList(It.IsAny <object[]>()));

            CallTree callTree = new CallTree(CodeFlowToTreeConverter.Convert(codeFlow, run: null), mockToolWindow.Object);

            return(callTree);
        }
        internal FileData CreateFileData(FileDataVersionOne v1FileData)
        {
            FileData fileData = null;

            if (v1FileData != null)
            {
                fileData = new FileData
                {
                    Hashes     = v1FileData.Hashes?.Select(CreateHash).ToList(),
                    Length     = v1FileData.Length,
                    MimeType   = v1FileData.MimeType,
                    Offset     = v1FileData.Offset,
                    ParentKey  = v1FileData.ParentKey,
                    Properties = v1FileData.Properties
                };

                if (v1FileData.Uri != null)
                {
                    fileData.FileLocation = new FileLocation
                    {
                        Uri       = v1FileData.Uri,
                        UriBaseId = v1FileData.UriBaseId
                    };
                }

                if (v1FileData.Contents != null)
                {
                    fileData.Contents = new FileContent();

                    if (MimeType.IsTextualMimeType(v1FileData.MimeType))
                    {
                        fileData.Contents.Text = SarifUtilities.DecodeBase64String(v1FileData.Contents);
                    }
                    else
                    {
                        fileData.Contents.Binary = v1FileData.Contents;
                    }
                }
            }

            return(fileData);
        }
        private AnalysisStep CreateAnalysisStep()
        {
            CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Importance   = ThreadFlowLocationImportance.Unimportant,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Importance   = ThreadFlowLocationImportance.Important,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Importance   = ThreadFlowLocationImportance.Essential,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Importance   = ThreadFlowLocationImportance.Unimportant,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Importance   = ThreadFlowLocationImportance.Unimportant,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Importance   = ThreadFlowLocationImportance.Essential,
                },
            });

            var analysisStep = new AnalysisStep(CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0));

            return(analysisStep);
        }
        public void CanConvertCodeFlowToTreeOnlyDeclarations()
        {
            CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Declaration
                },
            });

            List <AnalysisStepNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0);

            topLevelNodes.Count.Should().Be(3);
            topLevelNodes[0].Children.Should().BeEmpty();
            topLevelNodes[1].Children.Should().BeEmpty();
            topLevelNodes[2].Children.Should().BeEmpty();

            topLevelNodes[1].Location.NestingLevel.Should().Be(0); // Declaration
            topLevelNodes[0].Location.NestingLevel.Should().Be(0); // Declaration
            topLevelNodes[2].Location.NestingLevel.Should().Be(0); // Declaration

            topLevelNodes[0].Parent.Should().Be(null);
            topLevelNodes[1].Parent.Should().Be(null);
            topLevelNodes[2].Parent.Should().Be(null);

            List <AnalysisStepNode> flatNodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run: null, resultId: 0, runIndex: 0);

            VerifyCodeFlowFlatList(flatNodes, codeFlow, run: null);
        }
Example #14
0
        private Result ProcessSdvDefectStream(Stream input)
        {
            var result = new Result
            {
                Locations = new List <Location>(),
                CodeFlows = new []
                {
                    SarifUtilities.CreateSingleThreadedCodeFlow()
                }
            };

            using (var reader = new StreamReader(input))
            {
                int    nestingLevel = 0;
                string line;

                while (!string.IsNullOrEmpty(line = reader.ReadLine()))
                {
                    ProcessLine(line, ref nestingLevel, result);
                }
            }

            return(result);
        }
        public void CanConvertCodeFlowToTree()
        {
            var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "first parent"
                        }
                    }
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "second parent"
                        }
                    }
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 2, // CallReturn
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "third parent"
                        }
                    }
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 2, // CallReturn
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "fourth parent"
                        }
                    }
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 2, // CallReturn
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // CallReturn
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "fifth parent"
                        }
                    }
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // CallReturn,
                }
            });

            List <CallTreeNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null);

            topLevelNodes.Count.Should().Be(2);
            topLevelNodes[0].Children.Count.Should().Be(4);
            topLevelNodes[0].Children[2].Children.Count.Should().Be(1);

            // Check that we have the right nodes at the right places in the tree.
            topLevelNodes[0].Location.NestingLevel.Should().Be(0);                         // Call
            topLevelNodes[0].Children[0].Location.NestingLevel.Should().Be(1);             // Call
            topLevelNodes[0].Children[0].Children[0].Location.NestingLevel.Should().Be(2); // CallReturn
            topLevelNodes[0].Children[1].Location.NestingLevel.Should().Be(1);             // Call
            topLevelNodes[0].Children[1].Children[0].Location.NestingLevel.Should().Be(2); // CallReturn
            topLevelNodes[0].Children[2].Location.NestingLevel.Should().Be(1);             // Call
            topLevelNodes[0].Children[2].Children[0].Location.NestingLevel.Should().Be(2); // CallReturn
            topLevelNodes[0].Children[3].Location.NestingLevel.Should().Be(1);             // CallReturn
            topLevelNodes[1].Location.NestingLevel.Should().Be(0);                         // Call
            topLevelNodes[1].Children[0].Location.NestingLevel.Should().Be(1);             // CallReturn

            // Check parents
            topLevelNodes[0].Parent.Should().Be(null);
            topLevelNodes[0].Children[0].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[0].Children[0].Children[0].Parent.Location.Location.Message.Text.Should().Be("second parent");
            topLevelNodes[0].Children[1].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[0].Children[1].Children[0].Parent.Location.Location.Message.Text.Should().Be("third parent");
            topLevelNodes[0].Children[2].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[0].Children[2].Children[0].Parent.Location.Location.Message.Text.Should().Be("fourth parent");
            topLevelNodes[0].Children[3].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[1].Parent.Should().Be(null);
            topLevelNodes[1].Children[0].Parent.Location.Location.Message.Text.Should().Be("fifth parent");
        }
Example #16
0
        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 = new List <string> {
                                        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.PhysicalLocation.Id = 1;
                }
            }

            if (!string.IsNullOrEmpty(lastNodeId))
            {
                _resultToSnippetIdDictionary.Add(result, lastNodeId);
            }
        }
Example #17
0
        /// <summary>Converts this instance to <see cref="Result"/>.</summary>
        /// <returns>This instance as an <see cref="Result"/>.</returns>
        public Result ToSarifIssue()
        {
            if (this.Locations.Length == 0)
            {
                throw new InvalidOperationException("At least one location must be present in a SARIF result.");
            }

            var result = new Result
            {
                RuleId = this.Id,
            };

            result.SetProperty("Severity", this.Severity);

            if (!string.IsNullOrEmpty(this.VerboseMessage))
            {
                result.Message = new Message {
                    Text = this.VerboseMessage
                };
            }
            else
            {
                result.Message = new Message {
                    Text = this.Message
                };
            }

            PhysicalLocation lastLocationConverted;

            if (this.Locations.Length == 1)
            {
                lastLocationConverted = this.Locations[0].ToSarifPhysicalLocation();
            }
            else
            {
                var locations = new List <ThreadFlowLocation>
                {
                    Capacity = this.Locations.Length
                };

                foreach (CppCheckLocation loc in this.Locations)
                {
                    locations.Add(new ThreadFlowLocation
                    {
                        Location = new Location
                        {
                            PhysicalLocation = loc.ToSarifPhysicalLocation()
                        },
                        Importance = ThreadFlowLocationImportance.Essential
                    });
                }

                result.CodeFlows = new List <CodeFlow>()
                {
                    SarifUtilities.CreateSingleThreadedCodeFlow(locations)
                };

                // In the N != 1 case, set the overall location's location to
                // the last entry in the execution flow.
                lastLocationConverted = locations[locations.Count - 1].Location.PhysicalLocation;
            }

            result.Locations = new List <Location>
            {
                new Location
                {
                    PhysicalLocation = lastLocationConverted
                }
            };

            return(result);
        }
Example #18
0
        /// <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 <CodeFlowLocation>()
                {
                    new CodeFlowLocation {
                        Location = new Location {
                            PhysicalLocation = source
                        }
                    },
                    new CodeFlowLocation {
                        Location = new Location {
                            PhysicalLocation = primaryOrSink
                        }
                    }
                };
                result.CodeFlows = new List <CodeFlow>()
                {
                    SarifUtilities.CreateSingleThreadedCodeFlow(locations)
                };
            }

            return(result);
        }
        public void CanConvertCodeFlowToFlatListNonZeroBasedLevel()
        {
            CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 5,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 5",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Index = 0,
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 6,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 6",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Index = 0,
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 7,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 7",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Index = 0,
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 8,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 8",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Index = 0,
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 7,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 6,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 5,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 5,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 5",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Index = 1
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 5,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 5",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Index = 2
                            }
                        },
                    },
                },
            });

            var run = new Run
            {
                Artifacts = new[]
                {
                    new Artifact {
                        Location = new ArtifactLocation {
                            Uri = new Uri("path/to/file1.cpp", UriKind.Relative),
                        }
                    },
                    new Artifact {
                        Location = new ArtifactLocation {
                            Uri = new Uri("path/to/file2.cpp", UriKind.Relative),
                        }
                    },
                    new Artifact {
                        Location = new ArtifactLocation {
                            Uri = new Uri("path/to/file3.cpp", UriKind.Relative),
                        }
                    },
                },
            };
            List <AnalysisStepNode> nodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run, resultId: 0, runIndex: 0);

            VerifyCodeFlowFlatList(nodes, codeFlow, run: null);
        }
Example #20
0
        public void CanConvertCodeFlowToTreeNonCallOrReturn()
        {
            var codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "first parent",
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // CallReturn
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0, // Call
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "second parent",
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // Declaration
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1, // CallReturn
                },
            });

            List <AnalysisStepNode> topLevelNodes = CodeFlowToTreeConverter.Convert(codeFlow, run: null, resultId: 0, runIndex: 0);

            topLevelNodes.Count.Should().Be(2);
            topLevelNodes[0].Children.Count.Should().Be(4);
            topLevelNodes[1].Children.Count.Should().Be(3);

            // Spot-check that we have the right nodes at the right places in the tree.
            topLevelNodes[0].Location.NestingLevel.Should().Be(0);             // Call
            topLevelNodes[0].Children[0].Location.NestingLevel.Should().Be(1); // Declaration
            topLevelNodes[0].Children[3].Location.NestingLevel.Should().Be(1); // CallReturn
            topLevelNodes[1].Location.NestingLevel.Should().Be(0);             // Call
            topLevelNodes[1].Children[2].Location.NestingLevel.Should().Be(1); // CallReturn

            // Check parents
            topLevelNodes[0].Parent.Should().Be(null);
            topLevelNodes[0].Children[0].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[0].Children[1].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[0].Children[2].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[0].Children[3].Parent.Location.Location.Message.Text.Should().Be("first parent");
            topLevelNodes[1].Parent.Should().Be(null);
            topLevelNodes[1].Children[0].Parent.Location.Location.Message.Text.Should().Be("second parent");
            topLevelNodes[1].Children[1].Parent.Location.Location.Message.Text.Should().Be("second parent");
            topLevelNodes[1].Children[2].Parent.Location.Location.Message.Text.Should().Be("second parent");
        }
Example #21
0
        internal Result CreateResult(FxCopLogReader.Context context)
        {
            Result result = new Result();

            string uniqueId = context.GetUniqueId();

            if (!string.IsNullOrWhiteSpace(uniqueId))
            {
                if (result.PartialFingerprints == null)
                {
                    result.PartialFingerprints = new Dictionary <string, string>();
                }

                SarifUtilities.AddOrUpdateDictionaryEntry(result.PartialFingerprints, "UniqueId", uniqueId);
            }

            string status = context.Status;

            if ("ExcludedInSource".Equals(status))
            {
                result.Suppressions = new List <Suppression>
                {
                    new Suppression
                    {
                        Kind = SuppressionKind.InSource
                    }
                };
            }
            else if ("ExcludedInProject".Equals(status))
            {
                result.BaselineState = BaselineState.Unchanged;
            }

            result.RuleId = context.CheckId;
            string messageText = context.Message ?? ConverterResources.FxCopNoMessage;

            result.Message = new Message {
                Arguments = context.Items, Id = context.ResolutionName, Text = messageText
            };
            var location = new Location();

            string sourceFile = GetFilePath(context);
            string targetFile = context.Target;

            // If both source and target have values and they're different, set analysis target
            if (!string.IsNullOrWhiteSpace(sourceFile) &&
                !string.IsNullOrWhiteSpace(targetFile) &&
                !sourceFile.Equals(targetFile))
            {
                result.AnalysisTarget = BuildFileLocationFromFxCopReference(targetFile);
            }
            else
            {
                // One or the other or both is null, or they're different
                sourceFile = string.IsNullOrWhiteSpace(sourceFile) ? targetFile : sourceFile;
            }

            // Don't emit a location if neither physical location nor logical location information
            // is present. This is the case for CA0001 (unexpected error in analysis tool).
            // https://docs.microsoft.com/en-us/visualstudio/code-quality/ca0001?view=vs-2019
            bool emitLocation = false;

            // If we have a value, set physical location
            if (!string.IsNullOrWhiteSpace(sourceFile))
            {
                location.PhysicalLocation = new PhysicalLocation
                {
                    ArtifactLocation = BuildFileLocationFromFxCopReference(sourceFile),
                    Region           = context.Line == null ? null : Extensions.CreateRegion(context.Line.Value)
                };

                emitLocation = true;
            }

            string fullyQualifiedLogicalName = CreateFullyQualifiedLogicalName(context, out int logicalLocationIndex);

            if (!string.IsNullOrWhiteSpace(fullyQualifiedLogicalName) || logicalLocationIndex > -1)
            {
                location.LogicalLocation = new LogicalLocation
                {
                    FullyQualifiedName = fullyQualifiedLogicalName,
                    Index = logicalLocationIndex
                };

                emitLocation = true;
            }

            if (emitLocation)
            {
                result.Locations = new List <Location> {
                    location
                };
            }

            bool mapsDirectlyToSarifName;

            result.Level = ConvertFxCopLevelToResultLevel(context.Level ?? "Warning", out mapsDirectlyToSarifName);

            if (!mapsDirectlyToSarifName)
            {
                // We will not recapitulate FxCop MessageLevel names (such as
                // "Error" and "Warning") as a property. For names that differ
                // (such as "CriticalWarning" and "Information"), we will also
                // include the FxCop-specific values in the property bag.
                AddProperty(result, context.Level, "Level");
            }

            AddProperty(result, context.Category, "Category");
            AddProperty(result, context.FixCategory, "FixCategory");

            return(result);
        }
Example #22
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 <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)
            };
        }
Example #23
0
        internal Result CreateResult(FxCopLogReader.Context context)
        {
            Result result = new Result();

            string uniqueId = context.GetUniqueId();

            if (!String.IsNullOrWhiteSpace(uniqueId))
            {
                if (result.PartialFingerprints == null)
                {
                    result.PartialFingerprints = new Dictionary <string, string>();
                }

                SarifUtilities.AddOrUpdateDictionaryEntry(result.PartialFingerprints, "UniqueId", uniqueId);
            }

            string status = context.Status;

            if ("ExcludedInSource".Equals(status))
            {
                result.SuppressionStates = SuppressionStates.SuppressedInSource;
            }
            else if ("ExcludedInProject".Equals(status))
            {
                result.BaselineState = BaselineState.Unchanged;
            }

            result.RuleId  = context.CheckId;
            result.Message = new Message {
                Arguments = context.Items, MessageId = context.ResolutionName, Text = context.Message
            };
            var location = new Location();

            string sourceFile = GetFilePath(context);
            string targetFile = context.Target;

            // If both source and target have values and they're different, set analysis target
            if (!string.IsNullOrWhiteSpace(sourceFile) &&
                !string.IsNullOrWhiteSpace(targetFile) &&
                !sourceFile.Equals(targetFile))
            {
                result.AnalysisTarget = BuildFileLocationFromFxCopReference(targetFile);
            }
            else
            {
                // One or the other or both is null, or they're different
                sourceFile = string.IsNullOrWhiteSpace(sourceFile) ? targetFile : sourceFile;
            }

            // If we have a value, set physical location
            if (!string.IsNullOrWhiteSpace(sourceFile))
            {
                location.PhysicalLocation = new PhysicalLocation
                {
                    ArtifactLocation = BuildFileLocationFromFxCopReference(sourceFile),
                    Region           = context.Line == null ? null : Extensions.CreateRegion(context.Line.Value)
                };
            }

            location.FullyQualifiedLogicalName = CreateFullyQualifiedLogicalName(context, out int logicalLocationIndex);
            location.LogicalLocationIndex      = logicalLocationIndex;

            result.Locations = new List <Location> {
                location
            };

            bool mapsDirectlyToSarifName;

            result.Level = ConvertFxCopLevelToResultLevel(context.Level ?? "Warning", out mapsDirectlyToSarifName);

            if (!mapsDirectlyToSarifName)
            {
                // We will not recapitulate FxCop MessageLevel names (such as
                // "Error" and "Warning") as a property. For names that differ
                // (such as "CriticalWarning" and "Information"), we will also
                // include the FxCop-specific values in the property bag.
                AddProperty(result, context.Level, "Level");
            }

            AddProperty(result, context.Category, "Category");
            AddProperty(result, context.FixCategory, "FixCategory");

            return(result);
        }
Example #24
0
        private void EnhanceRun(
            IEnumerable <string> analysisTargets,
            OptionallyEmittedData dataToInsert,
            OptionallyEmittedData dataToRemove,
            IEnumerable <string> invocationTokensToRedact,
            IEnumerable <string> invocationPropertiesToLog,
            string defaultFileEncoding = null,
            IDictionary <string, HashData> filePathToHashDataMap = null)
        {
            _run.Invocations ??= new List <Invocation>();
            if (defaultFileEncoding != null)
            {
                _run.DefaultEncoding = defaultFileEncoding;
            }

            Encoding encoding = SarifUtilities.GetEncodingFromName(_run.DefaultEncoding);

            if (analysisTargets != null)
            {
                _run.Artifacts ??= new List <Artifact>();

                foreach (string target in analysisTargets)
                {
                    Uri uri = new Uri(UriHelper.MakeValidUri(target), UriKind.RelativeOrAbsolute);

                    HashData hashData = null;
                    if (dataToInsert.HasFlag(OptionallyEmittedData.Hashes))
                    {
                        filePathToHashDataMap?.TryGetValue(target, out hashData);
                    }

                    var artifact = Artifact.Create(
                        new Uri(target, UriKind.RelativeOrAbsolute),
                        dataToInsert,
                        encoding,
                        hashData: hashData);

                    var fileLocation = new ArtifactLocation
                    {
                        Uri = uri
                    };

                    artifact.Location = fileLocation;

                    // This call will insert the file object into run.Files if not already present
                    artifact.Location.Index = _run.GetFileIndex(
                        artifact.Location,
                        addToFilesTableIfNotPresent: true,
                        dataToInsert: dataToInsert,
                        encoding: encoding,
                        hashData: hashData);
                }
            }

            var invocation = Invocation.Create(
                emitMachineEnvironment: dataToInsert.HasFlag(OptionallyEmittedData.EnvironmentVariables),
                emitTimestamps: !dataToRemove.HasFlag(OptionallyEmittedData.NondeterministicProperties),
                invocationPropertiesToLog);

            // TODO we should actually redact across the complete log file context
            // by a dedicated rewriting visitor or some other approach.

            if (invocationTokensToRedact != null)
            {
                invocation.CommandLine = Redact(invocation.CommandLine, invocationTokensToRedact);
                invocation.Machine     = Redact(invocation.Machine, invocationTokensToRedact);
                invocation.Account     = Redact(invocation.Account, invocationTokensToRedact);

                if (invocation.WorkingDirectory != null)
                {
                    invocation.WorkingDirectory.Uri = Redact(invocation.WorkingDirectory.Uri, invocationTokensToRedact);
                }

                if (invocation.EnvironmentVariables != null)
                {
                    string[] keys = invocation.EnvironmentVariables.Keys.ToArray();

                    foreach (string key in keys)
                    {
                        string value = invocation.EnvironmentVariables[key];
                        invocation.EnvironmentVariables[key] = Redact(value, invocationTokensToRedact);
                    }
                }
            }

            _run.Invocations.Add(invocation);
        }
        public void CanConvertCodeFlowToFlatListZeroBasedLevel()
        {
            CodeFlow codeFlow = SarifUtilities.CreateSingleThreadedCodeFlow(new[]
            {
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 0",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Uri = new Uri("path/to/file.cpp", UriKind.Relative),
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 1",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Uri = new Uri("path/to/file.cpp", UriKind.Relative),
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 2,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 1",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Uri = new Uri("path/to/file.cpp", UriKind.Relative),
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 2,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 1",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Uri = new Uri("path/to/file.cpp", UriKind.Relative),
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 2,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 0,
                    Location     = new Location
                    {
                        Message = new Message
                        {
                            Text = "location level 0",
                        },
                        PhysicalLocation = new PhysicalLocation
                        {
                            ArtifactLocation = new ArtifactLocation
                            {
                                Uri = new Uri("path/to/file.cpp", UriKind.Relative),
                            }
                        },
                    },
                },
                new ThreadFlowLocation
                {
                    NestingLevel = 1,
                },
            });

            List <AnalysisStepNode> nodes = CodeFlowToTreeConverter.ToFlatList(codeFlow, run: null, resultId: 0, runIndex: 0);

            VerifyCodeFlowFlatList(nodes, codeFlow, run: null);
        }