1- // Copyright (c) 2001, 2002 Zope Corporation and Contributors.
2- //
3- // All Rights Reserved.
1+ // ===========================================================================
42//
53// This software is subject to the provisions of the Zope Public License,
6- // Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
4+ // Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
75// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
86// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
97// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
108// FOR A PARTICULAR PURPOSE.
9+ //
10+ // ===========================================================================
1111
1212using System ;
1313using System . IO ;
1414using System . Collections ;
1515using System . Collections . Specialized ;
16+ using System . Collections . Generic ;
1617using System . Reflection ;
1718using System . Reflection . Emit ;
1819
1920namespace Python . Runtime {
2021
2122 /// <summary>
22- /// The AssemblyManager maintains information about the assemblies and
23- /// namespaces that have been loaded, and provides a simplified internal
24- /// interface for finding and obtaining Type objects by qualified names.
23+ /// The AssemblyManager maintains information about loaded assemblies
24+ /// namespaces and provides an interface for name-based type lookup.
2525 /// </summary>
2626
2727 internal class AssemblyManager {
2828
29- static StringCollection pypath ;
30- static AssemblyLoadEventHandler lh ;
31- static ResolveEventHandler rh ;
32- static Hashtable namespaces ;
33- static ArrayList assemblies ;
34- static Hashtable probed ;
29+ static AssemblyLoadEventHandler lhandler ;
30+ static ResolveEventHandler rhandler ;
31+ static Dictionary < string , string > snames ;
32+ static Dictionary < string , Dictionary < Assembly , string > > namespaces ;
33+ static Dictionary < string , int > probed ;
34+ static List < Assembly > assemblies ;
35+ static List < string > pypath ;
3536 static int last ;
3637
3738 private AssemblyManager ( ) { }
3839
3940 //===================================================================
40- // Initialization performed on startup of the Python runtime.
41+ // Initialization performed on startup of the Python runtime. Here we
42+ // scan all of the currently loaded assemblies to determine exported
43+ // names, and register to be notified of new assembly loads.
4144 //===================================================================
4245
4346 internal static void Initialize ( ) {
44- pypath = new StringCollection ( ) ;
45- namespaces = new Hashtable ( ) ;
46- assemblies = new ArrayList ( ) ;
47- probed = new Hashtable ( ) ;
47+ snames = new Dictionary < string , string > ( ) ;
48+
49+ namespaces = new
50+ Dictionary < string , Dictionary < Assembly , string > > ( 32 ) ;
51+ probed = new Dictionary < string , int > ( 32 ) ;
52+ assemblies = new List < Assembly > ( 16 ) ;
53+ pypath = new List < string > ( 16 ) ;
4854
4955 AppDomain domain = AppDomain . CurrentDomain ;
5056
51- lh = new AssemblyLoadEventHandler ( AssemblyLoadHandler ) ;
52- domain . AssemblyLoad += lh ;
57+ lhandler = new AssemblyLoadEventHandler ( AssemblyLoadHandler ) ;
58+ domain . AssemblyLoad += lhandler ;
5359
54- rh = new ResolveEventHandler ( ResolveHandler ) ;
55- domain . AssemblyResolve += rh ;
60+ rhandler = new ResolveEventHandler ( ResolveHandler ) ;
61+ domain . AssemblyResolve += rhandler ;
5662
5763 Assembly [ ] items = domain . GetAssemblies ( ) ;
5864 for ( int i = 0 ; i < items . Length ; i ++ ) {
@@ -69,8 +75,8 @@ internal static void Initialize() {
6975
7076 internal static void Shutdown ( ) {
7177 AppDomain domain = AppDomain . CurrentDomain ;
72- domain . AssemblyLoad -= lh ;
73- domain . AssemblyResolve -= rh ;
78+ domain . AssemblyLoad -= lhandler ;
79+ domain . AssemblyResolve -= rhandler ;
7480 }
7581
7682
@@ -106,8 +112,33 @@ static Assembly ResolveHandler(Object ob, ResolveEventArgs args){
106112 return a ;
107113 }
108114 }
109- Assembly ao = LoadAssemblyPath ( args . Name ) ;
110- return ao ;
115+ return LoadAssemblyPath ( args . Name ) ;
116+ }
117+
118+
119+ //===================================================================
120+ // Certain kinds of names (such as the names of generic types) are
121+ // mangled so we need to perform mapping from human-friendly names
122+ // to inhumane names. Given a friendly name, this method will either
123+ // return the associated inhumane name or the original name with no
124+ // changes if there is no mapping for that name.
125+ //===================================================================
126+
127+ static string ConvertSpecialName ( string name ) {
128+ if ( snames . ContainsKey ( name ) ) {
129+ return snames [ name ] ;
130+ }
131+ return name ;
132+ }
133+
134+ static void AddSpecialName ( string nice , string ugly ) {
135+ if ( ! snames . ContainsKey ( nice ) ) {
136+ snames . Add ( nice , ugly ) ;
137+ }
138+ else {
139+ //Console.WriteLine("dup: {0} : {1}", nice, ugly);
140+ }
141+
111142 }
112143
113144
@@ -218,7 +249,7 @@ public static bool LoadImplicit(string name) {
218249 string s = "" ;
219250 for ( int i = 0 ; i < names . Length ; i ++ ) {
220251 s = ( i == 0 ) ? names [ 0 ] : s + "." + names [ i ] ;
221- if ( probed [ s ] == null ) {
252+ if ( ! probed . ContainsKey ( s ) ) {
222253 if ( LoadAssemblyPath ( s ) != null ) {
223254 loaded = true ;
224255 }
@@ -237,32 +268,48 @@ public static bool LoadImplicit(string name) {
237268 // mapping of valid namespaces. Note that for a given namespace
238269 // a.b.c.d, each of a, a.b, a.b.c and a.b.c.d are considered to
239270 // be valid namespaces (to better match Python import semantics).
271+ // {'System' : ['Reflection', 'String']}
240272 //===================================================================
241273
242274 static void ScanAssembly ( Assembly assembly ) {
243275
244- // TODO: this is a workaround for a current Mono bug: calling
245- // GetTypes on a generated assembly will cause it to fall over.
246- // For now we'll skip generated assemblies, which usually are
247- // uninteresting support code anyway.
248-
249- if ( assembly is AssemblyBuilder ) {
250- return ;
251- }
276+ // A couple of things we want to do here: first, we want to
277+ // gather a list of all of the namespaces contributed to by
278+ // the assembly. Since we have to rifle through all of the
279+ // types in the assembly anyway, we also build up a running
280+ // list of 'odd names' like generic names so that we can map
281+ // them appropriately later while still being lazy about
282+ // type lookup and instantiation.
252283
253284 Type [ ] types = assembly . GetTypes ( ) ;
254285 for ( int i = 0 ; i < types . Length ; i ++ ) {
255- string type_ns = types [ i ] . Namespace ;
256- if ( ( type_ns != null ) && ( ! namespaces . ContainsKey ( type_ns ) ) ) {
257- string [ ] names = type_ns . Split ( '.' ) ;
286+ Type t = types [ i ] ;
287+ string ns = t . Namespace ;
288+ if ( ( ns != null ) && ( ! namespaces . ContainsKey ( ns ) ) ) {
289+ string [ ] names = ns . Split ( '.' ) ;
258290 string s = "" ;
259291 for ( int n = 0 ; n < names . Length ; n ++ ) {
260292 s = ( n == 0 ) ? names [ 0 ] : s + "." + names [ n ] ;
261293 if ( ! namespaces . ContainsKey ( s ) ) {
262- namespaces . Add ( s , String . Empty ) ;
294+ namespaces . Add ( s ,
295+ new Dictionary < Assembly , string > ( )
296+ ) ;
263297 }
264298 }
265299 }
300+
301+ if ( ns != null && ! namespaces [ ns ] . ContainsKey ( assembly ) ) {
302+ namespaces [ ns ] . Add ( assembly , String . Empty ) ;
303+ }
304+
305+ if ( t . IsGenericTypeDefinition ) {
306+ string qname = t . FullName ;
307+ int tick = qname . IndexOf ( '`' ) ;
308+ if ( tick != - 1 ) {
309+ AddSpecialName ( qname . Substring ( 0 , tick ) , qname ) ;
310+ }
311+ }
312+
266313 }
267314 }
268315
@@ -277,16 +324,48 @@ public static bool IsValidNamespace(string name) {
277324 }
278325
279326
327+ //===================================================================
328+ // Returns the current list of valid names for the input namespace.
329+ //===================================================================
330+
331+ public static List < string > GetNames ( string nsname ) {
332+ List < string > names = new List < string > ( 32 ) ;
333+ if ( namespaces . ContainsKey ( nsname ) ) {
334+ foreach ( Assembly a in namespaces [ nsname ] . Keys ) {
335+ Type [ ] types = a . GetTypes ( ) ;
336+ for ( int i = 0 ; i < types . Length ; i ++ ) {
337+ Type t = types [ i ] ;
338+ if ( t . Namespace == nsname ) {
339+ names . Add ( ConvertSpecialName ( t . Name ) ) ;
340+ }
341+ }
342+ }
343+ int nslen = nsname . Length ;
344+ foreach ( string key in namespaces . Keys ) {
345+ if ( key . Length > nslen && key . StartsWith ( nsname ) ) {
346+ string tail = key . Substring ( nslen ) ;
347+ if ( key . IndexOf ( '.' ) == - 1 ) {
348+ names . Add ( key ) ;
349+ }
350+ }
351+ }
352+ }
353+ return names ;
354+ }
355+
280356 //===================================================================
281357 // Returns the System.Type object for a given qualified name,
282358 // looking in the currently loaded assemblies for the named
283359 // type. Returns null if the named type cannot be found.
284360 //===================================================================
285361
286- public static Type LookupType ( string qualifiedName ) {
362+ // funny names: generics,
363+
364+ public static Type LookupType ( string qname ) {
365+ string name = ConvertSpecialName ( qname ) ;
287366 for ( int i = 0 ; i < assemblies . Count ; i ++ ) {
288367 Assembly assembly = ( Assembly ) assemblies [ i ] ;
289- Type type = assembly . GetType ( qualifiedName ) ;
368+ Type type = assembly . GetType ( name ) ;
290369 if ( type != null ) {
291370 return type ;
292371 }
0 commit comments