2 // System.TypeIdentifier.cs
5 // Aleksey Kliger <aleksey@xamarin.com>
8 // Copyright (C) 2015 Xamarin, Inc (http://www.xamarin.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 // A TypeName is wrapper around type names in display form
33 // (that is, with special characters escaped).
35 // Note that in general if you unescape a type name, you will
36 // lose information: If the type name's DisplayName is
37 // Foo\+Bar+Baz (outer class ``Foo+Bar``, inner class Baz)
38 // unescaping the first plus will give you (outer class Foo,
39 // inner class Bar, innermost class Baz).
41 // The correct way to take a TypeName apart is to feed its
42 // DisplayName to TypeSpec.Parse()
44 internal interface TypeName
: System
.IEquatable
<TypeName
> {
49 // add a nested name under this one.
50 TypeName
NestedName (TypeIdentifier innerName
);
53 // A type identifier is a single component of a type name.
54 // Unlike a general typename, a type identifier can be be
55 // converted to internal form without loss of information.
56 internal interface TypeIdentifier
: TypeName
{
64 internal class TypeNames
{
65 internal static TypeName
FromDisplay (string displayName
)
67 return new Display (displayName
);
70 internal abstract class ATypeName
: TypeName
{
71 public abstract string DisplayName { get; }
73 public abstract TypeName
NestedName (TypeIdentifier innerName
);
75 public bool Equals(TypeName other
)
77 return other
!= null && DisplayName
== other
.DisplayName
;
80 public override int GetHashCode ()
82 return DisplayName
.GetHashCode();
85 public override bool Equals(object other
)
87 return Equals(other
as TypeName
);
92 private class Display
: ATypeName
{
95 internal Display (string displayName
)
97 this.displayName
= displayName
;
100 public override string DisplayName { get { return displayName; }
}
102 public override TypeName
NestedName (TypeIdentifier innerName
)
104 return new Display (DisplayName
+ "+" + innerName
.DisplayName
);
110 internal class TypeIdentifiers
{
112 internal static TypeIdentifier
FromDisplay (string displayName
)
114 return new Display (displayName
);
117 internal static TypeIdentifier
FromInternal (string internalName
)
119 return new Internal (internalName
);
122 internal static TypeIdentifier
FromInternal (string internalNameSpace
, TypeIdentifier typeName
)
124 return new Internal (internalNameSpace
, typeName
);
127 // Only use if simpleName is certain not to contain
128 // unexpected characters that ordinarily require
130 internal static TypeIdentifier
WithoutEscape (string simpleName
)
132 return new NoEscape (simpleName
);
135 private class Display
: TypeNames
.ATypeName
, TypeIdentifier
{
137 string internal_name
; //cached
139 internal Display (string displayName
)
141 this.displayName
= displayName
;
142 internal_name
= null;
145 public override string DisplayName
{
146 get { return displayName; }
149 public string InternalName
{
151 if (internal_name
== null)
152 internal_name
= GetInternalName ();
153 return internal_name
;
157 private string GetInternalName ()
159 return TypeSpec
.UnescapeInternalName(displayName
);
162 public override TypeName
NestedName (TypeIdentifier innerName
) {
163 return TypeNames
.FromDisplay (DisplayName
+ "+" + innerName
.DisplayName
);
168 private class Internal
: TypeNames
.ATypeName
, TypeIdentifier
{
170 string display_name
; //cached
172 internal Internal (string internalName
)
174 this.internalName
= internalName
;
175 this.display_name
= null;
178 internal Internal (string nameSpaceInternal
, TypeIdentifier typeName
)
180 this.internalName
= nameSpaceInternal
+ "." + typeName
.InternalName
;
181 this.display_name
= null;
184 public override string DisplayName
{
186 if (display_name
== null)
187 display_name
= GetDisplayName ();
192 public string InternalName
{
193 get { return internalName; }
196 private string GetDisplayName ()
198 return TypeSpec
.EscapeDisplayName (internalName
);
201 public override TypeName
NestedName (TypeIdentifier innerName
)
203 return TypeNames
.FromDisplay (DisplayName
+ "+" + innerName
.DisplayName
);
208 private class NoEscape
: TypeNames
.ATypeName
, TypeIdentifier
{
210 internal NoEscape (string simpleName
)
212 this.simpleName
= simpleName
;
214 checkNoBadChars(simpleName
);
218 public override string DisplayName { get { return simpleName; }
}
219 public string InternalName { get { return simpleName; }
}
222 static private void checkNoBadChars (string s
)
224 if (TypeSpec
.NeedsEscaping (s
))
225 throw new ArgumentException ("simpleName");
229 public override TypeName
NestedName (TypeIdentifier innerName
) {
230 return TypeNames
.FromDisplay (DisplayName
+ "+" + innerName
.DisplayName
);