Example #1
0
        /// <summary>
        /// Parses the current file contents to get the AST, tokens,
        /// and parse errors.
        /// </summary>
        private void ParseFileContents()
        {
            ParseError[] parseErrors = null;

            try
            {
                this.ScriptAst =
                    Parser.ParseInput(
                        this.Contents,
                        out this.scriptTokens,
                        out parseErrors);
            }
            catch (RuntimeException ex)
            {
                var parseError =
                    new ParseError(
                        null,
                        ex.ErrorRecord.FullyQualifiedErrorId,
                        ex.Message);

                parseErrors       = new[] { parseError };
                this.scriptTokens = new Token[0];
                this.ScriptAst    = null;
            }

            // Translate parse errors into syntax markers
            this.SyntaxMarkers =
                parseErrors
                .Select(ScriptFileMarker.FromParseError)
                .ToArray();

            //Get all dot sourced referenced files and store  them
            this.ReferencedFiles =
                AstOperations.FindDotSourcedIncludes(this.ScriptAst);
        }
        /// <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);
        }
        private SymbolReference FindDeclarationForBuiltinCommand(
            CommandInfo commandInfo,
            SymbolReference foundSymbol,
            Workspace workspace)
        {
            SymbolReference foundDefinition = null;

            if (commandInfo != null)
            {
                int          index = 0;
                ScriptFile[] nestedModuleFiles;

                nestedModuleFiles =
                    GetBuiltinCommandScriptFiles(
                        commandInfo.Module,
                        workspace);

                while (foundDefinition == null && index < nestedModuleFiles.Length)
                {
                    foundDefinition =
                        AstOperations.FindDefinitionOfSymbol(
                            nestedModuleFiles[index].ScriptAst,
                            foundSymbol);

                    if (foundDefinition != null)
                    {
                        foundDefinition.FilePath = nestedModuleFiles[index].FilePath;
                    }

                    index++;
                }
            }

            return(foundDefinition);
        }
        /// <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);
        }
Example #5
0
        private SymbolReference FindDeclarationForBuiltinCommand(
            CommandInfo commandInfo,
            SymbolReference foundSymbol,
            Workspace workspace)
        {
            if (commandInfo == null)
            {
                return(null);
            }

            ScriptFile[] nestedModuleFiles =
                GetBuiltinCommandScriptFiles(
                    commandInfo.Module,
                    workspace);

            SymbolReference foundDefinition = null;

            foreach (ScriptFile nestedModuleFile in nestedModuleFiles)
            {
                foundDefinition = AstOperations.FindDefinitionOfSymbol(
                    nestedModuleFile.ScriptAst,
                    foundSymbol);

                if (foundDefinition != null)
                {
                    foundDefinition.FilePath = nestedModuleFile.FilePath;
                    break;
                }
            }

            return(foundDefinition);
        }
        /// <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)
            {
                symbolReference.FilePath = scriptFile.FilePath;
                symbolDetails            =
                    await SymbolDetails.Create(
                        symbolReference,
                        this.powerShellContext);
            }
            else
            {
                // TODO #21: Return Result<T>
                return(null);
            }

            return(symbolDetails);
        }
        /// <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>
        /// 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);
        }
        /// <summary>
        /// Parses the current file contents to get the AST, tokens,
        /// and parse errors.
        /// </summary>
        private void ParseFileContents()
        {
            ParseError[] parseErrors = null;

            try
            {
#if PowerShellv5r2
                // This overload appeared with Windows 10 Update 1
                if (this.powerShellVersion.Major >= 5 &&
                    this.powerShellVersion.Build >= 10586)
                {
                    // Include the file path so that module relative
                    // paths are evaluated correctly
                    this.ScriptAst =
                        Parser.ParseInput(
                            this.Contents,
                            this.FilePath,
                            out this.scriptTokens,
                            out parseErrors);
                }
                else
                {
                    this.ScriptAst =
                        Parser.ParseInput(
                            this.Contents,
                            out this.scriptTokens,
                            out parseErrors);
                }
#else
                this.ScriptAst =
                    Parser.ParseInput(
                        this.Contents,
                        out this.scriptTokens,
                        out parseErrors);
#endif
            }
            catch (RuntimeException ex)
            {
                var parseError =
                    new ParseError(
                        null,
                        ex.ErrorRecord.FullyQualifiedErrorId,
                        ex.Message);

                parseErrors       = new[] { parseError };
                this.scriptTokens = new Token[0];
                this.ScriptAst    = null;
            }

            // Translate parse errors into syntax markers
            this.SyntaxMarkers =
                parseErrors
                .Select(ScriptFileMarker.FromParseError)
                .ToArray();

            //Get all dot sourced referenced files and store  them
            this.ReferencedFiles =
                AstOperations.FindDotSourcedIncludes(this.ScriptAst);
        }
Example #10
0
 protected override IEnumerable <SymbolReference> GetSymbolsImpl(
     ScriptFile scriptFile,
     Version psVersion)
 {
     return(AstOperations.FindSymbolsInDocument(
                scriptFile.ScriptAst,
                psVersion));
 }
Example #11
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(
                    new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);

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

            runspaceHandle.Dispose();

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

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

                    return(completionResults);
                }
                catch (ArgumentException e)
                {
                    // Bad completion results could return an invalid
                    // replacement range, catch that here
                    Logger.Write(
                        LogLevel.Error,
                        $"Caught exception while trying to create CompletionResults:\n\n{e.ToString()}");
                }
            }

            // If all else fails, return empty results
            return(new CompletionResults());
        }
Example #12
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> GetCompletionsInFileAsync(
            ScriptFile scriptFile,
            int lineNumber,
            int columnNumber)
        {
            Validate.IsNotNull(nameof(scriptFile), scriptFile);

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

            CommandCompletion commandCompletion =
                await AstOperations.GetCompletionsAsync(
                    scriptFile.ScriptAst,
                    scriptFile.ScriptTokens,
                    fileOffset,
                    _powerShellContext,
                    _logger,
                    new CancellationTokenSource(DefaultWaitTimeoutMilliseconds).Token);

            if (commandCompletion == null)
            {
                return(new CompletionResults());
            }

            try
            {
                CompletionResults completionResults =
                    CompletionResults.Create(
                        scriptFile,
                        commandCompletion);

                // save state of most recent completion
                _mostRecentCompletions   = completionResults;
                _mostRecentRequestFile   = scriptFile.Id;
                _mostRecentRequestLine   = lineNumber;
                _mostRecentRequestOffest = columnNumber;

                return(completionResults);
            }
            catch (ArgumentException e)
            {
                // Bad completion results could return an invalid
                // replacement range, catch that here
                _logger.Write(
                    LogLevel.Error,
                    $"Caught exception while trying to create CompletionResults:\n\n{e.ToString()}");

                return(new CompletionResults());
            }
        }
        /// <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 CommandHelpers.GetCommandInfo(
                        foundSymbol.SymbolName,
                        this.powerShellContext);

                if (commandInfo != null)
                {
                    try
                    {
                        IEnumerable <CommandParameterSetInfo> commandParamSets = commandInfo.ParameterSets;
                        return(new ParameterSetSignatures(commandParamSets, foundSymbol));
                    }
                    catch (RuntimeException e)
                    {
                        // A RuntimeException will be thrown when an invalid attribute is
                        // on a parameter binding block and then that command/script has
                        // its signatures resolved by typing it into a script.
                        this.logger.WriteException("RuntimeException encountered while accessing command parameter sets", e);

                        return(null);
                    }
                    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);
            }
        }
        /// <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 CommandHelpers.GetCommandInfo(
                        foundSymbol.SymbolName,
                        this.powerShellContext);

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

            return(foundDefinition != null ?
                   new GetDefinitionResult(foundDefinition) :
                   null);
        }
        /// <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);
            }
        }
        /// <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>
        /// 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);
        }
        /// <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 CommandHelpers.GetCommandInfo(
                        foundSymbol.SymbolName,
                        this.powerShellContext);

                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);
            }
        }
        /// <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)
                .Select(
                    reference => {
                reference.SourceLine =
                    scriptFile.GetLine(reference.ScriptRegion.StartLineNumber);
                reference.FilePath = scriptFile.FilePath;
                return(reference);
            });

            return
                (new FindOccurrencesResult {
                FoundOccurrences = symbolReferencesinFile
            });
        }
        private async Task <SymbolReference> FindDeclarationForBuiltinCommand(
            CommandInfo cmdInfo,
            SymbolReference foundSymbol,
            Workspace workspace)
        {
            SymbolReference foundDefinition = null;

            if (cmdInfo != null)
            {
                int          index = 0;
                ScriptFile[] nestedModuleFiles;

                CommandInfo commandInfo =
                    await CommandHelpers.GetCommandInfo(
                        foundSymbol.SymbolName,
                        this.powerShellContext);

                nestedModuleFiles =
                    GetBuiltinCommandScriptFiles(
                        commandInfo.Module,
                        workspace);

                while (foundDefinition == null && index < nestedModuleFiles.Length)
                {
                    foundDefinition =
                        AstOperations.FindDefinitionOfSymbol(
                            nestedModuleFiles[index].ScriptAst,
                            foundSymbol);

                    if (foundDefinition != null)
                    {
                        foundDefinition.FilePath = nestedModuleFiles[index].FilePath;
                    }

                    index++;
                }
            }

            return(foundDefinition);
        }
 protected override bool CanProvideFor(ScriptFile scriptFile)
 {
     return((scriptFile.FilePath != null &&
             scriptFile.FilePath.EndsWith(".psd1", StringComparison.OrdinalIgnoreCase)) ||
            AstOperations.IsPowerShellDataFileAst(scriptFile.ScriptAst));
 }
        /// <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 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>
        /// <param name="workspace">The workspace that will be searched for symbols</param>
        /// <returns>FindReferencesResult</returns>
        public async Task <FindReferencesResult> FindReferencesOfSymbol(
            SymbolReference foundSymbol,
            ScriptFile[] referencedFiles,
            Workspace workspace)
        {
            if (foundSymbol != null)
            {
                int symbolOffset = referencedFiles[0].GetOffsetAtPosition(
                    foundSymbol.ScriptRegion.StartLineNumber,
                    foundSymbol.ScriptRegion.StartColumnNumber);

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

                // We want to look for references first in referenced files, hence we use ordered dictionary
                var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
                foreach (ScriptFile file in referencedFiles)
                {
                    fileMap.Add(file.FilePath, file);
                }

                var allFiles = workspace.EnumeratePSFiles();
                foreach (var file in allFiles)
                {
                    if (!fileMap.Contains(file))
                    {
                        fileMap.Add(file, new ScriptFile(file, null, this.powerShellContext.LocalPowerShellVersion.Version));
                    }
                }

                List <SymbolReference> symbolReferences = new List <SymbolReference>();
                foreach (var fileName in fileMap.Keys)
                {
                    var file = (ScriptFile)fileMap[fileName];
                    IEnumerable <SymbolReference> symbolReferencesinFile =
                        AstOperations
                        .FindReferencesOfSymbol(
                            file.ScriptAst,
                            foundSymbol,
                            CmdletToAliasDictionary,
                            AliasToCmdletDictionary)
                        .Select(
                            reference =>
                    {
                        try
                        {
                            reference.SourceLine =
                                file.GetLine(reference.ScriptRegion.StartLineNumber);
                        }
                        catch (ArgumentOutOfRangeException e)
                        {
                            reference.SourceLine = string.Empty;
                            this.logger.WriteException("Found reference is out of range in script file", e);
                        }

                        reference.FilePath = file.FilePath;
                        return(reference);
                    });

                    symbolReferences.AddRange(symbolReferencesinFile);
                }

                return
                    (new FindReferencesResult
                {
                    SymbolFileOffset = symbolOffset,
                    SymbolName = foundSymbol.SymbolName,
                    FoundReferences = symbolReferences
                });
            }
            else
            {
                return(null);
            }
        }
Example #24
0
        /// <summary>
        /// Parses the current file contents to get the AST, tokens,
        /// and parse errors.
        /// </summary>
        private void ParseFileContents()
        {
            ParseError[] parseErrors = null;

            // First, get the updated file range
            int lineCount = this.FileLines.Count;

            if (lineCount > 0)
            {
                this.FileRange =
                    new BufferRange(
                        new BufferPosition(1, 1),
                        new BufferPosition(
                            lineCount + 1,
                            this.FileLines[lineCount - 1].Length + 1));
            }
            else
            {
                this.FileRange = BufferRange.None;
            }

            try
            {
                Token[] scriptTokens;

                // This overload appeared with Windows 10 Update 1
                if (this.powerShellVersion.Major >= 6 ||
                    (this.powerShellVersion.Major == 5 && this.powerShellVersion.Build >= 10586))
                {
                    // Include the file path so that module relative
                    // paths are evaluated correctly
                    this.ScriptAst =
                        Parser.ParseInput(
                            this.Contents,
                            this.FilePath,
                            out scriptTokens,
                            out parseErrors);
                }
                else
                {
                    this.ScriptAst =
                        Parser.ParseInput(
                            this.Contents,
                            out scriptTokens,
                            out parseErrors);
                }

                this.ScriptTokens = scriptTokens;
            }
            catch (RuntimeException ex)
            {
                var parseError =
                    new ParseError(
                        null,
                        ex.ErrorRecord.FullyQualifiedErrorId,
                        ex.Message);

                parseErrors       = new[] { parseError };
                this.ScriptTokens = new Token[0];
                this.ScriptAst    = null;
            }

            // Translate parse errors into syntax markers
            this.SyntaxMarkers =
                parseErrors
                .Select(ScriptFileMarker.FromParseError)
                .ToArray();

            // Untitled files have no directory
            // Discussed in https://github.com/PowerShell/PowerShellEditorServices/pull/815.
            // Rather than working hard to enable things for untitled files like a phantom directory,
            // users should save the file.
            if (IsUntitledPath(this.FilePath))
            {
                // Need to initialize the ReferencedFiles property to an empty array.
                this.ReferencedFiles = new string[0];
                return;
            }

            // Get all dot sourced referenced files and store them
            this.ReferencedFiles = AstOperations.FindDotSourcedIncludes(this.ScriptAst, Path.GetDirectoryName(this.FilePath));
        }
Example #25
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> GetDefinitionOfSymbolAsync(
            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.GetCommandInfoAsync(
                        foundSymbol.SymbolName,
                        _powerShellContext);

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

            return(foundDefinition != null ?
                   new GetDefinitionResult(foundDefinition) :
                   null);
        }
Example #26
0
        /// <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>
        /// <param name="workspace">The workspace that will be searched for symbols</param>
        /// <returns>FindReferencesResult</returns>
        public async Task <FindReferencesResult> FindReferencesOfSymbolAsync(
            SymbolReference foundSymbol,
            ScriptFile[] referencedFiles,
            Workspace workspace)
        {
            if (foundSymbol == null)
            {
                return(null);
            }

            int symbolOffset = referencedFiles[0].GetOffsetAtPosition(
                foundSymbol.ScriptRegion.StartLineNumber,
                foundSymbol.ScriptRegion.StartColumnNumber);

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

            // We want to look for references first in referenced files, hence we use ordered dictionary
            // TODO: File system case-sensitivity is based on filesystem not OS, but OS is a much cheaper heuristic
            var fileMap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
                ? new OrderedDictionary()
                : new OrderedDictionary(StringComparer.OrdinalIgnoreCase);

            foreach (ScriptFile scriptFile in referencedFiles)
            {
                fileMap[scriptFile.FilePath] = scriptFile;
            }

            foreach (string filePath in workspace.EnumeratePSFiles())
            {
                if (!fileMap.Contains(filePath))
                {
                    if (!workspace.TryGetFile(filePath, out ScriptFile scriptFile))
                    {
                        // If we can't access the file for some reason, just ignore it
                        continue;
                    }

                    fileMap[filePath] = scriptFile;
                }
            }

            var symbolReferences = new List <SymbolReference>();

            foreach (object fileName in fileMap.Keys)
            {
                var file = (ScriptFile)fileMap[fileName];
                await _aliasHandle.WaitAsync();

                try
                {
                    IEnumerable <SymbolReference> references = AstOperations.FindReferencesOfSymbol(
                        file.ScriptAst,
                        foundSymbol,
                        _cmdletToAliasDictionary,
                        _aliasToCmdletDictionary);

                    foreach (SymbolReference reference in references)
                    {
                        try
                        {
                            reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber);
                        }
                        catch (ArgumentOutOfRangeException e)
                        {
                            reference.SourceLine = string.Empty;
                            _logger.WriteException("Found reference is out of range in script file", e);
                        }
                        reference.FilePath = file.FilePath;
                        symbolReferences.Add(reference);
                    }
                }
                finally
                {
                    _aliasHandle.Release();
                }
            }

            return(new FindReferencesResult
            {
                SymbolFileOffset = symbolOffset,
                SymbolName = foundSymbol.SymbolName,
                FoundReferences = symbolReferences
            });
        }
Example #27
0
        /// <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>
        /// <param name="workspace">The workspace that will be searched for symbols</param>
        /// <returns>FindReferencesResult</returns>
        public async Task <FindReferencesResult> FindReferencesOfSymbol(
            SymbolReference foundSymbol,
            ScriptFile[] referencedFiles,
            Workspace workspace)
        {
            if (foundSymbol == null)
            {
                return(null);
            }

            int symbolOffset = referencedFiles[0].GetOffsetAtPosition(
                foundSymbol.ScriptRegion.StartLineNumber,
                foundSymbol.ScriptRegion.StartColumnNumber);

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

            // We want to look for references first in referenced files, hence we use ordered dictionary
            // TODO: File system case-sensitivity is based on filesystem not OS, but OS is a much cheaper heuristic
#if CoreCLR
            // The RuntimeInformation.IsOSPlatform is not supported in .NET Framework
            var fileMap = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
                ? new OrderedDictionary()
                : new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
#else
            var fileMap = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
#endif
            foreach (ScriptFile file in referencedFiles)
            {
                fileMap.Add(file.FilePath, file);
            }

            foreach (string file in workspace.EnumeratePSFiles())
            {
                if (!fileMap.Contains(file))
                {
                    ScriptFile scriptFile;
                    try
                    {
                        scriptFile = workspace.GetFile(file);
                    }
                    catch (Exception e) when(e is IOException ||
                                             e is SecurityException ||
                                             e is FileNotFoundException ||
                                             e is DirectoryNotFoundException ||
                                             e is PathTooLongException ||
                                             e is UnauthorizedAccessException)
                    {
                        // If we can't access the file for some reason, just ignore it
                        continue;
                    }

                    fileMap.Add(file, scriptFile);
                }
            }

            var symbolReferences = new List <SymbolReference>();
            foreach (object fileName in fileMap.Keys)
            {
                var file = (ScriptFile)fileMap[fileName];

                IEnumerable <SymbolReference> references = AstOperations.FindReferencesOfSymbol(
                    file.ScriptAst,
                    foundSymbol,
                    _cmdletToAliasDictionary,
                    _aliasToCmdletDictionary);

                foreach (SymbolReference reference in references)
                {
                    try
                    {
                        reference.SourceLine = file.GetLine(reference.ScriptRegion.StartLineNumber);
                    }
                    catch (ArgumentOutOfRangeException e)
                    {
                        reference.SourceLine = string.Empty;
                        _logger.WriteException("Found reference is out of range in script file", e);
                    }
                    reference.FilePath = file.FilePath;
                    symbolReferences.Add(reference);
                }
            }

            return(new FindReferencesResult
            {
                SymbolFileOffset = symbolOffset,
                SymbolName = foundSymbol.SymbolName,
                FoundReferences = symbolReferences
            });
        }