LxLeChat / FlowChartCore

PowerShell Module Written in C# to create DOT graphs from PS Scripts
MIT License
18 stars 3 forks source link

New-FLowChartGraph throw Object reference not set to an instance of an object. #17

Closed LaurentDardenne closed 3 years ago

LaurentDardenne commented 4 years ago

The following code based on a test of the switch statement raises an exception :

$sb={
    $grade = 92
    Switch ($Grade)
    {
        {$grade -ge 90} { "Grade A";Break}
        {$grade -ge 80} { "Grade B";Break}
        {$grade -ge 70} { "Grade C";Break}
        {$grade -ge 60} { "Grade D";Break}
        default { "Grade F" }
    }
}
$Result=Find-FLowChartNodes -ScriptBlock $Sb
New-FLowChartGraph  $Result > c:\temp\testIfWithSwitch.graph # <--------- BUG
C:\Tools\Graphviz\bin\dot -Tpng c:\temp\testIfWithSwitch.graph -o c:\temp\testIfWithSwitch.png
ii c:\temp\testIfWithSwitch.png

$stacktrace:


   at FlowChartCore.Graph.BreakBuilder.CreateSpecialEdge() in C:\Users\Laurent\Downloads\FlowChartCore\FlowChartCore-master\Code\Library\GraphBuilder\BreakBuilder.cs:line 59
   at FlowChartCore.Graph.BreakBuilder..ctor(BreakNode breaknode) in C:\Users\Laurent\Downloads\FlowChartCore\FlowChartCore-master\Code\Library\GraphBuilder\BreakBuilder.cs:line 22
   at FlowChartCore.BreakNode.GenerateGraph(Boolean recursive) in C:\Users\Laurent\Downloads\FlowChartCore\FlowChartCore-master\Code\Library\Nodes - Keywords\BreakNode.cs:line 41
   at FlowChartCore.SwitchCaseNode.GenerateGraph(Boolean recursive) in C:\Users\Laurent\Downloads\FlowChartCore\FlowChartCore-master\Code\Library\Nodes - Switch\SwitchCaseNode.cs:line 78
   at FlowChartCore.SwitchNode.GenerateGraph(Boolean recursive) in C:\Users\Laurent\Downloads\FlowChartCore\FlowChartCore-master\Code\Library\Nodes - Switch\SwitchNode.cs:line 66
   at FlowChartCore.Cmdlets.NewFlowChartGraph.ProcessRecord() in C:\Users\Laurent\Downloads\FlowChartCore\FlowChartCore-master\Code\Cmdlets\NewNodeGraph.cs:line 46
   at System.Management.Automation.CommandProcessor.ProcessRecord()
LaurentDardenne commented 4 years ago

Une autre construction dérivé, mais une autre exception : New-FLowChartGraph: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')


$sb={
    $grade = 92
    Switch ($Grade)
    {
        {$grade -ge 90} { "Grade A";Break}
        # {$grade -ge 80} { "Grade B";Break}
        # {$grade -ge 70} { "Grade C";Break}
        # {$grade -ge 60} { "Grade D";Break}
        # default { "Grade F" }
    }
}
$Result=Find-FLowChartNodes -ScriptBlock $Sb
New-FLowChartGraph  $Result > c:\temp\testIfWithSwitch.graph
C:\Tools\Graphviz\bin\dot -Tpng c:\temp\testIfWithSwitch.graph -o c:\temp\testIfWithSwitch.png
ii c:\temp\testIfWithSwitch.png

La suivante aboutie, mais la représentation est fausse il me semble:

$sb={
    $grade = 92
    Switch ($Grade)
    {
        {$grade -ge 90} { "Grade A";Break}
        # {$grade -ge 80} { "Grade B";Break}
        # {$grade -ge 70} { "Grade C";Break}
        # {$grade -ge 60} { "Grade D";Break}
         default { "Grade F" }
    }
    writelog "suite" #   !!!!!!!!  n'est pas considéré dans le graph  !!!!!!!!!!
}
del c:\temp\testIfWithSwitch.graphn, c:\temp\testIfWithSwitch.png -ea ignore
$Result=Find-FLowChartNodes -ScriptBlock $Sb
New-FLowChartGraph  $Result > c:\temp\testIfWithSwitch.graph
C:\Tools\Graphviz\bin\dot -Tpng c:\temp\testIfWithSwitch.graph -o c:\temp\testIfWithSwitch.png
ii c:\temp\testIfWithSwitch.png

image

LxLeChat commented 4 years ago

Super merci pour les exemple de code qui pose problème! je sais que j'ai le problème dans un autre cas, je vais me pencher la dessus

Merci beaucoup pour les issues @LaurentDardenne !

LxLeChat commented 4 years ago

Normalement c'est fixé ! j'ai testé les 3 cas que tu m as présenté et tout semble OK.

LaurentDardenne commented 4 years ago

Ce cas n'est pas géré et déclenche la même exception :


$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 80) { "Grade B"} #;Break}
    elseif ($grade -ge 70) { "Grade C"}
    elseif ($grade -ge 60) { "Grade D" }
    else { "Grade F"}
    writeLog "Suite"
    break
}
del c:\temp\testWithIF2.graph, c:\temp\testWithIF2.png -ea Ignore

Find-FLowChartNodes -ScriptBlock $Sb|New-FLowChartGraph 
#New-FLowChartGraph : La référence d'objet n'est pas définie à une instance d'un objet.
$stacktrace
<#
   à FlowChartCore.Graph.BreakBuilder.CreateSpecialEdge()
   à FlowChartCore.Graph.BreakBuilder..ctor(BreakNode breaknode)
   à FlowChartCore.BreakNode.GenerateGraph(Boolean recursive)
   à FlowChartCore.ElseIfNode.GenerateGraph(Boolean recursive)
   à FlowChartCore.IfNode.GenerateGraph(Boolean recursive)
   à FlowChartCore.Cmdlets.NewFlowChartGraph.ProcessRecord()
   à System.Management.Automation.CommandProcessor.ProcessRecord()
#>

La présence du break, peut importe sa position, déclenche l'exception.

En passant le libellé de fin devrait suivre le nom du paramètre : -Scriptblock ->'end_of_scriptblock ' -path 'end_of_script'

LaurentDardenne commented 4 years ago

Du coup avec cette version on peut visualiser la comparaison entre les instructions If et Switch :

$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 80) { "Grade B"} 
    elseif ($grade -ge 70) { "Grade C"}
    elseif ($grade -ge 60) { "Grade D" }
    else { "Grade F"}
    writeLog "Suite"
}
del c:\temp\testWithIF2.graph, c:\temp\testWithIF2.png -ea Ignore

Find-FLowChartNodes -ScriptBlock $Sb|New-FLowChartGraph |Set-Content c:\temp\testIF.graph
C:\Tools\Graphviz\bin\dot -Tpng c:\temp\testIf.graph -o c:\temp\testIf.png
ii c:\temp\testIf.png

$sb={
    $grade = 92
    Switch ($Grade)
    {
        {$grade -ge 90} { "Grade A"}
        {$grade -ge 80} { "Grade B"}
        {$grade -ge 70} { "Grade C"}
        {$grade -ge 60} { "Grade D"}
        default { "Grade F" }
    }
}
$Result=Find-FLowChartNodes -ScriptBlock $Sb
New-FLowChartGraph  $Result > c:\temp\testIfWithSwitch.graph
C:\Tools\Graphviz\bin\dot -Tpng c:\temp\testIfWithSwitch.graph -o c:\temp\testIfWithSwitch.png
ii c:\temp\testIfWithSwitch.png

image

Bien que le rendu soit différent, le 'fonctionnement' est identique.

LxLeChat commented 4 years ago

t as testé le break comme ça pour voir si ça balançait le même message d'erreur:

 Switch ($Grade)
    {
        {$grade -ge 90} { "Grade A";break}
        {$grade -ge 80} { "Grade B";break}
        {$grade -ge 70} { "Grade C";break}
        {$grade -ge 60} { "Grade D";break}
        default { "Grade F";break}
    }

je ne pense pas avoir gérer ce cas. en gros je me suis basé la dessus: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_break?view=powershell-7#do-not-use-break-outside-of-a-loop-switch-or-trap

je peux éventuellement le gérer si nécessaire, mais en gros ça fait quoi ? ça quitte ? un peu comme exit ou return ?

LaurentDardenne commented 4 years ago

Salut,

t as testé le break comme ça pour voir si ça balançait le même message d'erreur:

Oui, mais là il faut créer des fichiers de test pour vérifier les régressions, ça va vite avec ce genre d'outil.

Ce cas provoque une exception :

$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 80) { "Grade B"} 
    elseif ($grade -ge 70) { "Grade C";break}
    elseif ($grade -ge 60) { "Grade D" }
    else { "Grade F"}
    writeLog "Suite"
}

Et celui-ci:

$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 80) { "Grade B"} #;Break}
    elseif ($grade -ge 70) { "Grade C"}
    elseif ($grade -ge 60) { "Grade D" }
    else { "Grade F"}
    writeLog "Suite"
    break
}

ça quitte ? un peu comme exit ou return ?

Si tu parles bien de l'instruction Break ( j'ai un doute désolé) ?

je peux éventuellement le gérer si nécessaire,

Ici il peut y avoir 5 ou 6 constructions, avec ou sans sens, mais si le langage les permet, on peut les retrouver dans du code à la six-quatre-deux. Ce n'est pas nécessaire, mais il est possible de le rencontrer, C'est un choix à faire.

LxLeChat commented 4 years ago

bon faut que je regarde ces cas .. je crois que je vais écrire des tests ça sera moins relou ... un fichier contenant n scripblock, et un bon vieux tests pester dans une boucle qui ne doit pas throw ..

concernant le break ...le code de m... bah je vois 2 possibilités,

LaurentDardenne commented 4 years ago

bon faut que je regarde ces cas .. je crois que je vais écrire des tests ça sera moins relou ...

:-)

un fichier contenant n scriptblock, et un bon vieux tests pester dans une boucle qui ne doit pas throw ..

hum, tu peux vite te retrouver avec un paquet de code illisible et pour un cas précis tout exécuter et devoir aller chercher l'info. Et tu as l'approche laborieuse où tu vas passer bcp de temps à écrire des tests.

* la plus simple (je pense) ajouter le code nécessaire qui va générer le graph dans ce genre de cas, à savoir on quitte

Tu veux dire on ajoute un noeud 'Break' ou on quitte l'analyse ?

* la plus complexe, quand le `break` n'est pas au "bon endroit" je le considère comme une instruction qui fait partie d'un code block

Si l'AST indique que la construction d'un break est syntaxiquement correct, il est au 'bon endroit'. Ce serait à PSSA de dire là c'est du code en vrac, ce que n'est pas ton soft. Pour moi ce type de soft prend du code en entrée puis le transforme en graphe, que son rendu soit illisible/incohérent ce n'est pas le sujet. Avec n'importe quoi en entrée on a tjr n'importe quoi en sortie. On ne fait pas de l'alchimie :-)

Ces exemples sont bien évidement du n'importe quoi, mais ton soft ne devrait pas terminer sur une exception. Le rendu peut être faux ou incomplet, à partir de là tu pourras dire "ça je gère pas, ceci est pour la version 7", voir placer un label "t'as qu'a le faire", etc

Je peux prendre un peu de temps pour étudier comment automatiser et structurer ce type de test.

LxLeChat commented 4 years ago

(note to self!) pour les break .. j'ai un fix, mais vu que pour moi ce genre de cas ... n'existait pas .. je n'ai jamais pensé à passer le root dans le constructeur des keywords break, return, exit ... du coup va falloir que je repasse sur chacun!

le fix ne fonctionne pas, car je ne troue pas l index du noeud, quand le type break est de niveau 0, car le root n'est pas présent .. !

LxLeChat commented 4 years ago
$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 80) { "Grade B"} 
    elseif ($grade -ge 70) { "Grade C";break}
    elseif ($grade -ge 60) { "Grade D" }
    else { "Grade F"}
    writeLog "Suite"
}

image

et celui la:

$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 80) { "Grade B"} #;Break}
    elseif ($grade -ge 70) { "Grade C"}
    elseif ($grade -ge 60) { "Grade D" }
    else { "Grade F"}
    writeLog "Suite"
    break
}

image

Modif faite pour Breajk. J'ai prépa le terrain pour ce que j'appelle les "keywords" continue, exit, return ... parce t as raison PS ne l interdit pas, j'aurai juste a implémenter les correction de la generation du graph pour ceux la

LaurentDardenne commented 4 years ago

Les images que tu as intégrées proviennent de la dernière version ? J'ai une exception pour les deux (j'ai recompilé) :/ image

LxLeChat commented 4 years ago

Eh je crois que g pas merge le dernier que g fait hier soir ...!

LaurentDardenne commented 4 years ago

Ok, je préfére ça :-)

LxLeChat commented 4 years ago

done! par contres c'est étrange que tu importes la dll dotnet à chaque fois moi j'ai juste besoin d importer la flowchartcore.dll

j'ai testé aussi sur ps5.1 et pareil juste besoin d'importer la flowchartcore.dll

LaurentDardenne commented 4 years ago

Merci.

par contre c'est étrange que tu importes la dll dotnet à chaque fois

C'est une habitude, je place tout dans un script pour l'initialisation, ensuite je ne crée que le nécessaire. Et une fois une dll dotnet dans le domaine d'application on ne peut plus la décharger son ajout à répétition ne fait rien, comme un module PS ( bien qu'ici on puisse utiliser -Force) Et c'est aussi le code de repro, l'erreur pouvant provenir de mon côté ;-)

Ensuite on peut créer juste un manifeste (psd1), mais le téléchargement via Github ajoute le stream de sécurité à supprimer, là où l'installation d'un module via PSGallery ne le fait pas. Il y a ( avait ?) une gallery de dev sinon utiliser myget. Je l'utilise pour ne pas polluer la gallery avec des POC et autre outil perso.

LxLeChat commented 4 years ago

t as forké, tu peux participer à la fête, et ça sera plus simple que de dll le projet :) t auras juste à rebase ou je sais pas ce que c le terme git ! le psd1 ouais, après ça sera utile le jour ou je publierai sur la gallery

LaurentDardenne commented 4 years ago

t as forké, tu peux participer à la fête, et ça sera plus simple que de dll le projet :)

Certes, pense à d'autres qui peuvent tester sans devoir creuser le comment du pourquoi.

le psd1 ouais, après ça sera utile le jour ou je publierai sur la gallery

L'avantage de l'utiliser dés le début est que tu valides la chaîne (ton soft et le build) tout au long du développement. C'est le premier truc que je fais. Après tu fais comme tu veux :-)

LxLeChat commented 4 years ago

c vrai :) mais la vu que c du compilé ^^ tu build et boum ! mais ouais je vais créer une issue pour y penser !

d'habitude je fais ça aussi

LaurentDardenne commented 4 years ago

Autres constructions provoquant le bug :

#OK
$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 70)  { "Grade C"}
    else { "Grade D"}

}

#NOK
$sb={
    $grade = 92
    if ($grade -ge 90) { "Grade A" }
    elseif ($grade -ge 70)  { "Grade C"}
}

#NOK
#if dans une boucle for
$sb={
    for ($i = 1; ; ++$i)
    {
        if ($i * $i -gt 50)
        {
            dir
        }
    }
}
LxLeChat commented 4 years ago

it is corrigé ! j'avoue un for sans conditions je savais meme pas que ct possible :)

LaurentDardenne commented 4 years ago

j'avoue un for sans conditions je savais meme pas que ct possible :)

En direct du doc des spec de PS :

$break7=New-CodeUseCase 'Break use a string value as target' @'
$i = 1
while ($true)                       # infinite loop
{
    if ($i * $i -gt 100)
    {
        break                       # break out of current while loop
    }
    ++$i
}
    $lab = "go_here"
:go_here
    for ($i = 1; ; ++$i)
    {
        if ($i * $i -gt 50)
        {
            break $lab              # use a string value as target
        }
    }
:labelA
    for ($i = 1; $i -le 2; $i++)
    {
:labelB
        for ($j = 1; $j -le 2; $j++)
        {
:labelC
            for ($k = 1; $k -le 3; $k++)
            {
                if ($true) { break labelA }
            }
        }
    }                        
'@
LxLeChat commented 4 years ago

Concernant

$sb = {
    $lab = "go_here"
:go_here
    for ($i = 1; ; ++$i)
    {
        if ($i * $i -gt 50)
        {
            break $lab              # use a string value as target
        }
    }
}

ça je l'ai pas ... ! le problème c'est que si on regarde l'AST du break et bien la propriété label est vide ...

PS > $x = Find-FLowChartNodes -ScriptBlock $sb
PS > $break = $x.findnodes({$args[0] -is [FlowChartCore.BreakNode]},$true)
PS > $break.GetAst()

Label Extent Parent
----- ------ ------
      break  {…

Du coup si le label est vide, j'ai mis une description "Break from Previous Loop" qui donne la definition suivante

digraph "a" {
        "01"[label="CodeBlock"];
        "01" -> "02";
        "02"[label="For "];
        "02" -> "0210";
        "loop_02"[shape=ellipse,label="Loop"];
        "loop_02" -> "02"[label="++$i"];
        "loop_02" -> "end_of_script"[label="Loop End"];
        "0210"[label="If $i * $i -gt 50",shape=diamond];
        "end_0210"[shape=mdiamond,label="End If"];
        "0210" -> "021020"[label="True"];
        "end_0210" -> "loop_02";
        "021020"[label="Break"];
        "021020" -> "021021"[style=dotted];
        "021020" -> "end_of_script"[label="Break From Previous Loop"];
        "021021"[label="CodeBlock"];
        "021021" -> "end_0210";
}

J'ai par la même occasion corrigé un bug, sur les label qui était "Break From" au lieu de "Break From TheLabel" et j'ai ajouté la méthode GetAst à la classe BreakNode

LaurentDardenne commented 4 years ago

le problème c'est que si on regarde l'AST du break et bien la propriété label est vide ...

L'information existe mais sur le parent :

$break.GetAst().parent.gettype()
# IsPublic IsSerial Name                                     BaseType
# -------- -------- ----                                     --------
# True     False    StatementBlockAst                        System.Management.Automation.Language.Ast

$break.GetAst().parent|% {$_.statements|% {$_ -as [string]}}
# break
# $lab
LaurentDardenne commented 4 years ago

En même temps c'est plutôt rare de coder ainsi je pense.

LxLeChat commented 4 years ago

Oui et surtout je vois pas comment faire la corrélation vu que j ai aucune indication de quelle variable je dois chercher

LaurentDardenne commented 4 years ago

Avec Show-Ast : image

Selon les specs il n'y a que trois cas *: image

Je regarderais comment on recherche cela, j'ai jamais fait. [edit] A vérifier

LaurentDardenne commented 4 years ago

Le code utilsé:

$sb = {
    $lab = "go_here"
:go_here
    for ($i = 1; ; ++$i)
    {

    if ('a') {dir;break}
     if ($i * $i -gt 40)
         {
            break go_here
     }
    if ($i * $i -gt 50)
        {
      #write-host 'before'
      break $lab ; write-host 'truc'                # use a string value as target
      #write-host 'after'
        }
  }
  break
}
LxLeChat commented 4 years ago

ok j'ai un début de piste ... $lol etant le fameux break

$lol.GetAst().parent.Find({$args[0] -is [System.Management.Automation.Language.VariableExpressionAst]},$true)

manque plus qu a recup la valeur ...

On pourrait s'arreter la et dire "break from $lab" mais ça pue la défaite ça !!!

LxLeChat commented 4 years ago

bon c'est éventuellement faisable ... Mais, il faudrait lister toute les variables au préalable ... pour être précis, toute les AssignmentStatementAst contenant des CommandExpressionAst, looper dans le resultat qui est une liste, et trouver celle qui correspond ...

LaurentDardenne commented 4 years ago

mais ça pue la défaite ça !!!

Certains diront que c'est une retraite stratégique :-)

Les specs :

A labeled break need not be resolved in any local scope; the search for a matching label may continue up the calling stack even across script and function-call boundaries.

If no matching label is found, the current command invocation is terminated. The name of the label designated by label-expression need not have a constant value. If label-expression is a unary-expression, it is converted to a string.

Ici la présence du terme scope est une alerte. Un exemple. Et je ne sais même pas si on peut écrire ceci :-)

break $script:Lab 

Cela provient peut être d'un outil d'obfuscation (obscurcissement) ?

LxLeChat commented 4 years ago

hier j'étais entrain d'implémenter le cas de la variable, j'ai pas encore fini .. je trouve ça moins facile en c# qu'en PS ... je n'arrive pas à reproduire mon oneliner xD

LaurentDardenne commented 4 years ago

je trouve ça moins facile en C# qu'en PS

Oui le niveau de détail est plus important. On peut descendre d'un niveau : 'je trouve ça moins facile en C qu'en C#' L'avantage est que l'on a la possibilité de modifier les détails :-)

LxLeChat commented 4 years ago

le cas que j'ai pas gérer ... c'est si tu réaffectes: break $somevar

et enfait dans ton code tu fais un truc comme ça:


$somvar = "lol"
$somevar = "namaisohSerieux?"
...
break $somevar
`` 
LaurentDardenne commented 4 years ago

Autre cas qui déclenche l'exception :

Find-FLowChartNodes
#Find-FLowChartNodes : La référence d'objet n'est pas définie à une instance d'un objet.
LxLeChat commented 4 years ago

ah ouais rigolo ... hum faut que je regarde comment résoudre ça ... !

edit: c'est fixé

PS > Find-FLowChartNodes
Find-FLowChartNodes: Parameter set cannot be resolved using the specified named parameters. One or more parameters issued cannot be used 
together or an insufficient number of parameters were provided.
LaurentDardenne commented 4 years ago

Les constructions suivantes déclenchent l'exception sur New-FLowChartGraph :

New-CodeUseCase 'Switch -File' {
    $IsXml=$False
    #$FileName=(get-process -pid $pid).Path #test de syntaxe
    switch -file $FileName
    {
        #Début de la section XML 
       "<?xml version=`"1.0`" encoding=`"ibm850`"?>"  {$IsXml=$True;$_;continue}
        #Fin de la section XML 
       "</response>"                                  {$IsXml=$False;$_;break}

       default {if ($IsXml)
                  #On traite les lignes si on se trouve dans la section XML 
                 {$_}
               }
    }
}

New-CodeUseCase 'Switch Array' {
    switch (1,4,-1,3,"Hello",2,1)
    {
        {$_ -lt 0} { Continue }
        {$_ -isnot [Int32]} { Break }
        {$_ % 2} {
            "$_ is Odd"
        }
        {-not ($_ % 2)} {
            "$_ is Even"
        }
    }
}
LxLeChat commented 4 years ago

ah c le continue ... ça marche dans un switch ?? ça fait kewa ? ah ok ça passe a la prochaine iteration ...

LaurentDardenne commented 4 years ago

ah c le continue ... ça marche dans un switch ?? ça fait kewa ?

Cela dépend de la construction, dans un boucle on passe à l'itération suivante, ici comme on a un tableau en entrée d'un switch on passe à la valeur suivante ( ici le comportement est identique à celui dans une boucle) :

switch (1,4,-1,3,"Hello",2,1)
{
    {$_ -lt 0} { write-warning "continue : $_"; Continue }
    {$_ -isnot [Int32]} { write-warning "break : $_ ";Break }
    {$_ % 2} {
        write-warning "suite : $_ ";"$_ is Odd"
    }
    {-not ($_ % 2)} {
        write-warning "suite : $_ ";"$_ is Even"
    }
}

Mais l'exemple de code Switch -File n'est pas courante on filtre dans une boucle car switch -file lit tout le fichier $filename:


 function ParseXml([String] $FileName)
  { #Récupération des lignes de la déclaration XML issu de MsdnMan
    #L'extraction XML contient quelques lignes parasites.
    $IsXml=$False
    switch  -file $FileName
    {
        #Début de la section XML 
       "<?xml version=`"1.0`" encoding=`"ibm850`"?>"  {$IsXml=$True;$_;continue}
        #Fin de la section XML 
       "</response>"                                  {$IsXml=$False;$_;break}

       default {if ($IsXml)
                  #On traite les lignes si on se trouve dans la section XML 
                 {$_}
               }
    }
  }
LxLeChat commented 4 years ago

ok good ! image

Du coup j'ai aussi corriger un petit truc, je viens de découvrire que les flags sont des énums, du coup quand c'eétait un switch "classique", cela affichait switch none

LaurentDardenne commented 3 years ago

Il semble qu'il y ait une régression sur le foreach :

[-] FlowChartCode .When there is no violation.Foreach enhanced. 4ms (3ms|0ms)
 Expected no exception to be thrown, but an exception "Object reference not set to an instance of an object." was thrown
LxLeChat commented 3 years ago

étrange! j'ai rouler les tests hier soir et tout fonctionnait ... ! je check ça !

j'ai testé "manuellemen" en copiant le scriptblock du foreach enahanced,

$a = {
    [CmdletBinding()]
    [OutputType('FunctionPosition')]
    param(
      [Parameter(Position = 0, Mandatory,
        ValueFromPipeline, ValueFromPipelineByPropertyName)]
      [ValidateNotNullOrEmpty()]
      [Alias('PSPath')]
      [System.String[]]
      $Path
    )

    process {
      try {
        $filesToProcess = if ($_ -is [System.IO.FileSystemInfo]) {
          Write-Verbose "From pipeline"
          $_
        } else {
          Write-Verbose "From parameter, $Path"
          Get-Item -Path $Path
        }
        $parser = [System.Management.Automation.Language.Parser]
        Write-Verbose "lets start the foreach loop on `$filesToProcess with $($filesToProcess.count) as count"
        foreach ($item in $filesToProcess) {
          Write-Verbose "$item"
          if ($item.PSIsContainer -or
              $item.Extension -notin @('.ps1', '.psm1')) {
            continue
          }
          $tokens = $errors = $null
          $parser::ParseFile($item.FullName, ([REF]$tokens),
            ([REF]$errors)) | Out-Null
          if ($errors) {
            $msg = "File '{0}' has {1} parser errors." -f $item.FullName,
              $errors.Count
            Write-Warning $msg
          }
          :tokenLoop foreach ($token in $tokens) {
            if ($token.Kind -ne 'Function') {
              continue
            }
            $position = $token.Extent.StartLineNumber
            do {
              if (-not $foreach.MoveNext()) {
                break tokenLoop
              }
              $token = $foreach.Current
            } until ($token.Kind -in @('Generic', 'Identifier'))
            $functionPosition = [pscustomobject]@{
              Name       = $token.Text
              LineNumber = $position
              Path       = $item.FullName
            }
            Add-Member -InputObject $functionPosition `
              -TypeName FunctionPosition -PassThru
          }
        }
      }
      catch {
        throw
      }
    }
}

Find-FlowChartNodes -ScriptBlock $a

Et je n'ai pas d'exception ... ! whyyyyy ???

LaurentDardenne commented 3 years ago

Et je n'ai pas d'exception ... ! whyyyyy ???

La dernière fois, cette situation était due à une initialisation qui n'était pas faite. Une régression dans les sources :-/ ?

LxLeChat commented 3 years ago

Ok j'ai trouvé je vais corrigé... ! [edit] il ne s'agissait pas d'une regression ... juste que je ne savais pas que throw sans rien ça existait ... du coup j'essayai de setter ne propriété pipeline sur le noeud throw, alors que bah dans l'AST c'était completement vide... c'est corrigé, pusher en dev, et soon sur master

LaurentDardenne commented 3 years ago

Probléme à priori avec la présence du return dans ces constructions :

$sb={if (! $data) { return }}

$sb={
Function Lock-File{
#Verrouille un fichier à des fins de tests
  param([string] $Path)

  New-Object System.IO.FileStream($Path,
                                  [System.IO.FileMode]::Open,
                                  [System.IO.FileAccess]::ReadWrite,
                                  [System.IO.FileShare]::None)
} #Lock-File

return

&{
 try {
    $Filename="C:\Temp\t1.txt"
    $TestLockFile= Lock-File $FileName
    Test-IncludeFile $PsionicIncludeFiles
  } finally {
   $TestLockFile.Close()
  }
}
}

Même exception que pour le poste d'origine.

LxLeChat commented 3 years ago

ok c fixé !) j'ai du virer la branche dev .. je m y retrouvais plus et j avais trop de conflits xD si j'ai le time demain ... et normalement j'ai le temps vu que j'attends que des gens veuillent bien se mettre à travailler ... BREF .. je vais regarder les recommandations que tu as faits sur le renommage des cmlets ! Merci @LaurentDardenne en tout cas :)

LaurentDardenne commented 3 years ago

ok c fixé !)

Merci. J'avais testé sur 7000 fichiers, je vérifierais de nouveau.

LxLeChat commented 3 years ago

C est dans la branche feature-dev pour l instant! Si tu as besoin je merge dans master

7000 fichier!!!! Et alors il n y avait pas trop d erreur??

LaurentDardenne commented 3 years ago

7000 fichiers!!!! Et alors il n y avait pas trop d erreur??

Avec PS v7.1 non, sauf celles du return et bcp d'erreur de syntaxe dans les fichiers. Pour les constructions de base c'est rassurant.

LaurentDardenne commented 3 years ago

Tu peux clore je pense.