Skip to content

Commit 1a61035

Browse files
author
Kapil Borle
committed
Add logic to detect indentation violation
1 parent 0ed5eb1 commit 1a61035

2 files changed

Lines changed: 137 additions & 6 deletions

File tree

Rules/UseConsistentIndentation.cs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,20 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
2323
/// <summary>
2424
/// A class to walk an AST to check for [violation]
2525
/// </summary>
26-
#if !CORECLR
26+
#if !CORECLR
2727
[Export(typeof(IScriptRule))]
2828
#endif
2929
class UseConsistentIndentation : IScriptRule
3030
{
31+
private readonly int unitsPerIndentationLevel;
32+
33+
UseConsistentIndentation()
34+
{
35+
// TODO Add a parameter for indentation kind {Tab, Space}
36+
// TODO make this configurable
37+
unitsPerIndentationLevel = 4;
38+
}
39+
3140
/// <summary>
3241
/// Analyzes the given ast to find the [violation]
3342
/// </summary>
@@ -41,8 +50,103 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
4150
throw new ArgumentNullException("ast");
4251
}
4352

44-
// your code goes here
45-
yield return new DiagnosticRecord();
53+
var tokens = Helper.Instance.Tokens;
54+
var diagnosticRecords = new List<DiagnosticRecord>();
55+
var openBracePosStack = new Stack<int>();
56+
bool onNewLine = true;
57+
for (int k = 0; k < tokens.Length; k++)
58+
{
59+
var token = tokens[k];
60+
var curIndentationLevel = GetIndentationLevel(openBracePosStack);
61+
var curIndentation = GetIndentation(curIndentationLevel);
62+
switch (token.Kind)
63+
{
64+
case TokenKind.LCurly:
65+
AddViolation(token, curIndentationLevel, diagnosticRecords, ref onNewLine);
66+
openBracePosStack.Push(k);
67+
break;
68+
69+
case TokenKind.RCurly:
70+
if (openBracePosStack.Count > 0)
71+
{
72+
openBracePosStack.Pop();
73+
}
74+
AddViolation(token, GetIndentationLevel(openBracePosStack), diagnosticRecords, ref onNewLine);
75+
break;
76+
77+
case TokenKind.NewLine:
78+
onNewLine = true;
79+
break;
80+
81+
default:
82+
// we do not want to make a call for every token, hence
83+
// we add this redundant check
84+
if (onNewLine)
85+
{
86+
AddViolation(token, curIndentationLevel, diagnosticRecords, ref onNewLine);
87+
}
88+
break;
89+
}
90+
}
91+
92+
return diagnosticRecords;
93+
}
94+
95+
private void AddViolation(
96+
Token token,
97+
int curIndentationLevel,
98+
List<DiagnosticRecord> diagnosticRecords,
99+
ref bool onNewLine)
100+
{
101+
if (onNewLine)
102+
{
103+
onNewLine = false;
104+
if (token.Extent.StartColumnNumber - 1 != GetIndentation(curIndentationLevel))
105+
{
106+
var fileName = token.Extent.File;
107+
var extent = token.Extent;
108+
var violationExtent = extent = new ScriptExtent(
109+
new ScriptPosition(
110+
fileName,
111+
extent.StartLineNumber,
112+
1, // first column in the line
113+
extent.StartScriptPosition.Line),
114+
new ScriptPosition(
115+
fileName,
116+
extent.StartLineNumber,
117+
extent.StartColumnNumber,
118+
extent.StartScriptPosition.Line));
119+
diagnosticRecords.Add(
120+
new DiagnosticRecord(
121+
"not correct indenation", // TODO replace with localized string
122+
violationExtent,
123+
GetName(),
124+
GetDiagnosticSeverity(),
125+
fileName,
126+
null,
127+
null));
128+
}
129+
}
130+
}
131+
132+
private static int ClipNegative(int x)
133+
{
134+
return x > 0 ? x : 0;
135+
}
136+
137+
private int GetIndentationColumnNumber(int indentationLevel)
138+
{
139+
return GetIndentation(indentationLevel) + 1;
140+
}
141+
142+
private int GetIndentation(int indentationLevel)
143+
{
144+
return indentationLevel * this.unitsPerIndentationLevel;
145+
}
146+
147+
private int GetIndentationLevel(Stack<int> openBracePosStack)
148+
{
149+
return openBracePosStack.Count;
46150
}
47151

48152
/// <summary>
Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,36 @@
11
Import-Module PSScriptAnalyzer
2-
$ruleName = "UseConsistentIndentation"
2+
$ruleName = "PSUseConsistentIndentation"
33

44
Describe "UseConsistentIndentation" {
5-
Context "" {
6-
It "" {
5+
Context "When top level indentation is not consistent" {
6+
BeforeAll {
7+
$def = @'
8+
function foo ($param1)
9+
{
10+
11+
}
12+
'@
13+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -IncludeRule $ruleName
14+
}
15+
16+
It "Should detect a violation" {
17+
$violations.Count | Should Be 1
18+
}
19+
}
20+
21+
Context "When nested indenation of is not consistent" {
22+
BeforeAll {
23+
$def = @'
24+
function foo ($param1)
25+
{
26+
"abc"
27+
}
28+
'@
29+
$violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -IncludeRule $ruleName
30+
}
31+
32+
It "Should detect a violation" {
33+
$violations.Count | Should Be 1
734
}
835
}
936
}

0 commit comments

Comments
 (0)