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
31class TypeLibExporter;
32class TypeString;
33
34class TypeNameBuilder
35{
36 friend class TypeNameBuilderWrapper;
37
38public:
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
54private:
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
74private:
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
108public:
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
121public:
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
129private:
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
139private:
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).
153class TypeNameBuilderWrapper : public ITypeNameBuilder
154{
155public:
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
176private:
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
186class 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
194public:
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
213public:
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
251private:
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