/// <summary>
        /// Performs semantic analysis on the given ScriptFile and returns
        /// an array of ScriptFileMarkers.
        /// </summary>
        /// <param name="file">The ScriptFile which will be analyzed for semantic markers.</param>
        /// <returns>An array of ScriptFileMarkers containing semantic analysis results.</returns>
        public ScriptFileMarker[] GetSemanticMarkers(ScriptFile file)
        {
            if (file.IsAnalysisEnabled)
            {
                // TODO: This is a temporary fix until we can change how
                // ScriptAnalyzer invokes their async tasks.
                Task<ScriptFileMarker[]> analysisTask =
                    Task.Factory.StartNew<ScriptFileMarker[]>(
                        () =>
                        {
                            return
                                this.scriptAnalyzer
                                    .AnalyzeSyntaxTree(
                                        file.ScriptAst,
                                        file.ScriptTokens,
                                        file.FilePath)
                                    .Select(ScriptFileMarker.FromDiagnosticRecord)
                                    .ToArray();
                        },
                        CancellationToken.None,
                        TaskCreationOptions.None,
                        TaskScheduler.Default);

                return analysisTask.Result;
            }
            else
            {
                // Return an empty marker list
                return new ScriptFileMarker[0];
            }
        }
        /// <summary>
        /// Sets the list of breakpoints for the current debugging session.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which breakpoints will be set.</param>
        /// <param name="lineNumbers">The line numbers at which breakpoints will be set.</param>
        /// <param name="clearExisting">If true, causes all existing breakpoints to be cleared before setting new ones.</param>
        /// <returns>An awaitable Task that will provide details about the breakpoints that were set.</returns>
        public async Task<BreakpointDetails[]> SetBreakpoints(
            ScriptFile scriptFile, 
            int[] lineNumbers, 
            bool clearExisting = true)
        {
            IEnumerable<Breakpoint> resultBreakpoints = null;

            if (clearExisting)
            {
                await this.ClearBreakpointsInFile(scriptFile);
            }

            if (lineNumbers.Length > 0)
            {
                // Fix for issue #123 - file paths that contain wildcard chars [ and ] need to
                // quoted and have those wildcard chars escaped.
                string escapedScriptPath = PowerShellContext.EscapeWildcardsInPath(scriptFile.FilePath);

                PSCommand psCommand = new PSCommand();
                psCommand.AddCommand("Set-PSBreakpoint");
                psCommand.AddParameter("Script", escapedScriptPath);
                psCommand.AddParameter("Line", lineNumbers.Length > 0 ? lineNumbers : null);

                resultBreakpoints =
                    await this.powerShellContext.ExecuteCommand<Breakpoint>(
                        psCommand);

                return
                    resultBreakpoints
                        .Select(BreakpointDetails.Create)
                        .ToArray();
            }

            return new BreakpointDetails[0];
        }
        /// <summary>
        /// Gets an open file in the workspace.  If the file isn't open but
        /// exists on the filesystem, load and return it.
        /// </summary>
        /// <param name="filePath">The file path at which the script resides.</param>
        /// <exception cref="FileNotFoundException">
        /// <paramref name="filePath"/> is not found.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="filePath"/> contains a null or empty string.
        /// </exception>
        public ScriptFile GetFile(string filePath)
        {
            Validate.IsNotNullOrEmptyString("filePath", filePath);

            // Resolve the full file path 
            string resolvedFilePath = this.ResolveFilePath(filePath);
            string keyName = resolvedFilePath.ToLower();

            // Make sure the file isn't already loaded into the workspace
            ScriptFile scriptFile = null;
            if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
            {
                // This method allows FileNotFoundException to bubble up 
                // if the file isn't found.

                using (StreamReader streamReader = new StreamReader(resolvedFilePath, Encoding.UTF8))
                {
                    scriptFile = new ScriptFile(resolvedFilePath, filePath, streamReader);
                    this.workspaceFiles.Add(keyName, scriptFile);
                }

                Logger.Write(LogLevel.Verbose, "Opened file on disk: " + resolvedFilePath);
            }

            return scriptFile;
        }
        /// <summary>
        /// Sets the list of breakpoints for the current debugging session.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which breakpoints will be set.</param>
        /// <param name="lineNumbers">The line numbers at which breakpoints will be set.</param>
        /// <param name="clearExisting">If true, causes all existing breakpoints to be cleared before setting new ones.</param>
        /// <returns>An awaitable Task that will provide details about the breakpoints that were set.</returns>
        public async Task<BreakpointDetails[]> SetBreakpoints(
            ScriptFile scriptFile, 
            int[] lineNumbers, 
            bool clearExisting = true)
        {
            IEnumerable<Breakpoint> resultBreakpoints = null;

            if (clearExisting)
            {
                await this.ClearBreakpointsInFile(scriptFile);
            }

            if (lineNumbers.Length > 0)
            {
                PSCommand psCommand = new PSCommand();
                psCommand.AddCommand("Set-PSBreakpoint");
                psCommand.AddParameter("Script", scriptFile.FilePath);
                psCommand.AddParameter("Line", lineNumbers.Length > 0 ? lineNumbers : null);

                resultBreakpoints =
                    await this.powerShellContext.ExecuteCommand<Breakpoint>(
                        psCommand);

                return
                    resultBreakpoints
                        .Select(BreakpointDetails.Create)
                        .ToArray();
            }

            return new BreakpointDetails[0];
        }
        /// <summary>
        /// Gets completions for a statement contained in the given
        /// script file at the specified line and column position.
        /// </summary>
        /// <param name="scriptFile">
        /// The script file in which completions will be gathered.
        /// </param>
        /// <param name="lineNumber">
        /// The 1-based line number at which completions will be gathered.
        /// </param>
        /// <param name="columnNumber">
        /// The 1-based column number at which completions will be gathered.
        /// </param>
        /// <returns>
        /// A CommandCompletion instance completions for the identified statement.
        /// </returns>
        public async Task<CompletionResults> GetCompletionsInFile(
            ScriptFile scriptFile,
            int lineNumber,
            int columnNumber)
        {
            Validate.IsNotNull("scriptFile", scriptFile);

            // Get the offset at the specified position.  This method
            // will also validate the given position.
            int fileOffset =
                scriptFile.GetOffsetAtPosition(
                    lineNumber,
                    columnNumber);

            RunspaceHandle runspaceHandle =
                await this.powerShellContext.GetRunspaceHandle();

            CompletionResults completionResults =
                AstOperations.GetCompletions(
                    scriptFile.ScriptAst,
                    scriptFile.ScriptTokens,
                    fileOffset,
                    runspaceHandle.Runspace);

            runspaceHandle.Dispose();
                    
            // save state of most recent completion
            mostRecentCompletions = completionResults;
            mostRecentRequestFile = scriptFile.Id;
            mostRecentRequestLine = lineNumber;
            mostRecentRequestOffest = columnNumber;

            return completionResults;
        }
 internal static CompletionResults Create(
     ScriptFile scriptFile,
     CommandCompletion commandCompletion)
 {
     return new CompletionResults
     {
         Completions = GetCompletionsArray(commandCompletion),
         ReplacedRange = 
             scriptFile.GetRangeBetweenOffsets(
                 commandCompletion.ReplacementIndex,
                 commandCompletion.ReplacementIndex + commandCompletion.ReplacementLength)
     };
 }
        /// <summary>
        /// Gets completions for a statement contained in the given
        /// script file at the specified line and column position.
        /// </summary>
        /// <param name="scriptFile">
        /// The script file in which completions will be gathered.
        /// </param>
        /// <param name="lineNumber">
        /// The 1-based line number at which completions will be gathered.
        /// </param>
        /// <param name="columnNumber">
        /// The 1-based column number at which completions will be gathered.
        /// </param>
        /// <returns>
        /// A CommandCompletion instance completions for the identified statement.
        /// </returns>
        public async Task<CompletionResults> GetCompletionsInFile(
            ScriptFile scriptFile,
            int lineNumber,
            int columnNumber)
        {
            Validate.IsNotNull("scriptFile", scriptFile);

            // Get the offset at the specified position.  This method
            // will also validate the given position.
            int fileOffset =
                scriptFile.GetOffsetAtPosition(
                    lineNumber,
                    columnNumber);

            RunspaceHandle runspaceHandle =
                await this.powerShellContext.GetRunspaceHandle(
                    new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);

            CommandCompletion commandCompletion =
                AstOperations.GetCompletions(
                    scriptFile.ScriptAst,
                    scriptFile.ScriptTokens,
                    fileOffset,
                    runspaceHandle.Runspace);

            runspaceHandle.Dispose();

            if (commandCompletion != null)
            {
                CompletionResults completionResults =
                    CompletionResults.Create(
                        scriptFile,
                        commandCompletion);

                // save state of most recent completion
                mostRecentCompletions = completionResults;
                mostRecentRequestFile = scriptFile.Id;
                mostRecentRequestLine = lineNumber;
                mostRecentRequestOffest = columnNumber;

                return completionResults;
            }
            else
            {
                return new CompletionResults();
            }
        }
        /// <summary>
        /// Gets all file references by recursively searching 
        /// through referenced files in a scriptfile
        /// </summary>
        /// <param name="scriptFile">Contains the details and contents of an open script file</param>
        /// <returns>A scriptfile array where the first file 
        /// in the array is the "root file" of the search</returns>
        public ScriptFile[] ExpandScriptReferences(ScriptFile scriptFile)
        {
            Dictionary<string, ScriptFile> referencedScriptFiles = new Dictionary<string, ScriptFile>();
            List<ScriptFile> expandedReferences = new List<ScriptFile>();

            // add original file so it's not searched for, then find all file references
            referencedScriptFiles.Add(scriptFile.Id, scriptFile);
            RecursivelyFindReferences(scriptFile, referencedScriptFiles);

            // remove original file from referened file and add it as the first element of the
            // expanded referenced list to maintain order so the original file is always first in the list
            referencedScriptFiles.Remove(scriptFile.Id);
            expandedReferences.Add(scriptFile);

            if (referencedScriptFiles.Count > 0)
            {
                expandedReferences.AddRange(referencedScriptFiles.Values);
            }

            return expandedReferences.ToArray();
        }
        private void AssertFileChange(
            string initialString,
            string expectedString,
            FileChange fileChange)
        {
            using (StringReader stringReader = new StringReader(initialString))
            {
                // Create an in-memory file from the StringReader
                ScriptFile fileToChange = new ScriptFile("TestFile.ps1", "TestFile.ps1", stringReader);

                // Apply the FileChange and assert the resulting contents
                fileToChange.ApplyChange(fileChange);
                Assert.Equal(expectedString, fileToChange.Contents);
            }
        }
        /// <summary>
        /// Recusrively searches through referencedFiles in scriptFiles
        /// and builds a Dictonary of the file references
        /// </summary>
        /// <param name="scriptFile">Details an contents of "root" script file</param>
        /// <param name="referencedScriptFiles">A Dictionary of referenced script files</param>
        private void RecursivelyFindReferences(
            ScriptFile scriptFile, 
            Dictionary<string, ScriptFile> referencedScriptFiles)
        {
            // Get the base path of the current script for use in resolving relative paths
            string baseFilePath = 
                GetBaseFilePath(
                    scriptFile.FilePath);

            ScriptFile referencedFile;
            foreach (string referencedFileName in scriptFile.ReferencedFiles)
            {
                string resolvedScriptPath =
                    this.ResolveRelativeScriptPath(
                        baseFilePath,
                        referencedFileName);

                // Make sure file exists before trying to get the file
                if (File.Exists(resolvedScriptPath))
                {
                    // Get the referenced file if it's not already in referencedScriptFiles
                    referencedFile = this.GetFile(resolvedScriptPath);

                    // Normalize the resolved script path and add it to the
                    // referenced files list if it isn't there already
                    resolvedScriptPath = resolvedScriptPath.ToLower();
                    if (!referencedScriptFiles.ContainsKey(resolvedScriptPath))
                    {
                        referencedScriptFiles.Add(resolvedScriptPath, referencedFile);
                        RecursivelyFindReferences(referencedFile, referencedScriptFiles);
                    }
                }
            }
        }
        /// <summary>
        /// Closes a currently open script file with the given file path.
        /// </summary>
        /// <param name="scriptFile">The file path at which the script resides.</param>
        public void CloseFile(ScriptFile scriptFile)
        {
            Validate.IsNotNull("scriptFile", scriptFile);

            this.workspaceFiles.Remove(scriptFile.Id);
        }
Example #12
0
 /// <summary>
 /// Perform semantic analysis on the given ScriptFile with the given settings.
 /// </summary>
 /// <param name="file">The ScriptFile to be analyzed.</param>
 /// <param name="settings">ScriptAnalyzer settings</param>
 /// <returns></returns>
 public async Task <ScriptFileMarker[]> GetSemanticMarkersAsync(ScriptFile file, Hashtable settings)
 {
     return(await GetSemanticMarkersAsync <Hashtable>(file, null, settings));
 }
        /// <summary>
        /// Sets the list of line breakpoints for the current debugging session.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which breakpoints will be set.</param>
        /// <param name="breakpoints">BreakpointDetails for each breakpoint that will be set.</param>
        /// <param name="clearExisting">If true, causes all existing breakpoints to be cleared before setting new ones.</param>
        /// <returns>An awaitable Task that will provide details about the breakpoints that were set.</returns>
        public async Task <BreakpointDetails[]> SetLineBreakpoints(
            ScriptFile scriptFile,
            BreakpointDetails[] breakpoints,
            bool clearExisting = true)
        {
            var resultBreakpointDetails = new List <BreakpointDetails>();

            if (clearExisting)
            {
                await this.ClearBreakpointsInFile(scriptFile);
            }

            if (breakpoints.Length > 0)
            {
                // Fix for issue #123 - file paths that contain wildcard chars [ and ] need to
                // quoted and have those wildcard chars escaped.
                string escapedScriptPath =
                    PowerShellContext.EscapePath(scriptFile.FilePath, escapeSpaces: false);

                foreach (BreakpointDetails breakpoint in breakpoints)
                {
                    PSCommand psCommand = new PSCommand();
                    psCommand.AddCommand(@"Microsoft.PowerShell.Utility\Set-PSBreakpoint");
                    psCommand.AddParameter("Script", escapedScriptPath);
                    psCommand.AddParameter("Line", breakpoint.LineNumber);

                    // Check if the user has specified the column number for the breakpoint.
                    if (breakpoint.ColumnNumber.HasValue)
                    {
                        // It bums me out that PowerShell will silently ignore a breakpoint
                        // where either the line or the column is invalid.  I'd rather have an
                        // error or warning message I could relay back to the client.
                        psCommand.AddParameter("Column", breakpoint.ColumnNumber.Value);
                    }

                    // Check if this is a "conditional" line breakpoint.
                    if (breakpoint.Condition != null)
                    {
                        ScriptBlock actionScriptBlock =
                            GetBreakpointActionScriptBlock(breakpoint);

                        // If there was a problem with the condition string,
                        // move onto the next breakpoint.
                        if (actionScriptBlock == null)
                        {
                            resultBreakpointDetails.Add(breakpoint);
                            continue;
                        }

                        psCommand.AddParameter("Action", actionScriptBlock);
                    }

                    IEnumerable <Breakpoint> configuredBreakpoints =
                        await this.powerShellContext.ExecuteCommand <Breakpoint>(psCommand);

                    // The order in which the breakpoints are returned is significant to the
                    // VSCode client and should match the order in which they are passed in.
                    resultBreakpointDetails.AddRange(
                        configuredBreakpoints.Select(BreakpointDetails.Create));
                }
            }

            return(resultBreakpointDetails.ToArray());
        }
        public void FindsDotSourcedFiles()
        {
            string exampleScriptContents =
                @". .\athing.ps1"+"\r\n"+
                @". .\somefile.ps1"+"\r\n" +
                @". .\somefile.ps1"+"\r\n" +
                @"Do-Stuff $uri"+"\r\n" +
                @". simpleps.ps1";

            using (StringReader stringReader = new StringReader(exampleScriptContents))
            {
                ScriptFile scriptFile = new ScriptFile("DotSourceTestFile.ps1", "DotSourceTestFile.ps1", stringReader);
                Assert.Equal(3, scriptFile.ReferencedFiles.Length);
                System.Console.Write("a" + scriptFile.ReferencedFiles[0]);
                Assert.Equal(@".\athing.ps1", scriptFile.ReferencedFiles[0]);
            }
        }
        /// <summary>
        /// Finds the details of the symbol at the given script file location.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which the symbol can be located.</param>
        /// <param name="lineNumber">The line number at which the symbol can be located.</param>
        /// <param name="columnNumber">The column number at which the symbol can be located.</param>
        /// <returns></returns>
        public async Task<SymbolDetails> FindSymbolDetailsAtLocation(
            ScriptFile scriptFile,
            int lineNumber,
            int columnNumber)
        {
            SymbolDetails symbolDetails = null;
            SymbolReference symbolReference =
                AstOperations.FindSymbolAtPosition(
                    scriptFile.ScriptAst,
                    lineNumber,
                    columnNumber);

            if (symbolReference != null)
            {
                RunspaceHandle runspaceHandle =
                    await this.powerShellContext.GetRunspaceHandle();

                symbolReference.FilePath = scriptFile.FilePath;
                symbolDetails = new SymbolDetails(symbolReference, runspaceHandle.Runspace);

                runspaceHandle.Dispose();
            }
            else
            {
                // TODO #21: Return Result<T>
                return null;
            }

            return symbolDetails;
        }
        /// <summary>
        /// Finds all the references of a symbol
        /// </summary>
        /// <param name="foundSymbol">The symbol to find all references for</param>
        /// <param name="referencedFiles">An array of scriptFiles too search for references in</param>
        /// <returns>FindReferencesResult</returns>
        public async Task<FindReferencesResult> FindReferencesOfSymbol(
            SymbolReference foundSymbol,
            ScriptFile[] referencedFiles)
        {                
            if (foundSymbol != null)
            {
                int symbolOffset = referencedFiles[0].GetOffsetAtPosition(
                    foundSymbol.ScriptRegion.StartLineNumber,
                    foundSymbol.ScriptRegion.StartColumnNumber);

                // Make sure aliases have been loaded
                await GetAliases();

                List<SymbolReference> symbolReferences = new List<SymbolReference>();
                foreach (ScriptFile file in referencedFiles)
                {
                    IEnumerable<SymbolReference> symbolReferencesinFile =
                    AstOperations
                        .FindReferencesOfSymbol(
                            file.ScriptAst,
                            foundSymbol,
                            CmdletToAliasDictionary,
                            AliasToCmdletDictionary)
                        .Select(
                            reference =>
                            {
                                reference.SourceLine =
                                    file.GetLine(reference.ScriptRegion.StartLineNumber);
                                reference.FilePath = file.FilePath;
                                return reference;
                            });

                    symbolReferences.AddRange(symbolReferencesinFile);
                }

                return
                    new FindReferencesResult
                    {
                        SymbolFileOffset = symbolOffset,
                        SymbolName = foundSymbol.SymbolName,
                        FoundReferences = symbolReferences
                    };
            }
            else { return null; }
        }
Example #17
0
 protected abstract IEnumerable <SymbolReference> GetSymbolsImpl(ScriptFile scriptFile, Version psVersion);
        /// <summary>
        /// Finds command completion details for the script given a file location 
        /// </summary>
        /// <param name="file">The details and contents of a open script file</param>
        /// <param name="entryName">The name of the suggestion that needs details</param>
        /// <returns>CompletionResult object (contains information about the command completion)</returns>
        public CompletionDetails GetCompletionDetailsInFile(
            ScriptFile file,
            string entryName)
        {
            // Makes sure the most recent completions request was the same line and column as this request
            if (file.Id.Equals(mostRecentRequestFile))
            {
                CompletionDetails completionResult = 
                    mostRecentCompletions.Completions.FirstOrDefault(
                        result => result.CompletionText.Equals(entryName));

                return completionResult;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Finds the details of the symbol at the given script file location.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which the symbol can be located.</param>
        /// <param name="lineNumber">The line number at which the symbol can be located.</param>
        /// <param name="columnNumber">The column number at which the symbol can be located.</param>
        /// <returns></returns>
        public async Task<SymbolDetails> FindSymbolDetailsAtLocation(
            ScriptFile scriptFile,
            int lineNumber,
            int columnNumber)
        {
            SymbolDetails symbolDetails = null;
            SymbolReference symbolReference =
                AstOperations.FindSymbolAtPosition(
                    scriptFile.ScriptAst,
                    lineNumber,
                    columnNumber);

            if (symbolReference != null)
            {
                // Request a runspace handle with a short timeout
                RunspaceHandle runspaceHandle =
                    await this.powerShellContext.GetRunspaceHandle(
                        new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);

                symbolReference.FilePath = scriptFile.FilePath;
                symbolDetails = new SymbolDetails(symbolReference, runspaceHandle.Runspace);

                runspaceHandle.Dispose();
            }
            else
            {
                // TODO #21: Return Result<T>
                return null;
            }

            return symbolDetails;
        }
 protected override bool CanProvideFor(ScriptFile scriptFile)
 {
     return((scriptFile.FilePath != null &&
             scriptFile.FilePath.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) ||
            AstOperations.IsPowerShellDataFileAst(scriptFile.ScriptAst));
 }
 protected override bool CanProvideFor(ScriptFile scriptFile)
 {
     return(scriptFile.FilePath.EndsWith("tests.ps1", StringComparison.OrdinalIgnoreCase));
 }
        /// <summary>
        /// Gets a new ScriptFile instance which is identified by the given file
        /// path and initially contains the given buffer contents.
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="initialBuffer"></param>
        /// <returns></returns>
        public ScriptFile GetFileBuffer(string filePath, string initialBuffer)
        {
            Validate.IsNotNullOrEmptyString("filePath", filePath);

            // Resolve the full file path 
            string resolvedFilePath = this.ResolveFilePath(filePath);
            string keyName = resolvedFilePath.ToLower();

            // Make sure the file isn't already loaded into the workspace
            ScriptFile scriptFile = null;
            if (!this.workspaceFiles.TryGetValue(keyName, out scriptFile))
            {
                scriptFile = new ScriptFile(resolvedFilePath, filePath, initialBuffer);
                this.workspaceFiles.Add(keyName, scriptFile);

                Logger.Write(LogLevel.Verbose, "Opened file as in-memory buffer: " + resolvedFilePath);
            }

            return scriptFile;
        }
        /// <summary>
        /// Finds all the occurences of a symbol in the script given a file location
        /// </summary>
        /// <param name="file">The details and contents of a open script file</param>
        /// <param name="lineNumber">The line number of the cursor for the given script</param>
        /// <param name="columnNumber">The coulumn number of the cursor for the given script</param>
        /// <returns>FindOccurrencesResult</returns>
        public FindOccurrencesResult FindOccurrencesInFile(
            ScriptFile file,
            int lineNumber,
            int columnNumber)
        {
            SymbolReference foundSymbol =
                AstOperations.FindSymbolAtPosition(
                    file.ScriptAst,
                    lineNumber,
                    columnNumber);

            if (foundSymbol != null)
            {
                // find all references, and indicate that looking for aliases is not needed
                IEnumerable<SymbolReference> symbolOccurrences =
                    AstOperations
                        .FindReferencesOfSymbol(
                            file.ScriptAst,
                            foundSymbol,
                            false);

                return
                    new FindOccurrencesResult
                    {
                        FoundOccurrences = symbolOccurrences
                    };
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// Closes a currently open script file with the given file path.
        /// </summary>
        /// <param name="scriptFile">The file path at which the script resides.</param>
        public void CloseFile(ScriptFile scriptFile)
        {
            Validate.IsNotNull("scriptFile", scriptFile);

            this.workspaceFiles.Remove(scriptFile.Id);
        }
        private async Task ClearBreakpointsInFile(ScriptFile scriptFile)
        {
            List<Breakpoint> breakpoints = null;

            // Get the list of breakpoints for this file
            if (this.breakpointsPerFile.TryGetValue(scriptFile.Id, out breakpoints))
            {
                if (breakpoints.Count > 0)
                {
                    PSCommand psCommand = new PSCommand();
                    psCommand.AddCommand("Remove-PSBreakpoint");
                    psCommand.AddParameter("Breakpoint", breakpoints.ToArray());

                    await this.powerShellContext.ExecuteCommand<object>(psCommand);

                    // Clear the existing breakpoints list for the file
                    breakpoints.Clear();
                }
            }
        }
Example #26
0
 protected abstract bool CanProvideFor(ScriptFile scriptFile);
Example #27
0
        /// <summary>
        /// Finds the definition of a symbol in the script file or any of the
        /// files that it references.
        /// </summary>
        /// <param name="sourceFile">The initial script file to be searched for the symbol's definition.</param>
        /// <param name="foundSymbol">The symbol for which a definition will be found.</param>
        /// <param name="workspace">The Workspace to which the ScriptFile belongs.</param>
        /// <returns>The resulting GetDefinitionResult for the symbol's definition.</returns>
        public async Task <GetDefinitionResult> GetDefinitionOfSymbol(
            ScriptFile sourceFile,
            SymbolReference foundSymbol,
            Workspace workspace)
        {
            Validate.IsNotNull("sourceFile", sourceFile);
            Validate.IsNotNull("foundSymbol", foundSymbol);
            Validate.IsNotNull("workspace", workspace);

            ScriptFile[] referencedFiles =
                workspace.ExpandScriptReferences(
                    sourceFile);

            var filesSearched = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            // look through the referenced files until definition is found
            // or there are no more file to look through
            SymbolReference foundDefinition = null;

            for (int i = 0; i < referencedFiles.Length; i++)
            {
                foundDefinition =
                    AstOperations.FindDefinitionOfSymbol(
                        referencedFiles[i].ScriptAst,
                        foundSymbol);

                filesSearched.Add(referencedFiles[i].FilePath);
                if (foundDefinition != null)
                {
                    foundDefinition.FilePath = referencedFiles[i].FilePath;
                    break;
                }
            }

            // if the definition the not found in referenced files
            // look for it in all the files in the workspace
            if (foundDefinition == null)
            {
                // Get a list of all powershell files in the workspace path
                var allFiles = workspace.EnumeratePSFiles();
                foreach (var file in allFiles)
                {
                    if (filesSearched.Contains(file))
                    {
                        continue;
                    }

                    Token[]      tokens      = null;
                    ParseError[] parseErrors = null;
                    foundDefinition =
                        AstOperations.FindDefinitionOfSymbol(
                            Parser.ParseFile(file, out tokens, out parseErrors),
                            foundSymbol);

                    filesSearched.Add(file);
                    if (foundDefinition != null)
                    {
                        foundDefinition.FilePath = file;
                        break;
                    }
                }
            }

            // if definition is not found in file in the workspace
            // look for it in the builtin commands
            if (foundDefinition == null)
            {
                CommandInfo cmdInfo =
                    await CommandHelpers.GetCommandInfo(
                        foundSymbol.SymbolName,
                        this.powerShellContext);

                foundDefinition =
                    FindDeclarationForBuiltinCommand(
                        cmdInfo,
                        foundSymbol,
                        workspace);
            }

            return(foundDefinition != null ?
                   new GetDefinitionResult(foundDefinition) :
                   null);
        }
        /// <summary>
        /// Finds the symbol in the script given a file location
        /// </summary>
        /// <param name="scriptFile">The details and contents of a open script file</param>
        /// <param name="lineNumber">The line number of the cursor for the given script</param>
        /// <param name="columnNumber">The coulumn number of the cursor for the given script</param>
        /// <returns>A SymbolReference of the symbol found at the given location
        /// or null if there is no symbol at that location 
        /// </returns>
        public SymbolReference FindSymbolAtLocation(
            ScriptFile scriptFile,
            int lineNumber,
            int columnNumber)
        {
            SymbolReference symbolReference =
                AstOperations.FindSymbolAtPosition(
                    scriptFile.ScriptAst,
                    lineNumber,
                    columnNumber);

            if (symbolReference != null)
            {
                symbolReference.FilePath = scriptFile.FilePath;
            }

            return symbolReference;
        }
Example #29
0
        /// <summary>
        /// Finds the definition of a symbol in the script file or any of the
        /// files that it references.
        /// </summary>
        /// <param name="sourceFile">The initial script file to be searched for the symbol's definition.</param>
        /// <param name="foundSymbol">The symbol for which a definition will be found.</param>
        /// <param name="workspace">The Workspace to which the ScriptFile belongs.</param>
        /// <returns>The resulting GetDefinitionResult for the symbol's definition.</returns>
        public async Task <GetDefinitionResult> GetDefinitionOfSymbol(
            ScriptFile sourceFile,
            SymbolReference foundSymbol,
            Workspace workspace)
        {
            Validate.IsNotNull(nameof(sourceFile), sourceFile);
            Validate.IsNotNull(nameof(foundSymbol), foundSymbol);
            Validate.IsNotNull(nameof(workspace), workspace);

            ScriptFile[] referencedFiles =
                workspace.ExpandScriptReferences(
                    sourceFile);

            var filesSearched = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            // look through the referenced files until definition is found
            // or there are no more file to look through
            SymbolReference foundDefinition = null;

            foreach (ScriptFile scriptFile in referencedFiles)
            {
                foundDefinition =
                    AstOperations.FindDefinitionOfSymbol(
                        scriptFile.ScriptAst,
                        foundSymbol);

                filesSearched.Add(scriptFile.FilePath);
                if (foundDefinition != null)
                {
                    foundDefinition.FilePath = scriptFile.FilePath;
                    break;
                }

                if (foundSymbol.SymbolType == SymbolType.Function)
                {
                    // Dot-sourcing is parsed as a "Function" Symbol.
                    string dotSourcedPath = GetDotSourcedPath(foundSymbol, workspace, scriptFile);
                    if (scriptFile.FilePath == dotSourcedPath)
                    {
                        foundDefinition = new SymbolReference(SymbolType.Function, foundSymbol.SymbolName, scriptFile.ScriptAst.Extent, scriptFile.FilePath);
                        break;
                    }
                }
            }

            // if the definition the not found in referenced files
            // look for it in all the files in the workspace
            if (foundDefinition == null)
            {
                // Get a list of all powershell files in the workspace path
                IEnumerable <string> allFiles = workspace.EnumeratePSFiles();
                foreach (string file in allFiles)
                {
                    if (filesSearched.Contains(file))
                    {
                        continue;
                    }

                    Token[]      tokens      = null;
                    ParseError[] parseErrors = null;
                    foundDefinition =
                        AstOperations.FindDefinitionOfSymbol(
                            Parser.ParseFile(file, out tokens, out parseErrors),
                            foundSymbol);

                    filesSearched.Add(file);
                    if (foundDefinition != null)
                    {
                        foundDefinition.FilePath = file;
                        break;
                    }
                }
            }

            // if definition is not found in file in the workspace
            // look for it in the builtin commands
            if (foundDefinition == null)
            {
                CommandInfo cmdInfo =
                    await CommandHelpers.GetCommandInfo(
                        foundSymbol.SymbolName,
                        _powerShellContext);

                foundDefinition =
                    FindDeclarationForBuiltinCommand(
                        cmdInfo,
                        foundSymbol,
                        workspace);
            }

            return(foundDefinition != null ?
                   new GetDefinitionResult(foundDefinition) :
                   null);
        }
        /// <summary>
        /// Finds all the symbols in a file.
        /// </summary>
        /// <param name="scriptFile">The ScriptFile in which the symbol can be located.</param>
        /// <returns></returns>
        public FindOccurrencesResult FindSymbolsInFile(ScriptFile scriptFile)
        {
            Validate.IsNotNull("scriptFile", scriptFile);

            IEnumerable<SymbolReference> symbolReferencesinFile =
                AstOperations
                    .FindSymbolsInDocument(scriptFile.ScriptAst, this.powerShellContext.PowerShellVersion)
                    .Select(
                        reference => {
                            reference.SourceLine =
                                scriptFile.GetLine(reference.ScriptRegion.StartLineNumber);
                            reference.FilePath = scriptFile.FilePath;
                            return reference;
                        });

            return
                new FindOccurrencesResult {
                    FoundOccurrences = symbolReferencesinFile
                };
        }
Example #31
0
        /// <summary>
        /// Gets a path from a dot-source symbol.
        /// </summary>
        /// <param name="symbol">The symbol representing the dot-source expression.</param>
        /// <param name="workspace">The current workspace</param>
        /// <param name="scriptFile">The script file containing the symbol</param>
        /// <returns></returns>
        private static string GetDotSourcedPath(SymbolReference symbol, Workspace workspace, ScriptFile scriptFile)
        {
            string cleanedUpSymbol = PathUtils.NormalizePathSeparators(symbol.SymbolName.Trim('\'', '"'));
            string psScriptRoot    = Path.GetDirectoryName(scriptFile.FilePath);

            return(workspace.ResolveRelativeScriptPath(psScriptRoot,
                                                       Regex.Replace(cleanedUpSymbol, @"\$PSScriptRoot|\${PSScriptRoot}", psScriptRoot, RegexOptions.IgnoreCase)));
        }
        /// <summary>
        /// Finds the definition of a symbol in the script file or any of the
        /// files that it references.
        /// </summary>
        /// <param name="sourceFile">The initial script file to be searched for the symbol's definition.</param>
        /// <param name="foundSymbol">The symbol for which a definition will be found.</param>
        /// <param name="workspace">The Workspace to which the ScriptFile belongs.</param>
        /// <returns>The resulting GetDefinitionResult for the symbol's definition.</returns>
        public async Task<GetDefinitionResult> GetDefinitionOfSymbol(
            ScriptFile sourceFile,
            SymbolReference foundSymbol,
            Workspace workspace)
        {
            Validate.IsNotNull("sourceFile", sourceFile);
            Validate.IsNotNull("foundSymbol", foundSymbol);
            Validate.IsNotNull("workspace", workspace);

            ScriptFile[] referencedFiles =
                workspace.ExpandScriptReferences(
                    sourceFile);

            // look through the referenced files until definition is found
            // or there are no more file to look through
            SymbolReference foundDefinition = null;
            for (int i = 0; i < referencedFiles.Length; i++)
            {
                foundDefinition =
                    AstOperations.FindDefinitionOfSymbol(
                        referencedFiles[i].ScriptAst,
                        foundSymbol);

                if (foundDefinition != null)
                {
                    foundDefinition.FilePath = referencedFiles[i].FilePath;
                    break;
                }
            }

            // if definition is not found in referenced files 
            // look for it in the builtin commands
            if (foundDefinition == null)
            {
                CommandInfo cmdInfo = await GetCommandInfo(foundSymbol.SymbolName);

                foundDefinition = 
                    await FindDeclarationForBuiltinCommand(
                        cmdInfo, 
                        foundSymbol,
                        workspace);
            }

            return foundDefinition != null ?
                new GetDefinitionResult(foundDefinition) :
                null;
        }
Example #33
0
        /// <summary>
        /// Finds a function definition that follows or contains the given line number.
        /// </summary>
        /// <param name="scriptFile">Open script file.</param>
        /// <param name="lineNumber">The 1 based line on which to look for function definition.</param>
        /// <param name="helpLocation"></param>
        /// <returns>If found, returns the function definition, otherwise, returns null.</returns>
        public FunctionDefinitionAst GetFunctionDefinitionForHelpComment(
            ScriptFile scriptFile,
            int lineNumber,
            out string helpLocation)
        {
            // check if the next line contains a function definition
            FunctionDefinitionAst funcDefnAst = GetFunctionDefinitionAtLine(scriptFile, lineNumber + 1);

            if (funcDefnAst != null)
            {
                helpLocation = "before";
                return(funcDefnAst);
            }

            // find all the script definitions that contain the line `lineNumber`
            IEnumerable <Ast> foundAsts = scriptFile.ScriptAst.FindAll(
                ast =>
            {
                var fdAst = ast as FunctionDefinitionAst;
                if (fdAst == null)
                {
                    return(false);
                }

                return(fdAst.Body.Extent.StartLineNumber < lineNumber &&
                       fdAst.Body.Extent.EndLineNumber > lineNumber);
            },
                true);

            if (foundAsts == null || !foundAsts.Any())
            {
                helpLocation = null;
                return(null);
            }

            // of all the function definitions found, return the innermost function
            // definition that contains `lineNumber`
            foreach (FunctionDefinitionAst foundAst in foundAsts.Cast <FunctionDefinitionAst>())
            {
                if (funcDefnAst == null)
                {
                    funcDefnAst = foundAst;
                    continue;
                }

                if (funcDefnAst.Extent.StartOffset >= foundAst.Extent.StartOffset &&
                    funcDefnAst.Extent.EndOffset <= foundAst.Extent.EndOffset)
                {
                    funcDefnAst = foundAst;
                }
            }

            // TODO use tokens to check for non empty character instead of just checking for line offset
            if (funcDefnAst.Body.Extent.StartLineNumber == lineNumber - 1)
            {
                helpLocation = "begin";
                return(funcDefnAst);
            }

            if (funcDefnAst.Body.Extent.EndLineNumber == lineNumber + 1)
            {
                helpLocation = "end";
                return(funcDefnAst);
            }

            // If we didn't find a function definition, then return null
            helpLocation = null;
            return(null);
        }
        /// <summary>
        /// Finds the parameter set hints of a specific command (determined by a given file location)
        /// </summary>
        /// <param name="file">The details and contents of a open script file</param>
        /// <param name="lineNumber">The line number of the cursor for the given script</param>
        /// <param name="columnNumber">The coulumn number of the cursor for the given script</param>
        /// <returns>ParameterSetSignatures</returns>
        public async Task<ParameterSetSignatures> FindParameterSetsInFile(
            ScriptFile file,
            int lineNumber,
            int columnNumber)
        {
            SymbolReference foundSymbol =
                AstOperations.FindCommandAtPosition(
                    file.ScriptAst,
                    lineNumber,
                    columnNumber);

            if (foundSymbol != null)
            {
                CommandInfo commandInfo = await GetCommandInfo(foundSymbol.SymbolName);
                if (commandInfo != null)
                {
                    try
                    {
                        IEnumerable<CommandParameterSetInfo> commandParamSets = commandInfo.ParameterSets;
                        return new ParameterSetSignatures(commandParamSets, foundSymbol);
                    }
                    catch (InvalidOperationException)
                    {
                        // For some commands there are no paramsets (like applications).  Until
                        // the valid command types are better understood, catch this exception
                        // which gets raised when there are no ParameterSets for the command type.
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
Example #35
0
 /// <summary>
 /// Perform semantic analysis on the given ScriptFile and returns
 /// an array of ScriptFileMarkers.
 /// </summary>
 /// <param name="file">The ScriptFile which will be analyzed for semantic markers.</param>
 /// <returns>An array of ScriptFileMarkers containing semantic analysis results.</returns>
 public async Task <ScriptFileMarker[]> GetSemanticMarkersAsync(ScriptFile file)
 {
     return(await GetSemanticMarkersAsync <string>(file, ActiveRules, SettingsPath));
 }