The base architecture for code-contracts analysis
[mono.git] / mcs / class / Mono.CodeContracts / Mono.CodeContracts.Static.ControlFlow.Subroutines / MethodSubroutine.cs
1 // 
2 // MethodSubroutine.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
29 using System;
30 using System.Collections.Generic;
31 using Mono.CodeContracts.Static.AST;
32 using Mono.CodeContracts.Static.ControlFlow.Blocks;
33 using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
34 using Mono.CodeContracts.Static.Providers;
35
36 namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
37         class MethodSubroutine<Label, Handler> : SubroutineWithHandlers<Label, Handler>, IMethodInfo {
38                 private readonly Method method;
39                 private HashSet<BlockWithLabels<Label>> blocks_ending_in_return_point;
40
41                 public MethodSubroutine (SubroutineFacade subroutineFacade, Method method)
42                         : base (subroutineFacade)
43                 {
44                         this.method = method;
45                 }
46
47                 public MethodSubroutine (SubroutineFacade SubroutineFacade,
48                                          Method method, Label startLabel,
49                                          SubroutineWithHandlersBuilder<Label, Handler> builder) : base (SubroutineFacade, startLabel, builder)
50                 {
51                         this.method = method;
52                         IMetaDataProvider metaDataProvider = this.SubroutineFacade.MetaDataProvider;
53                         builder.BuildBlocks (startLabel, this);
54                         BlockWithLabels<Label> targetBlock = GetTargetBlock (startLabel);
55                         Commit ();
56
57                         TypeNode type = metaDataProvider.DeclaringType (method);
58                         Subroutine invariant = this.SubroutineFacade.GetInvariant (type);
59                         if (invariant != null && !metaDataProvider.IsConstructor (method) && !metaDataProvider.IsStatic (method)) {
60                                 AddEdgeSubroutine (Entry, targetBlock, invariant, EdgeTag.Entry);
61                                 Subroutine requires = this.SubroutineFacade.GetRequires (method);
62                                 if (requires != null)
63                                         AddEdgeSubroutine (Entry, targetBlock, requires, EdgeTag.Entry);
64                         } else
65                                 AddEdgeSubroutine (Entry, targetBlock, this.SubroutineFacade.GetRequires (method), EdgeTag.Entry);
66
67                         if (this.blocks_ending_in_return_point == null)
68                                 return;
69
70                         Subroutine ensures = this.SubroutineFacade.GetEnsures (method);
71                         bool putInvariantAfterExit = !metaDataProvider.IsStatic (method) 
72                                 && !metaDataProvider.IsFinalizer (method) && !metaDataProvider.IsDispose (method);
73                         foreach (var block in this.blocks_ending_in_return_point) {
74                                 if (putInvariantAfterExit)
75                                         AddEdgeSubroutine (block, Exit, invariant, EdgeTag.Exit);
76                                 AddEdgeSubroutine (block, Exit, ensures, EdgeTag.Exit);
77                         }
78
79                         if (ensures != null) {
80                                 throw new NotImplementedException();
81                         }
82
83                         this.blocks_ending_in_return_point = null;
84                 }
85
86                 #region Overrides of Subroutine
87                 public override void Initialize ()
88                 {
89                 }
90                 #endregion
91
92                 #region Overrides of SubroutineBase<Label>
93                 public override void AddReturnBlock (BlockWithLabels<Label> block)
94                 {
95                         if (this.blocks_ending_in_return_point == null)
96                                 this.blocks_ending_in_return_point = new HashSet<BlockWithLabels<Label>> ();
97
98                         this.blocks_ending_in_return_point.Add (block);
99
100                         base.AddReturnBlock (block);
101                 }
102                 #endregion
103
104                 #region Implementation of IMethodInfo<Method>
105                 public Method Method
106                 {
107                         get { return this.method; }
108                 }
109                 #endregion
110
111                 public override SubroutineKind Kind
112                 {
113                         get { return SubroutineKind.Method; }
114                 }
115
116                 public override bool HasReturnValue
117                 {
118                         get { return !this.SubroutineFacade.MetaDataProvider.IsVoidMethod (this.method); }
119                 }
120
121                 public override bool IsMethod
122                 {
123                         get { return true; }
124                 }
125
126                 public override bool IsConstructor
127                 {
128                         get { return this.SubroutineFacade.MetaDataProvider.IsConstructor (this.method); }
129                 }
130
131                 public override string Name
132                 {
133                         get { return this.SubroutineFacade.MetaDataProvider.FullName (this.method); }
134                 }
135         }
136 }