Skip to content

Commit 144acf2

Browse files
David ReynoldsDavid Reynolds
authored andcommitted
Split AvoidGlobalFuncations to AvoidGlobalFuncations and AvoidGlobalAliases
1 parent 88d9dc5 commit 144acf2

14 files changed

+328
-171
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#AvoidGlobalAliases
2+
**Severity Level: Warning**
3+
4+
##Description
5+
Globally scoped aliases override existing aliases within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules and scripts.
6+
7+
8+
To understand more about scoping, see ```Get-Help about_Scopes```.
9+
10+
##How to Fix
11+
Use other scope modifiers for new aliases.
12+
13+
##Example
14+
###Wrong:
15+
``` PowerShell
16+
nal -Name Name -Value Value -Scope "Global"
17+
```
18+
19+
###Correct:
20+
``` PowerShell
21+
New-Alias -Name Name1 -Value Value
22+
```

RuleDocumentation/AvoidGlobalFunctions.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,21 @@
22
**Severity Level: Warning**
33

44
##Description
5-
Globally scoped functions and alias override existing functions and aliases within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules and scripts.
5+
Globally scoped functions override existing functions within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules.
66

77

88
To understand more about scoping, see ```Get-Help about_Scopes```.
99

1010
##How to Fix
11-
Use other scope modifiers for functions and aliases.
11+
Use other scope modifiers for functions.
1212

1313
##Example
1414
###Wrong:
1515
``` PowerShell
16-
function global:functionName {}
17-
18-
New-Alias -Name CommandName -Value NewCommandAlias -scope:global
16+
function global:functionName {}
1917
```
2018

2119
###Correct:
2220
``` PowerShell
2321
function functionName {}
24-
25-
New-Alias -Name CommandName -Value NewCommandAlias
2622
```

Rules/AvoidGlobalAliases.cs

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
2+
using System;
3+
using System.Collections.Generic;
4+
#if !CORECLR
5+
using System.ComponentModel.Composition;
6+
#endif
7+
using System.Globalization;
8+
using System.Management.Automation.Language;
9+
10+
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
11+
{
12+
#if !CORECLR
13+
[Export(typeof(IScriptRule))]
14+
#endif
15+
class AvoidGlobalAliases : AstVisitor, IScriptRule
16+
{
17+
private List<DiagnosticRecord> records;
18+
private string fileName;
19+
20+
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
21+
{
22+
if (ast == null)
23+
{
24+
throw new ArgumentNullException(Strings.NullAstErrorMessage);
25+
}
26+
27+
records = new List<DiagnosticRecord>();
28+
this.fileName = fileName;
29+
30+
ast.Visit(this);
31+
32+
return records;
33+
}
34+
35+
#region VisitCommand functions
36+
public override AstVisitAction VisitCommand(CommandAst commandAst)
37+
{
38+
if (!IsNewAliasCmdlet(commandAst))
39+
{
40+
return AstVisitAction.SkipChildren;
41+
}
42+
43+
return AstVisitAction.Continue;
44+
}
45+
46+
public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst)
47+
{
48+
if (IsScopeParameterForNewAliasCmdlet(commandParameterAst))
49+
{
50+
if ((commandParameterAst.Argument != null) // if the cmdlet looks like -Scope:Global check Parameter.Argument
51+
&& (commandParameterAst.Argument.ToString().Equals("Global", StringComparison.OrdinalIgnoreCase)))
52+
{
53+
records.Add(new DiagnosticRecord(
54+
string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesError),
55+
commandParameterAst.Extent,
56+
GetName(),
57+
DiagnosticSeverity.Warning,
58+
fileName,
59+
commandParameterAst.ParameterName));
60+
}
61+
else
62+
{
63+
var nextAst = FindNextAst(commandParameterAst);
64+
65+
if ((nextAst is StringConstantExpressionAst) // if the cmdlet looks like -Scope Global
66+
&& (((StringConstantExpressionAst)nextAst).Value.ToString().Equals("Global", StringComparison.OrdinalIgnoreCase)))
67+
{
68+
records.Add(new DiagnosticRecord(
69+
string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesError),
70+
((StringConstantExpressionAst)nextAst).Extent,
71+
GetName(),
72+
DiagnosticSeverity.Warning,
73+
fileName,
74+
((StringConstantExpressionAst)nextAst).Value));
75+
}
76+
}
77+
}
78+
79+
return AstVisitAction.SkipChildren;
80+
}
81+
#endregion
82+
83+
private Ast FindNextAst(Ast ast)
84+
{
85+
IEnumerable<Ast> matchingLevelAsts = ast.Parent.FindAll(item => item is Ast, true);
86+
87+
Ast currentClosest = null;
88+
foreach (var matchingLevelAst in matchingLevelAsts)
89+
{
90+
if (currentClosest == null)
91+
{
92+
if (IsAstAfter(ast, matchingLevelAst))
93+
{
94+
currentClosest = matchingLevelAst;
95+
}
96+
}
97+
else
98+
{
99+
if ((IsAstAfter(ast, matchingLevelAst)) && (IsAstAfter(matchingLevelAst, currentClosest)))
100+
{
101+
currentClosest = matchingLevelAst;
102+
}
103+
}
104+
}
105+
106+
return currentClosest;
107+
}
108+
109+
private bool IsAstAfter(Ast ast1, Ast ast2)
110+
{
111+
if (ast1.Extent.EndLineNumber > ast2.Extent.StartLineNumber) // ast1 ends on a line after ast2 starts
112+
{
113+
return false;
114+
}
115+
else if (ast1.Extent.EndLineNumber == ast2.Extent.StartLineNumber)
116+
{
117+
if (ast2.Extent.StartColumnNumber > ast1.Extent.EndColumnNumber)
118+
{
119+
return true;
120+
}
121+
else
122+
{
123+
return false;
124+
}
125+
}
126+
else // ast2 starts on a line after ast 1 ends
127+
{
128+
return true;
129+
}
130+
}
131+
132+
private bool IsScopeParameterForNewAliasCmdlet(CommandParameterAst commandParameterAst)
133+
{
134+
if (commandParameterAst == null || commandParameterAst.ParameterName == null)
135+
{
136+
return false;
137+
}
138+
139+
if (commandParameterAst.ParameterName.Equals("Scope", StringComparison.OrdinalIgnoreCase)
140+
&& (commandParameterAst.Parent is CommandAst)
141+
&& IsNewAliasCmdlet((CommandAst)commandParameterAst.Parent))
142+
{
143+
return true;
144+
}
145+
146+
return false;
147+
}
148+
149+
private bool IsNewAliasCmdlet(CommandAst commandAst)
150+
{
151+
if (commandAst == null || commandAst.GetCommandName() == null)
152+
{
153+
return false;
154+
}
155+
156+
var AliasList = Helper.Instance.CmdletNameAndAliases("New-Alias");
157+
if (AliasList.Contains(commandAst.GetCommandName()))
158+
{
159+
return true;
160+
}
161+
162+
return false;
163+
}
164+
165+
public string GetCommonName()
166+
{
167+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesCommonName);
168+
}
169+
170+
public string GetDescription()
171+
{
172+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesDescription);
173+
}
174+
175+
public string GetName()
176+
{
177+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesName);
178+
}
179+
180+
public RuleSeverity GetSeverity()
181+
{
182+
return RuleSeverity.Warning;
183+
}
184+
185+
public string GetSourceName()
186+
{
187+
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
188+
}
189+
190+
public SourceType GetSourceType()
191+
{
192+
return SourceType.Builtin;
193+
}
194+
}
195+
}

0 commit comments

Comments
 (0)