#develop (short for SharpDevelop) is a free IDE for .NET programming languages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

397 lines
13 KiB

//
// NamingRule.cs
//
// Author:
// Michael Hutchinson <mhutch@xamarin.com>
// 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 : IEquatable<NamingRule>
{
public string Name { get; set; }
/// <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 allowed to be prefixed with one of these values.
/// </summary>
public string[] AllowedPrefixes { 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 IncludeStaticEntities { get; set; }
public bool IncludeInstanceMembers { get; set; }
public bool IsValid(string name)
{
string id = name;
bool foundPrefix = false;
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) {
var prefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (prefix == null) {
return false;
}
id = id.Substring(prefix.Length);
foundPrefix = true;
}
if (!foundPrefix && AllowedPrefixes != null && AllowedPrefixes.Length > 0) {
var prefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (prefix != null) {
id = id.Substring(prefix.Length);
foundPrefix = true;
}
}
if (!foundPrefix && ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) {
if (ForbiddenPrefixes.Any(p => id.StartsWith(p, StringComparison.Ordinal))) {
return false;
}
}
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) {
var suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s, StringComparison.Ordinal));
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, StringComparison.Ordinal))) {
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]) && NoUnderscore(id));
case NamingStyle.PascalCase:
return id.Length == 0 || (char.IsUpper(id [0]) && NoUnderscore(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;
IncludeStaticEntities = true;
IncludeInstanceMembers = true;
}
static bool NoUnderscore(string id)
{
return id.IndexOf('_') < 0;
}
// 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 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 requiredPrefix = null;
string allowedPrefix = null;
string suffix = null;
if (AllowedPrefixes != null && AllowedPrefixes.Length > 0) {
allowedPrefix = AllowedPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (allowedPrefix != null)
id = id.Substring(allowedPrefix.Length);
}
if (RequiredPrefixes != null && RequiredPrefixes.Length > 0) {
requiredPrefix = RequiredPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (requiredPrefix == null) {
errorMessage = string.Format(ctx.TranslateString("Name should have prefix '{0}'."), RequiredPrefixes [0]);
missingRequiredPrefix = true;
} else {
id = id.Substring(requiredPrefix.Length);
}
} else if (ForbiddenPrefixes != null && ForbiddenPrefixes.Length > 0) {
requiredPrefix = ForbiddenPrefixes.FirstOrDefault(p => id.StartsWith(p, StringComparison.Ordinal));
if (requiredPrefix != null) {
errorMessage = string.Format(ctx.TranslateString("Name has forbidden prefix '{0}'."), requiredPrefix);
id = id.Substring(requiredPrefix.Length);
}
}
if (RequiredSuffixes != null && RequiredSuffixes.Length > 0) {
suffix = RequiredSuffixes.FirstOrDefault(s => id.EndsWith(s, StringComparison.Ordinal));
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, StringComparison.Ordinal));
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(WordParser.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(WordParser.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 (!NoUnderscore(id)) {
errorMessage = string.Format(ctx.TranslateString("'{0}' should not separate words with an underscore."), name);
} else {
suggestedNames.Add(id);
break;
}
suggestedNames.Add(CamelCaseIdentifier(WordParser.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 (!NoUnderscore(id)) {
errorMessage = string.Format(ctx.TranslateString("'{0}' should not separate words with an underscore."), name);
} else {
suggestedNames.Add(id);
break;
}
suggestedNames.Add(PascalCaseIdentifier(WordParser.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(WordParser.BreakWords(id)));
break;
}
if (requiredPrefix != null) {
for (int i = 0; i < suggestedNames.Count; i++) {
suggestedNames [i] = requiredPrefix + suggestedNames [i];
}
} else if (allowedPrefix != null) {
int count = suggestedNames.Count;
for (int i = 0; i < count; i++) {
suggestedNames.Add(suggestedNames [i]);
suggestedNames [i] = allowedPrefix + 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 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]);
}
#region IEquatable implementation
public bool Equals (NamingRule other)
{
return Name == other.Name &&
AffectedEntity == other.AffectedEntity &&
VisibilityMask == other.VisibilityMask &&
NamingStyle == other.NamingStyle;
}
#endregion
public NamingRule Clone()
{
return (NamingRule)MemberwiseClone();
}
public override string ToString()
{
return string.Format("[NamingRule: Name={0}, AffectedEntity={1}, VisibilityMask={2}, NamingStyle={3}, IncludeStaticEntities={4}, IncludeInstanceMembers={5}]", Name, AffectedEntity, VisibilityMask, NamingStyle, IncludeStaticEntities, IncludeInstanceMembers);
}
}
}