@@ -26,13 +26,35 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
2626#if ! CORECLR
2727 [ Export ( typeof ( IScriptRule ) ) ]
2828#endif
29- class UseWhitespace : ConfigurableRule
29+ public class UseWhitespace : ConfigurableRule
3030 {
31+ private enum ErrorKind { Brace , Paren } ;
3132 private readonly int whiteSpaceSize = 1 ;
3233
34+ private List < Func < TokenOperations , IEnumerable < DiagnosticRecord > > > violationFinders
35+ = new List < Func < TokenOperations , IEnumerable < DiagnosticRecord > > > ( ) ;
36+
3337 [ ConfigurableRuleProperty ( defaultValue : true ) ]
3438 public bool CheckOpenBrace { get ; protected set ; }
3539
40+ [ ConfigurableRuleProperty ( defaultValue : true ) ]
41+ public bool CheckOpenParen { get ; protected set ; }
42+
43+
44+ public override void ConfigureRule ( IDictionary < string , object > paramValueMap )
45+ {
46+ base . ConfigureRule ( paramValueMap ) ;
47+ if ( CheckOpenBrace )
48+ {
49+ violationFinders . Add ( FindOpenBraceViolations ) ;
50+ }
51+
52+ if ( CheckOpenParen )
53+ {
54+ violationFinders . Add ( FindOpenParenViolations ) ;
55+ }
56+ }
57+
3658 /// <summary>
3759 /// Analyzes the given ast to find the [violation]
3860 /// </summary>
@@ -47,27 +69,78 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
4769 }
4870
4971 var tokenOperations = new TokenOperations ( Helper . Instance . Tokens , ast ) ;
72+ var diagnosticRecords = Enumerable . Empty < DiagnosticRecord > ( ) ;
73+ foreach ( var violationFinder in violationFinders )
74+ {
75+ diagnosticRecords = diagnosticRecords . Concat ( violationFinder ( tokenOperations ) ) ;
76+ }
77+
78+ return diagnosticRecords . ToArray ( ) ; // force evaluation here
79+ }
80+
81+ private string GetError ( ErrorKind kind )
82+ {
83+ switch ( kind )
84+ {
85+ case ErrorKind . Brace :
86+ return string . Format ( CultureInfo . CurrentCulture , Strings . UseWhitespaceErrorBeforeBrace ) ;
87+ default :
88+ return string . Format ( CultureInfo . CurrentCulture , Strings . UseWhitespaceErrorBeforeParen ) ;
89+ }
90+ }
5091
92+ private IEnumerable < DiagnosticRecord > FindOpenBraceViolations ( TokenOperations tokenOperations )
93+ {
5194 var tokensAndWhitespaces = tokenOperations . GetOpenBracesWithWhiteSpacesBefore ( ) ;
5295 foreach ( var item in tokensAndWhitespaces )
5396 {
5497 if ( item . Item2 != whiteSpaceSize )
5598 {
5699 yield return new DiagnosticRecord (
57- GetError ( ) ,
100+ GetError ( ErrorKind . Brace ) ,
58101 item . Item1 . Extent ,
59102 GetName ( ) ,
60103 GetDiagnosticSeverity ( ) ,
61- fileName ,
104+ tokenOperations . Ast . Extent . File ,
105+ null ,
106+ null ) ;
107+ }
108+ }
109+ }
110+
111+ private IEnumerable < DiagnosticRecord > FindOpenParenViolations ( TokenOperations tokenOperations )
112+ {
113+ foreach ( var lparen in tokenOperations . GetTokenNodes ( TokenKind . LParen ) )
114+ {
115+ if ( lparen . Previous == null
116+ || ! IsPreviousTokenOnSameLine ( lparen )
117+ || lparen . Previous . Value . Kind == TokenKind . LParen // if nested paren
118+ || lparen . Previous . Value . Kind == TokenKind . Param // if param block
119+ || ( lparen . Previous . Previous != null
120+ && lparen . Previous . Previous . Value . Kind == TokenKind . Function ) ) //if function block
121+
122+ {
123+ continue ;
124+ }
125+
126+ if ( whiteSpaceSize !=
127+ lparen . Value . Extent . StartColumnNumber - lparen . Previous . Value . Extent . EndColumnNumber )
128+ {
129+ yield return new DiagnosticRecord (
130+ GetError ( ErrorKind . Paren ) ,
131+ lparen . Value . Extent ,
132+ GetName ( ) ,
133+ GetDiagnosticSeverity ( ) ,
134+ tokenOperations . Ast . Extent . File ,
62135 null ,
63136 null ) ;
64137 }
65138 }
66139 }
67140
68- private string GetError ( )
141+ private bool IsPreviousTokenOnSameLine ( LinkedListNode < Token > lparen )
69142 {
70- return string . Format ( CultureInfo . CurrentCulture , Strings . UseWhitespaceError ) ;
143+ return lparen . Previous . Value . Extent . StartLineNumber == lparen . Value . Extent . EndLineNumber ;
71144 }
72145
73146 /// <summary>
0 commit comments