Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Worked on inconsistent naming issue.

  • Loading branch information...
commit 41d5b50008b8cbe10c0f29e29114d6bc5627eaec 1 parent a179782
@mkrueger mkrueger authored
View
5 ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs
@@ -40,6 +40,11 @@ public class LabelStatement : Statement
}
}
+ public Identifier LabelToken {
+ get { return GetChildByRole (Roles.Identifier); }
+ set { SetChildByRole (Roles.Identifier, value); }
+ }
+
public CSharpTokenNode Colon {
get { return GetChildByRole (Roles.Colon); }
}
View
6 ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
@@ -343,6 +343,11 @@
<Compile Include="Refactoring\CodeActions\ConvertDecToHexAction.cs" />
<Compile Include="Refactoring\CodeActions\CheckIfParameterIsNullAction.cs" />
<Compile Include="Refactoring\CodeActions\AddAnotherAccessorAction.cs" />
+ <Compile Include="Refactoring\CodeIssues\InconsistentNamingIssue\NamingStyle.cs" />
+ <Compile Include="Refactoring\CodeIssues\InconsistentNamingIssue\NamingRule.cs" />
+ <Compile Include="Refactoring\CodeIssues\InconsistentNamingIssue\AffectedEntity.cs" />
+ <Compile Include="Refactoring\CodeIssues\InconsistentNamingIssue\DefaultRules.cs" />
+ <Compile Include="Refactoring\CodeIssues\InconsistentNamingIssue\InconsistentNamingIssue.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@@ -354,6 +359,7 @@
<ItemGroup>
<Folder Include="Completion\" />
<Folder Include="Refactoring\CodeIssues\" />
+ <Folder Include="Refactoring\CodeIssues\InconsistentNamingIssue\" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
View
14 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs
@@ -54,8 +54,20 @@ protected void AddIssue(AstNode node, string title, System.Action<Script> fix =
protected void AddIssue(TextLocation start, TextLocation end, string title, System.Action<Script> fix = null)
{
- FoundIssues.Add(new CodeIssue (title, start, end, fix != null ? new CodeAction (title, fix) : null));
+ FoundIssues.Add(new CodeIssue(title, start, end, fix != null ? new CodeAction(title, fix) : null));
}
+
+ protected void AddIssue(AstNode node, string title, IEnumerable<CodeAction> fixes)
+ {
+ FoundIssues.Add(new CodeIssue(title, node.StartLocation, node.EndLocation, fixes));
+ }
+
+ protected void AddIssue(TextLocation start, TextLocation end, string title, IEnumerable<CodeAction> fixes)
+ {
+ FoundIssues.Add(new CodeIssue (title, start, end, fixes));
+ }
+
+
}
View
72 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/AffectedEntity.cs
@@ -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,
+
+ }
+}
View
106 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs
@@ -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
+ };
+ }
+ }
+}
+
View
185 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs
@@ -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);
+ }
+ }
+
+ }
+}
+
View
397 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingRule.cs
@@ -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]);
+ }
+ }
+}
+
View
59 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingStyle.cs
@@ -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
+ }
+
+}
+
View
8 ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs
@@ -49,9 +49,9 @@ public class StringIsNullOrEmptyIssue : ICodeIssueProvider
),
// str == "" || str == null
new BinaryOperatorExpression (
- PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.Equality, new PrimitiveExpression ("")),
+ PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.Equality, new PrimitiveExpression ("")),
BinaryOperatorType.ConditionalOr,
- PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.Equality, new NullReferenceExpression ())
+ PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.Equality, new NullReferenceExpression ())
),
};
@@ -64,9 +64,9 @@ public class StringIsNullOrEmptyIssue : ICodeIssueProvider
),
// str != "" && str != null
new BinaryOperatorExpression (
- PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.InEquality, new PrimitiveExpression ("")),
+ PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.InEquality, new PrimitiveExpression ("")),
BinaryOperatorType.ConditionalAnd,
- PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.InEquality, new NullReferenceExpression ())
+ PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.InEquality, new NullReferenceExpression ())
),
};
View
37 ICSharpCode.NRefactory.Tests/CSharp/Inspector/InconsistentNamingIssueTests.cs
@@ -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 ()
+ {
+ }
+ }
+}
+
View
1  ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj
@@ -247,6 +247,7 @@
<Compile Include="CSharp\CodeActions\AddAnotherAccessorTests.cs" />
<Compile Include="CSharp\CodeActions\RemoveRegionTests.cs" />
<Compile Include="CSharp\CodeActions\GeneratePropertyTests.cs" />
+ <Compile Include="CSharp\Inspector\InconsistentNamingIssueTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">
Please sign in to comment.
Something went wrong with that request. Please try again.