Skip to content

Commit 5a6c740

Browse files
author
Kapil Borle
authored
Merge pull request #624 from dcrreynolds/AvoidGlobalFunctions
Added new rule AvoidGlobalFunctions
2 parents 77a5690 + a5101d0 commit 5a6c740

14 files changed

+468
-4
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+
New-Alias -Name Name -Value Value -Scope "Global"
17+
```
18+
19+
###Correct:
20+
``` PowerShell
21+
New-Alias -Name Name1 -Value Value
22+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#AvoidGlobalFunctions
2+
**Severity Level: Warning**
3+
4+
##Description
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.
6+
7+
8+
To understand more about scoping, see ```Get-Help about_Scopes```.
9+
10+
##How to Fix
11+
Use other scope modifiers for functions.
12+
13+
##Example
14+
###Wrong:
15+
``` PowerShell
16+
function global:functionName {}
17+
```
18+
19+
###Correct:
20+
``` PowerShell
21+
function functionName {}
22+
```

Rules/AvoidGlobalAliases.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
using System;
2+
using System.Collections.Generic;
3+
#if !CORECLR
4+
using System.ComponentModel.Composition;
5+
#endif
6+
using System.Globalization;
7+
using System.Management.Automation.Language;
8+
using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
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+
/// <summary>
21+
/// Analyzes the ast to check that global aliases are not used.
22+
/// </summary>
23+
/// <param name="ast">The script's ast</param>
24+
/// <param name="fileName">The script's file name</param>
25+
/// <returns>A List of diagnostic results of this rule</returns>
26+
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
27+
{
28+
if (ast == null)
29+
{
30+
throw new ArgumentNullException(Strings.NullAstErrorMessage);
31+
}
32+
33+
records = new List<DiagnosticRecord>();
34+
this.fileName = fileName;
35+
36+
if (IsScriptModule())
37+
{
38+
ast.Visit(this);
39+
}
40+
41+
return records;
42+
}
43+
44+
#region VisitCommand functions
45+
/// <summary>
46+
/// Analyzes a CommandAst, if it is a New-Alias command, the AST is further analyzed.
47+
/// </summary>
48+
/// <param name="commandAst">The CommandAst to be analyzed</param>
49+
/// <returns>AstVisitAction to continue to analyze the ast's children</returns>
50+
public override AstVisitAction VisitCommand(CommandAst commandAst)
51+
{
52+
if (IsNewAliasCmdlet(commandAst))
53+
{
54+
// check the parameters of the New-Alias cmdlet for scope
55+
var parameterBindings = StaticParameterBinder.BindCommand(commandAst);
56+
57+
if (parameterBindings.BoundParameters.ContainsKey("Scope"))
58+
{
59+
var scopeValue = parameterBindings.BoundParameters["Scope"].ConstantValue;
60+
61+
if ((scopeValue != null) && (scopeValue.ToString().Equals("Global", StringComparison.OrdinalIgnoreCase)))
62+
{
63+
records.Add(new DiagnosticRecord(
64+
string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesError),
65+
commandAst.Extent,
66+
GetName(),
67+
DiagnosticSeverity.Warning,
68+
fileName));
69+
}
70+
}
71+
}
72+
73+
return AstVisitAction.SkipChildren;
74+
}
75+
#endregion
76+
77+
/// <summary>
78+
/// Determines if CommandAst is for the "New-Alias" command, checking aliases.
79+
/// </summary>
80+
/// <param name="commandAst">CommandAst to validate</param>
81+
/// <returns>True if the CommandAst is for the "New-Alias" command</returns>
82+
private bool IsNewAliasCmdlet(CommandAst commandAst)
83+
{
84+
if (commandAst == null || commandAst.GetCommandName() == null)
85+
{
86+
return false;
87+
}
88+
89+
var AliasList = Helper.Instance.CmdletNameAndAliases("New-Alias");
90+
if (AliasList.Contains(commandAst.GetCommandName()))
91+
{
92+
return true;
93+
}
94+
95+
return false;
96+
}
97+
98+
/// <summary>
99+
/// Determines if analyzing a script module.
100+
/// </summary>
101+
/// <returns>True is file name ends with ".psm1"</returns>
102+
private bool IsScriptModule()
103+
{
104+
return fileName.EndsWith(".psm1");
105+
}
106+
107+
public string GetCommonName()
108+
{
109+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesCommonName);
110+
}
111+
112+
public string GetDescription()
113+
{
114+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesDescription);
115+
}
116+
117+
public string GetName()
118+
{
119+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalAliasesName);
120+
}
121+
122+
public RuleSeverity GetSeverity()
123+
{
124+
return RuleSeverity.Warning;
125+
}
126+
127+
public string GetSourceName()
128+
{
129+
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
130+
}
131+
132+
public SourceType GetSourceType()
133+
{
134+
return SourceType.Builtin;
135+
}
136+
}
137+
}

Rules/AvoidGlobalFunctions.cs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
using System;
2+
using System.Collections.Generic;
3+
#if !CORECLR
4+
using System.ComponentModel.Composition;
5+
#endif
6+
using System.Globalization;
7+
using System.Management.Automation.Language;
8+
using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
9+
10+
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
11+
{
12+
#if !CORECLR
13+
[Export(typeof(IScriptRule))]
14+
#endif
15+
public class AvoidGlobalFunctions : AstVisitor, IScriptRule
16+
{
17+
private List<DiagnosticRecord> records;
18+
private string fileName;
19+
20+
/// <summary>
21+
/// Analyzes the ast to check that global functions are not used within modules.
22+
/// </summary>
23+
/// <param name="ast">The script's ast</param>
24+
/// <param name="fileName">The script's file name</param>
25+
/// <returns>A List of diagnostic results of this rule</returns>
26+
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
27+
{
28+
if (ast == null)
29+
{
30+
throw new ArgumentNullException(Strings.NullAstErrorMessage);
31+
}
32+
33+
records = new List<DiagnosticRecord>();
34+
this.fileName = fileName;
35+
36+
if (IsScriptModule())
37+
{
38+
ast.Visit(this);
39+
}
40+
41+
return records;
42+
}
43+
44+
#region VisitCommand functions
45+
/// <summary>
46+
/// Analyzes a FunctionDefinitionAst, if it is declared global a diagnostic record is created.
47+
/// </summary>
48+
/// <param name="functionDefinitionAst">FunctionDefinitionAst to be analyzed</param>
49+
/// <returns>AstVisitAction to continue analysis</returns>
50+
public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
51+
{
52+
if (functionDefinitionAst.Name.StartsWith("Global:", StringComparison.OrdinalIgnoreCase))
53+
{
54+
var functionNameExtent = Helper.Instance.GetScriptExtentForFunctionName(functionDefinitionAst);
55+
56+
records.Add(new DiagnosticRecord(
57+
string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalFunctionsError),
58+
functionNameExtent,
59+
GetName(),
60+
DiagnosticSeverity.Warning,
61+
fileName,
62+
functionDefinitionAst.Name));
63+
}
64+
65+
return AstVisitAction.Continue;
66+
}
67+
#endregion
68+
69+
/// <summary>
70+
/// Determines if analyzing a script module.
71+
/// </summary>
72+
/// <returns>True is file name ends with ".psm1"</returns>
73+
private bool IsScriptModule()
74+
{
75+
return fileName.EndsWith(".psm1");
76+
}
77+
78+
public string GetCommonName()
79+
{
80+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalFunctionsCommonName);
81+
}
82+
83+
public string GetDescription()
84+
{
85+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalFunctionsDescription);
86+
}
87+
88+
public string GetName()
89+
{
90+
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidGlobalFunctionsName);
91+
}
92+
93+
public RuleSeverity GetSeverity()
94+
{
95+
return RuleSeverity.Warning;
96+
}
97+
98+
public string GetSourceName()
99+
{
100+
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
101+
}
102+
103+
public SourceType GetSourceType()
104+
{
105+
return SourceType.Builtin;
106+
}
107+
}
108+
}

Rules/ScriptAnalyzerBuiltinRules.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@
7070
<Compile Include="AvoidAlias.cs" />
7171
<Compile Include="AvoidDefaultTrueValueSwitchParameter.cs" />
7272
<Compile Include="AvoidEmptyCatchBlock.cs" />
73+
<Compile Include="AvoidGlobalAliases.cs" />
74+
<Compile Include="AvoidGlobalFunctions.cs" />
7375
<Compile Include="AvoidGlobalVars.cs" />
7476
<Compile Include="AvoidInvokingEmptyMembers.cs" />
7577
<Compile Include="AvoidNullOrEmptyHelpMessageAttribute.cs" />
@@ -95,6 +97,7 @@
9597
<DependentUpon>Strings.resx</DependentUpon>
9698
</Compile>
9799
<Compile Include="UseBOMForUnicodeEncodedFile.cs" />
100+
<Compile Include="UseCompatibleCmdlets.cs" />
98101
<Compile Include="UseLiteralInitializerForHashtable.cs" />
99102
<Compile Include="UseToExportFieldsInManifest.cs" />
100103
<Compile Include="UseOutputTypeCorrectly.cs" />
@@ -114,7 +117,6 @@
114117
<Compile Include="UseStandardDSCFunctionsInResource.cs" />
115118
<Compile Include="UseUTF8EncodingForHelpFile.cs" />
116119
<Compile Include="ReturnCorrectTypesForDSCFunctions.cs" />
117-
<Compile Include="UseCompatibleCmdlets.cs" />
118120
</ItemGroup>
119121
<ItemGroup>
120122
<ProjectReference Include="..\Engine\ScriptAnalyzerEngine.csproj">

Rules/Strings.Designer.cs

Lines changed: 72 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)