Based on a few good articles, I was able to successfully create some custom StyleCop rules. For reference, several articles that I found very useful in this thread are listed here:
I am using Visual Studio 2010 Ultimate version with StyleCop version 4.4.0.14.
Creating a Custom StyleCop Rule Creates a class file along with the corresponding XML file, which is used to add rules to StyleCop settings. When I do this, all of my user rules are executed correctly. However, I do not like that in the StyleCop settings tree you get several "Custom Rules" nodes, one for each XML file.
Skipping the details of the implementation of the various rules, this is what I did. Take the following two simple classes of custom rules for the corresponding XML files:
File: CustomRule1.cs
namespace StyleCop.CustomRules
{
[SourceAnalyzer(typeof(CsParser))]
public class CustomRule1 : SourceAnalyzer
{
public override void AnalyzeDocument(CodeDocument document)
{
Param.RequireNotNull(document, "document");
CsDocument csDocument = document as CsDocument;
if ((csDocument.RootElement != null) && !csDocument.RootElement.Generated)
{
}
}
}
}
File: CustomRule2.cs
namespace StyleCop.CustomRules
{
[SourceAnalyzer(typeof(CsParser))]
public class CustomRule2 : SourceAnalyzer
{
public override void AnalyzeDocument(CodeDocument document)
{
Param.RequireNotNull(document, "document");
CsDocument csDocument = document as CsDocument;
if ((csDocument.RootElement != null) && !csDocument.RootElement.Generated)
{
}
}
}
}
File: CustomRule1.xml
<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Custom Rules">
<Description>
These custom rules provide extensions to the ones provided with StyleCop.
</Description>
<Rules>
<Rule Name="CustomRule1" CheckId="CR1001">
<Context>Test rule 1.</Context>
<Description>Test rule 1.</Description>
</Rule>
</Rules>
</SourceAnalyzer>
File: CustomRule2.xml
<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Custom Rules">
<Description>
These custom rules provide extensions to the ones provided with StyleCop.
</Description>
<Rules>
<Rule Name="CustomRule2" CheckId="CR1002">
<Context>Test rule 2.</Context>
<Description>Test rule 2.</Description>
</Rule>
</Rules>
</SourceAnalyzer>
With the above, all (both) of my rules were correctly followed. The following appeared in the StyleCop settings tree (square brackets are a check box):
[] C#
[] {} Custom Rules
[] {} CR1001: CustomRule1
[] {} Custom Rules
[] {} CR1002: CustomRule2
[] {} Documentation Rules
[] {} Layout Rules
etc.
, node " " StyleCop :
[] C#
[] {} Custom Rules
[] {} CR1001: CustomRule1
[] {} CR1002: CustomRule2
[] {} Documentation Rules
[] {} Layout Rules
etc.
" " node StyleCop, XML :
: CustomRule1.xml
<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Custom Rules">
<Description>
These custom rules provide extensions to the ones provided with StyleCop.
</Description>
<Rules>
<Rule Name="CustomRule1" CheckId="CR1001">
<Context>Test rule 1.</Context>
<Description>Test rule 1.</Description>
</Rule>
<Rule Name="CustomRule2" CheckId="CR1002">
<Context>Test rule 2.</Context>
<Description>Test rule 2.</Description>
</Rule>
</Rules>
</SourceAnalyzer>
, , , CustomRule1, , () XML.
CustomRule2, XML :
namespace StyleCop.CustomRules
{
[SourceAnalyzer(typeof(CsParser), "CustomRule1.xml")]
public class CustomRule2 : SourceAnalyzer
{
public override void AnalyzeDocument(CodeDocument document)
{
Param.RequireNotNull(document, "document");
CsDocument csDocument = document as CsDocument;
if ((csDocument.RootElement != null) && !csDocument.RootElement.Generated)
{
}
}
}
}
, , XML, . StyleCop, CustomRule1.
?
Update:
, .
, , , , . , :
[SourceAnalyzer(typeof(CsParser))]
public class CustomRules : SourceAnalyzer
{
private enum CustomRuleName
{
CustomRule1,
CustomRule2
}
private CustomRuleName currentRule;
public override void AnalyzeDocument(CodeDocument document)
{
Param.RequireNotNull(document, "document");
CsDocument doc = document as CsDocument;
if (doc.RootElement == null || doc.RootElement.Generated)
{
return;
}
this.currentRule = CustomRuleName.CustomRule1;
doc.WalkDocument(VisitElement);
this.currentRule = CustomRuleName.CustomRule2;
doc.WalkDocument(VisitElement);
}
private bool VisitElement(CsElement element, CsElement parentElement, object context)
{
if (this.currentRule == CustomRuleName.CustomRule1)
{
}
else if (this.currentRule == CustomRuleName.CustomRule2)
{
}
}
}
Update:
, . .
, , , VisitElement, StatementWalker ExpressionWalker .
[SourceAnalyzer(typeof(CsParser))]
public class CustomRules : SourceAnalyzer
{
public override void AnalyzeDocument(CodeDocument document)
{
Param.RequireNotNull(document, "document");
CsDocument doc = document as CsDocument;
if (doc.RootElement == null || doc.RootElement.Generated)
{
return;
}
IDictionary<string, Field> fields = new Dictionary<string, Field>();
doc.WalkDocument(VisitElement, StatementWalker, ExpressionWalker, fields);
}
private bool VisitElement(CsElement element, CsElement parentElement, object context)
{
return true;
}
private bool StatementWalker(Statement statement, Expression parentExpression, Statement parentStatement, CsElement parentElement, object context)
{
return true;
}
private bool ExpressionWalker(Expression expression, Expression parentExpression, Statement parentStatement, CsElement parentElement, object context)
{
return true;
}
}