/// <summary>
        /// Handle the file configuration change notification
        /// </summary>
        /// <param name="newSettings"></param>
        /// <param name="oldSettings"></param>
        /// <param name="eventContext"></param>
        public async Task HandleDidChangeConfigurationNotification(
            SqlToolsSettings newSettings,
            SqlToolsSettings oldSettings,
            EventContext eventContext)
        {
            bool oldEnableIntelliSense = oldSettings.SqlTools.IntelliSense.EnableIntellisense;
            bool?oldEnableDiagnostics  = oldSettings.SqlTools.IntelliSense.EnableErrorChecking;

            // update the current settings to reflect any changes
            CurrentSettings.Update(newSettings);

            // if script analysis settings have changed we need to clear the current diagnostic markers
            if (oldEnableIntelliSense != newSettings.SqlTools.IntelliSense.EnableIntellisense ||
                oldEnableDiagnostics != newSettings.SqlTools.IntelliSense.EnableErrorChecking)
            {
                // if the user just turned off diagnostics then send an event to clear the error markers
                if (!newSettings.IsDiagnositicsEnabled)
                {
                    ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];

                    foreach (var scriptFile in WorkspaceService <SqlToolsSettings> .Instance.Workspace.GetOpenedFiles())
                    {
                        await DiagnosticsHelper.PublishScriptDiagnostics(scriptFile, emptyAnalysisDiagnostics, eventContext);
                    }
                }
                // otherwise rerun diagnostic analysis on all opened SQL files
                else
                {
                    await this.RunScriptDiagnostics(CurrentWorkspace.GetOpenedFiles(), eventContext);
                }
            }
        }
        private void PublishScriptDiagnostics(ScriptFile scriptFile, IReadOnlyList <ScriptFileMarker> markers)
        {
            var diagnostics = new Diagnostic[markers.Count];

            CorrectionTableEntry fileCorrections = _mostRecentCorrectionsByFile.GetOrAdd(
                scriptFile,
                CorrectionTableEntry.CreateForFile);

            fileCorrections.Corrections.Clear();

            for (int i = 0; i < markers.Count; i++)
            {
                ScriptFileMarker marker = markers[i];

                Diagnostic diagnostic = GetDiagnosticFromMarker(marker);

                if (marker.Correction != null)
                {
                    string diagnosticId = GetUniqueIdFromDiagnostic(diagnostic);
                    fileCorrections.Corrections[diagnosticId] = marker.Correction;
                }

                diagnostics[i] = diagnostic;
            }

            _languageServer.TextDocument.PublishDiagnostics(new PublishDiagnosticsParams
            {
                Uri         = scriptFile.DocumentUri,
                Diagnostics = new Container <Diagnostic>(diagnostics)
            });
        }
        protected async Task HandleDidChangeConfigurationNotification(
            DidChangeConfigurationParams <SettingsWrapper> configChangeParams,
            EventContext eventContext)
        {
            bool oldScriptAnalysisEnabled =
                this.currentSettings.ScriptAnalysis.Enable.HasValue;

            this.currentSettings.Update(
                configChangeParams.Settings.Powershell);

            if (oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable)
            {
                // If the user just turned off script analysis, send a diagnostics
                // event to clear the analysis markers that they already have
                if (!this.currentSettings.ScriptAnalysis.Enable.Value)
                {
                    ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];

                    foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles())
                    {
                        await PublishScriptDiagnostics(
                            scriptFile,
                            emptyAnalysisDiagnostics,
                            eventContext);
                    }
                }
            }
        }
Example #4
0
        private async Task <ScriptFileMarker[]> GetSemanticMarkersFromCommandAsync(PSCommand command, Runspace runspace)
        {
            PowerShellResult result = await InvokePowerShellAsync(command, runspace).ConfigureAwait(false);

            IReadOnlyCollection <PSObject> diagnosticResults = result?.Output ?? s_emptyDiagnosticResult;

            _logger.LogDebug(String.Format("Found {0} violations", diagnosticResults.Count));

            var scriptMarkers = new ScriptFileMarker[diagnosticResults.Count];
            int i             = 0;

            foreach (PSObject diagnostic in diagnosticResults)
            {
                // scriptMarkers[i] = ScriptFileMarker.FromDiagnosticRecord(diagnostic);
                scriptMarkers[i] = ScriptFileMarker.FromUpgradePlan(diagnostic);
                if (scriptMarkers[i].RuleName != "ReadyToUpgradeCmdletParameter")
                {
                    i++;
                }
            }

            Array.Resize(ref scriptMarkers, i);

            return(scriptMarkers);
        }
Example #5
0
        private static async Task DelayThenInvokeDiagnostics(
            int delayMilliseconds,
            ScriptFile[] filesToAnalyze,
            EditorSession editorSession,
            EventContext eventContext,
            CancellationToken cancellationToken)
        {
            // First of all, wait for the desired delay period before
            // analyzing the provided list of files
            try
            {
                await Task.Delay(delayMilliseconds, cancellationToken);
            }
            catch (TaskCanceledException)
            {
                // If the task is cancelled, exit directly
                return;
            }

            // If we've made it past the delay period then we don't care
            // about the cancellation token anymore.  This could happen
            // when the user stops typing for long enough that the delay
            // period ends but then starts typing while analysis is going
            // on.  It makes sense to send back the results from the first
            // delay period while the second one is ticking away.

            // Get the requested files
            foreach (ScriptFile scriptFile in filesToAnalyze)
            {
                ScriptFileMarker[] semanticMarkers = null;
                if (editorSession.AnalysisService != null)
                {
                    Logger.Write(LogLevel.Verbose, "Analyzing script file: " + scriptFile.FilePath);

                    semanticMarkers =
                        editorSession.AnalysisService.GetSemanticMarkers(
                            scriptFile);

                    Logger.Write(LogLevel.Verbose, "Analysis complete.");
                }
                else
                {
                    // Semantic markers aren't available if the AnalysisService
                    // isn't available
                    semanticMarkers = new ScriptFileMarker[0];
                }

                var allMarkers = scriptFile.SyntaxMarkers.Concat(semanticMarkers);

                await PublishScriptDiagnostics(
                    scriptFile,
                    semanticMarkers,
                    eventContext);
            }
        }
Example #6
0
        private async Task <ScriptFileMarker[]> GetSemanticMarkersFromCommandAsync(PSCommand command)
        {
            PowerShellResult result = await InvokePowerShellAsync(command).ConfigureAwait(false);

            IReadOnlyCollection <PSObject> diagnosticResults = result?.Output ?? s_emptyDiagnosticResult;

            _logger.LogDebug(String.Format("Found {0} violations", diagnosticResults.Count));

            var scriptMarkers = new ScriptFileMarker[diagnosticResults.Count];
            int i             = 0;

            foreach (PSObject diagnostic in diagnosticResults)
            {
                scriptMarkers[i] = ScriptFileMarker.FromDiagnosticRecord(diagnostic);
                i++;
            }

            return(scriptMarkers);
        }
        public void GetDiagnosticFromMarkerTest()
        {
            var scriptFileMarker = new ScriptFileMarker()
            {
                Message      = "Message",
                Level        = ScriptFileMarkerLevel.Error,
                ScriptRegion = new ScriptRegion()
                {
                    File              = "file://nofile.sql",
                    StartLineNumber   = 1,
                    StartColumnNumber = 1,
                    StartOffset       = 0,
                    EndLineNumber     = 1,
                    EndColumnNumber   = 1,
                    EndOffset         = 0
                }
            };
            var diagnostic = DiagnosticsHelper.GetDiagnosticFromMarker(scriptFileMarker);

            Assert.Equal(diagnostic.Message, scriptFileMarker.Message);
        }
 /// <summary>
 /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible
 /// </summary>
 /// <param name="scriptFileMarker"></param>
 /// <returns></returns>
 internal static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
 {
     return(new Diagnostic
     {
         Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
         Message = scriptFileMarker.Message,
         Range = new Range
         {
             Start = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
             },
             End = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
             }
         }
     });
 }
 /// <summary>
 /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible
 /// </summary>
 /// <param name="scriptFileMarker"></param>
 /// <returns></returns>
 internal static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
 {
     return(new Diagnostic
     {
         Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
         Message = scriptFileMarker.Message,
         Range = new Microsoft.SqlTools.ServiceLayer.Workspace.Contracts.Range
         {
             Start = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
             },
             End = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
             }
         }
     });
 }
Example #10
0
        /// <summary>
        /// Parses the given script to provide message, warning, error.
        /// </summary>
        /// <param name="scriptToParse">Script that will be parsed</param>
        /// <param name="telemetryManager">Used to emit telemetry events</param>
        /// <returns></returns>
        public static IList <ScriptFileMarker> CodeSense(string scriptToParse)
        {
            if (scriptToParse == null)
            {
                return(EmptyCodeSenseItemList);
            }

            int CurrentScriptlength = scriptToParse.Length;

            if (CurrentScriptlength > maxStringLength)
            {
                ScriptFileMarker maxStringLengthCodeSenseItem = new ScriptFileMarker
                {
                    Level        = ScriptFileMarkerLevel.Error,
                    Message      = SR.ScriptTooLarge(maxStringLength, CurrentScriptlength),
                    ScriptRegion = new ScriptRegion
                    {
                        // underline first row in the text
                        StartLineNumber   = 1,
                        StartColumnNumber = 1,
                        EndLineNumber     = 2,
                        EndColumnNumber   = 1
                    }
                };

                return(new ScriptFileMarker[] { maxStringLengthCodeSenseItem });
            }

            TSqlFragment     rootFragment = GetAbstractSyntaxTree(scriptToParse);
            TsqlMultiVisitor multiVisitor = new TsqlMultiVisitor(isCodeSenseRequest: true); // Use the vistor pattern to examine the parse tree

            rootFragment.AcceptChildren(multiVisitor);                                      // Now walk the tree

            if (multiVisitor.CodeSenseErrors != null && multiVisitor.CodeSenseErrors.Count != 0)
            {
                multiVisitor.CodeSenseMessages.AddRange(multiVisitor.CodeSenseErrors);
            }

            return(multiVisitor.CodeSenseMessages);
        }
 private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
 {
     return(new Diagnostic
     {
         Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
         Message = scriptFileMarker.Message,
         Range = new Range
         {
             // TODO: What offsets should I use?
             Start = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
             },
             End = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
             }
         }
     });
 }
 private static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker)
 {
     return new Diagnostic
     {
         Severity = MapDiagnosticSeverity(scriptFileMarker.Level),
         Message = scriptFileMarker.Message,
         Range = new Range
         {
             // TODO: What offsets should I use?
             Start = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1
             },
             End = new Position
             {
                 Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1,
                 Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1
             }
         }
     };
 }
        private async static Task PublishScriptDiagnostics(
            ScriptFile scriptFile,
            ScriptFileMarker[] semanticMarkers,
            EventContext eventContext)
        {
            var allMarkers = scriptFile.SyntaxMarkers.Concat(semanticMarkers);

            // Always send syntax and semantic errors.  We want to 
            // make sure no out-of-date markers are being displayed.
            await eventContext.SendEvent(
                PublishDiagnosticsNotification.Type,
                new PublishDiagnosticsNotification
                {
                    Uri = scriptFile.ClientFilePath,
                    Diagnostics =
                       allMarkers
                            .Select(GetDiagnosticFromMarker)
                            .ToArray()
                });
        }
        protected async Task HandleDidChangeConfigurationNotification(
            DidChangeConfigurationParams<SettingsWrapper> configChangeParams,
            EventContext eventContext)
        {
            bool oldScriptAnalysisEnabled =
                this.currentSettings.ScriptAnalysis.Enable.HasValue;

            this.currentSettings.Update(
                configChangeParams.Settings.Powershell);

            if (oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable)
            {
                // If the user just turned off script analysis, send a diagnostics
                // event to clear the analysis markers that they already have
                if (!this.currentSettings.ScriptAnalysis.Enable.Value)
                {
                    ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];

                    foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles())
                    {
                        await PublishScriptDiagnostics(
                            scriptFile,
                            emptyAnalysisDiagnostics,
                            eventContext);
                    }
                }
            }
        }
        protected async Task HandleDidChangeConfigurationNotification(
            DidChangeConfigurationParams <LanguageServerSettingsWrapper> configChangeParams,
            EventContext eventContext)
        {
            bool oldLoadProfiles          = this.currentSettings.EnableProfileLoading;
            bool oldScriptAnalysisEnabled =
                this.currentSettings.ScriptAnalysis.Enable.HasValue;
            string oldScriptAnalysisSettingsPath =
                this.currentSettings.ScriptAnalysis.SettingsPath;

            this.currentSettings.Update(
                configChangeParams.Settings.Powershell,
                this.editorSession.Workspace.WorkspacePath);

            if (!this.profilesLoaded &&
                this.currentSettings.EnableProfileLoading &&
                oldLoadProfiles != this.currentSettings.EnableProfileLoading)
            {
                await this.editorSession.PowerShellContext.LoadHostProfiles();

                this.profilesLoaded = true;
            }

            // If there is a new settings file path, restart the analyzer with the new settigs.
            bool   settingsPathChanged = false;
            string newSettingsPath     = this.currentSettings.ScriptAnalysis.SettingsPath;

            if (!string.Equals(oldScriptAnalysisSettingsPath, newSettingsPath, StringComparison.OrdinalIgnoreCase))
            {
                this.editorSession.RestartAnalysisService(newSettingsPath);
                settingsPathChanged = true;
            }

            // If script analysis settings have changed we need to clear & possibly update the current diagnostic records.
            if ((oldScriptAnalysisEnabled != this.currentSettings.ScriptAnalysis.Enable) || settingsPathChanged)
            {
                // If the user just turned off script analysis or changed the settings path, send a diagnostics
                // event to clear the analysis markers that they already have.
                if (!this.currentSettings.ScriptAnalysis.Enable.Value || settingsPathChanged)
                {
                    ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0];

                    foreach (var scriptFile in editorSession.Workspace.GetOpenedFiles())
                    {
                        await PublishScriptDiagnostics(
                            scriptFile,
                            emptyAnalysisDiagnostics,
                            eventContext);
                    }
                }

                // If script analysis is enabled and the settings file changed get new diagnostic records.
                if (this.currentSettings.ScriptAnalysis.Enable.Value && settingsPathChanged)
                {
                    await this.RunScriptDiagnostics(
                        this.editorSession.Workspace.GetOpenedFiles(),
                        this.editorSession,
                        eventContext);
                }
            }
        }