コード例 #1
0
        public void GetMessageInlines_RendersWebLinkWithBackslashesInLinkText()
        {
            string url     = "http://example.com";
            string message = $@"The file [..\directory\file.cpp]({url}) has a problem.";

            var link = new Hyperlink();

            link.Tag = new Tuple <int, object>(1, new Uri(url, UriKind.Absolute));
            link.Inlines.Add(new Run(@"..\directory\file.cpp"));

            var expected = new List <Inline>
            {
                new Run("The file "),
                link,
                new Run(" has a problem.")
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
        }
コード例 #2
0
        public SarifLocationTextMarkerTagger(
            ITextView textView,
            ITextBuffer textBuffer,
            IPersistentSpanFactory persistentSpanFactory,
            ITextViewCaretListenerService <ITextMarkerTag> textViewCaretListenerService,
            ISarifErrorListEventSelectionService sarifErrorListEventSelectionService)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            if (!SdkUIUtilities.TryGetFileNameFromTextBuffer(textBuffer, out this.filePath))
            {
                throw new ArgumentException("Always expect to be able to get file name from text buffer.", nameof(textBuffer));
            }

            this.TextBuffer            = textBuffer;
            this.persistentSpanFactory = persistentSpanFactory;
            this.sarifErrorListEventSelectionService = sarifErrorListEventSelectionService;

            // Subscribe to the SARIF error item being selected from the error list
            // so we can properly filter the tags being shown in the editor
            // to the currently selected item.
            this.sarifErrorListEventSelectionService.SelectedItemChanged += this.SelectedSarifItemChanged;

            // Subscribe to the caret position so we can send enter and exit notifications
            // to the tags so they can decide potentially change their colors.
            textViewCaretListenerService.CreateListener(textView, this);
        }
コード例 #3
0
        public void GetMessageInlines_RendersTwoLinksAndHandlesLinkAtTheEnd()
        {
            const string message = @"The quick [brown fox](1) jumps over the [lazy dog](2)";

            var link1 = new Hyperlink();

            link1.Tag = 1;
            link1.Inlines.Add(new Run("brown fox"));

            var link2 = new Hyperlink();

            link2.Tag = 2;
            link2.Inlines.Add(new Run("lazy dog"));

            var expected = new List <Inline>
            {
                new Run("The quick "),
                link1,
                new Run(" jumps over the "),
                link2,
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, clickHandler: this.Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
            VerifyHyperlink(expected[3], actual[3]);
        }
コード例 #4
0
 private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
 {
     if (this.NavigateUri != null)
     {
         SdkUIUtilities.OpenExternalUrl(this.NavigateUri);
     }
 }
コード例 #5
0
        private static void VerifyErrorListItemEntry(SarifErrorListItem error, SarifResultTableEntry entry, dynamic test)
        {
            error.ShortMessage.Should().Be(test.ShortMessage);
            error.Message.Should().Be(test.FullMessage);
            error.RawMessage.Should().Be(test.RawMessage.Trim());
            error.HasEmbeddedLinks.Should().Be(test.ContainsHyperlink);

            entry.TryGetValue(StandardTableKeyNames.Text, out object textColumn).Should().BeTrue();
            entry.TryGetValue(StandardTableKeyNames.FullText, out object fullTextColumn).Should().BeTrue();
            entry.TryGetValue(StandardTableKeyNames2.TextInlines, out object textInlinesColumn).Should().BeTrue();
            entry.TryGetValue(SarifResultTableEntry.FullTextInlinesColumnName, out object fullTextInlinesColumn).Should().BeTrue();

            ((string)textColumn).Should().Be(test.ShortMessage);
            ((string)fullTextColumn).Should().Be(error.HasDetailsContent ? test.FullMessage : null);

            if (test.ContainsHyperlink)
            {
                var textInlines = textInlinesColumn as List <Inline>;
                textInlines.Should().NotBeNull();
                SdkUIUtilities.GetPlainText(textInlines).Should().Be(test.ShortPlainText);

                var fullTextInlines = fullTextInlinesColumn as List <Inline>;
                fullTextInlines.Should().NotBeNull();
                SdkUIUtilities.GetPlainText(fullTextInlines).Should().Be(test.FullPlainText);
            }
            else
            {
                textInlinesColumn.Should().BeNull();
                fullTextInlinesColumn.Should().BeNull();
            }
        }
コード例 #6
0
        internal static async Task ProcessSarifLogAsync(SarifLog sarifLog, string logFilePath, bool cleanErrors, bool openInEditor)
        {
            // The creation of the data models must be done on the UI thread (for now).
            // VS's table data source constructs are indeed thread safe.
            // The object model (which is eventually handed to WPF\XAML) could also
            // be constructed on any thread as well.
            // However the current implementation of the data model and
            // the "run data cache" have not been augmented to support this
            // and are not thread safe.
            // This work could be done in the future to do even less work on the UI
            // thread if needed.
            if (!SarifViewerPackage.IsUnitTesting)
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
            }

            // Clear previous data
            if (cleanErrors)
            {
                CleanAllErrors();
            }

            bool hasResults = false;

            foreach (Run run in sarifLog.Runs)
            {
                // run.tool is required, add one if it's missing
                if (run.Tool == null)
                {
                    run.Tool = new Tool
                    {
                        Driver = new ToolComponent
                        {
                            Name = Resources.UnknownToolName,
                        },
                    };
                }

                if (Instance.WriteRunToErrorList(run, logFilePath, sarifLog) > 0)
                {
                    hasResults = true;
                }
            }

            if (openInEditor && !SarifViewerPackage.IsUnitTesting)
            {
                SdkUIUtilities.OpenDocument(ServiceProvider.GlobalProvider, logFilePath, usePreviewPane: false);
            }

            if (hasResults)
            {
                if (!SarifViewerPackage.IsUnitTesting)
                {
                    // We cannot show UI during unit-tests.
                    SdkUIUtilities.ShowToolWindowAsync(new Guid(ToolWindowGuids80.ErrorList), activate: false).FileAndForget(Constants.FileAndForgetFaultEventNames.ShowErrorList);
                }
            }

            RaiseLogProcessed(ExceptionalConditionsCalculator.Calculate(sarifLog));
        }
コード例 #7
0
        public void GetMessageInlines_RendersOneLinkPlusLiteralBrackets()
        {
            const string message = @"The quick [brown fox](1) jumps over the \[lazy dog\].";

            var link = new Hyperlink {
                Tag = 1
            };

            link.Inlines.Add(new Run("brown fox"));

            var expected = new List <Inline>
            {
                new Run("The quick "),
                link,
                new Run(" jumps over the [lazy dog]."),
            };

            List <Inline> actual = SdkUIUtilities.GetMessageInlines(message, clickHandler: this.Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
        }
コード例 #8
0
        public void GetFileLocationPath_UriPathCanBeResolved()
        {
            string repoPath = "file:///C:/code/myProject/src/";
            var    run      = new Microsoft.CodeAnalysis.Sarif.Run
            {
                OriginalUriBaseIds = new Dictionary <string, ArtifactLocation>
                {
                    ["REPO_ROOT"] = new ArtifactLocation
                    {
                        Uri = new Uri(repoPath),
                    }
                },
            };
            var dataCache = new RunDataCache();
            int runId     = CodeAnalysisResultManager.Instance.GetNextRunIndex();

            CodeAnalysisResultManager.Instance.RunIndexToRunDataCache.Add(runId, dataCache);
            CodeAnalysisResultManager.Instance.CacheUriBasePaths(run);

            string filePath = @"AnalysisStep.cs";
            var    artifact = new ArtifactLocation {
                Uri = new Uri(filePath, UriKind.Relative), UriBaseId = "REPO_ROOT"
            };
            string path = SdkUIUtilities.GetFileLocationPath(artifact, runId);

            path.Should().Be(@"C:\code\myProject\src\AnalysisStep.cs");
        }
コード例 #9
0
        public void GetMessageInlines_RendersWebLink()
        {
            string url     = "http://example.com";
            string message = $"The quick [brown fox]({url}) jumps over the lazy dog.";

            var link = new Hyperlink();

            link.Tag = new Tuple <int, object>(1, new Uri(url, UriKind.Absolute));
            link.Inlines.Add(new Run("brown fox"));

            var expected = new List <Inline>
            {
                new Run("The quick "),
                link,
                new Run(" jumps over the lazy dog.")
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
        }
コード例 #10
0
        public void SarifSnapshot_GetMessageEmbeddedLinkInlines_TwoLinksAndEndsWithLink()
        {
            string message = @"The quick [brown fox](1) jumps over the [lazy dog](2)";

            var link1 = new Hyperlink();

            link1.Tag = new Tuple <int, int>(1, 1);
            link1.Inlines.Add(new Run("brown fox"));

            var link2 = new Hyperlink();

            link2.Tag = new Tuple <int, int>(1, 2);
            link2.Inlines.Add(new Run("lazy dog"));

            var expected = new List <Inline>
            {
                new Run("The quick "),
                link1,
                new Run(" jumps over the "),
                link2
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
            VerifyHyperlink(expected[3], actual[3]);
        }
コード例 #11
0
        public void GetPlainText_ConvertInlinesWithTwoHttpLinks()
        {
            // raw text "The quick [brown fox](https://example.com) jumps over the [lazy dog](1).";
            const string url      = "http://example.com";
            const string expected = @"The quick brown fox jumps over the lazy dog.";

            var hyperlink1 = new Hyperlink(new Run("brown fox"));

            hyperlink1.NavigateUri = new Uri(url);

            var hyperlink2 = new Hyperlink(new Run("lazy dog"));

            hyperlink2.Tag = 1;

            var inputs = new List <Inline>
            {
                new Run("The quick "),
                hyperlink1,
                new Run(" jumps over the "),
                hyperlink2,
                new Run("."),
            };

            string actual = SdkUIUtilities.GetPlainText(inputs);

            actual.Should().NotBeNull();
            actual.Should().Be(expected);
        }
コード例 #12
0
 internal virtual void SaveFixLedger()
 {
     if (s_sourceFileFixLedger.Count > 0)
     {
         SdkUIUtilities.StoreObject <Dictionary <string, FixOffsetList> >(s_sourceFileFixLedger, s_sourceFileFixLedgerFileName);
     }
 }
コード例 #13
0
 // Event handler for HyperLink click event in a XAML element
 private static void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
 {
     if (sender is Hyperlink hyperlink && !string.IsNullOrWhiteSpace(hyperlink.NavigateUri?.AbsoluteUri))
     {
         SdkUIUtilities.OpenExternalUrl(hyperlink.NavigateUri.AbsoluteUri);
         e.Handled = true;
     }
 }
コード例 #14
0
        public void GetMessageInlines_DoesNotGenerateLinkForEscapedBrackets()
        {
            string message = @"The quick \[brown fox\] jumps over the lazy dog.";

            // Because there are no embedded links, we shouldn't get anything back
            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            actual.Count.Should().Be(0);
        }
コード例 #15
0
        private void RefreshPersistentSpans()
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            // If this text buffer is not associated with a file, it cannot have any SARIF errors.
            this.errorsInFile = SdkUIUtilities.TryGetFileNameFromTextBuffer(this.textBuffer, out string fileName)
                ? GetErrorsInFile(fileName)
                : Enumerable.Empty <SarifErrorListItem>().ToList();
            this.CalculatePersistentSpans(this.errorsInFile);
        }
コード例 #16
0
        public void GetPlainText_GetNullIfInputIsNullOrEmpty()
        {
            List <Inline> inputs = null;
            string        actual = SdkUIUtilities.GetPlainText(inputs);

            actual.Should().BeNull();

            inputs = new List <Inline>();
            actual = SdkUIUtilities.GetPlainText(inputs);
            actual.Should().BeNull();
        }
コード例 #17
0
        public void SarifSnapshot_GetMessageEmbeddedLinkInlines_ZeroLinksEscapedBrackets()
        {
            string message = @"The quick \[brown fox\] jumps over the lazy dog.";

            var expected = new List <Inline>
            {
                new Run("The quick [brown fox] jumps over the lazy dog.")
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            VerifyTextRun(expected[0], actual[0]);
        }
        public SarifLocationErrorTagger(ITextBuffer textBuffer, IPersistentSpanFactory persistentSpanFactory, ISarifErrorListEventSelectionService sarifErrorListEventSelectionService)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            if (!SdkUIUtilities.TryGetFileNameFromTextBuffer(textBuffer, out this.filePath))
            {
                throw new ArgumentException("Always expect to be able to get file name from text buffer.", nameof(textBuffer));
            }

            this.TextBuffer = textBuffer;

            this.persistentSpanFactory = persistentSpanFactory;
            this.sarifErrorListEventSelectionService = sarifErrorListEventSelectionService;
            this.sarifErrorListEventSelectionService.SelectedItemChanged += this.SarifErrorListEventSelectionService_SelectedItemChanged;
        }
コード例 #19
0
        public void GetFileLocationPath_UriIsLocalPath()
        {
            var dataCache = new RunDataCache();
            int runId     = CodeAnalysisResultManager.Instance.GetNextRunIndex();

            CodeAnalysisResultManager.Instance.RunIndexToRunDataCache.Add(runId, dataCache);

            string filePath = @"C:\repo\src\AnalysisStep.cs";
            var    artifact = new ArtifactLocation {
                Uri = new Uri(filePath, UriKind.Absolute)
            };
            string path = SdkUIUtilities.GetFileLocationPath(artifact, runId);

            path.Should().Be(filePath);
        }
コード例 #20
0
        public void GetFileLocationPath_UriIsNull()
        {
            var dataCache = new RunDataCache();
            int runId     = CodeAnalysisResultManager.Instance.GetNextRunIndex();

            CodeAnalysisResultManager.Instance.RunIndexToRunDataCache.Add(runId, dataCache);

            var    artifact = new ArtifactLocation();
            string path     = SdkUIUtilities.GetFileLocationPath(artifact, runId);

            path.Should().BeNull();

            artifact = null;
            path     = SdkUIUtilities.GetFileLocationPath(artifact, runId);
            path.Should().BeNull();
        }
コード例 #21
0
        public void GetPlainText_ConvertInlinesWithPathLink()
        {
            // raw text "The quick brown fox jumps over the lazy dog."
            const string expected = @"The quick brown fox jumps over the lazy dog.";

            var inputs = new List <Inline>
            {
                new Run("The quick "),
                new Run("brown fox"),
                new Run(" jumps over the "),
                new Run("lazy dog."),
            };

            string actual = SdkUIUtilities.GetPlainText(inputs);

            actual.Should().NotBeNull();
            actual.Should().Be(expected);
        }
コード例 #22
0
#pragma warning restore IDE0044
#pragma warning restore CS0649

        /// <inheritdoc/>
        /// <remarks>
        /// Note that Visual Studio's tagger aggregation expects and correctly handles null
        /// if a tagger provider does not want to provide tags.
        /// </remarks>
        public ITagger <T> CreateTagger <T>(ITextView textView, ITextBuffer textBuffer)
            where T : ITag
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            if (textView == null)
            {
                throw new ArgumentNullException(nameof(textView));
            }

            if (textBuffer == null)
            {
                throw new ArgumentNullException(nameof(textBuffer));
            }

            // The SARIF viewer needs a text buffer to have a file name in order to be able to associate a SARIF
            // result location with the file. Visual Studio allows text buffers to be created at any time with our without a filename.
            // So, if there is no file name, then do not create a tagger for this buffer.
            if (!SdkUIUtilities.TryGetFileNameFromTextBuffer(textBuffer, out _))
            {
                return(null);
            }

            ISarifLocationTagger newTagger = null;

            if (typeof(T) == typeof(IErrorTag))
            {
                newTagger = new SarifLocationErrorTagger(textBuffer, this.persistentSpanFactory, this.sarifErrorListEventSelectionService);
            }

            if (typeof(T) == typeof(ITextMarkerTag))
            {
                newTagger = new SarifLocationTextMarkerTagger(textView, textBuffer, this.persistentSpanFactory, this.textViewCaretListenerService, this.sarifErrorListEventSelectionService);
            }

            if (newTagger != null)
            {
                this.sarifLocationTaggerService.AddTagger(newTagger);
            }

            return(newTagger as ITagger <T>);
        }
コード例 #23
0
        internal virtual void LoadFixLedger()
        {
            if (s_sourceFileFixLedger == null)
            {
                s_sourceFileFixLedger = SdkUIUtilities.GetStoredObject <Dictionary <string, FixOffsetList> >(s_sourceFileFixLedgerFileName) ?? new Dictionary <string, FixOffsetList>();

                // Remove entries where the last modified timestamps don't match
                // This could indicate that the file was modified or overwritten externally
                List <string> remove = s_sourceFileFixLedger
                                       .Where(e => !File.Exists(e.Key) || File.GetLastWriteTime(e.Key) != e.Value.LastModified)
                                       .Select(e => e.Key)
                                       .ToList();

                if (remove.Count > 0)
                {
                    remove.ForEach(p => s_sourceFileFixLedger.Remove(p));
                    SaveFixLedger();
                }
            }
        }
コード例 #24
0
        public void GetPlainText_ConvertInlinesWithLiteralBrackets()
        {
            // raw text "The file ['..\directory\file.cpp']({url}) has a \[problem\]."
            const string expected = @"The file '..\directory\file.cpp' has a \[problem\].";

            var hyperlink = new Hyperlink(new Run(@"'..\directory\file.cpp'"));

            hyperlink.NavigateUri = new Uri("file://*****:*****@" has a \[problem\]."),
            };

            string actual = SdkUIUtilities.GetPlainText(inputs);

            actual.Should().NotBeNull();
            actual.Should().Be(expected);
        }
コード例 #25
0
        public void SarifSnapshot_GetMessageEmbeddedLinkInlines_DontCreateLinks()
        {
            string message = @"The quick [brown fox](2) jumps over the lazy dog.";

            var expected = new List <Inline>
            {
                new Run("The quick "),
                new Run("brown fox"),
                new Run(" jumps over the lazy dog.")
            };

            var actual = SdkUIUtilities.GetInlinesForErrorMessage(message);

            actual.Count.Should().Be(expected.Count);

            for (int i = 0; i < actual.Count; i++)
            {
                VerifyTextRun(expected[i], actual[i]);
            }
        }
コード例 #26
0
        public void GetInlinesForErrorMessage_DoesNotCreateLinks()
        {
            const string message = @"The quick [brown fox](2) jumps over the lazy dog.";

            var expected = new List <Inline>
            {
                new Run("The quick "),
                new Run("brown fox"),
                new Run(" jumps over the lazy dog."),
            };

            List <Inline> actual = SdkUIUtilities.GetInlinesForErrorMessage(message);

            actual.Count.Should().Be(expected.Count);

            for (int i = 0; i < actual.Count; i++)
            {
                VerifyTextRun(expected[i], actual[i]);
            }
        }
コード例 #27
0
        public void GetInlinesForErrorMessage_IgnoresInvalidLink()
        {
            // That is, the fact that the link destination doesn't look like a URL
            // doesn't bother it.
            string message = @"The quick [brown fox](some text) jumps over the lazy dog.";

            var expected = new List <Inline>
            {
                new Run("The quick "),
                new Run("brown fox"),
                new Run(" jumps over the lazy dog.")
            };

            var actual = SdkUIUtilities.GetInlinesForErrorMessage(message);

            actual.Count.Should().Be(expected.Count);

            for (int i = 0; i < actual.Count; i++)
            {
                VerifyTextRun(expected[i], actual[i]);
            }
        }
コード例 #28
0
        internal void InlineLink_Click(object sender, RoutedEventArgs e)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            if (!(sender is XamlDoc.Hyperlink hyperLink))
            {
                return;
            }

            string uriString = null;

            if (hyperLink.Tag is string uriAsString)
            {
                uriString = uriAsString;
            }
            else if (hyperLink.Tag is Uri uri)
            {
                uriString = uri.ToString();
            }

            if (!string.IsNullOrEmpty(uriString) && Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out Uri _))
            {
                SdkUIUtilities.OpenExternalUrl(uriString);
            }
        }
コード例 #29
0
        public void SarifSnapshot_GetMessageEmbeddedLinkInlines_OneLinkPlusEscapedBrackets()
        {
            string message = @"The quick [brown fox](1) jumps over the \[lazy dog\].";

            var link = new Hyperlink();

            link.Tag = new Tuple <int, int>(1, 1);
            link.Inlines.Add(new Run("brown fox"));

            var expected = new List <Inline>
            {
                new Run("The quick "),
                link,
                new Run(" jumps over the [lazy dog].")
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
        }
コード例 #30
0
        public void GetMessageInlines_RendersOneLink()
        {
            string message = @"The quick [brown fox](1) jumps over the lazy dog.";

            var link = new Hyperlink();

            link.Tag = new Tuple <int, object>(1, 1);
            link.Inlines.Add(new Run("brown fox"));

            var expected = new List <Inline>
            {
                new Run("The quick "),
                link,
                new Run(" jumps over the lazy dog.")
            };

            var actual = SdkUIUtilities.GetMessageInlines(message, index: 1, clickHandler: Hyperlink_Click);

            actual.Count.Should().Be(expected.Count);

            VerifyTextRun(expected[0], actual[0]);
            VerifyHyperlink(expected[1], actual[1]);
            VerifyTextRun(expected[2], actual[2]);
        }