diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1300UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1300UnitTests.cs
index 6ab51355c..b53f58c35 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1300UnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/NamingRules/SA1300UnitTests.cs
@@ -44,6 +44,31 @@ public async Task TestLowerCaseNamespaceAsync()
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}
+ [Fact]
+ public async Task TestAllowedLowerCaseNamespaceIsNotReportedAsync()
+ {
+ var customTestSettings = @"
+{
+ ""settings"": {
+ ""namingRules"": {
+ ""allowedNamespaceComponents"": [ ""eBay"" ]
+ }
+ }
+}
+";
+
+ var testCode = @"namespace eBay
+{
+
+}";
+
+ await new CSharpTest
+ {
+ TestCode = testCode,
+ Settings = customTestSettings,
+ }.RunAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+
[Fact]
public async Task TestLowerCaseComlicatedNamespaceAsync()
{
@@ -67,6 +92,31 @@ public async Task TestLowerCaseComlicatedNamespaceAsync()
await VerifyCSharpFixAsync(testCode, expected, fixedCode, CancellationToken.None).ConfigureAwait(false);
}
+ [Fact]
+ public async Task TestAllowedLowerCaseComplicatedNamespaceIsNotReportedAsync()
+ {
+ var customTestSettings = @"
+{
+ ""settings"": {
+ ""namingRules"": {
+ ""allowedNamespaceComponents"": [ ""iPod"" ]
+ }
+ }
+}
+";
+
+ var testCode = @"namespace Apple.iPod.Library
+{
+
+}";
+
+ await new CSharpTest
+ {
+ TestCode = testCode,
+ Settings = customTestSettings,
+ }.RunAsync(CancellationToken.None).ConfigureAwait(false);
+ }
+
[Fact]
public async Task TestUpperCaseClassAsync()
{
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Settings/SettingsUnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Settings/SettingsUnitTests.cs
index 21454bca2..6a0747704 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Settings/SettingsUnitTests.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Settings/SettingsUnitTests.cs
@@ -29,6 +29,7 @@ public void VerifySettingsDefaults()
Assert.Equal("Copyright (c) PlaceholderCompany. All rights reserved.", styleCopSettings.DocumentationRules.GetCopyrightText("unused"));
Assert.True(styleCopSettings.NamingRules.AllowCommonHungarianPrefixes);
Assert.Empty(styleCopSettings.NamingRules.AllowedHungarianPrefixes);
+ Assert.Empty(styleCopSettings.NamingRules.AllowedNamespaceComponents);
Assert.NotNull(styleCopSettings.OrderingRules);
Assert.Equal(UsingDirectivesPlacement.InsideNamespace, styleCopSettings.OrderingRules.UsingDirectivesPlacement);
@@ -61,6 +62,7 @@ public async Task VerifySettingsAreReadCorrectlyAsync()
""namingRules"": {
""allowCommonHungarianPrefixes"": false,
""allowedHungarianPrefixes"": [""a"", ""ab"", ""ignoredTooLong""],
+ ""allowedNamespaceComponents"": [""eBay"", ""iMac""],
""unrecognizedValue"": 3
},
""layoutRules"": {
@@ -93,6 +95,7 @@ public async Task VerifySettingsAreReadCorrectlyAsync()
Assert.Equal("ru-RU", styleCopSettings.DocumentationRules.DocumentationCulture);
Assert.False(styleCopSettings.NamingRules.AllowCommonHungarianPrefixes);
Assert.Equal(new[] { "a", "ab" }, styleCopSettings.NamingRules.AllowedHungarianPrefixes);
+ Assert.Equal(new[] { "eBay", "iMac" }, styleCopSettings.NamingRules.AllowedNamespaceComponents);
Assert.NotNull(styleCopSettings.LayoutRules);
Assert.Equal(OptionSetting.Require, styleCopSettings.LayoutRules.NewlineAtEndOfFile);
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1300ElementMustBeginWithUpperCaseLetter.cs b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1300ElementMustBeginWithUpperCaseLetter.cs
index e486cc1da..88cff047a 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1300ElementMustBeginWithUpperCaseLetter.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/NamingRules/SA1300ElementMustBeginWithUpperCaseLetter.cs
@@ -12,6 +12,7 @@ namespace StyleCop.Analyzers.NamingRules
using Microsoft.CodeAnalysis.Diagnostics;
using StyleCop.Analyzers.Helpers;
using StyleCop.Analyzers.Lightup;
+ using StyleCop.Analyzers.Settings.ObjectModel;
///
/// The name of a C# element does not begin with an upper-case letter.
@@ -29,6 +30,9 @@ namespace StyleCop.Analyzers.NamingRules
/// class. A NativeMethods class is any class which contains a name ending in NativeMethods, and is
/// intended as a placeholder for Win32 or COM wrappers. StyleCop will ignore this violation if the item is placed
/// within a NativeMethods class.
+ ///
+ /// For namespace components that begin with a small letter, due to branding issues or other reasons, add the
+ /// term to the allowedNamespaceComponents list.
///
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class SA1300ElementMustBeginWithUpperCaseLetter : DiagnosticAnalyzer
@@ -45,7 +49,7 @@ internal class SA1300ElementMustBeginWithUpperCaseLetter : DiagnosticAnalyzer
private static readonly DiagnosticDescriptor Descriptor =
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.NamingRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
- private static readonly Action NamespaceDeclarationAction = HandleNamespaceDeclaration;
+ private static readonly Action NamespaceDeclarationAction = HandleNamespaceDeclaration;
private static readonly Action ClassDeclarationAction = HandleClassDeclaration;
private static readonly Action EnumDeclarationAction = HandleEnumDeclaration;
private static readonly Action EnumMemberDeclarationAction = HandleEnumMemberDeclaration;
@@ -82,13 +86,13 @@ public override void Initialize(AnalysisContext context)
context.RegisterSyntaxNodeAction(PropertyDeclarationAction, SyntaxKind.PropertyDeclaration);
}
- private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context)
+ private static void HandleNamespaceDeclaration(SyntaxNodeAnalysisContext context, StyleCopSettings settings)
{
NameSyntax nameSyntax = ((NamespaceDeclarationSyntax)context.Node).Name;
- CheckNameSyntax(context, nameSyntax);
+ CheckNamespaceNameSyntax(context, nameSyntax, settings);
}
- private static void CheckNameSyntax(SyntaxNodeAnalysisContext context, NameSyntax nameSyntax)
+ private static void CheckNamespaceNameSyntax(SyntaxNodeAnalysisContext context, NameSyntax nameSyntax, StyleCopSettings settings)
{
if (nameSyntax == null || nameSyntax.IsMissing)
{
@@ -97,12 +101,13 @@ private static void CheckNameSyntax(SyntaxNodeAnalysisContext context, NameSynta
if (nameSyntax is QualifiedNameSyntax qualifiedNameSyntax)
{
- CheckNameSyntax(context, qualifiedNameSyntax.Left);
- CheckNameSyntax(context, qualifiedNameSyntax.Right);
+ CheckNamespaceNameSyntax(context, qualifiedNameSyntax.Left, settings);
+ CheckNamespaceNameSyntax(context, qualifiedNameSyntax.Right, settings);
return;
}
- if (nameSyntax is SimpleNameSyntax simpleNameSyntax)
+ if (nameSyntax is SimpleNameSyntax simpleNameSyntax &&
+ !settings.NamingRules.AllowedNamespaceComponents.Contains(simpleNameSyntax.Identifier.ValueText))
{
CheckElementNameToken(context, simpleNameSyntax.Identifier);
return;
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Settings/ObjectModel/NamingSettings.cs b/StyleCop.Analyzers/StyleCop.Analyzers/Settings/ObjectModel/NamingSettings.cs
index 27367006f..0523281c9 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/Settings/ObjectModel/NamingSettings.cs
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Settings/ObjectModel/NamingSettings.cs
@@ -3,7 +3,9 @@
namespace StyleCop.Analyzers.Settings.ObjectModel
{
+ using System.Collections.Generic;
using System.Collections.Immutable;
+ using System.Linq;
using System.Text.RegularExpressions;
using LightJson;
@@ -14,6 +16,11 @@ internal class NamingSettings
///
private readonly ImmutableArray.Builder allowedHungarianPrefixes;
+ ///
+ /// This is the backing field for the property.
+ ///
+ private readonly ImmutableArray.Builder allowedNamespaceComponents;
+
///
/// Initializes a new instance of the class.
///
@@ -21,6 +28,7 @@ protected internal NamingSettings()
{
this.AllowCommonHungarianPrefixes = true;
this.allowedHungarianPrefixes = ImmutableArray.CreateBuilder();
+ this.allowedNamespaceComponents = ImmutableArray.CreateBuilder();
this.IncludeInferredTupleElementNames = false;
this.TupleElementNameCasing = TupleElementNameCase.PascalCase;
@@ -57,6 +65,11 @@ protected internal NamingSettings(JsonObject namingSettingsObject)
break;
+ case "allowedNamespaceComponents":
+ kvp.AssertIsArray();
+ this.allowedNamespaceComponents.AddRange(kvp.Value.AsJsonArray.Select(x => x.ToStringValue(kvp.Key)));
+ break;
+
case "includeInferredTupleElementNames":
this.IncludeInferredTupleElementNames = kvp.ToBooleanValue();
break;
@@ -76,6 +89,9 @@ protected internal NamingSettings(JsonObject namingSettingsObject)
public ImmutableArray AllowedHungarianPrefixes
=> this.allowedHungarianPrefixes.ToImmutable();
+ public ImmutableArray AllowedNamespaceComponents
+ => this.allowedNamespaceComponents.ToImmutable();
+
public bool IncludeInferredTupleElementNames { get; }
public TupleElementNameCase TupleElementNameCasing { get; }
diff --git a/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json b/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json
index 7835dbc00..34c319a7b 100644
--- a/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json
+++ b/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json
@@ -128,6 +128,15 @@
"uniqueItems": true
}
},
+ "allowedNamespaceComponents": {
+ "type": "array",
+ "description": "Allowed namespace components, such as ones beginning with a lowercase letter.",
+ "default": [],
+ "items": {
+ "type": "string",
+ "uniqueItems": true
+ }
+ },
"includeInferredTupleElementNames": {
"type": "boolean",
"description": "Specifies whether inferred tuple element names will be analyzed as well.",
diff --git a/documentation/Configuration.md b/documentation/Configuration.md
index 7a849f309..420b3add4 100644
--- a/documentation/Configuration.md
+++ b/documentation/Configuration.md
@@ -314,6 +314,30 @@ The following example shows a settings file which allows the common prefixes as
}
```
+### Namespace Components
+
+The following property is used to configure allowable namespace components (e.g. ones that start with a lowercase letter).
+
+| Property | Default Value | Minimum Version | Summary |
+| --- | --- | --- | --- |
+| `allowedNamespaceComponents` | `[ ]` | 1.2.0 | Specifies namespace components that are allowed to be used. See the example below for more information. |
+
+The following example shows a settings file which allows namespace components such as `eBay` or `Apple.iPod`.
+
+```json
+{
+ "settings": {
+ "namingRules": {
+ "allowedNamespaceComponents": [
+ "eBay",
+ "iPod"
+ ]
+ }
+ }
+}
+```
+
+
### Tuple element names
The following properties are used to configure the behavior of the tuple element name analyzers.
diff --git a/documentation/SA1300.md b/documentation/SA1300.md
index fa9ef4faf..000421d6d 100644
--- a/documentation/SA1300.md
+++ b/documentation/SA1300.md
@@ -42,10 +42,14 @@ begin with a lower-case letter, place the field or variable within a special `Na
class is any class which contains a name ending in `NativeMethods`, and is intended as a placeholder for Win32 or COM
wrappers. StyleCop will ignore this violation if the item is placed within a `NativeMethods` class.
+For namespace components that begin with a small letter, due to branding issues or other reasons, add the appropriate
+term to the `allowedNamespaceComponents` list.
+
## How to fix violations
-To fix a violation of this rule, change the name of the element so that it begins with an upper-case letter, or place
-the item within a `NativeMethods` class if appropriate.
+To fix a violation of this rule, change the name of the element so that it begins with an upper-case letter, place
+the item within a `NativeMethods` class if appropriate, or add it to the `allowedNamespaceComponents` list if
+it is a namespace component.
## How to suppress violations