2
// VariableLookupVisitor.cs
5
// Mike KrĆ¼ger <mkrueger@novell.com>
7
// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
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
29
using System.Collections.Generic;
30
using ICSharpCode.NRefactory.Visitors;
31
using ICSharpCode.NRefactory.Ast;
32
using MonoDevelop.Projects.Dom;
33
using MonoDevelop.Projects.Dom.Parser;
34
using ICSharpCode.NRefactory;
35
using Mono.TextEditor;
37
namespace MonoDevelop.Refactoring.ExtractMethod
39
public class VariableDescriptor
46
public bool GetsChanged {
51
public bool InitialValueUsed {
56
public bool GetsAssigned {
61
public bool IsDefined {
66
public IReturnType ReturnType {
71
public DocumentLocation Location {
76
public VariableDescriptor (string name)
79
this.GetsChanged = this.IsDefined = this.InitialValueUsed = false;
82
public override string ToString ()
84
return string.Format("[VariableDescriptor: Name={0}, GetsChanged={1}, InitialValueUsed={2}, GetsAssigned={3}, IsDefined={4}, ReturnType={5}, Location={6}]", Name, GetsChanged, InitialValueUsed, GetsAssigned, IsDefined, ReturnType, Location);
88
public class VariableLookupVisitor : AbstractAstVisitor
90
List<KeyValuePair <string, IReturnType>> unknownVariables = new List<KeyValuePair <string, IReturnType>> ();
91
Dictionary<string, VariableDescriptor> variables = new Dictionary<string, VariableDescriptor> ();
93
public bool ReferencesMember {
98
public List<KeyValuePair <string, IReturnType>> UnknownVariables {
100
return unknownVariables;
104
public Dictionary<string, VariableDescriptor> Variables {
110
public List<VariableDescriptor> VariableList {
112
return new List<VariableDescriptor> (variables.Values);
116
public Location MemberLocation {
122
DomLocation position;
123
public DomRegion CutRegion {
127
public VariableLookupVisitor (IResolver resolver, DomLocation position)
129
this.resolver = resolver;
130
this.position = position;
131
this.MemberLocation = Location.Empty;
134
static IReturnType ConvertTypeReference (TypeReference typeRef)
138
DomReturnType result = new DomReturnType (typeRef.Type);
139
foreach (TypeReference genericArgument in typeRef.GenericTypes) {
140
result.AddTypeParameter (ConvertTypeReference (genericArgument));
142
result.PointerNestingLevel = typeRef.PointerNestingLevel;
143
if (typeRef.IsArrayType) {
144
result.ArrayDimensions = typeRef.RankSpecifier.Length;
145
for (int i = 0; i < typeRef.RankSpecifier.Length; i++) {
146
result.SetDimension (i, typeRef.RankSpecifier[i]);
152
public override object VisitLocalVariableDeclaration (LocalVariableDeclaration localVariableDeclaration, object data)
154
if (!CutRegion.Contains (localVariableDeclaration.StartLocation.Line - 1, localVariableDeclaration.StartLocation.Column -1)) {
155
foreach (VariableDeclaration varDecl in localVariableDeclaration.Variables) {
156
variables[varDecl.Name] = new VariableDescriptor (varDecl.Name) {
158
ReturnType = ConvertTypeReference (localVariableDeclaration.TypeReference),
159
Location = new DocumentLocation (MemberLocation.Line + localVariableDeclaration.StartLocation.Line - 1, localVariableDeclaration.StartLocation.Column - 1)
163
return base.VisitLocalVariableDeclaration(localVariableDeclaration, data);
166
public override object VisitIdentifierExpression (ICSharpCode.NRefactory.Ast.IdentifierExpression identifierExpression, object data)
168
if (!variables.ContainsKey (identifierExpression.Identifier)) {
170
ExpressionResult expressionResult = new ExpressionResult (identifierExpression.Identifier);
172
ResolveResult result = resolver.Resolve (expressionResult, position);
174
MemberResolveResult mrr = result as MemberResolveResult;
175
ReferencesMember |= mrr != null && mrr.ResolvedMember != null && !mrr.ResolvedMember.IsStatic;
177
if (!(result is LocalVariableResolveResult || result is ParameterResolveResult))
178
return base.VisitIdentifierExpression (identifierExpression, data);
180
// result.ResolvedType == null may be true for namespace names or undeclared variables
181
if (!result.StaticResolve && !variables.ContainsKey (identifierExpression.Identifier)) {
182
variables[identifierExpression.Identifier] = new VariableDescriptor (identifierExpression.Identifier) {
183
InitialValueUsed = !valueGetsChanged,
184
Location = new DocumentLocation (MemberLocation.Line + identifierExpression.StartLocation.Line - 1, identifierExpression.StartLocation.Column - 1)
187
variables[identifierExpression.Identifier].ReturnType = result.ResolvedType;
189
if (result != null && !result.StaticResolve && result.ResolvedType != null && !(result is MethodResolveResult) && !(result is NamespaceResolveResult) && !(result is MemberResolveResult))
190
unknownVariables.Add (new KeyValuePair <string, IReturnType> (identifierExpression.Identifier, result.ResolvedType));
192
return base.VisitIdentifierExpression (identifierExpression, data);
194
bool valueGetsChanged = false;
195
public override object VisitAssignmentExpression (ICSharpCode.NRefactory.Ast.AssignmentExpression assignmentExpression, object data)
197
assignmentExpression.Right.AcceptVisitor(this, data);
199
valueGetsChanged = true;
200
IdentifierExpression left = assignmentExpression.Left as IdentifierExpression;
201
bool isInitialUse = left != null && !variables.ContainsKey (left.Identifier);
202
assignmentExpression.Left.AcceptVisitor(this, data);
203
valueGetsChanged = false;
205
if (left != null && variables.ContainsKey (left.Identifier)) {
206
variables[left.Identifier].GetsChanged = true;
208
variables[left.Identifier].GetsAssigned = true;
213
public override object VisitUnaryOperatorExpression (ICSharpCode.NRefactory.Ast.UnaryOperatorExpression unaryOperatorExpression, object data)
215
switch (unaryOperatorExpression.Op) {
216
case UnaryOperatorType.Increment:
217
case UnaryOperatorType.Decrement:
218
case UnaryOperatorType.PostIncrement:
219
case UnaryOperatorType.PostDecrement:
220
valueGetsChanged = true;
223
object result = base.VisitUnaryOperatorExpression (unaryOperatorExpression, data);
224
valueGetsChanged = false;
225
switch (unaryOperatorExpression.Op) {
226
case UnaryOperatorType.Increment:
227
case UnaryOperatorType.Decrement:
228
case UnaryOperatorType.PostIncrement:
229
case UnaryOperatorType.PostDecrement:
230
IdentifierExpression left = unaryOperatorExpression.Expression as IdentifierExpression;
231
if (left != null && variables.ContainsKey (left.Identifier))
232
variables[left.Identifier].GetsChanged = true;
238
public override object VisitDirectionExpression (ICSharpCode.NRefactory.Ast.DirectionExpression directionExpression, object data)
240
valueGetsChanged = true;
241
IdentifierExpression left = directionExpression.Expression as IdentifierExpression;
242
bool isInitialUse = left != null && !variables.ContainsKey (left.Identifier);
243
object result = base.VisitDirectionExpression (directionExpression, data);
244
valueGetsChanged = false;
245
if (left != null && variables.ContainsKey (left.Identifier)) {
246
variables[left.Identifier].GetsChanged = true;
247
if (isInitialUse && directionExpression.FieldDirection == FieldDirection.Out)
248
variables[left.Identifier].GetsAssigned = true;
254
public override object VisitMethodDeclaration (MethodDeclaration methodDeclaration, object data)
256
if (!MemberLocation.IsEmpty && methodDeclaration.StartLocation.Line != MemberLocation.Line)
258
return base.VisitMethodDeclaration (methodDeclaration, data);
261
public override object VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, object data)
263
if (!MemberLocation.IsEmpty && propertyDeclaration.StartLocation.Line != MemberLocation.Line)
265
return base.VisitPropertyDeclaration (propertyDeclaration, data);
268
public override object VisitEventDeclaration (EventDeclaration eventDeclaration, object data)
270
if (!MemberLocation.IsEmpty && eventDeclaration.StartLocation.Line != MemberLocation.Line)
272
return base.VisitEventDeclaration (eventDeclaration, data);