/// <summary> /// Get the import strings for a given method, following forward pointers as necessary. /// </summary> /// <returns> /// A list of import strings. There should always be at least one entry, for the global namespace. /// </returns> public static ImmutableArray <string> GetVisualBasicImportStrings(this ISymUnmanagedReader reader, int methodToken) { ImmutableArray <string> importStrings = reader.GetBaselineMethod(methodToken).GetImportStrings(); // Follow at most one forward link. if (importStrings.Length > 0) { // As in PdbUtil::GetRawNamespaceListCore, we consider only the first string when // checking for forwarding. string importString = importStrings[0]; if (importString.Length >= 2 && importString[0] == '@') { char ch1 = importString[1]; if ('0' <= ch1 && ch1 <= '9') { int tempMethodToken; if (int.TryParse(importString.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture, out tempMethodToken)) { return(reader.GetBaselineMethod(tempMethodToken).GetImportStrings()); } } } } return(importStrings); }
/// <summary> /// Get the import strings for a given method, following forward pointers as necessary. /// </summary> /// <returns> /// For each namespace enclosing the method, a list of import strings, innermost to outermost. /// There should always be at least one entry, for the global namespace. /// </returns> public static ImmutableArray <ImmutableArray <string> > GetCSharpGroupedImportStrings(this ISymUnmanagedReader reader, int methodToken, out ImmutableArray <string> externAliasStrings) { externAliasStrings = default(ImmutableArray <string>); ImmutableArray <short> groupSizes = default(ImmutableArray <short>); bool seenForward = false; RETRY: var bytes = reader.GetCustomDebugInfo(methodToken); if (bytes == null) { return(default(ImmutableArray <ImmutableArray <string> >)); } int offset = 0; byte globalVersion; byte unusedGlobalCount; ReadGlobalHeader(bytes, ref offset, out globalVersion, out unusedGlobalCount); CheckVersion(globalVersion, methodToken); while (offset < bytes.Length) { byte version; CustomDebugInfoKind kind; int size; ReadRecordHeader(bytes, ref offset, out version, out kind, out size); CheckVersion(version, methodToken); if (kind == CustomDebugInfoKind.UsingInfo) { if (!groupSizes.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one Using record for method {0}", FormatMethodToken(methodToken))); } ReadUsingRecord(bytes, ref offset, size, out groupSizes); } else if (kind == CustomDebugInfoKind.ForwardInfo) { if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Did not expect both Forward and ForwardToModule records for method {0}", FormatMethodToken(methodToken))); } ReadForwardRecord(bytes, ref offset, size, out methodToken); if (!seenForward) // Follow at most one forward link. { seenForward = true; goto RETRY; } } else if (kind == CustomDebugInfoKind.ForwardToModuleInfo) { if (!externAliasStrings.IsDefault) { throw new InvalidOperationException(string.Format("Expected at most one ForwardToModule record for method {0}", FormatMethodToken(methodToken))); } int moduleInfoMethodToken; ReadForwardToModuleRecord(bytes, ref offset, size, out moduleInfoMethodToken); ImmutableArray <string> allModuleInfoImportStrings = GetImportStrings(reader.GetBaselineMethod(moduleInfoMethodToken)); ArrayBuilder <string> externAliasBuilder = ArrayBuilder <string> .GetInstance(); foreach (string importString in allModuleInfoImportStrings) { if (IsCSharpExternAliasInfo(importString)) { externAliasBuilder.Add(importString); } } externAliasStrings = externAliasBuilder.ToImmutableAndFree(); } else { SkipRecord(bytes, ref offset, size); } } if (groupSizes.IsDefault) { throw new InvalidOperationException(string.Format("Didn't find usings info for method {0}", FormatMethodToken(methodToken))); } ImmutableArray <string> importStrings = GetImportStrings(reader.GetBaselineMethod(methodToken)); int numImportStrings = importStrings.Length; ArrayBuilder <ImmutableArray <string> > resultBuilder = ArrayBuilder <ImmutableArray <string> > .GetInstance(groupSizes.Length); ArrayBuilder <string> groupBuilder = ArrayBuilder <string> .GetInstance(); int pos = 0; foreach (short groupSize in groupSizes) { for (int i = 0; i < groupSize; i++, pos++) { if (pos >= numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates more imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } string importString = importStrings[pos]; if (IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Encountered extern alias info before all import strings were consumed (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } resultBuilder.Add(groupBuilder.ToImmutable()); groupBuilder.Clear(); } if (externAliasStrings.IsDefault) { Debug.Assert(groupBuilder.Count == 0); // Extern alias detail strings (prefix "Z") are not included in the group counts. for (; pos < numImportStrings; pos++) { string importString = importStrings[pos]; if (!IsCSharpExternAliasInfo(importString)) { throw new InvalidOperationException(string.Format("Expected only extern alias info strings after consuming the indicated number of imports (method {0}).", FormatMethodToken(methodToken))); } groupBuilder.Add(importString); } externAliasStrings = groupBuilder.ToImmutableAndFree(); } else { groupBuilder.Free(); if (pos < numImportStrings) { throw new InvalidOperationException(string.Format("Group size indicates fewer imports than there are import strings (method {0}).", FormatMethodToken(methodToken))); } } return(resultBuilder.ToImmutableAndFree()); }