| 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 | |