1616using System . Globalization ;
1717using System . Linq ;
1818using System . Management . Automation . Language ;
19+ using System . Text ;
1920using Microsoft . Windows . PowerShell . ScriptAnalyzer . Generic ;
21+ using System . Reflection ;
2022
2123namespace Microsoft . Windows . PowerShell . ScriptAnalyzer . BuiltinRules
2224{
@@ -28,6 +30,42 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
2830#endif
2931 class PlaceOpenBrace : IScriptRule
3032 {
33+ private class RuleArguments
34+ {
35+ public bool OnSameLine { get ; set ; } = true ;
36+
37+ public static RuleArguments Create ( Dictionary < string , object > arguments )
38+ {
39+ try
40+ {
41+ var ruleArguments = new RuleArguments ( ) ;
42+ var properties = ruleArguments . GetType ( ) . GetProperties ( ) ;
43+ foreach ( var property in properties )
44+ {
45+ if ( arguments . ContainsKey ( property . Name ) )
46+ {
47+ var type = property . PropertyType ;
48+ var obj = arguments [ property . Name ] ;
49+ property . SetValue ( ruleArguments , System . Convert . ChangeType ( obj , Type . GetTypeCode ( type ) ) ) ;
50+ }
51+ }
52+
53+ return ruleArguments ;
54+ }
55+ catch
56+ {
57+ return new RuleArguments ( ) ; // return arguments with defaults
58+ }
59+ }
60+ }
61+
62+ private RuleArguments ruleArgs ;
63+
64+ public PlaceOpenBrace ( )
65+ {
66+ ruleArgs = RuleArguments . Create ( Helper . Instance . GetRuleArguments ( this . GetName ( ) ) ) ;
67+ }
68+
3169 /// <summary>
3270 /// Analyzes the given ast to find the [violation]
3371 /// </summary>
@@ -46,26 +84,90 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
4684 // * on-new-line
4785 // * new-line-after
4886 // * no-empty-line-after
49- // * stick-a-space-before
5087
5188 var tokens = Helper . Instance . Tokens ;
52- for ( int k = 2 ; k < tokens . Length ; k ++ )
89+ if ( ruleArgs . OnSameLine )
90+ {
91+ for ( int k = 2 ; k < tokens . Length ; k ++ )
92+ {
93+ if ( tokens [ k ] . Kind == TokenKind . LCurly
94+ && tokens [ k - 1 ] . Kind == TokenKind . NewLine )
95+ {
96+ yield return new DiagnosticRecord (
97+ GetError ( ) ,
98+ tokens [ k ] . Extent ,
99+ GetName ( ) ,
100+ GetDiagnosticSeverity ( ) ,
101+ fileName ,
102+ null ,
103+ GetSuggestedCorrections ( tokens [ k - 2 ] , tokens [ k ] , fileName ) ) ;
104+ }
105+ }
106+ }
107+ else
53108 {
54- if ( tokens [ k ] . Kind == TokenKind . LCurly
55- && tokens [ k - 1 ] . Kind == TokenKind . NewLine )
109+ for ( int k = 1 ; k < tokens . Length ; k ++ )
56110 {
57- yield return new DiagnosticRecord (
58- GetError ( ) ,
59- tokens [ k ] . Extent ,
60- GetName ( ) ,
61- GetDiagnosticSeverity ( ) ,
62- fileName ,
63- null ,
64- GetSuggestedCorrections ( tokens [ k - 2 ] , tokens [ k ] , fileName ) ) ;
111+ if ( tokens [ k ] . Kind == TokenKind . LCurly
112+ && tokens [ k - 1 ] . Kind != TokenKind . NewLine )
113+ {
114+ yield return new DiagnosticRecord (
115+ GetError ( ) ,
116+ tokens [ k ] . Extent ,
117+ GetName ( ) ,
118+ GetDiagnosticSeverity ( ) ,
119+ fileName ,
120+ null ,
121+ GetSuggestedCorrectionsForNotOneSameLine ( tokens , k - 1 , k , fileName ) ) ;
122+ }
65123 }
66124 }
67125 }
68126
127+ private List < CorrectionExtent > GetSuggestedCorrectionsForNotOneSameLine (
128+ Token [ ] tokens ,
129+ int prevTokenPos ,
130+ int closeBraceTokenPos ,
131+ string fileName )
132+ {
133+ var corrections = new List < CorrectionExtent > ( ) ;
134+ var prevToken = tokens [ prevTokenPos ] ;
135+ var closeBraceToken = tokens [ closeBraceTokenPos ] ;
136+ corrections . Add (
137+ new CorrectionExtent (
138+ prevToken . Extent . StartLineNumber ,
139+ closeBraceToken . Extent . EndLineNumber ,
140+ prevToken . Extent . StartColumnNumber ,
141+ closeBraceToken . Extent . EndColumnNumber ,
142+ ( new StringBuilder ( ) )
143+ . Append ( prevToken . Text )
144+ . AppendLine ( )
145+ . Append ( GetIndentation ( tokens , closeBraceTokenPos ) )
146+ . Append ( closeBraceToken . Text )
147+ . ToString ( ) ,
148+ fileName ) ) ;
149+ return corrections ;
150+ }
151+
152+ private string GetIndentation ( Token [ ] tokens , int refTokenPos )
153+ {
154+ return new String ( ' ' , GetStartColumnNumberOfTokenLine ( tokens , refTokenPos ) - 1 ) ;
155+ }
156+
157+ private int GetStartColumnNumberOfTokenLine ( Token [ ] tokens , int refTokenPos )
158+ {
159+ var refToken = tokens [ refTokenPos ] ;
160+ for ( int k = refTokenPos - 1 ; k >= 0 ; k -- )
161+ {
162+ if ( tokens [ k ] . Extent . StartLineNumber != refToken . Extent . StartLineNumber )
163+ {
164+ return tokens [ k ] . Extent . StartColumnNumber ;
165+ }
166+ }
167+
168+ return refToken . Extent . StartColumnNumber ;
169+ }
170+
69171 private List < CorrectionExtent > GetSuggestedCorrections ( Token precedingExpression , Token lCurly , string fileName )
70172 {
71173 var corrections = new List < CorrectionExtent > ( ) ;
0 commit comments