5
// Simon Lindgren <simon.n.lindgren@gmail.com>
7
// Copyright (c) 2012 Simon Lindgren
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
using System.Collections.Generic;
29
using ICSharpCode.NRefactory.TypeSystem;
30
using ICSharpCode.NRefactory.Semantics;
32
namespace ICSharpCode.NRefactory.CSharp.Refactoring
34
public class NamingHelper
36
ISet<string> usedVariableNames;
37
RefactoringContext context;
39
public NamingHelper(RefactoringContext context)
41
this.context = context;
42
if (usedVariableNames == null) {
43
var visitor = new VariableFinderVisitor();
44
var astNode = context.GetNode<Statement>();
45
astNode.AcceptVisitor(visitor);
46
usedVariableNames = visitor.VariableNames;
50
public static IEnumerable<string> GenerateNameProposals(AstType type)
52
if (type is PrimitiveType) {
53
var pt = (PrimitiveType)type;
82
if (type is SimpleType) {
83
name = ((SimpleType)type).Identifier;
84
} else if (type is MemberType) {
85
name = ((MemberType)type).MemberName;
90
var names = WordParser.BreakWords(name);
91
if (names.Count > 0) {
92
names [0] = Char.ToLower(names [0] [0]) + names [0].Substring(1);
94
yield return string.Join("", names);
98
/// Generates a variable name for a variable of the specified type.
101
/// The variable name.
103
/// <param name='type'>
104
/// The type of the variable.
106
/// <param name='baseName'>
107
/// Suggested base name.
109
public string GenerateVariableName(AstType type, string baseName = null)
111
if (baseName == null) {
112
foreach (var name in NamingHelper.GenerateNameProposals(type)) {
113
baseName = baseName ?? name;
114
if (NameIsUnused(name)) {
115
usedVariableNames.Add(name);
119
} else if (NameIsUnused(baseName)) {
123
// If we get here, all of the standard suggestions are already used.
124
// This will at least be the second variable named based on firstSuggestion, so start at 2
128
proposedName = baseName + counter++;
129
} while (!NameIsUnused(proposedName));
130
usedVariableNames.Add(proposedName);
134
bool NameIsUnused(string name)
136
return !usedVariableNames.Contains(name) && LookupVariable(name) == null;
140
/// Generates a variable name for a variable of the specified type.
143
/// The variable name.
145
/// <param name='type'>
146
/// The type of the variable.
148
/// <param name='baseName'>
149
/// Suggested base name.
151
public string GenerateVariableName(IType type, string baseName = null)
153
AstType astType = ToAstType(type);
154
return GenerateVariableName(astType, baseName);
157
AstType ToAstType(IType type)
159
switch (type.FullName) {
160
case "System.Object":
161
return new PrimitiveType("object");
162
case "System.String":
163
return new PrimitiveType("string");
164
case "System.Boolean":
165
return new PrimitiveType("bool");
167
return new PrimitiveType("char");
169
return new PrimitiveType("sbyte");
171
return new PrimitiveType("byte");
173
return new PrimitiveType("short");
174
case "System.UInt16":
175
return new PrimitiveType("ushort");
177
return new PrimitiveType("int");
178
case "System.UInt32":
179
return new PrimitiveType("uint");
181
return new PrimitiveType("long");
182
case "System.UInt64":
183
return new PrimitiveType("ulong");
184
case "System.Single":
185
return new PrimitiveType("float");
186
case "System.Double":
187
return new PrimitiveType("double");
188
case "System.Decimal":
189
return new PrimitiveType("decimal");
191
return new SimpleType(type.Name);
195
IVariable LookupVariable(string name)
197
var blockStatement = context.GetNode<BlockStatement>();
198
var resolverState = context.GetResolverStateAfter(blockStatement.RBraceToken.PrevSibling);
199
var simpleNameRR = resolverState.ResolveSimpleName(name, new List<IType>()) as LocalResolveResult;
200
if (simpleNameRR == null)
202
return simpleNameRR.Variable;
205
class VariableFinderVisitor : DepthFirstAstVisitor
208
public ISet<string> VariableNames = new HashSet<string>();
210
public override void VisitVariableInitializer(VariableInitializer variableInitializer)
212
ProcessName(variableInitializer.Name);
213
base.VisitVariableInitializer(variableInitializer);
216
public override void VisitQueryLetClause(QueryLetClause queryLetClause)
218
ProcessName(queryLetClause.Identifier);
219
base.VisitQueryLetClause(queryLetClause);
222
public override void VisitQueryFromClause(QueryFromClause queryFromClause)
224
ProcessName(queryFromClause.Identifier);
225
base.VisitQueryFromClause(queryFromClause);
228
public override void VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
230
ProcessName(queryContinuationClause.Identifier);
231
base.VisitQueryContinuationClause(queryContinuationClause);
234
void ProcessName(string name)
236
if (!VariableNames.Contains(name))
237
VariableNames.Add(name);