PowerShell / PowerShell/PowerShell

The Parser is handing out Internal objects like candy and (may be) poisoning children

Open
#9,562 11 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Issue-Question KeepOpen Up-for-Grabs WG-Engine WG-Reviewed
Dominant language
C#
Stars
55.5k
Forks
8.5k
Avg merge
1d 2h
Merged PRs (30d)
88

Description

Trying to write a ScriptAnalyzer rule, and needed to generate an Extent for the DiagnosticRecord which is slightly modified from the ones found in the AST object that are passed to me ...

Imagine my surprise when I tried to cast the .Extent on one of these AST objects to a System.Management.Automation.Language.ScriptExtent and got an exception saying PowerShell doesn't know how to convert a System.Management.Automation.Language.InternalScriptExtent to that.

So then I tried to just make one:

[System.Management.Automation.Language.ScriptExtent]::new(
   $FunctionAst.Extent.StartScriptPosition, 
   $FunctionAst.Extent.EndScriptPosition)

Did you know that InternalScriptExtent.StartScriptPosition and EndScriptPosition are also internal classes? Of course! So now I get a giant wall of red which is best summarized as:
Cannot convert "InternalScriptPosition" to type "ScriptPosition"

All I wanted to do was increment the line numbers, so I had to write this:

# Because we can't just modify $comment.Extent:
# $comment.Extent.StartScriptPosition.LineNumber += $Extent.StartLineNumber -1
# We have to create a whole new ScriptExtent object:
$Extent = [System.Management.Automation.Language.ScriptExtent]::new(
            [System.Management.Automation.Language.ScriptPosition]::new(
            $FunctionAst.Extent.StartScriptPosition.File,
            ($FunctionAst.Extent.StartScriptPosition.LineNumber + $comment.Extent.StartScriptPosition.LineNumber - 1),
            $FunctionAst.Extent.StartScriptPosition.ColumnNumber,
            $comment.Extent.StartScriptPosition.Line,
            $FunctionAst.Extent.StartScriptPosition.GetFullScript()),

            [System.Management.Automation.Language.ScriptPosition]::new(
            $FunctionAst.Extent.EndScriptPosition.File,
            ($FunctionAst.Extent.EndScriptPosition.LineNumber + $comment.Extent.EndScriptPosition.LineNumber - 1),
            $FunctionAst.Extent.EndScriptPosition.ColumnNumber,
            $comment.Extent.EndScriptPosition.Line,
            $FunctionAst.Extent.EndScriptPosition.GetFullScript())
        )

But I found the output of this has the StartOffset and EndOffset always equal to zero -- and they are not settable in any way, because they're ReadOnly and not exposed to the constructors.

  1. Feature request: add a cast operator to the ScriptExtents please
  2. Feature request: add a cast operator to the ScriptPositions please
  3. Feature request: make all of the numbers on the public objects settable
  4. Bug: stop returning Internal objects from public APIs (in this case, Parser.Parse)

cc @daxian-dbw

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing Parser.Parse and the public ScriptExtent and ScriptPosition types, comparing them with the InternalScriptExtent and InternalScriptPosition objects described in the report. Clarify which of the four requested changes is in scope, then add focused coverage for the chosen public API behavior, including preservation of offsets where applicable.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, powershell
Domain
backend-api-design, cli, compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.