PageRenderTime 58ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/Mono.CodeContracts/Mono.CodeContracts.Static.Analysis.NonNull/Analysis.cs

https://bitbucket.org/foobar22/mono
C# | 421 lines | 327 code | 66 blank | 28 comment | 60 complexity | 4783ddc26fba98f108d2ae4528675aa2 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0, Unlicense, Apache-2.0, LGPL-2.0
  1. //
  2. // Analysis.cs
  3. //
  4. // Authors:
  5. // Alexander Chebaturkin (chebaturkin@gmail.com)
  6. //
  7. // Copyright (C) 2011 Alexander Chebaturkin
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Linq;
  32. using Mono.CodeContracts.Static.AST;
  33. using Mono.CodeContracts.Static.AST.Visitors;
  34. using Mono.CodeContracts.Static.Analysis.Drivers;
  35. using Mono.CodeContracts.Static.ControlFlow;
  36. using Mono.CodeContracts.Static.DataFlowAnalysis;
  37. using Mono.CodeContracts.Static.DataStructures;
  38. using Mono.CodeContracts.Static.Lattices;
  39. using Mono.CodeContracts.Static.Providers;
  40. using Mono.CodeContracts.Static.Proving;
  41. namespace Mono.CodeContracts.Static.Analysis.NonNull {
  42. class Analysis<E, V> : ILVisitorBase<APC, V, V, NonNullDomain<V>, NonNullDomain<V>>,
  43. IAnalysis<APC, NonNullDomain<V>, IILVisitor<APC, V, V, NonNullDomain<V>, NonNullDomain<V>>, IImmutableMap<V, Sequence<V>>>,
  44. IMethodResult<V>, IFactBase<V>
  45. where E : IEquatable<E>
  46. where V : IEquatable<V>
  47. {
  48. private readonly Dictionary<APC, NonNullDomain<V>> callSiteCache = new Dictionary<APC, NonNullDomain<V>> ();
  49. private readonly IMethodDriver<E, V> method_driver;
  50. private IFixPointInfo<APC, NonNullDomain<V>> fix_point_info;
  51. public Analysis (IMethodDriver<E, V> mdriver)
  52. {
  53. this.method_driver = mdriver;
  54. }
  55. protected internal IExpressionContextProvider<E, V> ContextProvider
  56. {
  57. get { return this.method_driver.ContextProvider; }
  58. }
  59. protected IMetaDataProvider MetaDataProvider
  60. {
  61. get { return this.method_driver.MetaDataProvider; }
  62. }
  63. #region IAnalysis<APC,Domain<V>,IILVisitor<APC,V,V,Domain<V>,Domain<V>>,IImmutableMap<V,Sequence<V>>> Members
  64. public IILVisitor<APC, V, V, NonNullDomain<V>, NonNullDomain<V>> GetVisitor ()
  65. {
  66. return this;
  67. }
  68. public NonNullDomain<V> Join (Pair<APC, APC> edge, NonNullDomain<V> newstate, NonNullDomain<V> prevstate, out bool weaker, bool widen)
  69. {
  70. bool nonNullWeaker;
  71. SetDomain<V> nonNulls = prevstate.NonNulls.Join (newstate.NonNulls, widen, out nonNullWeaker);
  72. bool nullWeaker;
  73. SetDomain<V> nulls = prevstate.Nulls.Join (newstate.Nulls, widen, out nullWeaker);
  74. weaker = nonNullWeaker || nullWeaker;
  75. return new NonNullDomain<V> (nonNulls, nulls);
  76. }
  77. public NonNullDomain<V> ImmutableVersion (NonNullDomain<V> state)
  78. {
  79. return state;
  80. }
  81. public NonNullDomain<V> MutableVersion (NonNullDomain<V> state)
  82. {
  83. return state;
  84. }
  85. public NonNullDomain<V> EdgeConversion (APC from, APC to, bool isJoinPoint, IImmutableMap<V, Sequence<V>> data, NonNullDomain<V> state)
  86. {
  87. if (data == null)
  88. return state;
  89. SetDomain<V> oldNonNulls = state.NonNulls;
  90. SetDomain<V> nonNulls = SetDomain<V>.TopValue;
  91. SetDomain<V> oldNulls = state.Nulls;
  92. SetDomain<V> nulls = SetDomain<V>.TopValue;
  93. foreach (V variable in data.Keys) {
  94. bool nonNullContains = oldNonNulls.Contains (variable);
  95. bool nullContains = oldNulls.Contains (variable);
  96. if (nonNullContains || nullContains) {
  97. foreach (V anotherVariable in data [variable].AsEnumerable ()) {
  98. if (nonNullContains)
  99. nonNulls = nonNulls.With (anotherVariable);
  100. if (nullContains)
  101. nulls = nulls.With (anotherVariable);
  102. }
  103. }
  104. }
  105. return new NonNullDomain<V> (nonNulls, nulls);
  106. }
  107. public bool IsBottom (APC pc, NonNullDomain<V> state)
  108. {
  109. return state.NonNulls.IsBottom;
  110. }
  111. public Predicate<APC> SaveFixPointInfo (IFixPointInfo<APC, NonNullDomain<V>> fixPointInfo)
  112. {
  113. this.fix_point_info = fixPointInfo;
  114. //todo: implement this
  115. return pc => true;
  116. }
  117. public void Dump (Pair<NonNullDomain<V>, TextWriter> pair)
  118. {
  119. TextWriter tw = pair.Value;
  120. tw.Write ("NonNulls: ");
  121. pair.Key.NonNulls.Dump (tw);
  122. tw.Write ("Nulls: ");
  123. pair.Key.Nulls.Dump (tw);
  124. }
  125. #endregion
  126. #region IFactBase<V> Members
  127. public FlatDomain<bool> IsNull(APC pc, V variable)
  128. {
  129. if (ContextProvider.ValueContext.IsZero (pc, variable))
  130. return ProofOutcome.True;
  131. NonNullDomain<V> domain;
  132. if (!PreStateLookup (pc, out domain) || domain.NonNulls.IsBottom)
  133. return ProofOutcome.Bottom;
  134. if (domain.IsNonNull (variable))
  135. return ProofOutcome.False;
  136. if (domain.IsNull (variable))
  137. return ProofOutcome.True;
  138. return ProofOutcome.Top;
  139. }
  140. public FlatDomain<bool> IsNonNull(APC pc, V variable)
  141. {
  142. NonNullDomain<V> domain;
  143. if (!PreStateLookup (pc, out domain) || domain.NonNulls.IsBottom)
  144. return ProofOutcome.Bottom;
  145. if (domain.IsNonNull (variable))
  146. return ProofOutcome.True;
  147. if (ContextProvider.ValueContext.IsZero (pc, variable) || domain.IsNull (variable))
  148. return ProofOutcome.False;
  149. FlatDomain<TypeNode> aType = ContextProvider.ValueContext.GetType (pc, variable);
  150. if (aType.IsNormal() && MetaDataProvider.IsManagedPointer (aType.Value))
  151. return ProofOutcome.True;
  152. return ProofOutcome.Top;
  153. }
  154. public bool IsUnreachable (APC pc)
  155. {
  156. NonNullDomain<V> domain;
  157. if (!PreStateLookup (pc, out domain) || domain.NonNulls.IsBottom)
  158. return true;
  159. return false;
  160. }
  161. #endregion
  162. public override NonNullDomain<V> DefaultVisit (APC pc, NonNullDomain<V> data)
  163. {
  164. return data;
  165. }
  166. public static NonNullDomain<V> AssumeNonNull (V dest, NonNullDomain<V> domain)
  167. {
  168. if (!domain.NonNulls.Contains (dest))
  169. return new NonNullDomain<V> (domain.NonNulls.With (dest), domain.Nulls);
  170. return domain;
  171. }
  172. public static NonNullDomain<V> AssumeNull (V dest, NonNullDomain<V> before)
  173. {
  174. if (!before.Nulls.Contains (dest))
  175. return new NonNullDomain<V> (before.NonNulls, before.Nulls.With (dest));
  176. return before;
  177. }
  178. public override NonNullDomain<V> Assert(APC pc, EdgeTag tag, V condition, NonNullDomain<V> data)
  179. {
  180. return ContextProvider.ExpressionContext.Decode
  181. <Pair<bool, NonNullDomain<V>>, NonNullDomain<V>, ExpressionAssumeDecoder<E, V>>
  182. (
  183. ContextProvider.ExpressionContext.Refine (pc, condition),
  184. new ExpressionAssumeDecoder<E, V> (ContextProvider),
  185. new Pair<bool, NonNullDomain<V>> (true, data));
  186. }
  187. public override NonNullDomain<V> Assume (APC pc, EdgeTag tag, V condition, NonNullDomain<V> data)
  188. {
  189. IExpressionContext<E, V> exprCtx = ContextProvider.ExpressionContext;
  190. E expr = exprCtx.Refine (pc, condition);
  191. return exprCtx.Decode<Pair<bool, NonNullDomain<V>>, NonNullDomain<V>, ExpressionAssumeDecoder<E, V>>
  192. (expr, new ExpressionAssumeDecoder<E, V> (ContextProvider),
  193. new Pair<bool, NonNullDomain<V>> (tag != EdgeTag.False, data));
  194. }
  195. public override NonNullDomain<V> Unary (APC pc, UnaryOperator op, bool unsigned, V dest, V source, NonNullDomain<V> data)
  196. {
  197. switch (op) {
  198. case UnaryOperator.Conv_i:
  199. case UnaryOperator.Conv_u:
  200. if (data.IsNonNull (source))
  201. return AssumeNonNull (dest, data);
  202. break;
  203. }
  204. return data;
  205. }
  206. public override NonNullDomain<V> Call<TypeList, ArgList> (APC pc, Method method, bool virt, TypeList extraVarargs, V dest, ArgList args, NonNullDomain<V> data)
  207. {
  208. this.callSiteCache [pc] = data;
  209. if (!MetaDataProvider.IsStatic (method))
  210. return AssumeNonNull (args [0], data);
  211. return data;
  212. }
  213. public override NonNullDomain<V> CastClass (APC pc, TypeNode type, V dest, V obj, NonNullDomain<V> data)
  214. {
  215. if (data.NonNulls.Contains (obj))
  216. return AssumeNonNull (dest, data);
  217. return data;
  218. }
  219. public override NonNullDomain<V> Entry (APC pc, Method method, NonNullDomain<V> data)
  220. {
  221. APC at = ContextProvider.MethodContext.CFG.Next (pc);
  222. NonNullDomain<V> domain = data;
  223. IIndexable<Parameter> parameters = MetaDataProvider.Parameters (method);
  224. TypeNode eventArgsType;
  225. bool systemType = MetaDataProvider.TryGetSystemType ("System.EventArgs", out eventArgsType);
  226. for (int i = 0; i < parameters.Count; i++) {
  227. Parameter p = parameters [i];
  228. TypeNode pType = MetaDataProvider.ParameterType (p);
  229. if (MetaDataProvider.IsManagedPointer (pType)) {
  230. V sv;
  231. if (ContextProvider.ValueContext.TryParameterValue (at, p, out sv))
  232. domain = AssumeNonNull (sv, domain);
  233. } else {
  234. V sv;
  235. if (i == 0 && parameters.Count == 1 && MetaDataProvider.IsArray (pType)
  236. && MetaDataProvider.Name (method) == "Main" && MetaDataProvider.IsStatic (method) &&
  237. ContextProvider.ValueContext.TryParameterValue (pc, p, out sv))
  238. domain = AssumeNonNull (sv, domain);
  239. }
  240. }
  241. V sv1;
  242. if (systemType && parameters.Count == 2 && MetaDataProvider.Equal (MetaDataProvider.System_Object, MetaDataProvider.ParameterType (parameters [0])) &&
  243. MetaDataProvider.DerivesFrom (MetaDataProvider.ParameterType (parameters [1]), eventArgsType)
  244. && ContextProvider.ValueContext.TryParameterValue (pc, parameters [1], out sv1))
  245. domain = AssumeNonNull (sv1, domain);
  246. if (!MetaDataProvider.IsStatic (method) && ContextProvider.ValueContext.TryParameterValue (pc, MetaDataProvider.This (method), out sv1))
  247. domain = AssumeNonNull (sv1, domain);
  248. return domain;
  249. }
  250. public override NonNullDomain<V> LoadStack (APC pc, int offset, V dest, V source, bool isOld, NonNullDomain<V> data)
  251. {
  252. NonNullDomain<V> old;
  253. if (isOld && TryFindOldState (pc, out old)) {
  254. if (old.IsNonNull (source))
  255. return AssumeNonNull (dest, data);
  256. if (old.IsNull (source))
  257. return AssumeNull (dest, data);
  258. }
  259. return data;
  260. }
  261. public override NonNullDomain<V> Isinst (APC pc, TypeNode type, V dest, V obj, NonNullDomain<V> data)
  262. {
  263. if (data.IsNonNull (obj)) {
  264. FlatDomain<TypeNode> aType = ContextProvider.ValueContext.GetType (pc, obj);
  265. if (aType.IsNormal() && MetaDataProvider.DerivesFrom (aType.Value, type))
  266. return AssumeNonNull (dest, data);
  267. }
  268. return data;
  269. }
  270. public override NonNullDomain<V> LoadArgAddress (APC pc, Parameter argument, bool isOld, V dest, NonNullDomain<V> data)
  271. {
  272. return AssumeNonNull (dest, data);
  273. }
  274. public override NonNullDomain<V> LoadConst (APC pc, TypeNode type, object constant, V dest, NonNullDomain<V> data)
  275. {
  276. if (constant is string)
  277. return AssumeNonNull (dest, data);
  278. return data;
  279. }
  280. public override NonNullDomain<V> LoadElement (APC pc, TypeNode type, V dest, V array, V index, NonNullDomain<V> data)
  281. {
  282. return AssumeNonNull (array, data);
  283. }
  284. public override NonNullDomain<V> LoadField (APC pc, Field field, V dest, V obj, NonNullDomain<V> data)
  285. {
  286. NonNullDomain<V> domain = AssumeNonNull (obj, data);
  287. FlatDomain<TypeNode> aType = ContextProvider.ValueContext.GetType (ContextProvider.MethodContext.CFG.Next (pc), dest);
  288. if (aType.IsNormal() && MetaDataProvider.IsManagedPointer (aType.Value))
  289. domain = AssumeNonNull (dest, domain);
  290. return domain;
  291. }
  292. public override NonNullDomain<V> LoadFieldAddress (APC pc, Field field, V dest, V obj, NonNullDomain<V> data)
  293. {
  294. NonNullDomain<V> domain = AssumeNonNull (obj, data);
  295. return AssumeNonNull (dest, domain);
  296. }
  297. public override NonNullDomain<V> LoadStaticFieldAddress (APC pc, Field field, V dest, NonNullDomain<V> data)
  298. {
  299. return AssumeNonNull (dest, data);
  300. }
  301. public override NonNullDomain<V> LoadLength (APC pc, V dest, V array, NonNullDomain<V> data)
  302. {
  303. return AssumeNonNull (array, data);
  304. }
  305. public override NonNullDomain<V> NewArray<ArgList> (APC pc, TypeNode type, V dest, ArgList lengths, NonNullDomain<V> data)
  306. {
  307. return AssumeNonNull (dest, data);
  308. }
  309. public override NonNullDomain<V> NewObj<ArgList> (APC pc, Method ctor, V dest, ArgList args, NonNullDomain<V> data)
  310. {
  311. return AssumeNonNull (dest, data);
  312. }
  313. public override NonNullDomain<V> StoreElement (APC pc, TypeNode type, V array, V index, V value, NonNullDomain<V> data)
  314. {
  315. return AssumeNonNull (array, data);
  316. }
  317. public override NonNullDomain<V> StoreField (APC pc, Field field, V obj, V value, NonNullDomain<V> data)
  318. {
  319. return AssumeNonNull (obj, data);
  320. }
  321. private bool TryFindOldState (APC pc, out NonNullDomain<V> old)
  322. {
  323. if (pc.SubroutineContext.AsEnumerable().Any (edge => edge.Tag.Is (EdgeTag.AfterMask)))
  324. return this.callSiteCache.TryGetValue (pc, out old);
  325. return false.Without (out old);
  326. }
  327. public NonNullDomain<V> InitialValue (Func<V, int> keyConverter)
  328. {
  329. return new NonNullDomain<V> (new SetDomain<V> (keyConverter), new SetDomain<V> (keyConverter));
  330. }
  331. #region Implementation of IMethodResult<Variable>
  332. public IMethodAnalysis MethodAnalysis { get; set; }
  333. public void ValidateImplicitAssertions (IFactQuery<BoxedExpression, V> facts, List<string> proofResults)
  334. {
  335. }
  336. public IFactQuery<BoxedExpression, V> FactQuery
  337. {
  338. get { return new SimpleLogicInference<E, V> (ContextProvider, this, this.method_driver.BasicFacts.IsUnreachable); }
  339. }
  340. public FlatDomain<bool> ValidateExplicitAssertion(APC pc, V value)
  341. {
  342. NonNullDomain<V> domain;
  343. if (PreStateLookup (pc, out domain) && !domain.NonNulls.IsBottom) {
  344. IExpressionContext<E, V> exprCtx = ContextProvider.ExpressionContext;
  345. return exprCtx.Decode<bool, FlatDomain<bool>, ExpressionAssertDischarger<E, V>>(exprCtx.Refine(pc, value), new ExpressionAssertDischarger<E, V>(this, pc), true);
  346. }
  347. return ProofOutcome.Bottom;
  348. }
  349. private bool PreStateLookup (APC pc, out NonNullDomain<V> domain)
  350. {
  351. return this.fix_point_info.PreStateLookup (pc, out domain);
  352. }
  353. #endregion
  354. }
  355. }