11 changed files with 885 additions and 5 deletions
@ -0,0 +1,72 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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