2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / tools / ictool / peer.cs
1 //\r
2 // file:        peer.cs\r
3 // author:      Dan Lewis (dihlewis@yahoo.co.uk)\r
4 //              (C) 2002\r
5 //\r
6 \r
7 using System;\r
8 using System.Reflection;\r
9 using System.Collections;\r
10 \r
11 class Peer {\r
12         public Peer (Type clr_type, string name, bool is_opaque) {\r
13                 this.clr_type = clr_type;\r
14                 this.name = name;\r
15                 this.is_opaque = is_opaque;\r
16 \r
17                 this.nearest_base = null;       // resolve later\r
18                 this.underlying = null;\r
19                 this.enum_constants = null;\r
20                 this.fields = new PeerFieldCollection ();\r
21 \r
22                 this.is_enum = CLRIsEnum (clr_type);\r
23                 this.is_value_type = CLRIsValueType (clr_type);\r
24         }\r
25 \r
26         public string Name {\r
27                 get { return name; }\r
28         }\r
29 \r
30         public Type CLRType {\r
31                 get { return clr_type; }\r
32         }\r
33 \r
34         public bool IsOpaque {\r
35                 get { return is_opaque; }\r
36         }\r
37 \r
38         public bool IsValueType {\r
39                 get { return is_value_type; }\r
40         }\r
41 \r
42         public bool IsEnum {\r
43                 get { return is_enum; }\r
44         }\r
45 \r
46         public Peer NearestBase {\r
47                 get { return nearest_base; }\r
48                 set { nearest_base = value; }\r
49         }\r
50 \r
51         public Peer UnderlyingPeer {\r
52                 get { return underlying; }\r
53                 set { underlying = value; }\r
54         }\r
55 \r
56         public IDictionary EnumConstants {\r
57                 get { return enum_constants; }\r
58                 set { enum_constants = value; }\r
59         }\r
60 \r
61         public PeerFieldCollection Fields {\r
62                 get { return fields; }\r
63         }\r
64 \r
65         public string GetTypedef (int refs) {\r
66                 if (refs == 0)\r
67                         return String.Format ("{0} ", name);\r
68 \r
69                 return String.Format ("{0} {1}", name, new string ('*', refs));\r
70         }\r
71 \r
72         // internal\r
73 \r
74         internal static bool CLRIsValueType (Type clr_type) {\r
75                 return clr_type.IsValueType;\r
76                 /*\r
77                 if (clr_type.BaseType == null)\r
78                         return false;\r
79         \r
80                 return\r
81                         clr_type.BaseType.FullName == "System.ValueType" ||\r
82                         clr_type.BaseType.FullName == "System.Enum";\r
83                 */\r
84         }\r
85 \r
86         internal static bool CLRIsEnum (Type clr_type) {\r
87                 return clr_type.IsEnum;\r
88                 /*\r
89                 if (clr_type.BaseType == null)\r
90                         return false;\r
91 \r
92                 return clr_type.BaseType.FullName == "System.Enum";\r
93                 */\r
94         }\r
95 \r
96         internal static Type CLRUnderlyingType (Type clr_type) {\r
97                 return Enum.GetUnderlyingType (clr_type);\r
98                 /*\r
99                 Type ebase = type.BaseType;\r
100 \r
101                 return (Type)ebase.InvokeMember ("GetUnderlyingType",\r
102                         BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static,\r
103                         null, null,\r
104                         new object[] { type }\r
105                 );\r
106                 */\r
107         }\r
108 \r
109         // private\r
110 \r
111         private Type clr_type;\r
112         private bool is_opaque;\r
113         private bool is_value_type;\r
114         private bool is_enum;\r
115 \r
116         private string name;\r
117         private Peer nearest_base;\r
118         private Peer underlying;\r
119         private IDictionary enum_constants;\r
120         private PeerFieldCollection fields;\r
121 }\r
122 \r
123 class PeerField {\r
124         public PeerField (Peer peer, string name) {\r
125                 this.peer = peer;\r
126                 this.name = name;\r
127         }\r
128 \r
129         public Peer Peer {\r
130                 get { return peer; }\r
131         }\r
132 \r
133         public string Name {\r
134                 get { return name; }\r
135         }\r
136 \r
137         private Peer peer;\r
138         private string name;\r
139 }\r
140 \r
141 class PeerFieldCollection : CollectionBase {\r
142         public void Add (PeerField f) {\r
143                 List.Add (f);\r
144         }\r
145 \r
146         public PeerField this[int i] {\r
147                 get { return (PeerField)List[i]; }\r
148         }\r
149 }\r
150 \r
151 class PeerMap {\r
152         public PeerMap () {\r
153                 peers = new Hashtable ();\r
154         }\r
155 \r
156         public void Add (Peer peer) {\r
157                 Add (peer.CLRType, peer);\r
158         }\r
159 \r
160         public void Add (Type clr_type, Peer peer) {\r
161                 peers.Add (clr_type, peer);\r
162         }\r
163 \r
164         public ICollection Peers {\r
165                 get { return peers.Values; }\r
166         }\r
167 \r
168         public Peer this[Type clr_type] {\r
169                 get {\r
170                         if (peers.Contains (clr_type))\r
171                                 return (Peer)peers[clr_type];\r
172 \r
173                         return null;\r
174                 }\r
175         }\r
176 \r
177         public Peer GetPeer (Type clr_type) {\r
178                 Peer peer;\r
179 \r
180                 if (Peer.CLRIsValueType (clr_type)) {\r
181                         peer = this[clr_type];\r
182                         if (peer != null)\r
183                                 return peer;\r
184 \r
185                         if (Peer.CLRIsEnum (clr_type)) {\r
186                                 peer = this[Peer.CLRUnderlyingType (clr_type)];\r
187                                 if (peer != null)\r
188                                 return peer;\r
189 \r
190                                 throw new ArgumentException ("Could not find peer or underlying peer for enum " + clr_type);\r
191                         }\r
192                         else\r
193                                 throw new ArgumentException ("Could not find peer for value type " + clr_type);\r
194                 }\r
195                 else {\r
196                         Type type = clr_type;\r
197                         while (type != null) {\r
198                                 peer = this[type];\r
199                                 if (peer != null)\r
200                                         return peer;\r
201 \r
202                                 type = type.BaseType;\r
203                         }\r
204 \r
205                         throw new ArgumentException ("Could not find peer for class " + clr_type);\r
206                 }\r
207         }\r
208 \r
209         public void ResolvePeers () {\r
210                 BindingFlags binding =\r
211                         BindingFlags.DeclaredOnly |\r
212                         BindingFlags.Instance |\r
213                         BindingFlags.NonPublic |\r
214                         BindingFlags.Public;\r
215 \r
216                 // base type\r
217 \r
218                 foreach (Peer peer in Peers) {\r
219                         if (peer.IsOpaque || peer.IsValueType || peer.CLRType.BaseType == null)\r
220                                 continue;\r
221 \r
222                         peer.NearestBase = GetPeer (peer.CLRType.BaseType);\r
223                         if (peer.NearestBase == null) {\r
224                                 Console.Error.WriteLine ("Error: cannot find an internal base type for {0}.", peer.Name);\r
225                                 Environment.Exit (-1);\r
226                         }\r
227                 }\r
228 \r
229                 // fields\r
230 \r
231                 foreach (Peer peer in Peers) {\r
232                         if (peer.IsOpaque || peer.IsEnum)\r
233                                 continue;\r
234 \r
235                         Type clr_base = null;\r
236                         if (peer.NearestBase != null)\r
237                                 clr_base = peer.NearestBase.CLRType;\r
238 \r
239                         Stack declared = new Stack ();\r
240                         Type type = peer.CLRType;\r
241 \r
242                         while (type != clr_base) {\r
243                                 declared.Push (type);\r
244                                 type = type.BaseType;\r
245                         }\r
246 \r
247                         // build declared field list\r
248 \r
249                         while (declared.Count > 0) {\r
250                                 type = (Type)declared.Pop ();\r
251                                 foreach (FieldInfo info in type.GetFields (binding)) {\r
252                                         PeerField field = new PeerField (\r
253                                                 GetPeer (info.FieldType),\r
254                                                 info.Name\r
255                                         );\r
256 \r
257                                         peer.Fields.Add (field);\r
258                                 }\r
259                         }\r
260                 }\r
261 \r
262                 // enums\r
263 \r
264                 foreach (Peer peer in Peers) {\r
265                         if (peer.IsOpaque || !peer.IsEnum)\r
266                                 continue;\r
267 \r
268                         Type clr_type = peer.CLRType;\r
269 \r
270                         // constants\r
271 \r
272                         Hashtable constants = new Hashtable ();\r
273                         foreach (string name in Enum.GetNames (clr_type))\r
274                                 constants.Add (name, (int)Enum.Parse (clr_type, name));\r
275 \r
276                         peer.UnderlyingPeer = GetPeer (Enum.GetUnderlyingType (clr_type));\r
277                         peer.EnumConstants = constants;\r
278                 }\r
279         }\r
280 \r
281         // private\r
282 \r
283         private Hashtable peers;\r
284 }\r