PageRenderTime 17ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Refactoring/ExtractMethod/VariableLookupVisitor.cs

https://github.com/louissalin/monodevelop
C# | 287 lines | 189 code | 33 blank | 65 comment | 37 complexity | f99aa223d4b25bb03f0cb83cbe741907 MD5 | raw file
  1. //
  2. // VariableLookupVisitor.cs
  3. //
  4. // Author:
  5. // Mike Kr├╝ger <mkrueger@novell.com>
  6. //
  7. // Copyright (c) 2009 Novell, Inc (http://www.novell.com)
  8. //
  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:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  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
  25. // THE SOFTWARE.
  26. using System;
  27. using System.Linq;
  28. using System.Collections.Generic;
  29. using MonoDevelop.Projects.Dom;
  30. using MonoDevelop.Projects.Dom.Parser;
  31. using Mono.TextEditor;
  32. using ICSharpCode.NRefactory.CSharp;
  33. namespace MonoDevelop.CSharp.Refactoring.ExtractMethod
  34. {
  35. public class VariableDescriptor
  36. {
  37. public string Name {
  38. get;
  39. set;
  40. }
  41. public IReturnType ReturnType {
  42. get;
  43. set;
  44. }
  45. public bool IsDefinedInsideCutRegion {
  46. get;
  47. set;
  48. }
  49. public bool UsedInCutRegion {
  50. get;
  51. set;
  52. }
  53. public bool UsedBeforeCutRegion {
  54. get;
  55. set;
  56. }
  57. public bool UsedAfterCutRegion {
  58. get;
  59. set;
  60. }
  61. public bool IsChangedInsideCutRegion {
  62. get;
  63. set;
  64. }
  65. public VariableDeclarationStatement Declaration {
  66. get;
  67. set;
  68. }
  69. public VariableDescriptor (string name)
  70. {
  71. this.Name = name;
  72. }
  73. public override string ToString ()
  74. {
  75. return string.Format ("[VariableDescriptor: Name={0}, ReturnType={1}, IsDefinedInsideCutRegion={2}, UsedInCutRegion={3}, UsedBeforeCutRegion={4}, UsedAfterCutRegion={5}, IsChangedInsideCutRegion={6}]", Name, ReturnType, IsDefinedInsideCutRegion, UsedInCutRegion, UsedBeforeCutRegion, UsedAfterCutRegion, IsChangedInsideCutRegion);
  76. }
  77. }
  78. public class VariableLookupVisitor : DepthFirstAstVisitor<object, object>
  79. {
  80. List<KeyValuePair <string, IReturnType>> unknownVariables = new List<KeyValuePair <string, IReturnType>> ();
  81. Dictionary<string, VariableDescriptor> variables = new Dictionary<string, VariableDescriptor> ();
  82. // bool valueGetsChanged;
  83. public bool ReferencesMember {
  84. get;
  85. set;
  86. }
  87. public List<KeyValuePair <string, IReturnType>> UnknownVariables {
  88. get {
  89. return unknownVariables;
  90. }
  91. }
  92. public Dictionary<string, VariableDescriptor> Variables {
  93. get {
  94. return variables;
  95. }
  96. }
  97. public List<VariableDescriptor> VariableList {
  98. get {
  99. return new List<VariableDescriptor> (variables.Values);
  100. }
  101. }
  102. public DomLocation MemberLocation {
  103. get;
  104. set;
  105. }
  106. IResolver resolver;
  107. DomLocation position;
  108. public DomRegion CutRegion {
  109. get;
  110. set;
  111. }
  112. public VariableLookupVisitor (IResolver resolver, DomLocation position)
  113. {
  114. this.resolver = resolver;
  115. this.position = position;
  116. this.MemberLocation = DomLocation.Empty;
  117. }
  118. public override object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data)
  119. {
  120. bool isDefinedInsideCutRegion = CutRegion.Contains (variableDeclarationStatement.StartLocation.Line, variableDeclarationStatement.StartLocation.Column);
  121. foreach (var varDecl in variableDeclarationStatement.Variables) {
  122. var descr = new VariableDescriptor (varDecl.Name) {
  123. IsDefinedInsideCutRegion = isDefinedInsideCutRegion,
  124. Declaration = variableDeclarationStatement
  125. };
  126. if (varDecl.Initializer != null) {
  127. if (isDefinedInsideCutRegion) {
  128. descr.UsedInCutRegion = true;
  129. } else if (variableDeclarationStatement.StartLocation < new AstLocation (CutRegion.Start.Line, CutRegion.Start.Column)) {
  130. descr.UsedBeforeCutRegion = !varDecl.Initializer.IsNull;
  131. } else {
  132. descr.UsedAfterCutRegion = true;
  133. }
  134. }
  135. variables[varDecl.Name] = descr;
  136. }
  137. return base.VisitVariableDeclarationStatement (variableDeclarationStatement, data);
  138. }
  139. public override object VisitIdentifierExpression (ICSharpCode.NRefactory.CSharp.IdentifierExpression identifierExpression, object data)
  140. {
  141. ExpressionResult expressionResult = new ExpressionResult (identifierExpression.Identifier);
  142. ResolveResult result = resolver.Resolve (expressionResult, position);
  143. MemberResolveResult mrr = result as MemberResolveResult;
  144. ReferencesMember |= mrr != null && mrr.ResolvedMember != null && !mrr.ResolvedMember.IsStatic;
  145. if (!(result is LocalVariableResolveResult || result is ParameterResolveResult))
  146. return null;
  147. if (!variables.ContainsKey (identifierExpression.Identifier))
  148. return null;
  149. var v = variables[identifierExpression.Identifier];
  150. v.ReturnType = result.ResolvedType;
  151. if (CutRegion.Contains (identifierExpression.StartLocation.Line, identifierExpression.StartLocation.Column)) {
  152. if (!v.IsChangedInsideCutRegion)
  153. v.UsedInCutRegion = true;
  154. } else if (identifierExpression.StartLocation < new AstLocation (CutRegion.Start.Line, CutRegion.Start.Column)) {
  155. v.UsedBeforeCutRegion = true;
  156. } else {
  157. v.UsedAfterCutRegion = true;
  158. }
  159. return null;
  160. }
  161. public override object VisitAssignmentExpression (ICSharpCode.NRefactory.CSharp.AssignmentExpression assignmentExpression, object data)
  162. {
  163. assignmentExpression.Right.AcceptVisitor(this, data);
  164. // valueGetsChanged = true;
  165. var left = assignmentExpression.Left as ICSharpCode.NRefactory.CSharp.IdentifierExpression;
  166. if (left != null && variables.ContainsKey (left.Identifier)) {
  167. var v = variables[left.Identifier];
  168. v.IsChangedInsideCutRegion = CutRegion.Contains (assignmentExpression.StartLocation.Line, assignmentExpression.StartLocation.Column);
  169. if (!v.IsChangedInsideCutRegion) {
  170. if (assignmentExpression.StartLocation < new AstLocation (CutRegion.Start.Line, CutRegion.Start.Column)) {
  171. v.UsedBeforeCutRegion = true;
  172. } else {
  173. v.UsedAfterCutRegion = true;
  174. }
  175. }
  176. }
  177. return null;
  178. }
  179. public override object VisitUnaryOperatorExpression (ICSharpCode.NRefactory.CSharp.UnaryOperatorExpression unaryOperatorExpression, object data)
  180. {
  181. base.VisitUnaryOperatorExpression (unaryOperatorExpression, data);
  182. if (CutRegion.Contains (unaryOperatorExpression.StartLocation.Line, unaryOperatorExpression.StartLocation.Column)) {
  183. var left = unaryOperatorExpression.Expression as ICSharpCode.NRefactory.CSharp.IdentifierExpression;
  184. if (left != null && variables.ContainsKey (left.Identifier)) {
  185. variables[left.Identifier].IsChangedInsideCutRegion = true;
  186. }
  187. }
  188. /*
  189. switch (unaryOperatorExpression.UnaryOperatorType) {
  190. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.Increment:
  191. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.Decrement:
  192. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.PostIncrement:
  193. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.PostDecrement:
  194. valueGetsChanged = true;
  195. break;
  196. }
  197. object result = base.VisitUnaryOperatorExpression (unaryOperatorExpression, data);
  198. valueGetsChanged = false;
  199. switch (unaryOperatorExpression.UnaryOperatorType) {
  200. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.Increment:
  201. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.Decrement:
  202. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.PostIncrement:
  203. case ICSharpCode.NRefactory.CSharp.UnaryOperatorType.PostDecrement:
  204. var left = unaryOperatorExpression.Expression as ICSharpCode.NRefactory.CSharp.IdentifierExpression;
  205. if (left != null && variables.ContainsKey (left.Identifier.Name))
  206. variables[left.Identifier.Name].GetsChanged = true;
  207. break;
  208. }*/
  209. return null;
  210. }
  211. public override object VisitBinaryOperatorExpression (BinaryOperatorExpression binaryOperatorExpression, object data)
  212. {
  213. return base.VisitBinaryOperatorExpression (binaryOperatorExpression, data);
  214. }
  215. public override object VisitMethodDeclaration (MethodDeclaration methodDeclaration, object data)
  216. {
  217. if (!MemberLocation.IsEmpty && methodDeclaration.StartLocation.Line != MemberLocation.Line)
  218. return null;
  219. foreach (var param in methodDeclaration.Parameters) {
  220. variables[param.Name] = new VariableDescriptor (param.Name);
  221. }
  222. return base.VisitMethodDeclaration (methodDeclaration, data);
  223. }
  224. public override object VisitPropertyDeclaration (PropertyDeclaration propertyDeclaration, object data)
  225. {
  226. if (!MemberLocation.IsEmpty && propertyDeclaration.StartLocation.Line != MemberLocation.Line)
  227. return null;
  228. return base.VisitPropertyDeclaration (propertyDeclaration, data);
  229. }
  230. public override object VisitEventDeclaration (EventDeclaration eventDeclaration, object data)
  231. {
  232. if (!MemberLocation.IsEmpty && eventDeclaration.StartLocation.Line != MemberLocation.Line)
  233. return null;
  234. return base.VisitEventDeclaration (eventDeclaration, data);
  235. }
  236. /*
  237. public override object VisitDirectionExpression (ICSharpCode.OldNRefactory.Ast.DirectionExpression directionExpression, object data)
  238. {
  239. valueGetsChanged = true;
  240. IdentifierExpression left = directionExpression.Expression as IdentifierExpression;
  241. bool isInitialUse = left != null && !variables.ContainsKey (left.Identifier);
  242. object result = base.VisitDirectionExpression (directionExpression, data);
  243. valueGetsChanged = false;
  244. if (left != null && variables.ContainsKey (left.Identifier)) {
  245. variables[left.Identifier].GetsChanged = true;
  246. if (isInitialUse && directionExpression.FieldDirection == FieldDirection.Out)
  247. variables[left.Identifier].GetsAssigned = true;
  248. }
  249. return result;
  250. }
  251. */
  252. }
  253. }