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

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

@ -343,6 +343,11 @@ @@ -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 @@ @@ -354,6 +359,7 @@
<ItemGroup>
<Folder Include="Completion\" />
<Folder Include="Refactoring\CodeIssues\" />
<Folder Include="Refactoring\CodeIssues\InconsistentNamingIssue\" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>

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

@ -54,8 +54,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -54,8 +54,20 @@ namespace ICSharpCode.NRefactory.CSharp
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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ -49,9 +49,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
),
// 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 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring @@ -64,9 +64,9 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
),
// 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 ())
),
};

37
ICSharpCode.NRefactory.Tests/CSharp/Inspector/InconsistentNamingIssueTests.cs

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

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

@ -247,6 +247,7 @@ @@ -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">

Loading…
Cancel
Save