StyleCop offers to check for consistent use of spaces, but sadly lacks the opposite idea: Force source code to use tabs. Is there some way to add this functionality? It does not have to be StyleCop, other tools are welcome as well.
问题:
回答1:
You can use StyleCop+ plugin to enforce usage of tabs.
After downloading StyleCopPlus.dll
place it in Custom Rules
folder inside the main StyleCop folder C:\Program Files (x86)\StyleCop 4.7\Custom Rules
or directly in the main folder.
Now, when opening a Settings.StyleCop
with StyleCopSettingsEditor
you will be able to set rule SP2001: CheckAllowedIndentationCharacters
.
This rule can be found under the StyleCop+
tab, under the More Custom Rules
subtab, under the Formatting
heading:
回答2:
I'm a tabs-not-spaces person, too, though there are plenty of reasons to use either one and there are other places to get into why you think one is better than the other. :)
I actually wanted the same thing - a rule to check for tab indents - so I wrote it based on the SpacingRules source from StyleCop. It seems to work reasonably well, though I've only used it on a few projects so far. It could probably be optimized or whatever... but it works.
using System;
using System.Text.RegularExpressions;
using Microsoft.StyleCop;
using Microsoft.StyleCop.CSharp;
namespace CustomRules.StyleCop.CSharp
{
[SourceAnalyzer(typeof(CsParser))]
public class SpacingRules : SourceAnalyzer
{
public SpacingRules()
{
}
public override void AnalyzeDocument(CodeDocument document)
{
Param.RequireNotNull(document, "document");
CsDocument csdocument = (CsDocument)document;
if (csdocument.RootElement != null && !csdocument.RootElement.Generated)
{
this.CheckSpacing(csdocument.Tokens);
}
}
private void CheckSpacing(MasterList<CsToken> tokens)
{
Param.AssertNotNull(tokens, "tokens");
foreach (var token in tokens)
{
if (this.Cancel)
{
break;
}
if (token.Generated)
{
continue;
}
switch (token.CsTokenType)
{
case CsTokenType.WhiteSpace:
this.CheckWhitespace(token as Whitespace);
break;
case CsTokenType.XmlHeader:
XmlHeader header = (XmlHeader)token;
foreach (var xmlChild in header.ChildTokens)
{
this.CheckTabsInComment(xmlChild);
}
break;
case CsTokenType.SingleLineComment:
case CsTokenType.MultiLineComment:
this.CheckTabsInComment(token);
break;
}
switch (token.CsTokenClass)
{
case CsTokenClass.ConstructorConstraint:
this.CheckSpacing(((ConstructorConstraint)token).ChildTokens);
break;
case CsTokenClass.GenericType:
this.CheckGenericSpacing((GenericType)token);
this.CheckSpacing(((TypeToken)token).ChildTokens);
break;
case CsTokenClass.Type:
this.CheckSpacing(((TypeToken)token).ChildTokens);
break;
}
}
}
private void CheckGenericSpacing(GenericType generic)
{
Param.AssertNotNull(generic, "generic");
if (generic.ChildTokens.Count == 0)
{
return;
}
foreach (var token in generic.ChildTokens)
{
if (this.Cancel)
{
break;
}
if (token.CsTokenClass == CsTokenClass.GenericType)
{
this.CheckGenericSpacing(token as GenericType);
}
if (!token.Generated && token.CsTokenType == CsTokenType.WhiteSpace)
{
this.CheckWhitespace(token as Whitespace);
}
}
}
private void CheckWhitespace(Whitespace whitespace)
{
Param.AssertNotNull(whitespace, "whitespace");
if (whitespace.Location.StartPoint.IndexOnLine == 0 && Regex.IsMatch(whitespace.Text, "^ +"))
{
this.AddViolation(whitespace.FindParentElement(), whitespace.LineNumber, "TabsMustBeUsed");
}
}
private void CheckTabsInComment(CsToken comment)
{
Param.AssertNotNull(comment, "comment");
var lines = comment.Text.Split('\n');
for (int i = 0; i < lines.Length; i++)
{
if (Regex.IsMatch(lines[i], "^ +"))
{
this.AddViolation(comment.FindParentElement(), comment.LineNumber + i, "TabsMustBeUsed");
}
}
}
}
}
Note that you also have to have the embedded XML file "SpacingRules.xml" in the assembly alongside this thing. (Read the StyleCop SDK doc for more on that.)
<?xml version="1.0" encoding="utf-8" ?>
<SourceAnalyzer Name="Custom Spacing Rules">
<Description>
Rules which verify the spacing placed between keywords and symbols in the code.
</Description>
<Rules>
<Rule Name="TabsMustBeUsed" CheckId="MY1027">
<Context>Spaces are not allowed. Use tabs instead.</Context>
<Description>Verifies that the code does not contain spaces.</Description>
</Rule>
</Rules>
</SourceAnalyzer>
回答3:
One thing you could do, assuming you are using Visual Studio as your IDE, and that your team-mates buy-in to this idea, would be to set VS to use tabs instead of spaces, export and share the settings file.
The setting can be found under Tools > Options > Text Editor > All Languages (or the language you wish to use) > Tabs and then on the right hand side you can pick to 'Insert Spaces' or 'Keep Tabs'.
To export the settings from your visual studio: Tools > Import and Export Settings > Export selected environment settings > select the 'Options'
Just a thought - but to be honest the real problem seems to be the buy-in from your team-mates. They can always revert back to their settings otherwise. Alternatively, upon check-in, as Sam suggested, you can do some automated re-formatting.
HTH
回答4:
StyleCop supports creation of custom rules, so you can add your own "use leading tabs instead of spaces" rule. If you don't feel like trying to develop your own, you can get an existing rule at either http://stylecopcontrib.codeplex.com/ or http://github.com/AArnott/nerdbank.stylecop.rules.
回答5:
Ok I managed to figure out the problem because the reason why this warning appear, It appear because the developer sometimes copy and paste the code
if you are using VS2010 Go to solution explorer Check in Setting Style Cop then modify the setting inside the style Cop e.g disable or uncheck the setting[Spacing.....]
回答6:
The package approach:
It seems that the current trend is to do this through nuget packages (and that the classic StyleCop may be phased out at some point). So, to do this with the packages, do the following:
via nuget:
Install-Package Microsoft.CodeAnalysis.FxCopAnalyzers
Install-Package StyleCop.Analyzers -Version 1.1.0-beta006
Notice the reference to the pre-releaset (at this time), the settings for tabs are only available in the beta.
add the following code to your project as ca.ruleset:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Custom Rulset" Description="Custom Rulset" ToolsVersion="14.0">
<Rules AnalyzerId="AsyncUsageAnalyzers" RuleNamespace="AsyncUsageAnalyzers">
<Rule Id="UseConfigureAwait" Action="Warning" />
</Rules>
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CA1001" Action="Warning" />
<Rule Id="CA1009" Action="Warning" />
<Rule Id="CA1016" Action="Warning" />
<Rule Id="CA1033" Action="Warning" />
<Rule Id="CA1049" Action="Warning" />
<Rule Id="CA1060" Action="Warning" />
<Rule Id="CA1061" Action="Warning" />
<Rule Id="CA1063" Action="Warning" />
<Rule Id="CA1065" Action="Warning" />
<Rule Id="CA1301" Action="Warning" />
<Rule Id="CA1400" Action="Warning" />
<Rule Id="CA1401" Action="Warning" />
<Rule Id="CA1403" Action="Warning" />
<Rule Id="CA1404" Action="Warning" />
<Rule Id="CA1405" Action="Warning" />
<Rule Id="CA1410" Action="Warning" />
<Rule Id="CA1415" Action="Warning" />
<Rule Id="CA1821" Action="Warning" />
<Rule Id="CA1900" Action="Warning" />
<Rule Id="CA1901" Action="Warning" />
<Rule Id="CA2002" Action="Warning" />
<Rule Id="CA2100" Action="Warning" />
<Rule Id="CA2101" Action="Warning" />
<Rule Id="CA2108" Action="Warning" />
<Rule Id="CA2111" Action="Warning" />
<Rule Id="CA2112" Action="Warning" />
<Rule Id="CA2114" Action="Warning" />
<Rule Id="CA2116" Action="Warning" />
<Rule Id="CA2117" Action="Warning" />
<Rule Id="CA2122" Action="Warning" />
<Rule Id="CA2123" Action="Warning" />
<Rule Id="CA2124" Action="Warning" />
<Rule Id="CA2126" Action="Warning" />
<Rule Id="CA2131" Action="Warning" />
<Rule Id="CA2132" Action="Warning" />
<Rule Id="CA2133" Action="Warning" />
<Rule Id="CA2134" Action="Warning" />
<Rule Id="CA2137" Action="Warning" />
<Rule Id="CA2138" Action="Warning" />
<Rule Id="CA2140" Action="Warning" />
<Rule Id="CA2141" Action="Warning" />
<Rule Id="CA2146" Action="Warning" />
<Rule Id="CA2147" Action="Warning" />
<Rule Id="CA2149" Action="Warning" />
<Rule Id="CA2200" Action="Warning" />
<Rule Id="CA2202" Action="Warning" />
<Rule Id="CA2207" Action="Warning" />
<Rule Id="CA2212" Action="Warning" />
<Rule Id="CA2213" Action="Warning" />
<Rule Id="CA2214" Action="Warning" />
<Rule Id="CA2216" Action="Warning" />
<Rule Id="CA2220" Action="Warning" />
<Rule Id="CA2229" Action="Warning" />
<Rule Id="CA2231" Action="Warning" />
<Rule Id="CA2232" Action="Warning" />
<Rule Id="CA2235" Action="Warning" />
<Rule Id="CA2236" Action="Warning" />
<Rule Id="CA2237" Action="Warning" />
<Rule Id="CA2238" Action="Warning" />
<Rule Id="CA2240" Action="Warning" />
<Rule Id="CA2241" Action="Warning" />
<Rule Id="CA2242" Action="Warning" />
<Rule Id="CA1012" Action="Warning" />
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1305" Action="Warning" />
<Rule Id="SA1412" Action="Warning" />
<Rule Id="SA1600" Action="None" />
<Rule Id="SA1609" Action="Warning" />
</Rules>
</RuleSet>
Add it to your project file by editing the .csproj file and adding:
<PropertyGroup>
<CodeAnalysisRuleSet>ca.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
To override the tab (and other) settings, you will need to add a stylecop.json file to your project. In the file properties, set the Build Action to '(analyzer) additional file'. Depending on the project type, the actual word 'analyzer' may not be present.
Edit the stylecop.json file to something like the following:
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"companyName": "YourCompanyName",
"copyrightText": "Copyright (c) {companyName}. All Rights Reserved.\r\nLicensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.",
"xmlHeader": false,
"fileNamingConvention": "metadata"
},
"indentation": {
"useTabs": true
}
}
}
At least for .NET standard projects, you need to insure that the following is in the csproj file (and no other references to file):
<ItemGroup>
<AdditionalFiles Include="stylecop.json" />
</ItemGroup>
You may have to reload the project and the packages to get them to recognize the stylecop.json file.
References:
DotNetAnalyzers/StyleCopAnalyzers
.NET Core, Code Analysis and StyleCop
回答7:
Do it within your source control server. Use a pre-commit script to check the file for lines starting with multiple spaces and prevent the commit.
I agree tabs are better than spaces. It's a personal preference, but team consistency is very important.