@@ -23,43 +23,90 @@ namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules
2323 /// AvoidUsingWriteHost: Check that Write-Host or Console.Write are not used
2424 /// </summary>
2525 [ Export ( typeof ( IScriptRule ) ) ]
26- public class AvoidUsingWriteHost : IScriptRule
26+ public class AvoidUsingWriteHost : AstVisitor , IScriptRule
2727 {
28+ List < DiagnosticRecord > records ;
29+ string fileName ;
30+
2831 /// <summary>
2932 /// AnalyzeScript: check that Write-Host or Console.Write are not used.
3033 /// </summary>
3134 public IEnumerable < DiagnosticRecord > AnalyzeScript ( Ast ast , string fileName )
3235 {
3336 if ( ast == null ) throw new ArgumentNullException ( Strings . NullAstErrorMessage ) ;
3437
35- // Finds all CommandAsts.
36- IEnumerable < Ast > commandAsts = ast . FindAll ( testAst => testAst is CommandAst , true ) ;
38+ records = new List < DiagnosticRecord > ( ) ;
39+ this . fileName = fileName ;
40+
41+ ast . Visit ( this ) ;
42+
43+ return records ;
44+ }
45+
46+
47+ /// <summary>
48+ /// Visit function and skips any function that starts with show
49+ /// </summary>
50+ /// <param name="funcAst"></param>
51+ /// <returns></returns>
52+ public override AstVisitAction VisitFunctionDefinition ( FunctionDefinitionAst funcAst )
53+ {
54+ if ( funcAst == null || funcAst . Name == null )
55+ {
56+ return AstVisitAction . SkipChildren ;
57+ }
58+
59+ if ( funcAst . Name . StartsWith ( "show" , StringComparison . OrdinalIgnoreCase ) )
60+ {
61+ return AstVisitAction . SkipChildren ;
62+ }
63+
64+ return AstVisitAction . Continue ;
65+ }
66+
67+ /// <summary>
68+ /// Checks that write-host command is not used
69+ /// </summary>
70+ /// <param name="cmdAst"></param>
71+ /// <returns></returns>
72+ public override AstVisitAction VisitCommand ( CommandAst cmdAst )
73+ {
74+ if ( cmdAst == null )
75+ {
76+ return AstVisitAction . SkipChildren ;
77+ }
3778
38- // Iterrates all CommandAsts and check the command name.
39- foreach ( CommandAst cmdAst in commandAsts )
79+ if ( cmdAst . GetCommandName ( ) != null && String . Equals ( cmdAst . GetCommandName ( ) , "write-host" , StringComparison . OrdinalIgnoreCase ) )
4080 {
41- if ( cmdAst . GetCommandName ( ) != null && String . Equals ( cmdAst . GetCommandName ( ) , "write-host" , StringComparison . OrdinalIgnoreCase ) )
42- {
43- yield return new DiagnosticRecord ( String . Format ( CultureInfo . CurrentCulture , Strings . AvoidUsingWriteHostError , System . IO . Path . GetFileName ( fileName ) ) ,
44- cmdAst . Extent , GetName ( ) , DiagnosticSeverity . Warning , fileName ) ;
45- }
81+ records . Add ( new DiagnosticRecord ( String . Format ( CultureInfo . CurrentCulture , Strings . AvoidUsingWriteHostError , System . IO . Path . GetFileName ( fileName ) ) ,
82+ cmdAst . Extent , GetName ( ) , DiagnosticSeverity . Warning , fileName ) ) ;
4683 }
4784
48- // Finds all InvokeMemberExpressionAst
49- IEnumerable < Ast > invokeAsts = ast . FindAll ( testAst => testAst is InvokeMemberExpressionAst , true ) ;
85+ return AstVisitAction . Continue ;
86+ }
5087
51- foreach ( InvokeMemberExpressionAst invokeAst in invokeAsts )
88+ public override AstVisitAction VisitInvokeMemberExpression ( InvokeMemberExpressionAst imeAst )
89+ {
90+ if ( imeAst == null )
5291 {
53- TypeExpressionAst typeAst = invokeAst . Expression as TypeExpressionAst ;
54- if ( typeAst == null || typeAst . TypeName == null || typeAst . TypeName . FullName == null ) continue ;
55-
56- if ( typeAst . TypeName . FullName . EndsWith ( "console" , StringComparison . OrdinalIgnoreCase )
57- && ! String . IsNullOrWhiteSpace ( invokeAst . Member . Extent . Text ) && invokeAst . Member . Extent . Text . StartsWith ( "Write" , StringComparison . OrdinalIgnoreCase ) )
58- {
59- yield return new DiagnosticRecord ( String . Format ( CultureInfo . CurrentCulture , Strings . AvoidUsingConsoleWriteError , System . IO . Path . GetFileName ( fileName ) , invokeAst . Member . Extent . Text ) ,
60- invokeAst . Extent , GetName ( ) , DiagnosticSeverity . Warning , fileName ) ;
61- }
92+ return AstVisitAction . SkipChildren ;
6293 }
94+
95+ TypeExpressionAst typeAst = imeAst . Expression as TypeExpressionAst ;
96+
97+ if ( typeAst == null || typeAst . TypeName == null || typeAst . TypeName . FullName == null )
98+ {
99+ return AstVisitAction . SkipChildren ;
100+ }
101+
102+ if ( typeAst . TypeName . FullName . EndsWith ( "console" , StringComparison . OrdinalIgnoreCase )
103+ && ! String . IsNullOrWhiteSpace ( imeAst . Member . Extent . Text ) && imeAst . Member . Extent . Text . StartsWith ( "Write" , StringComparison . OrdinalIgnoreCase ) )
104+ {
105+ records . Add ( new DiagnosticRecord ( String . Format ( CultureInfo . CurrentCulture , Strings . AvoidUsingConsoleWriteError , System . IO . Path . GetFileName ( fileName ) , imeAst . Member . Extent . Text ) ,
106+ imeAst . Extent , GetName ( ) , DiagnosticSeverity . Warning , fileName ) ) ;
107+ }
108+
109+ return AstVisitAction . Continue ;
63110 }
64111
65112 /// <summary>
0 commit comments