1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // --------------------------------------------------------------------------- |
5 | // typestring.cpp |
6 | // --------------------------------------------------------------------------- |
7 | // |
8 | |
9 | // |
10 | // This module contains all helper functions required to produce |
11 | // string representations of types, with options to control the |
12 | // appearance of namespace and assembly information. Its primary use |
13 | // is in reflection (Type.Name, Type.FullName, Type.ToString, etc) but |
14 | // over time it could replace the use of TypeHandle.GetName etc for |
15 | // diagnostic messages. |
16 | // |
17 | // --------------------------------------------------------------------------- |
18 | |
19 | |
20 | #ifndef TYPESTRING_H |
21 | #define TYPESTRING_H |
22 | |
23 | #include "common.h" |
24 | #include "class.h" |
25 | #include "typehandle.h" |
26 | #include "sstring.h" |
27 | #include "typekey.h" |
28 | #include "typeparse.h" |
29 | #include "field.h" |
30 | |
31 | class TypeLibExporter; |
32 | class TypeString; |
33 | |
34 | class TypeNameBuilder |
35 | { |
36 | friend class TypeNameBuilderWrapper; |
37 | |
38 | public: |
39 | static void QCALLTYPE _ReleaseTypeNameBuilder(TypeNameBuilder * pTnb); |
40 | static TypeNameBuilder * QCALLTYPE _CreateTypeNameBuilder(); |
41 | static void QCALLTYPE _OpenGenericArguments(TypeNameBuilder * pTnb); |
42 | static void QCALLTYPE _CloseGenericArguments(TypeNameBuilder *pTnb); |
43 | static void QCALLTYPE _OpenGenericArgument(TypeNameBuilder * pTnb); |
44 | static void QCALLTYPE _CloseGenericArgument(TypeNameBuilder * pTnb); |
45 | static void QCALLTYPE _AddName(TypeNameBuilder * pTnb, LPCWSTR wszName); |
46 | static void QCALLTYPE _AddPointer(TypeNameBuilder * pTnb); |
47 | static void QCALLTYPE _AddByRef(TypeNameBuilder * pTnb); |
48 | static void QCALLTYPE _AddSzArray(TypeNameBuilder * pTnb); |
49 | static void QCALLTYPE _AddArray(TypeNameBuilder * pTnb, DWORD dwRank); |
50 | static void QCALLTYPE _AddAssemblySpec(TypeNameBuilder * pTnb, LPCWSTR wszAssemblySpec); |
51 | static void QCALLTYPE _ToString(TypeNameBuilder * pTnb, QCall::StringHandleOnStack retString); |
52 | static void QCALLTYPE _Clear(TypeNameBuilder * pTnb); |
53 | |
54 | private: |
55 | friend class TypeString; |
56 | friend SString* TypeName::ToString(SString*, BOOL, BOOL, BOOL); |
57 | friend TypeHandle TypeName::GetTypeWorker(BOOL, BOOL, Assembly*, BOOL, BOOL, Assembly*, |
58 | ICLRPrivBinder * pPrivHostBinder, |
59 | BOOL, OBJECTREF *); |
60 | HRESULT OpenGenericArguments(); |
61 | HRESULT CloseGenericArguments(); |
62 | HRESULT OpenGenericArgument(); |
63 | HRESULT CloseGenericArgument(); |
64 | HRESULT AddName(LPCWSTR szName); |
65 | HRESULT AddName(LPCWSTR szName, LPCWSTR szNamespace); |
66 | HRESULT AddPointer(); |
67 | HRESULT AddByRef(); |
68 | HRESULT AddSzArray(); |
69 | HRESULT AddArray(DWORD rank); |
70 | HRESULT AddAssemblySpec(LPCWSTR szAssemblySpec); |
71 | HRESULT ToString(BSTR* pszStringRepresentation); |
72 | HRESULT Clear(); |
73 | |
74 | private: |
75 | class Stack |
76 | { |
77 | public: |
78 | Stack() : m_depth(0) { LIMITED_METHOD_CONTRACT; } |
79 | |
80 | public: |
81 | COUNT_T Push(COUNT_T element) { WRAPPER_NO_CONTRACT; *m_stack.Append() = element; m_depth++; return Tos(); } |
82 | COUNT_T Pop() |
83 | { |
84 | CONTRACTL |
85 | { |
86 | THROWS; |
87 | GC_NOTRIGGER; |
88 | MODE_ANY; |
89 | PRECONDITION(GetDepth() > 0); |
90 | } |
91 | CONTRACTL_END; |
92 | |
93 | COUNT_T tos = Tos(); |
94 | m_stack.Delete(m_stack.End() - 1); |
95 | m_depth--; |
96 | return tos; |
97 | } |
98 | COUNT_T Tos() { WRAPPER_NO_CONTRACT; return m_stack.End()[-1]; } |
99 | void Clear() { WRAPPER_NO_CONTRACT; while(GetDepth()) Pop(); } |
100 | COUNT_T GetDepth() { WRAPPER_NO_CONTRACT; return m_depth; } |
101 | |
102 | private: |
103 | INT32 m_depth; |
104 | InlineSArray<COUNT_T, 16> m_stack; |
105 | }; |
106 | |
107 | |
108 | public: |
109 | typedef enum |
110 | { |
111 | ParseStateSTART = 0x0001, |
112 | ParseStateNAME = 0x0004, |
113 | ParseStateGENARGS = 0x0008, |
114 | ParseStatePTRARR = 0x0010, |
115 | ParseStateBYREF = 0x0020, |
116 | ParseStateASSEMSPEC = 0x0080, |
117 | ParseStateERROR = 0x0100, |
118 | } |
119 | ParseState; |
120 | |
121 | public: |
122 | TypeNameBuilder(SString* pStr, ParseState parseState = ParseStateSTART); |
123 | TypeNameBuilder() { WRAPPER_NO_CONTRACT; m_pStr = &m_str; Clear(); } |
124 | void SetUseAngleBracketsForGenerics(BOOL value) { m_bUseAngleBracketsForGenerics = value; } |
125 | void Append(LPCWSTR pStr) { WRAPPER_NO_CONTRACT; m_pStr->Append(pStr); } |
126 | void Append(WCHAR c) { WRAPPER_NO_CONTRACT; m_pStr->Append(c); } |
127 | SString* GetString() { WRAPPER_NO_CONTRACT; return m_pStr; } |
128 | |
129 | private: |
130 | void EscapeName(LPCWSTR szName); |
131 | void EscapeAssemblyName(LPCWSTR szName); |
132 | void EscapeEmbeddedAssemblyName(LPCWSTR szName); |
133 | BOOL CheckParseState(int validState) { WRAPPER_NO_CONTRACT; return ((int)m_parseState & validState) != 0; } |
134 | //BOOL CheckParseState(int validState) { WRAPPER_NO_CONTRACT; ASSERT(((int)m_parseState & validState) != 0); return TRUE; } |
135 | HRESULT Fail() { WRAPPER_NO_CONTRACT; m_parseState = ParseStateERROR; return E_FAIL; } |
136 | void PushOpenGenericArgument(); |
137 | void PopOpenGenericArgument(); |
138 | |
139 | private: |
140 | ParseState m_parseState; |
141 | SString* m_pStr; |
142 | InlineSString<256> m_str; |
143 | DWORD m_instNesting; |
144 | BOOL m_bFirstInstArg; |
145 | BOOL m_bNestedName; |
146 | BOOL m_bHasAssemblySpec; |
147 | BOOL m_bUseAngleBracketsForGenerics; |
148 | Stack m_stack; |
149 | }; |
150 | |
151 | // Class that's exposed to COM and wraps TypeNameBuilder (so that it can thunk |
152 | // all the entry points in order to perform stack probes). |
153 | class TypeNameBuilderWrapper : public ITypeNameBuilder |
154 | { |
155 | public: |
156 | virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppUnk); |
157 | virtual ULONG STDMETHODCALLTYPE AddRef(); |
158 | virtual ULONG STDMETHODCALLTYPE Release(); |
159 | |
160 | virtual HRESULT STDMETHODCALLTYPE OpenGenericArguments(); |
161 | virtual HRESULT STDMETHODCALLTYPE CloseGenericArguments(); |
162 | virtual HRESULT STDMETHODCALLTYPE OpenGenericArgument(); |
163 | virtual HRESULT STDMETHODCALLTYPE CloseGenericArgument(); |
164 | virtual HRESULT STDMETHODCALLTYPE AddName(LPCWSTR szName); |
165 | virtual HRESULT STDMETHODCALLTYPE AddPointer(); |
166 | virtual HRESULT STDMETHODCALLTYPE AddByRef(); |
167 | virtual HRESULT STDMETHODCALLTYPE AddSzArray(); |
168 | virtual HRESULT STDMETHODCALLTYPE AddArray(DWORD rank); |
169 | virtual HRESULT STDMETHODCALLTYPE AddAssemblySpec(LPCWSTR szAssemblySpec); |
170 | virtual HRESULT STDMETHODCALLTYPE ToString(BSTR* pszStringRepresentation); |
171 | virtual HRESULT STDMETHODCALLTYPE Clear(); |
172 | |
173 | TypeNameBuilderWrapper() : m_ref(0) { WRAPPER_NO_CONTRACT; } |
174 | virtual ~TypeNameBuilderWrapper() {} |
175 | |
176 | private: |
177 | LONG m_ref; |
178 | TypeNameBuilder m_tnb; |
179 | }; |
180 | |
181 | // -------------------------------------------------------------------------- |
182 | // This type can generate names for types. It is used by reflection methods |
183 | // like System.RuntimeType.RuntimeTypeCache.ConstructName |
184 | // |
185 | |
186 | class TypeString |
187 | { |
188 | // ----------------------------------------------------------------------- |
189 | // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING |
190 | // ----------------------------------------------------------------------- |
191 | // Do no change the formatting of these strings as they are used by |
192 | // serialization, and it would break serialization backwards-compatibility. |
193 | |
194 | public: |
195 | |
196 | typedef enum |
197 | { |
198 | FormatBasic = 0x00000000, // Not a bitmask, simply the tersest flag settings possible |
199 | FormatNamespace = 0x00000001, // Include namespace and/or enclosing class names in type names |
200 | FormatFullInst = 0x00000002, // Include namespace and assembly in generic types (regardless of other flag settings) |
201 | FormatAssembly = 0x00000004, // Include assembly display name in type names |
202 | FormatSignature = 0x00000008, // Include signature in method names |
203 | FormatNoVersion = 0x00000010, // Suppress version and culture information in all assembly names |
204 | #ifdef _DEBUG |
205 | FormatDebug = 0x00000020, // For debug printing of types only |
206 | #endif |
207 | FormatAngleBrackets = 0x00000040, // Whether generic types are C<T> or C[T] |
208 | FormatStubInfo = 0x00000080, // Include stub info like {unbox-stub} |
209 | FormatGenericParam = 0x00000100, // Use !name and !!name for generic type and method parameters |
210 | } |
211 | FormatFlags; |
212 | |
213 | public: |
214 | // Append the name of the type td to the string |
215 | // The following flags in the FormatFlags argument are significant: FormatNamespace |
216 | static void AppendTypeDef(SString& tnb, IMDInternalImport *pImport, mdTypeDef td, DWORD format = FormatNamespace); |
217 | |
218 | // Append a square-bracket-enclosed, comma-separated list of n type parameters in inst to the string s |
219 | // and enclose each parameter in square brackets to disambiguate the commas |
220 | // The following flags in the FormatFlags argument are significant: FormatNamespace FormatFullInst FormatAssembly FormatNoVersion |
221 | static void AppendInst(SString& s, Instantiation inst, DWORD format = FormatNamespace); |
222 | |
223 | // Append a representation of the type t to the string s |
224 | // The following flags in the FormatFlags argument are significant: FormatNamespace FormatFullInst FormatAssembly FormatNoVersion |
225 | static void AppendType(SString& s, TypeHandle t, DWORD format = FormatNamespace); |
226 | |
227 | // Append a representation of the type t to the string s, using the generic |
228 | // instantiation info provided, instead of the instantiation in the TypeHandle. |
229 | static void AppendType(SString& s, TypeHandle t, Instantiation typeInstantiation, DWORD format = FormatNamespace); |
230 | |
231 | static void AppendTypeKey(SString& s, TypeKey *pTypeKey, DWORD format = FormatNamespace); |
232 | |
233 | // Appends the method name and generic instantiation info. This might |
234 | // look like "Namespace.ClassName[T].Foo[U, V]()" |
235 | static void AppendMethod(SString& s, MethodDesc *pMD, Instantiation typeInstantiation, const DWORD format = FormatNamespace|FormatSignature); |
236 | |
237 | // Append a representation of the method m to the string s |
238 | // The following flags in the FormatFlags argument are significant: FormatNamespace FormatFullInst FormatAssembly FormatSignature FormatNoVersion |
239 | static void AppendMethodInternal(SString& s, MethodDesc *pMD, const DWORD format = FormatNamespace|FormatSignature|FormatStubInfo); |
240 | |
241 | // Append the field name and generic instantiation info. |
242 | static void AppendField(SString& s, FieldDesc *pFD, Instantiation typeInstantiation, const DWORD format = FormatNamespace); |
243 | #ifdef _DEBUG |
244 | // These versions are NOTHROWS. They are meant for diagnostic purposes only |
245 | // as they may leave "s" in a bad state if there are any problems/exceptions. |
246 | static void AppendMethodDebug(SString& s, MethodDesc *pMD); |
247 | static void AppendTypeDebug(SString& s, TypeHandle t); |
248 | static void AppendTypeKeyDebug(SString& s, TypeKey* pTypeKey); |
249 | #endif |
250 | |
251 | private: |
252 | friend class TypeLibExporter; |
253 | friend class TypeNameBuilder; |
254 | static void AppendMethodImpl(SString& s, MethodDesc *pMD, Instantiation typeInstantiation, const DWORD format); |
255 | static void AppendTypeDef(TypeNameBuilder& tnb, IMDInternalImport *pImport, mdTypeDef td, DWORD format = FormatNamespace); |
256 | static void AppendNestedTypeDef(TypeNameBuilder& tnb, IMDInternalImport *pImport, mdTypeDef td, DWORD format = FormatNamespace); |
257 | static void AppendInst(TypeNameBuilder& tnb, Instantiation inst, DWORD format = FormatNamespace); |
258 | static void AppendType(TypeNameBuilder& tnb, TypeHandle t, Instantiation typeInstantiation, DWORD format = FormatNamespace); // ???? |
259 | static void AppendTypeKey(TypeNameBuilder& tnb, TypeKey *pTypeKey, DWORD format = FormatNamespace); |
260 | static void AppendParamTypeQualifier(TypeNameBuilder& tnb, CorElementType kind, DWORD rank); |
261 | static void EscapeSimpleTypeName(SString* ssTypeName, SString* ssEscapedTypeName); |
262 | static bool ContainsReservedChar(LPCWSTR pTypeName); |
263 | }; |
264 | |
265 | #endif |
266 | |
267 | |