Browse Source

Worked on inconsistent naming issue.

newNRvisualizers
Mike Krüger 14 years ago
parent
commit
41d5b50008
  1. 5
      ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs
  2. 6
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  3. 14
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs
  4. 72
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/AffectedEntity.cs
  5. 106
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/DefaultRules.cs
  6. 185
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/InconsistentNamingIssue.cs
  7. 397
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingRule.cs
  8. 59
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/InconsistentNamingIssue/NamingStyle.cs
  9. 8
      ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs
  10. 37
      ICSharpCode.NRefactory.Tests/CSharp/Inspector/InconsistentNamingIssueTests.cs
  11. 1
      ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

5
ICSharpCode.NRefactory.CSharp/Ast/Statements/LabelStatement.cs

@ -40,6 +40,11 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public Identifier LabelToken {
get { return GetChildByRole (Roles.Identifier); }
set { SetChildByRole (Roles.Identifier, value); }
}
public CSharpTokenNode Colon { public CSharpTokenNode Colon {
get { return GetChildByRole (Roles.Colon); } get { return GetChildByRole (Roles.Colon); }
} }

6
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -343,6 +343,11 @@
<Compile Include="Refactoring\CodeActions\ConvertDecToHexAction.cs" /> <Compile Include="Refactoring\CodeActions\ConvertDecToHexAction.cs" />
<Compile Include="Refactoring\CodeActions\CheckIfParameterIsNullAction.cs" /> <Compile Include="Refactoring\CodeActions\CheckIfParameterIsNullAction.cs" />
<Compile Include="Refactoring\CodeActions\AddAnotherAccessorAction.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>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
@ -354,6 +359,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="Completion\" /> <Folder Include="Completion\" />
<Folder Include="Refactoring\CodeIssues\" /> <Folder Include="Refactoring\CodeIssues\" />
<Folder Include="Refactoring\CodeIssues\InconsistentNamingIssue\" />
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>

14
ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/GatherVisitorBase.cs

@ -54,8 +54,20 @@ namespace ICSharpCode.NRefactory.CSharp
protected void AddIssue(TextLocation start, TextLocation end, string title, System.Action<Script> fix = null) 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));
}
} }

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,
}
}

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
};
}
}
}

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);
}
}
}
}

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]);
}
}
}

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
}
}

8
ICSharpCode.NRefactory.CSharp/Refactoring/CodeIssues/StringIsNullOrEmptyIssue.cs

@ -49,9 +49,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
), ),
// str == "" || str == null // str == "" || str == null
new BinaryOperatorExpression ( new BinaryOperatorExpression (
PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.Equality, new PrimitiveExpression ("")), PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.Equality, new PrimitiveExpression ("")),
BinaryOperatorType.ConditionalOr, BinaryOperatorType.ConditionalOr,
PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.Equality, new NullReferenceExpression ()) PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.Equality, new NullReferenceExpression ())
), ),
}; };
@ -64,9 +64,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
), ),
// str != "" && str != null // str != "" && str != null
new BinaryOperatorExpression ( new BinaryOperatorExpression (
PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.InEquality, new PrimitiveExpression ("")), PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.InEquality, new PrimitiveExpression ("")),
BinaryOperatorType.ConditionalAnd, BinaryOperatorType.ConditionalAnd,
PatternHelper.CommutativeOperator(new AnyNode ("str"), BinaryOperatorType.InEquality, new NullReferenceExpression ()) PatternHelper.CommutativeOperator(new Backreference ("str"), BinaryOperatorType.InEquality, new NullReferenceExpression ())
), ),
}; };

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 ()
{
}
}
}

1
ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -247,6 +247,7 @@
<Compile Include="CSharp\CodeActions\AddAnotherAccessorTests.cs" /> <Compile Include="CSharp\CodeActions\AddAnotherAccessorTests.cs" />
<Compile Include="CSharp\CodeActions\RemoveRegionTests.cs" /> <Compile Include="CSharp\CodeActions\RemoveRegionTests.cs" />
<Compile Include="CSharp\CodeActions\GeneratePropertyTests.cs" /> <Compile Include="CSharp\CodeActions\GeneratePropertyTests.cs" />
<Compile Include="CSharp\Inspector\InconsistentNamingIssueTests.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj"> <ProjectReference Include="..\..\Mono.Cecil\Mono.Cecil.csproj">

Loading…
Cancel
Save