.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

232 lines
6.6 KiB

//
// NamingHelper.cs
//
// Author:
// Simon Lindgren <simon.n.lindgren@gmail.com>
//
// Copyright (c) 2012 Simon Lindgren
//
// 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.Text;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Semantics;
namespace ICSharpCode.NRefactory.CSharp.Refactoring
{
public class NamingHelper
{
ISet<string> usedVariableNames;
RefactoringContext context;
public NamingHelper(RefactoringContext context)
{
this.context = context;
if (usedVariableNames == null) {
var visitor = new VariableFinderVisitor();
var astNode = context.GetNode<Statement>();
astNode.AcceptVisitor(visitor);
usedVariableNames = visitor.VariableNames;
}
}
public static IEnumerable<string> GenerateNameProposals(AstType type)
{
if (type is PrimitiveType) {
var pt = (PrimitiveType)type;
switch (pt.Keyword) {
case "object":
yield return "o";
yield return "obj";
break;
case "bool":
yield return "b";
yield return "pred";
break;
case "double":
case "float":
case "decimal":
yield return "d";
yield return "f";
yield return "m";
break;
case "char":
yield return "c";
break;
default:
yield return "i";
yield return "j";
yield return "k";
break;
}
yield break;
}
string name;
if (type is SimpleType) {
name = ((SimpleType)type).Identifier;
} else if (type is MemberType) {
name = ((MemberType)type).MemberName;
} else {
yield break;
}
var names = WordParser.BreakWords(name);
if (names.Count > 0) {
names [0] = Char.ToLower(names [0] [0]) + names [0].Substring(1);
}
yield return string.Join("", names);
}
/// <summary>
/// Generates a variable name for a variable of the specified type.
/// </summary>
/// <returns>
/// The variable name.
/// </returns>
/// <param name='type'>
/// The type of the variable.
/// </param>
public string GenerateVariableName(AstType type)
{
string firstSuggestion = null;
foreach (var name in NamingHelper.GenerateNameProposals(type)) {
firstSuggestion = firstSuggestion ?? name;
if (NameIsUnused(name)) {
usedVariableNames.Add(name);
return name;
}
}
// If we get here, all of the standard suggestions are already used.
// This will at least be the second variable named based on firstSuggestion, so start at 2
int counter = 2;
string proposedName;
do {
proposedName = firstSuggestion + counter++;
} while (!NameIsUnused(proposedName));
usedVariableNames.Add(proposedName);
return proposedName;
}
bool NameIsUnused(string name)
{
return !usedVariableNames.Contains(name) && LookupVariable(name) == null;
}
/// <summary>
/// Generates a variable name for a variable of the specified type.
/// </summary>
/// <returns>
/// The variable name.
/// </returns>
/// <param name='type'>
/// The type of the variable.
/// </param>
public string GenerateVariableName(IType type)
{
AstType astType = ToAstType(type);
return GenerateVariableName(astType);
}
AstType ToAstType(IType type)
{
switch (type.FullName) {
case "System.Object":
return new PrimitiveType("object");
case "System.String":
return new PrimitiveType("string");
case "System.Boolean":
return new PrimitiveType("bool");
case "System.Char":
return new PrimitiveType("char");
case "System.SByte":
return new PrimitiveType("sbyte");
case "System.Byte":
return new PrimitiveType("byte");
case "System.Int16":
return new PrimitiveType("short");
case "System.UInt16":
return new PrimitiveType("ushort");
case "System.Int32":
return new PrimitiveType("int");
case "System.UInt32":
return new PrimitiveType("uint");
case "System.Int64":
return new PrimitiveType("long");
case "System.UInt64":
return new PrimitiveType("ulong");
case "System.Single":
return new PrimitiveType("float");
case "System.Double":
return new PrimitiveType("double");
case "System.Decimal":
return new PrimitiveType("decimal");
default:
return new SimpleType(type.Name);
}
}
IVariable LookupVariable(string name)
{
var blockStatement = context.GetNode<BlockStatement>();
var resolverState = context.GetResolverStateAfter(blockStatement.RBraceToken.PrevSibling);
var simpleNameRR = resolverState.ResolveSimpleName(name, new List<IType>()) as LocalResolveResult;
if (simpleNameRR == null)
return null;
return simpleNameRR.Variable;
}
class VariableFinderVisitor : DepthFirstAstVisitor
{
public ISet<string> VariableNames = new HashSet<string>();
public override void VisitVariableInitializer(VariableInitializer variableInitializer)
{
ProcessName(variableInitializer.Name);
base.VisitVariableInitializer(variableInitializer);
}
public override void VisitQueryLetClause(QueryLetClause queryLetClause)
{
ProcessName(queryLetClause.Identifier);
base.VisitQueryLetClause(queryLetClause);
}
public override void VisitQueryFromClause(QueryFromClause queryFromClause)
{
ProcessName(queryFromClause.Identifier);
base.VisitQueryFromClause(queryFromClause);
}
public override void VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
{
ProcessName(queryContinuationClause.Identifier);
base.VisitQueryContinuationClause(queryContinuationClause);
}
void ProcessName(string name)
{
if (!VariableNames.Contains(name))
VariableNames.Add(name);
}
}
}
}