11 changed files with 885 additions and 5 deletions
@ -0,0 +1,72 @@ |
|||||||
|
//
|
||||||
|
// AffectedEntity.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Xamarin <http://xamarin.com>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
using System; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||||
|
{ |
||||||
|
[Flags] |
||||||
|
public enum AffectedEntity |
||||||
|
{ |
||||||
|
None, |
||||||
|
|
||||||
|
Namespace = 1 << 0, |
||||||
|
|
||||||
|
Class = 1 << 1, |
||||||
|
Struct = 1 << 2, |
||||||
|
Enum = 1 << 3, |
||||||
|
Interface = 1 << 4, |
||||||
|
Delegate = 1 << 5, |
||||||
|
|
||||||
|
CustomAttributes = 1 << 6, |
||||||
|
CustomEventArgs = 1 << 7, |
||||||
|
CustomExceptions = 1 << 8, |
||||||
|
|
||||||
|
Property = 1 << 9, |
||||||
|
Method = 1 << 10, |
||||||
|
Field = 1 << 11, |
||||||
|
Event = 1 << 12, |
||||||
|
EnumMember = 1 << 13, |
||||||
|
|
||||||
|
Parameter = 1 << 14, |
||||||
|
TypeParameter = 1 << 15, |
||||||
|
|
||||||
|
// Unit test special case
|
||||||
|
TestType = 1 << 16, |
||||||
|
TestMethod = 1 << 17, |
||||||
|
|
||||||
|
// private entities
|
||||||
|
LambdaParameter = 1 << 18, |
||||||
|
LocalVariable = 1 << 19, |
||||||
|
Label = 1 << 20, |
||||||
|
|
||||||
|
LocalVars = LocalVariable | Parameter | LambdaParameter, |
||||||
|
|
||||||
|
Member = Property | Method | Field | Event | EnumMember, |
||||||
|
|
||||||
|
Type = Class | Struct | Enum | Interface | Delegate, |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,106 @@ |
|||||||
|
//
|
||||||
|
// DefaultRules.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Xamarin <http://xamarin.com>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||||
|
{ |
||||||
|
public static class DefaultRules |
||||||
|
{ |
||||||
|
public static readonly List<NamingRule> Rules = new List<NamingRule>(); |
||||||
|
|
||||||
|
static DefaultRules() |
||||||
|
{ |
||||||
|
Rules.AddRange(GetFdgRules()); |
||||||
|
} |
||||||
|
|
||||||
|
public static IEnumerable<NamingRule> GetFdgRules() |
||||||
|
{ |
||||||
|
// PascalCasing for namespace
|
||||||
|
yield return new NamingRule(AffectedEntity.Namespace) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
|
||||||
|
// PascalCasing for types
|
||||||
|
yield return new NamingRule(AffectedEntity.Type) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.Interface) { |
||||||
|
NamingStyle = NamingStyle.PascalCase, |
||||||
|
RequiredPrefixes = new [] { "I" } |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.CustomAttributes) { |
||||||
|
NamingStyle = NamingStyle.PascalCase, |
||||||
|
RequiredSuffixes = new [] { "Attribute" } |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.CustomEventArgs) { |
||||||
|
NamingStyle = NamingStyle.PascalCase, |
||||||
|
RequiredSuffixes = new [] { "EventArgs" } |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.CustomExceptions) { |
||||||
|
NamingStyle = NamingStyle.PascalCase, |
||||||
|
RequiredSuffixes = new [] { "Exception" } |
||||||
|
}; |
||||||
|
|
||||||
|
// PascalCasing for members
|
||||||
|
yield return new NamingRule(AffectedEntity.Method) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.Field) { |
||||||
|
NamingStyle = NamingStyle.PascalCase, |
||||||
|
VisibilityMask = Modifiers.Public | Modifiers.Protected | Modifiers.Internal |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.Property) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.Event) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
|
||||||
|
yield return new NamingRule(AffectedEntity.EnumMember) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
|
||||||
|
// Parameters should be camelCase
|
||||||
|
yield return new NamingRule(AffectedEntity.Parameter) { |
||||||
|
NamingStyle = NamingStyle.CamelCase |
||||||
|
}; |
||||||
|
|
||||||
|
// Type parameter should be PascalCase
|
||||||
|
yield return new NamingRule(AffectedEntity.TypeParameter) { |
||||||
|
NamingStyle = NamingStyle.PascalCase |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,185 @@ |
|||||||
|
//
|
||||||
|
// InconsistentNamingIssue.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Xamarin <http://xamarin.com>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||||
|
{ |
||||||
|
/* [IssueDescription("Inconsistent Naming", |
||||||
|
Description = "Name doesn't match the defined style for this entity.", |
||||||
|
Category = IssueCategories.ConstraintViolations, |
||||||
|
Severity = Severity.Warning)]*/ |
||||||
|
public class InconsistentNamingIssue |
||||||
|
{ |
||||||
|
public IEnumerable<CodeIssue> GetIssues(BaseRefactoringContext context) |
||||||
|
{ |
||||||
|
var visitor = new GatherVisitor(context, this); |
||||||
|
context.RootNode.AcceptVisitor(visitor); |
||||||
|
return visitor.FoundIssues; |
||||||
|
} |
||||||
|
|
||||||
|
class GatherVisitor : GatherVisitorBase |
||||||
|
{ |
||||||
|
readonly InconsistentNamingIssue inspector; |
||||||
|
List<NamingRule> rules; |
||||||
|
|
||||||
|
public GatherVisitor (BaseRefactoringContext ctx, InconsistentNamingIssue inspector) : base (ctx) |
||||||
|
{ |
||||||
|
this.inspector = inspector; |
||||||
|
rules = new List<NamingRule> (DefaultRules.Rules); |
||||||
|
} |
||||||
|
|
||||||
|
void CheckName(AffectedEntity entity, Identifier identifier) |
||||||
|
{ |
||||||
|
foreach (var rule in rules) { |
||||||
|
if (!rule.AffectedEntity.HasFlag(entity)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (!rule.IsValid(identifier.Name)) { |
||||||
|
IList<string> suggestedNames; |
||||||
|
var msg = rule.GetErrorMessage(ctx, identifier.Name, out suggestedNames); |
||||||
|
|
||||||
|
AddIssue(identifier, msg, suggestedNames.Select(n => new CodeAction(string.Format(ctx.TranslateString("Rename to '{0}'"), n), (Script script) => { |
||||||
|
script.Replace(identifier, Identifier.Create(n)); |
||||||
|
}))); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) |
||||||
|
{ |
||||||
|
base.VisitNamespaceDeclaration(namespaceDeclaration); |
||||||
|
foreach (var id in namespaceDeclaration.Identifiers) { |
||||||
|
CheckName(AffectedEntity.Namespace, id); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) |
||||||
|
{ |
||||||
|
base.VisitTypeDeclaration(typeDeclaration); |
||||||
|
AffectedEntity entity; |
||||||
|
switch (typeDeclaration.ClassType) { |
||||||
|
case ClassType.Class: |
||||||
|
entity = AffectedEntity.Class; |
||||||
|
break; |
||||||
|
case ClassType.Struct: |
||||||
|
entity = AffectedEntity.Struct; |
||||||
|
break; |
||||||
|
case ClassType.Interface: |
||||||
|
entity = AffectedEntity.Interface; |
||||||
|
break; |
||||||
|
case ClassType.Enum: |
||||||
|
entity = AffectedEntity.Enum; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new System.ArgumentOutOfRangeException(); |
||||||
|
} |
||||||
|
|
||||||
|
CheckName(entity, typeDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) |
||||||
|
{ |
||||||
|
base.VisitDelegateDeclaration(delegateDeclaration); |
||||||
|
CheckName(AffectedEntity.Delegate, delegateDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) |
||||||
|
{ |
||||||
|
base.VisitPropertyDeclaration(propertyDeclaration); |
||||||
|
CheckName(AffectedEntity.Property, propertyDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) |
||||||
|
{ |
||||||
|
base.VisitMethodDeclaration(methodDeclaration); |
||||||
|
CheckName(AffectedEntity.Method, methodDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitFieldDeclaration(FieldDeclaration fieldDeclaration) |
||||||
|
{ |
||||||
|
base.VisitFieldDeclaration(fieldDeclaration); |
||||||
|
CheckName(AffectedEntity.Field, fieldDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration) |
||||||
|
{ |
||||||
|
base.VisitFixedFieldDeclaration(fixedFieldDeclaration); |
||||||
|
CheckName(AffectedEntity.Field, fixedFieldDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitEventDeclaration(EventDeclaration eventDeclaration) |
||||||
|
{ |
||||||
|
base.VisitEventDeclaration(eventDeclaration); |
||||||
|
CheckName(AffectedEntity.Event, eventDeclaration.NameToken); |
||||||
|
foreach (var init in eventDeclaration.Variables) { |
||||||
|
CheckName(AffectedEntity.Event, init.NameToken); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration) |
||||||
|
{ |
||||||
|
base.VisitCustomEventDeclaration(eventDeclaration); |
||||||
|
CheckName(AffectedEntity.Event, eventDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration) |
||||||
|
{ |
||||||
|
base.VisitEnumMemberDeclaration(enumMemberDeclaration); |
||||||
|
CheckName(AffectedEntity.EnumMember, enumMemberDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) |
||||||
|
{ |
||||||
|
base.VisitParameterDeclaration(parameterDeclaration); |
||||||
|
CheckName(parameterDeclaration.Parent is LambdaExpression ? AffectedEntity.LambdaParameter : AffectedEntity.Parameter, parameterDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration) |
||||||
|
{ |
||||||
|
base.VisitTypeParameterDeclaration(typeParameterDeclaration); |
||||||
|
CheckName(AffectedEntity.TypeParameter, typeParameterDeclaration.NameToken); |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) |
||||||
|
{ |
||||||
|
base.VisitVariableDeclarationStatement(variableDeclarationStatement); |
||||||
|
foreach (var init in variableDeclarationStatement.Variables) { |
||||||
|
CheckName(AffectedEntity.LocalVariable, init.NameToken); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public override void VisitLabelStatement(LabelStatement labelStatement) |
||||||
|
{ |
||||||
|
base.VisitLabelStatement(labelStatement); |
||||||
|
CheckName(AffectedEntity.Label, labelStatement.LabelToken); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,397 @@ |
|||||||
|
//
|
||||||
|
// NamingRule.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Xamarin <http://xamarin.com>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
using System; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||||
|
{ |
||||||
|
public class NamingRule |
||||||
|
{ |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set, identifiers are required to be prefixed with one of these values.
|
||||||
|
/// </summary>
|
||||||
|
public string[] RequiredPrefixes { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set, identifiers are required to be suffixed with one of these values.
|
||||||
|
/// </summary>
|
||||||
|
public string[] RequiredSuffixes { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set, identifiers cannot be prefixed by any of these values.
|
||||||
|
/// </summary>
|
||||||
|
public string[] ForbiddenPrefixes { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set, identifiers cannot be suffixed by with any of these values.
|
||||||
|
/// </summary
|
||||||
|
public string[] ForbiddenSuffixes { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the affected entity.
|
||||||
|
/// </summary>
|
||||||
|
public AffectedEntity AffectedEntity { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the modifiers mask
|
||||||
|
/// </summary>
|
||||||
|
public Modifiers VisibilityMask { get; set; } |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The way that the identifier is cased and that words are separated.
|
||||||
|
/// </summary
|
||||||
|
public NamingStyle NamingStyle { get; set; } |
||||||
|
|
||||||
|
public bool IsValid(string name) |
||||||
|
{ |
||||||
|
string id = name; |
||||||
|
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) { |
||||||
|
var prefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p)); |
||||||
|
if (prefix == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
id = id.Substring(prefix.Length); |
||||||
|
} else if (ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) { |
||||||
|
if (ForbiddenPrefixes.Any(p => id.StartsWith(p))) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) { |
||||||
|
var suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s)); |
||||||
|
if (suffix == null) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
id = id.Substring(0, id.Length - suffix.Length); |
||||||
|
} else if (ForbiddenSuffixes != null && ForbiddenSuffixes.Length > 0) { |
||||||
|
if (ForbiddenSuffixes.Any(p => id.EndsWith(p))) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
switch (NamingStyle) { |
||||||
|
case NamingStyle.AllLower: |
||||||
|
return !id.Any(ch => char.IsLetter(ch) && char.IsUpper(ch)); |
||||||
|
case NamingStyle.AllUpper: |
||||||
|
return !id.Any(ch => char.IsLetter(ch) && char.IsLower(ch)); |
||||||
|
case NamingStyle.CamelCase: |
||||||
|
return id.Length == 0 || (char.IsLower(id [0]) && NoUnderscoreWithoutNumber(id)); |
||||||
|
case NamingStyle.PascalCase: |
||||||
|
return id.Length == 0 || (char.IsUpper(id [0]) && NoUnderscoreWithoutNumber(id)); |
||||||
|
case NamingStyle.FirstUpper: |
||||||
|
return id.Length == 0 && char.IsUpper(id [0]) && !id.Skip(1).Any(ch => char.IsLetter(ch) && char.IsUpper(ch)); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public NamingRule(AffectedEntity affectedEntity) |
||||||
|
{ |
||||||
|
AffectedEntity = affectedEntity; |
||||||
|
VisibilityMask = Modifiers.VisibilityMask; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
static bool NoUnderscoreWithoutNumber(string id) |
||||||
|
{ |
||||||
|
int idx = id.IndexOf('_'); |
||||||
|
while (idx >= 0 && idx < id.Length) { |
||||||
|
if ((idx + 2 >= id.Length || !char.IsDigit(id [idx + 1])) && (idx == 0 || !char.IsDigit(id [idx - 1]))) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
idx = id.IndexOf('_', idx + 1); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public string GetPreview() |
||||||
|
{ |
||||||
|
var result = new StringBuilder(); |
||||||
|
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) { |
||||||
|
result.Append(RequiredPrefixes [0]); |
||||||
|
} |
||||||
|
switch (NamingStyle) { |
||||||
|
case NamingStyle.PascalCase: |
||||||
|
result.Append("PascalCase"); |
||||||
|
break; |
||||||
|
case NamingStyle.CamelCase: |
||||||
|
result.Append("camelCase"); |
||||||
|
break; |
||||||
|
case NamingStyle.AllUpper: |
||||||
|
result.Append("ALL_UPPER"); |
||||||
|
break; |
||||||
|
case NamingStyle.AllLower: |
||||||
|
result.Append("all_lower"); |
||||||
|
break; |
||||||
|
case NamingStyle.FirstUpper: |
||||||
|
result.Append("First_upper"); |
||||||
|
break; |
||||||
|
} |
||||||
|
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) { |
||||||
|
result.Append(RequiredSuffixes [0]); |
||||||
|
} |
||||||
|
return result.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
public string GetErrorMessage(BaseRefactoringContext ctx, string name, out IList<string> suggestedNames) |
||||||
|
{ |
||||||
|
suggestedNames = new List<string>(); |
||||||
|
string id = name; |
||||||
|
|
||||||
|
string errorMessage = null; |
||||||
|
|
||||||
|
bool missingRequiredPrefix = false; |
||||||
|
bool missingRequiredSuffix = false; |
||||||
|
string prefix = null; |
||||||
|
string suffix = null; |
||||||
|
|
||||||
|
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) { |
||||||
|
prefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p)); |
||||||
|
if (prefix == null) { |
||||||
|
errorMessage = string.Format(ctx.TranslateString("Name should have prefix '{0}'."), RequiredPrefixes [0]); |
||||||
|
missingRequiredPrefix = true; |
||||||
|
} else { |
||||||
|
id = id.Substring(prefix.Length); |
||||||
|
} |
||||||
|
} else if (ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) { |
||||||
|
prefix = ForbiddenPrefixes.FirstOrDefault(p => id.StartsWith(p)); |
||||||
|
if (prefix != null) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("Name has forbidden prefix '{0}'."), prefix); |
||||||
|
id = id.Substring(prefix.Length); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) { |
||||||
|
suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s)); |
||||||
|
if (suffix == null) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("Name should have suffix '{0}'."), RequiredSuffixes [0]); |
||||||
|
missingRequiredSuffix = true; |
||||||
|
} else { |
||||||
|
id = id.Substring(0, id.Length - suffix.Length); |
||||||
|
} |
||||||
|
} else if (ForbiddenSuffixes != null && ForbiddenSuffixes.Length > 0) { |
||||||
|
suffix = ForbiddenSuffixes.FirstOrDefault(p => id.EndsWith(p)); |
||||||
|
if (suffix != null) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("Name has forbidden suffix '{0}'."), suffix); |
||||||
|
id = id.Substring(0, id.Length - suffix.Length); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
switch (NamingStyle) { |
||||||
|
case NamingStyle.AllLower: |
||||||
|
if (id.Any(ch => char.IsLetter(ch) && char.IsUpper(ch))) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' contains upper case letters."), name); |
||||||
|
suggestedNames.Add(LowerCaseIdentifier(BreakWords(id))); |
||||||
|
} else { |
||||||
|
suggestedNames.Add(id); |
||||||
|
} |
||||||
|
break; |
||||||
|
case NamingStyle.AllUpper: |
||||||
|
if (id.Any(ch => char.IsLetter(ch) && char.IsLower(ch))) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' contains lower case letters."), name); |
||||||
|
suggestedNames.Add(UpperCaseIdentifier(BreakWords(id))); |
||||||
|
} else { |
||||||
|
suggestedNames.Add(id); |
||||||
|
} |
||||||
|
break; |
||||||
|
case NamingStyle.CamelCase: |
||||||
|
if (id.Length > 0 && char.IsUpper(id [0])) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' should start with a lower case letter."), name); |
||||||
|
} else if (!NoUnderscoreWithoutNumber(id)) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' should not separate words with an underscore."), name); |
||||||
|
} else { |
||||||
|
suggestedNames.Add(id); |
||||||
|
break; |
||||||
|
} |
||||||
|
suggestedNames.Add(CamelCaseIdentifier(BreakWords(id))); |
||||||
|
break; |
||||||
|
case NamingStyle.PascalCase: |
||||||
|
if (id.Length > 0 && char.IsLower(id [0])) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' should start with an upper case letter."), name); |
||||||
|
} else if (!NoUnderscoreWithoutNumber(id)) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' should not separate words with an underscore."), name); |
||||||
|
} else { |
||||||
|
suggestedNames.Add(id); |
||||||
|
break; |
||||||
|
} |
||||||
|
suggestedNames.Add(PascalCaseIdentifier(BreakWords(id))); |
||||||
|
break; |
||||||
|
case NamingStyle.FirstUpper: |
||||||
|
if (id.Length > 0 && char.IsLower(id [0])) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' should start with an upper case letter."), name); |
||||||
|
} else if (id.Take(1).Any(ch => char.IsLetter(ch) && char.IsUpper(ch))) { |
||||||
|
errorMessage = string.Format (ctx.TranslateString("'{0}' contains an upper case letter after the first."), name); |
||||||
|
} else { |
||||||
|
suggestedNames.Add(id); |
||||||
|
break; |
||||||
|
} |
||||||
|
suggestedNames.Add(FirstUpperIdentifier(BreakWords(id))); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (prefix != null) { |
||||||
|
for (int i = 0; i < suggestedNames.Count; i++) { |
||||||
|
suggestedNames [i] = prefix + suggestedNames [i]; |
||||||
|
} |
||||||
|
} else if (missingRequiredPrefix) { |
||||||
|
for (int i = 0; i < suggestedNames.Count; i++) { |
||||||
|
var n = suggestedNames [i]; |
||||||
|
bool first = true; |
||||||
|
foreach (var p in RequiredPrefixes) { |
||||||
|
if (first) { |
||||||
|
first = false; |
||||||
|
suggestedNames [i] = p + n; |
||||||
|
} else { |
||||||
|
suggestedNames.Add(p + n); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (suffix != null) { |
||||||
|
for (int i = 0; i < suggestedNames.Count; i++) { |
||||||
|
suggestedNames [i] = suggestedNames [i] + suffix; |
||||||
|
} |
||||||
|
} else if (missingRequiredSuffix) { |
||||||
|
for (int i = 0; i < suggestedNames.Count; i++) { |
||||||
|
var n = suggestedNames [i]; |
||||||
|
bool first = true; |
||||||
|
foreach (var s in RequiredSuffixes) { |
||||||
|
if (first) { |
||||||
|
first = false; |
||||||
|
suggestedNames [i] = n + s; |
||||||
|
} else { |
||||||
|
suggestedNames.Add(n + s); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return errorMessage |
||||||
|
// should never happen.
|
||||||
|
?? "no known errors."; |
||||||
|
} |
||||||
|
|
||||||
|
static List<string> BreakWords (string identifier) |
||||||
|
{ |
||||||
|
var words = new List<string> (); |
||||||
|
int wordStart = 0; |
||||||
|
bool lastWasLower = false, lastWasUpper = false; |
||||||
|
for (int i = 0; i < identifier.Length; i++) { |
||||||
|
char c = identifier[i]; |
||||||
|
if (c == '_') { |
||||||
|
if ((i - wordStart) > 0) { |
||||||
|
words.Add (identifier.Substring (wordStart, i - wordStart)); |
||||||
|
} |
||||||
|
wordStart = i + 1; |
||||||
|
lastWasLower = lastWasUpper = false; |
||||||
|
} else if (Char.IsLower (c)) { |
||||||
|
if (lastWasUpper && (i - wordStart) > 2) { |
||||||
|
words.Add (identifier.Substring (wordStart, i - wordStart - 1)); |
||||||
|
wordStart = i - 1; |
||||||
|
} |
||||||
|
lastWasLower = true; |
||||||
|
lastWasUpper = false; |
||||||
|
} else if (Char.IsUpper (c)) { |
||||||
|
if (lastWasLower) { |
||||||
|
words.Add (identifier.Substring (wordStart, i - wordStart)); |
||||||
|
wordStart = i; |
||||||
|
} |
||||||
|
lastWasLower = false; |
||||||
|
lastWasUpper = true; |
||||||
|
} |
||||||
|
} |
||||||
|
if (wordStart < identifier.Length) |
||||||
|
words.Add (identifier.Substring (wordStart)); |
||||||
|
return words; |
||||||
|
} |
||||||
|
|
||||||
|
static string CamelCaseIdentifier (List<string> words) |
||||||
|
{ |
||||||
|
var sb = new StringBuilder (); |
||||||
|
sb.Append (words[0].ToLower ()); |
||||||
|
for (int i = 1; i < words.Count; i++) { |
||||||
|
if (sb.Length > 0 && (char.IsDigit (sb[sb.Length-1]) || char.IsDigit (words[i][0]))) |
||||||
|
sb.Append ('_'); |
||||||
|
AppendCapitalized (words[i], sb); |
||||||
|
} |
||||||
|
return sb.ToString (); |
||||||
|
} |
||||||
|
|
||||||
|
static string PascalCaseIdentifier (List<string> words) |
||||||
|
{ |
||||||
|
var sb = new StringBuilder (); |
||||||
|
for (int i = 0; i < words.Count; i++) { |
||||||
|
if (sb.Length > 0 && (char.IsDigit (sb[sb.Length-1]) || char.IsDigit (words[i][0]))) |
||||||
|
sb.Append ('_'); |
||||||
|
AppendCapitalized (words[i], sb); |
||||||
|
} |
||||||
|
return sb.ToString (); |
||||||
|
} |
||||||
|
|
||||||
|
static string LowerCaseIdentifier (List<string> words) |
||||||
|
{ |
||||||
|
var sb = new StringBuilder (); |
||||||
|
sb.Append (words[0].ToLower ()); |
||||||
|
for (int i = 1; i < words.Count; i++) { |
||||||
|
sb.Append ('_'); |
||||||
|
sb.Append (words[i].ToLower ()); |
||||||
|
} |
||||||
|
return sb.ToString (); |
||||||
|
} |
||||||
|
|
||||||
|
static string UpperCaseIdentifier (List<string> words) |
||||||
|
{ |
||||||
|
var sb = new StringBuilder (); |
||||||
|
sb.Append (words[0].ToUpper ()); |
||||||
|
for (int i = 1; i < words.Count; i++) { |
||||||
|
sb.Append ('_'); |
||||||
|
sb.Append (words[i].ToUpper ()); |
||||||
|
} |
||||||
|
return sb.ToString (); |
||||||
|
} |
||||||
|
|
||||||
|
static string FirstUpperIdentifier (List<string> words) |
||||||
|
{ |
||||||
|
var sb = new StringBuilder (); |
||||||
|
AppendCapitalized (words[0], sb); |
||||||
|
for (int i = 1; i < words.Count; i++) { |
||||||
|
sb.Append ('_'); |
||||||
|
sb.Append (words[i].ToLower ()); |
||||||
|
} |
||||||
|
return sb.ToString (); |
||||||
|
} |
||||||
|
|
||||||
|
static void AppendCapitalized(string word, StringBuilder sb) |
||||||
|
{ |
||||||
|
sb.Append(word.ToLower()); |
||||||
|
sb [sb.Length - word.Length] = char.ToUpper(sb [sb.Length - word.Length]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,59 @@ |
|||||||
|
//
|
||||||
|
// NamingStyle.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Xamarin <http://xamarin.com>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory.CSharp.Refactoring |
||||||
|
{ |
||||||
|
public enum NamingStyle { |
||||||
|
None, |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PascalCase
|
||||||
|
/// </summary>
|
||||||
|
PascalCase, |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// camelCase
|
||||||
|
/// </summary>
|
||||||
|
CamelCase, |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ALLUPPER
|
||||||
|
/// </summary>
|
||||||
|
AllUpper, |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// alllower
|
||||||
|
/// </summary>
|
||||||
|
AllLower, |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Firstupper
|
||||||
|
/// </summary>
|
||||||
|
FirstUpper |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,37 @@ |
|||||||
|
//
|
||||||
|
// InconsistentNamingIssueTests.cs
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Mike Krüger <mkrueger@xamarin.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 Xamarin <http://xamarin.com>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
using System; |
||||||
|
|
||||||
|
namespace ICSharpCode.NRefactory |
||||||
|
{ |
||||||
|
public class InconsistentNamingIssueTests |
||||||
|
{ |
||||||
|
public InconsistentNamingIssueTests () |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
Loading…
Reference in new issue