/// <summary>
        /// Attempts to locate an active "code window" view for the given text buffer.
        /// </summary>
        /// <param name="textBuffer">The text buffer for which to locate a view.</param>
        /// <param name="wpfTextView">On successful return, contains an instance of <see cref="IWpfTextView"/> that is being used to display the text buffer contents.</param>
        /// <returns>Returns true if a view can be located.</returns>
        public static bool TryGetActiveViewForTextBuffer(ITextBuffer textBuffer, out IWpfTextView wpfTextView)
        {
            wpfTextView = null;

            if (!textBuffer.Properties.TryGetProperty(typeof(IVsTextBuffer), out IVsTextBuffer vsTextBuffer))
            {
                return(false);
            }

            if (!(Package.GetGlobalService(typeof(SVsTextManager)) is IVsTextManager2 textManager2))
            {
                return(false);
            }

            if (textManager2.GetActiveView2(fMustHaveFocus: 0, pBuffer: vsTextBuffer, grfIncludeViewFrameType: (uint)_VIEWFRAMETYPE.vftCodeWindow, ppView: out IVsTextView vsTextView) != VSConstants.S_OK)
            {
                return(false);
            }

            if (!SdkUIUtilities.TryGetWpfTextView(vsTextView, out wpfTextView))
            {
                return(false);
            }

            return(true);
        }
        public void NavigateTo(bool usePreviewPane = true)
        {
            if (LineMarker != null)
            {
                LineMarker?.NavigateTo(usePreviewPane);
            }
            else
            {
                // The user clicked an inline link with an integer target, which points to
                // a Location object that does NOT have a region associated with it.

                // Before anything else, see if this is an external link we should open in the browser.
                if (Uri.TryCreate(this.FilePath, UriKind.Absolute, out Uri uri))
                {
                    if (!uri.IsFile)
                    {
                        System.Diagnostics.Process.Start(uri.OriginalString);
                        return;
                    }
                }

                if (!File.Exists(this.FilePath))
                {
                    CodeAnalysisResultManager.Instance.TryRebaselineAllSarifErrors(RunId, this.UriBaseId, this.FilePath);
                }

                if (File.Exists(this.FilePath))
                {
                    SdkUIUtilities.OpenDocument(SarifViewerPackage.ServiceProvider, this.FilePath, usePreviewPane);
                }
            }
        }
        private string GetDocumentName(uint docCookie, IVsWindowFrame pFrame)
        {
            string documentName = null;
            IVsRunningDocumentTable runningDocTable = SdkUIUtilities.GetService <SVsRunningDocumentTable, IVsRunningDocumentTable>(ServiceProvider);

            if (runningDocTable != null)
            {
                uint         grfRDTFlags;
                uint         dwReadLocks;
                uint         dwEditLocks;
                IVsHierarchy pHier;
                uint         itemId;
                IntPtr       docData = IntPtr.Zero;
                try
                {
                    int hr = runningDocTable.GetDocumentInfo(docCookie,
                                                             out grfRDTFlags,
                                                             out dwReadLocks,
                                                             out dwEditLocks,
                                                             out documentName,
                                                             out pHier,
                                                             out itemId,
                                                             out docData);
                }
                finally
                {
                    if (docData != IntPtr.Zero)
                    {
                        Marshal.Release(docData);
                    }
                }
            }
            return(documentName);
        }
Example #4
0
        internal IVsWindowFrame NavigateTo(bool usePreviewPane)
        {
            // Fall back to the file and line number

            if (!File.Exists(this.FullFilePath))
            {
                if (!CodeAnalysisResultManager.Instance.TryRebaselineAllSarifErrors(this.UriBaseId, this.FullFilePath))
                {
                    return(null);
                }
            }

            IVsWindowFrame windowFrame = SdkUIUtilities.OpenDocument(SarifViewerPackage.ServiceProvider, this.FullFilePath, usePreviewPane);

            if (windowFrame != null)
            {
                IVsTextView textView = GetTextViewFromFrame(windowFrame);
                if (textView == null)
                {
                    return(null);
                }

                var sourceLocation = this.GetSourceLocation();

                // Navigate the caret to the desired location. Text span uses 0-based indexes
                TextSpan ts;
                ts.iEndLine  = ts.iStartLine = sourceLocation.StartLine - 1;
                ts.iEndIndex = ts.iStartIndex = Math.Max(sourceLocation.StartColumn - 1, 0);

                textView.EnsureSpanVisible(ts);
                textView.SetSelection(ts.iStartLine, ts.iStartIndex, ts.iEndLine, ts.iEndIndex);
            }
            return(windowFrame);
        }
        public SarifErrorListItem(Run run, int runIndex, Notification notification, string logFilePath, ProjectNameCache projectNameCache)
            : this()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            this.RunIndex = runIndex;
            string ruleId = null;

            if (notification.AssociatedRule != null)
            {
                ruleId = notification.AssociatedRule.Id;
            }
            else if (notification.Descriptor != null)
            {
                ruleId = notification.Descriptor.Id;
            }

            run.TryGetRule(ruleId, out ReportingDescriptor rule);
            this.RawMessage = notification.Message.Text?.Trim() ?? string.Empty;
            (this.ShortMessage, this.Message) = SdkUIUtilities.SplitResultMessage(this.RawMessage, MaxConcisedTextLength);

            this.Level       = notification.Level;
            this.LogFilePath = logFilePath;
            this.FileName    = SdkUIUtilities.GetFileLocationPath(notification.Locations?[0]?.PhysicalLocation?.ArtifactLocation, this.RunIndex) ?? string.Empty;
            this.ProjectName = projectNameCache.GetName(this.FileName);
            this.Locations.Add(new LocationModel(resultId: this.ResultId, runIndex: this.RunIndex)
            {
                FilePath = FileName
            });

            this.Tool             = run.Tool.ToToolModel();
            this.Rule             = rule.ToRuleModel(ruleId);
            this.Invocation       = run.Invocations?[0]?.ToInvocationModel();
            this.WorkingDirectory = Path.Combine(Path.GetTempPath(), this.RunIndex.ToString());
            this.HelpLink         = this.Rule?.HelpUri;
        }
 internal void AddAllowedDownloadHost(string host)
 {
     if (!this._allowedDownloadHosts.Contains(host))
     {
         this._allowedDownloadHosts.Add(host);
         SdkUIUtilities.StoreObject <List <string> >(this._allowedDownloadHosts, AllowedDownloadHostsFileName);
     }
 }
Example #7
0
        // This method is called when you click an inline link, with an integer target, which
        // points to a Location object that has a region associated with it.
        internal IVsWindowFrame NavigateTo(bool usePreviewPane)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            // Before anything else, see if this is an external link we should open in the browser.
            Uri uri;

            if (Uri.TryCreate(this.FullFilePath, UriKind.Absolute, out uri))
            {
                if (!uri.IsFile)
                {
                    System.Diagnostics.Process.Start(uri.OriginalString);
                    return(null);
                }
            }

            // Fall back to the file and line number
            if (!File.Exists(this.FullFilePath))
            {
                if (!CodeAnalysisResultManager.Instance.TryRebaselineAllSarifErrors(_runId, this.UriBaseId, this.FullFilePath))
                {
                    return(null);
                }
            }

            if (File.Exists(this.FullFilePath) && Uri.TryCreate(this.FullFilePath, UriKind.Absolute, out uri))
            {
                // Fill out the region's properties
                FileRegionsCache regionsCache = CodeAnalysisResultManager.Instance.RunDataCaches[_runId].FileRegionsCache;
                Region = regionsCache.PopulateTextRegionProperties(Region, uri, true);
            }

            IVsWindowFrame windowFrame = SdkUIUtilities.OpenDocument(SarifViewerPackage.ServiceProvider, this.FullFilePath, usePreviewPane);

            if (windowFrame != null)
            {
                IVsTextView textView = GetTextViewFromFrame(windowFrame);
                if (textView == null)
                {
                    return(null);
                }

                var sourceLocation = this.GetSourceLocation();

                // Navigate the caret to the desired location. Text span uses 0-based indexes
                TextSpan ts;
                ts.iStartLine  = sourceLocation.StartLine - 1;
                ts.iEndLine    = sourceLocation.EndLine - 1;
                ts.iStartIndex = Math.Max(sourceLocation.StartColumn - 1, 0);
                ts.iEndIndex   = Math.Max(sourceLocation.EndColumn - 1, 0);

                textView.EnsureSpanVisible(ts);
                textView.SetSelection(ts.iStartLine, ts.iStartIndex, ts.iEndLine, ts.iEndIndex);
            }
            return(windowFrame);
        }
Example #8
0
        // This ctor is internal rather than private for unit test purposes.
        internal CodeAnalysisResultManager(
            IFileSystem fileSystem,
            PromptForResolvedPathDelegate promptForResolvedPathDelegate = null)
        {
            this._fileSystem = fileSystem;
            this._promptForResolvedPathDelegate = promptForResolvedPathDelegate ?? this.PromptForResolvedPath;

            this._allowedDownloadHosts = SdkUIUtilities.GetStoredObject <List <string> >(AllowedDownloadHostsFileName) ?? new List <string>();

            // Get temporary path for embedded files.
            this.temporaryFilePath = Path.GetTempPath();
            this.temporaryFilePath = Path.Combine(this.temporaryFilePath, TemporaryFileDirectoryName);
        }
        public SarifErrorListItem(Run run, int runIndex, Result result, string logFilePath, ProjectNameCache projectNameCache)
            : this()
        {
            if (!SarifViewerPackage.IsUnitTesting)
            {
#pragma warning disable VSTHRD108 // Assert thread affinity unconditionally
                ThreadHelper.ThrowIfNotOnUIThread();
#pragma warning restore VSTHRD108
            }

            bool runHasSuppressions  = run.HasSuppressedResults();
            bool runHasAbsentResults = run.HasAbsentResults();

            this.RunIndex    = runIndex;
            this.ResultId    = Interlocked.Increment(ref currentResultId);
            this.SarifResult = result;
            ReportingDescriptor rule = result.GetRule(run);
            this.Tool             = run.Tool.ToToolModel();
            this.Rule             = rule.ToRuleModel(result.RuleId);
            this.Invocation       = run.Invocations?[0]?.ToInvocationModel();
            this.WorkingDirectory = Path.Combine(Path.GetTempPath(), this.RunIndex.ToString());
            this.HelpLink         = this.Rule?.HelpUri;

            this.RawMessage = result.GetMessageText(rule, concise: false).Trim();
            (this.ShortMessage, this.Message) = SdkUIUtilities.SplitResultMessage(this.RawMessage, MaxConcisedTextLength);

            string xamlContent = null;
            if (this.SarifResult?.Message?.TryGetProperty(XamlPropertyName, out xamlContent) == true)
            {
                this.XamlMessage = Regex.Unescape(xamlContent);
            }

            this.FileName    = result.GetPrimaryTargetFile(run);
            this.ProjectName = projectNameCache.GetName(this.FileName);
            this.Category    = runHasAbsentResults ? result.GetCategory() : nameof(BaselineState.None);
            this.Region      = result.GetPrimaryTargetRegion();
            this.Level       = this.GetEffectiveLevel(result);

            this.VSSuppressionState = runHasSuppressions && result.IsSuppressed() ? VSSuppressionState.Suppressed : VSSuppressionState.Active;

            this.LogFilePath = logFilePath;

            if (this.Region != null)
            {
                this.LineNumber   = this.Region.StartLine;
                this.ColumnNumber = this.Region.StartColumn;
            }
        }
        // This ctor is internal rather than private for unit test purposes.
        internal CodeAnalysisResultManager(
            IFileSystem fileSystem,
            PromptForResolvedPathDelegate promptForResolvedPathDelegate = null)
        {
            _fileSystem = fileSystem;
            _promptForResolvedPathDelegate = promptForResolvedPathDelegate ?? PromptForResolvedPath;

            this.SarifErrors       = new List <SarifErrorListItem>();
            _remappedUriBasePaths  = new Dictionary <string, Uri>();
            _remappedPathPrefixes  = new List <Tuple <string, string> >();
            _fileToNewLineIndexMap = new Dictionary <string, NewLineIndex>();
            _allowedDownloadHosts  = SdkUIUtilities.GetStoredObject <List <string> >(AllowedDownloadHostsFileName) ?? new List <string>();

            // Get temporary path for embedded files.
            TemporaryFilePath = Path.GetTempPath();
            TemporaryFilePath = Path.Combine(TemporaryFilePath, TemporaryFileDirectoryName);
        }
Example #11
0
        /// <summary>
        /// Open the file using the current document state scope
        /// </summary>
        private static IVsWindowFrame OpenDocumentInCurrentScope(IServiceProvider provider, string file)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            IVsUIShellOpenDocument  openDoc         = SdkUIUtilities.GetService <SVsUIShellOpenDocument, IVsUIShellOpenDocument>(provider);
            IVsRunningDocumentTable runningDocTable = SdkUIUtilities.GetService <SVsRunningDocumentTable, IVsRunningDocumentTable>(provider);

            if (openDoc == null || runningDocTable == null)
            {
                throw Marshal.GetExceptionForHR(VSConstants.E_FAIL);
            }

            uint cookieDocLock = FindDocument(runningDocTable, file);

            IVsWindowFrame windowFrame;
            Guid           textViewGuid = VSConstants.LOGVIEWID_TextView;
            // Unused variables
            IVsUIHierarchy uiHierarchy;

            Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider;
            uint itemId;
            int  hr = openDoc.OpenDocumentViaProject(file, ref textViewGuid, out serviceProvider, out uiHierarchy, out itemId, out windowFrame);

            if (ErrorHandler.Failed(hr))
            {
                throw Marshal.GetExceptionForHR(hr);
            }

            if (cookieDocLock == 0) // Document was not open earlier, and should be open now.
            {
                cookieDocLock = FindDocument(runningDocTable, file);
            }

            if (windowFrame != null)
            {
                // This will make the document visible to the user and switch focus to it. ShowNoActivate doesn't help because for tabbed documents they
                // are not brought to the front if they are already opened.
                windowFrame.Show();
            }
            return(windowFrame);
        }
Example #12
0
        public SarifErrorListItem(Run run, Notification notification, string logFilePath, ProjectNameCache projectNameCache) : this()
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            _runId = CodeAnalysisResultManager.Instance.CurrentRunId;
            ReportingDescriptor rule;
            string ruleId = null;

            if (notification.AssociatedRule != null)
            {
                ruleId = notification.AssociatedRule.Id;
            }
            else if (notification.Descriptor != null)
            {
                ruleId = notification.Descriptor.Id;
            }

            run.TryGetRule(ruleId, out rule);
            Message      = notification.Message.Text.Trim();
            ShortMessage = ExtensionMethods.GetFirstSentence(notification.Message.Text);
            if (!Message.EndsWith("."))
            {
                ShortMessage = ShortMessage.TrimEnd('.');
            }
            Level       = notification.Level;
            LogFilePath = logFilePath;
            FileName    = SdkUIUtilities.GetFileLocationPath(notification.Locations?[0]?.PhysicalLocation?.ArtifactLocation, _runId) ?? "";
            ProjectName = projectNameCache.GetName(FileName);
            Locations.Add(new LocationModel()
            {
                FilePath = FileName
            });

            Tool             = run.Tool.ToToolModel();
            Rule             = rule.ToRuleModel(ruleId);
            Invocation       = run.Invocations?[0]?.ToInvocationModel();
            WorkingDirectory = Path.Combine(Path.GetTempPath(), _runId.ToString());
        }
 internal void AddAllowedDownloadHost(string host)
 {
     _allowedDownloadHosts.Add(host);
     SdkUIUtilities.StoreObject <List <string> >(_allowedDownloadHosts, AllowedDownloadHostsFileName);
 }
        /// <summary>
        /// Attempts to navigate a VS editor to the text marker.
        /// </summary>
        /// <param name="usePreviewPane">Indicates whether to use VS's preview pane.</param>
        /// <param name="moveFocusToCaretLocation">Indicates whether to move focus to the caret location.</param>
        /// <returns>Returns true if a VS editor was opened.</returns>
        /// <remarks>
        /// The <paramref name="usePreviewPane"/> indicates whether Visual Studio opens the document as a preview (tab to the right)
        /// rather than as an "open code editor" (tab attached to other open documents on the left).
        /// </remarks>
        public bool NavigateTo(bool usePreviewPane, bool moveFocusToCaretLocation)
        {
            ThreadHelper.ThrowIfNotOnUIThread();

            bool documentWasOpened = false;

            // Make sure to fully populate region.
            if (!this.TryToFullyPopulateRegionAndFilePath())
            {
                return(false);
            }

            // If the tag doesn't have a persistent span, or its associated document isn't open,
            // then this indicates that we need to attempt to open the document and cause it to
            // be tagged.
            if (!this.PersistentSpanValid())
            {
                // Now, we need to make sure the document gets tagged before the next section of code
                // in this method attempts to navigate to it.
                // So the flow looks like this. Get Visual Studio to open the document for us.
                // That will cause Visual Studio to create a text view for it.
                // Now, just because a text view is created does not mean that
                // a request for "tags" has occurred. Tagging (and the display of those tags)
                // is highly asynchronous. Taggers are created on demand and disposed when they are no longer
                // needed. It is quite common to have multiple taggers active for the same text view and text buffers
                // at the same time. (An easy example is a split-window scenario).
                // This class relies on a persistent span (this.persistentSpan) being non-null and valid.
                // This class "creates" the persistent span when it is asked for its tags in the GetTags
                // method.
                // To facilitate that, we will:
                // 1) Open the document
                // 2) Get the text view from the document.
                // 2a) That alone may be enough to make the persistent span valid if it was already created.
                // 3) If the persistent span still isn't valid (likely because we have crated the persistent span yet), ask ourselves for the tags which will
                //    cause the span to be created.
                IVsWindowFrame vsWindowFrame = SdkUIUtilities.OpenDocument(ServiceProvider.GlobalProvider, this.resolvedFullFilePath, usePreviewPane);
                if (vsWindowFrame == null)
                {
                    return(false);
                }

                vsWindowFrame.Show();

                documentWasOpened = true;

                // At this point, the persistent span may have "become valid" due to the document open.
                // If not, then ask ourselves for the tags which will create the persistent span.
                if (!this.PersistentSpanValid())
                {
                    if (!SdkUIUtilities.TryGetTextViewFromFrame(vsWindowFrame, out ITextView textView))
                    {
                        return(false);
                    }

                    var componentModel = (IComponentModel)Package.GetGlobalService(typeof(SComponentModel));
                    if (componentModel == null)
                    {
                        return(false);
                    }

                    IPersistentSpanFactory persistentSpanFactory = componentModel.GetService <IPersistentSpanFactory>();
                    if (persistentSpanFactory == null)
                    {
                        return(false);
                    }

                    if (!this.TryCreatePersistentSpan(textView.TextBuffer, persistentSpanFactory))
                    {
                        return(false);
                    }
                }
            }

            if (!this.PersistentSpanValid())
            {
                return(false);
            }

            // Now, if the span IS valid it doesn't mean that the editor is visible, so make sure we open the document
            // for the user if needed.
            // But before we try to call "open document" let's see if we can find an active view because calling
            // "open document" is super slow (which causes keyboard navigation from items in the SARIF explorer to be slow
            // IF "open document" is called every time.
            if (!documentWasOpened ||
                !SdkUIUtilities.TryGetActiveViewForTextBuffer(this.persistentSpan.Span.TextBuffer, out IWpfTextView wpfTextView))
            {
                IVsWindowFrame vsWindowFrame = SdkUIUtilities.OpenDocument(ServiceProvider.GlobalProvider, this.resolvedFullFilePath, usePreviewPane);
                if (vsWindowFrame == null)
                {
                    return(false);
                }

                vsWindowFrame.Show();

                if (!SdkUIUtilities.TryGetActiveViewForTextBuffer(this.persistentSpan.Span.TextBuffer, out wpfTextView))
                {
                    return(false);
                }
            }

            ITextSnapshot currentSnapshot = this.persistentSpan.Span.TextBuffer.CurrentSnapshot;

            // Note that "GetSpan" is not really a great name. What is actually happening
            // is the "Span" that "GetSpan" is called on is "mapped" onto the passed in
            // text snapshot. In essence what this means is take the "persistent span"
            // that we have and "replay" any edits that have occurred and return a new
            // span. So, if the span is no longer relevant (lets say the text has been deleted)
            // then you'll get back an empty span.
            SnapshotSpan trackingSpanSnapshot = this.persistentSpan.Span.GetSpan(currentSnapshot);

            // If the caret is already in the text within the marker, don't re-select it
            // otherwise users cannot move the caret in the region.
            // If the caret isn't in the marker, move it there.
            if (!trackingSpanSnapshot.Contains(wpfTextView.Caret.Position.BufferPosition) &&
                !trackingSpanSnapshot.IsEmpty)
            {
                wpfTextView.Selection.Select(trackingSpanSnapshot, isReversed: false);
                wpfTextView.Caret.MoveTo(trackingSpanSnapshot.End);
                wpfTextView.Caret.EnsureVisible();

                if (moveFocusToCaretLocation)
                {
                    wpfTextView.VisualElement.Focus();
                }
            }

            return(true);
        }