@@ -28,14 +28,25 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
2828#endif
2929 class AlignAssignmentStatement : ConfigurableRule
3030 {
31+ // We keep this switch even though the rule has only one switch (this) as of now, because we want
32+ // to let the rule be expandable in the future to allow formatting assignments even
33+ // in variable assignments. But for now we will stick to only one option.
34+ /// <summary>
35+ /// Check if key value pairs in a hashtable are aligned or not.
36+ /// </summary>
37+ /// <returns></returns>
38+ [ ConfigurableRuleProperty ( defaultValue : true ) ]
39+ public bool CheckHashtable { get ; set ; }
40+
3141 private readonly char whitespaceChar = ' ' ;
3242
3343 private List < Func < TokenOperations , IEnumerable < DiagnosticRecord > > > violationFinders
3444 = new List < Func < TokenOperations , IEnumerable < DiagnosticRecord > > > ( ) ;
3545
36- [ ConfigurableRuleProperty ( defaultValue : true ) ]
37- public bool CheckHashtable { get ; set ; }
38-
46+ /// <summary>
47+ /// Sets the configurable properties of this rule.
48+ /// </summary>
49+ /// <param name="paramValueMap">A dictionary that maps parameter name to it value. Must be non-null</param>
3950 public override void ConfigureRule ( IDictionary < string , object > paramValueMap )
4051 {
4152 base . ConfigureRule ( paramValueMap ) ;
@@ -45,6 +56,92 @@ public override void ConfigureRule(IDictionary<string, object> paramValueMap)
4556 }
4657 }
4758
59+
60+ /// <summary>
61+ /// Analyzes the given ast to find if consecutive assignment statements are aligned.
62+ /// </summary>
63+ /// <param name="ast">AST to be analyzed. This should be non-null</param>
64+ /// <param name="fileName">Name of file that corresponds to the input AST.</param>
65+ /// <returns>A an enumerable type containing the violations</returns>
66+ public override IEnumerable < DiagnosticRecord > AnalyzeScript ( Ast ast , string fileName )
67+ {
68+ if ( ast == null )
69+ {
70+ throw new ArgumentNullException ( "ast" ) ;
71+ }
72+ // only handles one line assignments
73+ // if the rule encounters assignment statements that are multi-line, the rule will ignore that block
74+
75+ var tokenOps = new TokenOperations ( Helper . Instance . Tokens , ast ) ;
76+ foreach ( var violationFinder in violationFinders )
77+ {
78+ foreach ( var diagnosticRecord in violationFinder ( tokenOps ) )
79+ {
80+ yield return diagnosticRecord ;
81+ }
82+ }
83+ }
84+
85+ /// <summary>
86+ /// Retrieves the common name of this rule.
87+ /// </summary>
88+ public override string GetCommonName ( )
89+ {
90+ return string . Format ( CultureInfo . CurrentCulture , Strings . AlignAssignmentStatementCommonName ) ;
91+ }
92+
93+ /// <summary>
94+ /// Retrieves the description of this rule.
95+ /// </summary>
96+ public override string GetDescription ( )
97+ {
98+ return string . Format ( CultureInfo . CurrentCulture , Strings . AlignAssignmentStatementDescription ) ;
99+ }
100+
101+ /// <summary>
102+ /// Retrieves the name of this rule.
103+ /// </summary>
104+ public override string GetName ( )
105+ {
106+ return string . Format (
107+ CultureInfo . CurrentCulture ,
108+ Strings . NameSpaceFormat ,
109+ GetSourceName ( ) ,
110+ Strings . AlignAssignmentStatementName ) ;
111+ }
112+
113+ /// <summary>
114+ /// Retrieves the severity of the rule: error, warning or information.
115+ /// </summary>
116+ public override RuleSeverity GetSeverity ( )
117+ {
118+ return RuleSeverity . Warning ;
119+ }
120+
121+ /// <summary>
122+ /// Gets the severity of the returned diagnostic record: error, warning, or information.
123+ /// </summary>
124+ /// <returns></returns>
125+ public DiagnosticSeverity GetDiagnosticSeverity ( )
126+ {
127+ return DiagnosticSeverity . Warning ;
128+ }
129+
130+ /// <summary>
131+ /// Retrieves the name of the module/assembly the rule is from.
132+ /// </summary>
133+ public override string GetSourceName ( )
134+ {
135+ return string . Format ( CultureInfo . CurrentCulture , Strings . SourceName ) ;
136+ }
137+
138+ /// <summary>
139+ /// Retrieves the type of the rule, Builtin, Managed or Module.
140+ /// </summary>
141+ public override SourceType GetSourceType ( )
142+ {
143+ return SourceType . Builtin ;
144+ }
48145 private IEnumerable < DiagnosticRecord > FindHashtableViolations ( TokenOperations tokenOps )
49146 {
50147 var hashtableAsts = tokenOps . Ast . FindAll ( ast => ast is HashtableAst , true ) ;
@@ -54,19 +151,17 @@ private IEnumerable<DiagnosticRecord> FindHashtableViolations(TokenOperations to
54151 }
55152
56153 // it is probably much easier have a hashtable writer that formats the hashtable and writes it
57- // but it my make handling comments hard. So we need to use this approach.
154+ // but it makes handling comments hard. So we need to use this approach.
58155
59- // check if each key is on a separate line
60- // align only if each key=val pair is on a separate line
61- // if each pair on a separate line
156+ // This is how the algorithm actually works:
157+ // if each key value pair are on a separate line
62158 // find all the assignment operators
63159 // if all the assignment operators are aligned (check the column number of each alignment operator)
64160 // skip
65161 // else
66- // find the distance between the assignment operaters its left expression
162+ // find the distance between the assignment operators and their corresponding LHS
67163 // find the longest left expression
68164 // make sure all the assignment operators are in the same column as that of the longest left hand.
69- // else
70165
71166 var alignments = new List < int > ( ) ;
72167 foreach ( var astItem in hashtableAsts )
@@ -173,91 +268,5 @@ private bool HasKeysOnSeparateLines(HashtableAst hashtableAst)
173268
174269 return true ;
175270 }
176-
177- /// <summary>
178- /// Analyzes the given ast to find if consecutive assignment statements are aligned.
179- /// </summary>
180- /// <param name="ast">AST to be analyzed. This should be non-null</param>
181- /// <param name="fileName">Name of file that corresponds to the input AST.</param>
182- /// <returns>A an enumerable type containing the violations</returns>
183- public override IEnumerable < DiagnosticRecord > AnalyzeScript ( Ast ast , string fileName )
184- {
185- if ( ast == null )
186- {
187- throw new ArgumentNullException ( "ast" ) ;
188- }
189- // only handles one line assignments
190- // if the rule encounters assignment statements that are multi-line, the rule will ignore that block
191-
192- var tokenOps = new TokenOperations ( Helper . Instance . Tokens , ast ) ;
193- foreach ( var violationFinder in violationFinders )
194- {
195- foreach ( var diagnosticRecord in violationFinder ( tokenOps ) )
196- {
197- yield return diagnosticRecord ;
198- }
199- }
200- }
201-
202- /// <summary>
203- /// Retrieves the common name of this rule.
204- /// </summary>
205- public override string GetCommonName ( )
206- {
207- return string . Format ( CultureInfo . CurrentCulture , Strings . AlignAssignmentStatementCommonName ) ;
208- }
209-
210- /// <summary>
211- /// Retrieves the description of this rule.
212- /// </summary>
213- public override string GetDescription ( )
214- {
215- return string . Format ( CultureInfo . CurrentCulture , Strings . AlignAssignmentStatementDescription ) ;
216- }
217-
218- /// <summary>
219- /// Retrieves the name of this rule.
220- /// </summary>
221- public override string GetName ( )
222- {
223- return string . Format (
224- CultureInfo . CurrentCulture ,
225- Strings . NameSpaceFormat ,
226- GetSourceName ( ) ,
227- Strings . AlignAssignmentStatementName ) ;
228- }
229-
230- /// <summary>
231- /// Retrieves the severity of the rule: error, warning or information.
232- /// </summary>
233- public override RuleSeverity GetSeverity ( )
234- {
235- return RuleSeverity . Warning ;
236- }
237-
238- /// <summary>
239- /// Gets the severity of the returned diagnostic record: error, warning, or information.
240- /// </summary>
241- /// <returns></returns>
242- public DiagnosticSeverity GetDiagnosticSeverity ( )
243- {
244- return DiagnosticSeverity . Warning ;
245- }
246-
247- /// <summary>
248- /// Retrieves the name of the module/assembly the rule is from.
249- /// </summary>
250- public override string GetSourceName ( )
251- {
252- return string . Format ( CultureInfo . CurrentCulture , Strings . SourceName ) ;
253- }
254-
255- /// <summary>
256- /// Retrieves the type of the rule, Builtin, Managed or Module.
257- /// </summary>
258- public override SourceType GetSourceType ( )
259- {
260- return SourceType . Builtin ;
261- }
262271 }
263272}
0 commit comments