-->

FXCop Custom Rule does not show up in RuleSet

2019-05-14 13:47发布

问题:

I followed the steps here to create a new custom rule and add it to the ruleset in VSStudio 2013:

http://blog.tatham.oddie.com.au/2010/01/06/custom-code-analysis-rules-in-vs2010-and-how-to-make-them-run-in-fxcop-and-vs2008-too/

However, despite all my efforts, the custom rule does not show up in the ruleset file.

If I add the rule in the FXCop Editor, it shows up and analyzes the target project correctly.

This is the Rule File, which is an embedded resource in the project:

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="PSI Custom FxCop Rules">
<Rule TypeName="EnforceHungarianNotation" Category="PSIRules" CheckId="CR0001">
<Name>Enforce Hungarian Notation</Name>
<Description>Checks fields for compliance with Hungarian notation.</Description>
<Resolution>Field {0} is not in Hungarian notation. Field name should be prefixed with '{1}'.</Resolution>
<MessageLevel Certainty="100">Error</MessageLevel>
<FixCategories>Breaking</FixCategories>
<Url />
<Owner />
<Email />
</Rule>
</Rules>

This is my RuleSet:

<?xml version="1.0" encoding="utf-8"?>
    <RuleSet Name="New Rule Set" Description=" " ToolsVersion="10.0">
         <RuleHintPaths>       
             <Path>C:\App\PSI\Development\Source\JHA.ProfitStars.PSI\JHA.ProfitStars  
                   .PSI.FxCop\bin\Debug</Path>
         </RuleHintPaths>
    </RuleSet>

I even tried adding the line below, but now it shows an Unknown rule in the ruleset:

    <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis"  
         RuleNamespace="Microsoft.Rules.Managed">
         <Rule Id="CR0001" Action="Error" />
    </Rules>

Could someone please help me understand what I am doing wrong here?

Edited:

BaseClass for rules:

internal abstract class BaseFxCopRule : BaseIntrospectionRule
{
    protected BaseFxCopRule(string ruleName)
        : base(ruleName, "JHA.ProfitStars.PSI.FxCop.Rules", typeof(BaseFxCopRule).Assembly)
    { }
}

Rules Class:

internal sealed class EnforceHungarianNotation : BaseFxCopRule
{
    public EnforceHungarianNotation()
        : base("EnforceHungarianNotation")
    { 
    }

    public override TargetVisibilities TargetVisibility
    {
        get
        {
            return TargetVisibilities.NotExternallyVisible;
        }
    }

    public override ProblemCollection Check(Member member)
    {
        Field field = member as Field;
        if (field == null)
        {
            // This rule only applies to fields.
            // Return a null ProblemCollection so no violations are reported for this member.
            return null;
        }

        if (field.IsStatic)
        {
            CheckFieldName(field, s_staticFieldPrefix);
        }
        else
        {
            CheckFieldName(field, s_nonStaticFieldPrefix);
        }

        // By default the Problems collection is empty so no violations will be reported
        // unless CheckFieldName found and added a problem.
        return Problems;
    }
    private const string s_staticFieldPrefix = "s_";
    private const string s_nonStaticFieldPrefix = "m_";

    private void CheckFieldName(Field field, string expectedPrefix)
    {
        if (!field.Name.Name.StartsWith(expectedPrefix, StringComparison.Ordinal))
        {
            Resolution resolution = GetResolution(
              field,  // Field {0} is not in Hungarian notation.
              expectedPrefix  // Field name should be prefixed with {1}.
              );
            Problem problem = new Problem(resolution);
            Problems.Add(problem);
        }
    }
}

回答1:

Looks like your path is kind of shaky, remove some spacing and unwanted characters:

<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="New Rule Set" Description=" " ToolsVersion="10.0">
     <RuleHintPaths>       
         <Path>C:\App\PSI\Development\Source\JHA.ProfitStars.PSI\JHA.ProfitStars.PSI.FxCop\bin\Debug</Path>
     </RuleHintPaths>
</RuleSet>

Also adding the rulesdll to Microsoft Visual Studio [Version]\Team Tools\Static Analysis Tools\FxCop\Ruleslocation would solve the issue of having to use Rulehintpaths.

As I can't detect anything wrong with your custom rules, see if you have selected the option to show all rules:

Also, using the following BaseRule might help:

protected BaseRule(string name)
        : base(

            // The name of the rule (must match exactly to an entry
            // in the manifest XML)
            name,

            // The name of the manifest XML file, qualified with the
            // namespace and missing the extension
            typeof(BaseRule).Assembly.GetName().Name + ".Rules",

            // The assembly to find the manifest XML in
            typeof(BaseRule).Assembly)
    {
    }


回答2:

Close your solution. Use the Source Control Explorer to locate your Rule Set File. Doubleclick onto your ruleset. The Rule Set Editor now should show all your custom rules. If this still doesn't work, try to use a relative path in the Path tag of the RuleHintPaths section.

Have a look at the LoadFromFile() method of the Microsoft.VisualStudio.CodeAnalysis.dll:

public static RuleSet LoadFromFile(string filePath, IEnumerable<RuleInfoProvider> ruleProviders)
    {
      RuleSet ruleSet = RuleSetXmlProcessor.ReadFromFile(filePath);
      if (ruleProviders != null)
      {
        string relativePathBase = string.IsNullOrEmpty(filePath) ? (string) null : Path.GetDirectoryName(ruleSet.FilePath);
        Dictionary<RuleInfoProvider, RuleInfoCollection> allRulesByProvider;
        Dictionary<string, IRuleInfo> rules = RuleSet.GetRules((IEnumerable<string>) ruleSet.RuleHintPaths, ruleProviders, relativePathBase, out allRulesByProvider);
        foreach (RuleReference ruleReference in (Collection<RuleReference>) ruleSet.Rules)
        {
          IRuleInfo ruleInfo;
          if (rules.TryGetValue(ruleReference.FullId, out ruleInfo))
          {
            if (ruleInfo.AnalyzerId == ruleReference.AnalyzerId)
              ruleReference.RuleInfo = ruleInfo;
            else
              CATrace.Info("RuleSet.LoadFromFile: Rule {0} was listed under analyzer id {1} in the rule set, but the corresponding IRuleInfo returned analyzer id {2}", (object) ruleReference.FullId, (object) ruleReference.AnalyzerId, (object) ruleInfo.AnalyzerId);
          }
        }
      }
      return ruleSet;
    }

If the relativePathBase is calculated wrong, the rule DLLs will not be found.



标签: c# fxcop