Skip to content

Instantly share code, notes, and snippets.

@rjmholt
Created August 17, 2021 18:06
Show Gist options
  • Save rjmholt/f05a0207503c22ac6830b9adf4ebe9c7 to your computer and use it in GitHub Desktop.
Save rjmholt/f05a0207503c22ac6830b9adf4ebe9c7 to your computer and use it in GitHub Desktop.
AvoidMultipleTypeAttributes
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
{
/// <summary>
/// UseConsistentCasing: Check if cmdlet is cased correctly.
/// </summary>
#if !CORECLR
[Export(typeof(IScriptRule))]
#endif
public sealed class AvoidMultipleTypeAttributesRule : IScriptRule
{
public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
{
IEnumerable<AttributedExpressionAst> baseAttributedExpressions = ast
.FindAll(subAst => subAst is AttributedExpressionAst attrExpr && subAst.Child is not AttributedExpressionAst, searchNestedScriptBlocks: true)
.OfType<AttributedExpressionAst>();
foreach (AttributedExpressionAst baseAttributedExpression in baseAttributedExpressions)
{
// Look up the attributes applied to this expression and look for duplicate types
bool seenType = false;
AttributedExpressionAst currAttrExprAst = baseAttributedExpression;
do
{
if (currAttrExprAst is ConvertExpressionAst typeConversionAst)
{
if (seenType)
{
yield return CreateDiagnosticForTypeConversionAst(typeConversionAst);
}
seenType = true;
}
currAttrExprAst = currAttrExprAst.Parent as AttributedExpressionAst;
} while (currAttrExprAst is not null);
}
}
private DiagnosticRecord CreateDiagnosticForTypeConversionAst(ConvertExpressionAst typeConversionAst)
{
// Implement some boilerplate here to create a diagnostic from the AST and its extent (typeConversionAst.Extent)
}
/// <summary>
/// GetName: Retrieves the name of this rule.
/// </summary>
/// <returns>The name of this rule</returns>
public string GetName()
{
return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidMultipleTypeAttributesName);
}
/// <summary>
/// GetCommonName: Retrieves the common name of this rule.
/// </summary>
/// <returns>The common name of this rule</returns>
public string GetCommonName()
{
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidMultipleTypeAttributesCommonName);
}
/// <summary>
/// GetDescription: Retrieves the description of this rule.
/// </summary>
/// <returns>The description of this rule</returns>
public string GetDescription()
{
return string.Format(CultureInfo.CurrentCulture, Strings.AvoidMultipleTypeAttributesDescription);
}
/// <summary>
/// GetSourceType: Retrieves the type of the rule, Builtin, Managed or Module.
/// </summary>
public SourceType GetSourceType()
{
return SourceType.Builtin;
}
/// <summary>
/// GetSeverity: Retrieves the severity of the rule: error, warning or information.
/// </summary>
/// <returns></returns>
public RuleSeverity GetSeverity()
{
return RuleSeverity.Error;
}
/// <summary>
/// GetSourceName: Retrieves the name of the module/assembly the rule is from.
/// </summary>
public string GetSourceName()
{
return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment