internal static PEMethodSymbol GetSourceMethod(this CSharpCompilation compilation, Guid moduleVersionId, int methodToken) { var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var method = GetMethod(compilation, moduleVersionId, methodHandle); var metadataDecoder = new MetadataDecoder((PEModuleSymbol)method.ContainingModule); var containingType = method.ContainingType; string sourceMethodName; if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(containingType.Name, GeneratedNameKind.StateMachineType, out sourceMethodName)) { foreach (var member in containingType.ContainingType.GetMembers(sourceMethodName)) { var candidateMethod = member as PEMethodSymbol; if (candidateMethod != null) { var module = metadataDecoder.Module; methodHandle = candidateMethod.Handle; string stateMachineTypeName; if (module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out stateMachineTypeName) || module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out stateMachineTypeName)) { if (metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType)) { return candidateMethod; } } } } } return method; }
private static Imports BuildImports(CSharpCompilation compilation, PEModuleSymbol module, ImmutableArray<ImportRecord> importRecords, InContainerBinder binder, MetadataDecoder metadataDecoder) { // We make a first pass to extract all of the extern aliases because other imports may depend on them. var externsBuilder = ArrayBuilder<AliasAndExternAliasDirective>.GetInstance(); foreach (var importRecord in importRecords) { if (importRecord.TargetKind != ImportTargetKind.Assembly) { continue; } var alias = importRecord.Alias; IdentifierNameSyntax aliasNameSyntax; if (!TryParseIdentifierNameSyntax(alias, out aliasNameSyntax)) { Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid extern alias '{alias}'"); continue; } var externAliasSyntax = SyntaxFactory.ExternAliasDirective(aliasNameSyntax.Identifier); var aliasSymbol = new AliasSymbol(binder, externAliasSyntax); // Binder is only used to access compilation. externsBuilder.Add(new AliasAndExternAliasDirective(aliasSymbol, externAliasDirective: null)); // We have one, but we pass null for consistency. } var externs = externsBuilder.ToImmutableAndFree(); if (externs.Any()) { // NB: This binder (and corresponding Imports) is only used to bind the other imports. // We'll merge the externs into a final Imports object and return that to be used in // the actual binder chain. binder = new InContainerBinder( binder.Container, binder, Imports.FromCustomDebugInfo(binder.Compilation, ImmutableDictionary<string, AliasAndUsingDirective>.Empty, ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externs)); } var usingAliases = ImmutableDictionary.CreateBuilder<string, AliasAndUsingDirective>(); var usingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance(); foreach (var importRecord in importRecords) { switch (importRecord.TargetKind) { case ImportTargetKind.Type: { var portableImportRecord = importRecord as PortableImportRecord; TypeSymbol typeSymbol = portableImportRecord != null ? portableImportRecord.GetTargetType(metadataDecoder) : metadataDecoder.GetTypeSymbolForSerializedType(importRecord.TargetString); Debug.Assert((object)typeSymbol != null); if (typeSymbol.IsErrorType()) { // Type is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } else if (importRecord.Alias == null && !typeSymbol.IsStatic) { // Only static types can be directly imported. continue; } if (!TryAddImport(importRecord.Alias, typeSymbol, usingsBuilder, usingAliases, binder, importRecord)) { continue; } break; } case ImportTargetKind.Namespace: { var namespaceName = importRecord.TargetString; NameSyntax targetSyntax; if (!SyntaxHelpers.TryParseDottedName(namespaceName, out targetSyntax)) { // DevDiv #999086: Some previous version of VS apparently generated type aliases as "UA{alias} T{alias-qualified type name}". // Neither Roslyn nor Dev12 parses such imports. However, Roslyn discards them, rather than interpreting them as "UA{alias}" // (which will rarely work and never be correct). Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid target '{importRecord.TargetString}'"); continue; } NamespaceSymbol namespaceSymbol; var portableImportRecord = importRecord as PortableImportRecord; if (portableImportRecord != null) { var targetAssembly = portableImportRecord.GetTargetAssembly<ModuleSymbol, AssemblySymbol>(module, module.Module); if ((object)targetAssembly == null) { namespaceSymbol = BindNamespace(namespaceName, compilation.GlobalNamespace); } else if (targetAssembly.IsMissing) { Debug.WriteLine($"Import record '{importRecord}' has invalid assembly reference '{targetAssembly.Identity}'"); continue; } else { namespaceSymbol = BindNamespace(namespaceName, targetAssembly.GlobalNamespace); } } else { var globalNamespace = compilation.GlobalNamespace; var externAlias = ((NativeImportRecord)importRecord).ExternAlias; if (externAlias != null) { IdentifierNameSyntax externAliasSyntax = null; if (!TryParseIdentifierNameSyntax(externAlias, out externAliasSyntax)) { Debug.WriteLine($"Import record '{importRecord}' has syntactically invalid extern alias '{externAlias}'"); continue; } var unusedDiagnostics = DiagnosticBag.GetInstance(); var aliasSymbol = (AliasSymbol)binder.BindNamespaceAliasSymbol(externAliasSyntax, unusedDiagnostics); unusedDiagnostics.Free(); if ((object)aliasSymbol == null) { Debug.WriteLine($"Import record '{importRecord}' requires unknown extern alias '{externAlias}'"); continue; } globalNamespace = (NamespaceSymbol)aliasSymbol.Target; } namespaceSymbol = BindNamespace(namespaceName, globalNamespace); } if ((object)namespaceSymbol == null) { // Namespace is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } if (!TryAddImport(importRecord.Alias, namespaceSymbol, usingsBuilder, usingAliases, binder, importRecord)) { continue; } break; } case ImportTargetKind.Assembly: { // Handled in first pass (above). break; } default: { throw ExceptionUtilities.UnexpectedValue(importRecord.TargetKind); } } } return Imports.FromCustomDebugInfo(binder.Compilation, usingAliases.ToImmutableDictionary(), usingsBuilder.ToImmutableAndFree(), externs); }
private static Imports BuildImports(CSharpCompilation compilation, ImmutableArray<string> importStrings, InContainerBinder binder, MetadataDecoder metadataDecoder) { // We make a first pass to extract all of the extern aliases because other imports may depend on them. var externsBuilder = ArrayBuilder<AliasAndExternAliasDirective>.GetInstance(); foreach (var importString in importStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine("Unable to parse import string '{0}'", (object)importString); continue; } else if (kind != ImportTargetKind.Assembly) { continue; } Debug.Assert(alias == null); Debug.Assert(externAlias != null); Debug.Assert(target == null); NameSyntax aliasNameSyntax; if (!SyntaxHelpers.TryParseDottedName(externAlias, out aliasNameSyntax) || aliasNameSyntax.Kind() != SyntaxKind.IdentifierName) { Debug.WriteLine("Import string '{0}' has syntactically invalid extern alias '{1}'", importString, externAlias); continue; } var aliasToken = ((IdentifierNameSyntax)aliasNameSyntax).Identifier; var externAliasSyntax = SyntaxFactory.ExternAliasDirective(aliasToken); var aliasSymbol = new AliasSymbol(binder, externAliasSyntax); // Binder is only used to access compilation. externsBuilder.Add(new AliasAndExternAliasDirective(aliasSymbol, externAliasSyntax)); } var externs = externsBuilder.ToImmutableAndFree(); if (externs.Any()) { // NB: This binder (and corresponding Imports) is only used to bind the other imports. // We'll merge the externs into a final Imports object and return that to be used in // the actual binder chain. binder = new InContainerBinder( binder.Container, binder, Imports.FromCustomDebugInfo(binder.Compilation, new Dictionary<string, AliasAndUsingDirective>(), ImmutableArray<NamespaceOrTypeAndUsingDirective>.Empty, externs)); } var usingAliases = new Dictionary<string, AliasAndUsingDirective>(); var usingsBuilder = ArrayBuilder<NamespaceOrTypeAndUsingDirective>.GetInstance(); foreach (var importString in importStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine("Unable to parse import string '{0}'", (object)importString); continue; } switch (kind) { case ImportTargetKind.Type: { Debug.Assert(target != null, string.Format("Type import string '{0}' has no target", importString)); Debug.Assert(externAlias == null, string.Format("Type import string '{0}' has an extern alias (should be folded into target)", importString)); TypeSymbol typeSymbol = metadataDecoder.GetTypeSymbolForSerializedType(target); Debug.Assert((object)typeSymbol != null); if (typeSymbol.IsErrorType()) { // Type is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } else if (alias == null && !typeSymbol.IsStatic) { // Only static types can be directly imported. continue; } NameSyntax typeSyntax = SyntaxFactory.ParseName(typeSymbol.ToDisplayString(s_fullNameFormat)); if (!TryAddImport(alias, typeSyntax, typeSymbol, usingsBuilder, usingAliases, binder, importString)) { continue; } break; } case ImportTargetKind.Namespace: { Debug.Assert(target != null, string.Format("Namespace import string '{0}' has no target", importString)); NameSyntax targetSyntax; if (!SyntaxHelpers.TryParseDottedName(target, out targetSyntax)) { // DevDiv #999086: Some previous version of VS apparently generated type aliases as "UA{alias} T{alias-qualified type name}". // Neither Roslyn nor Dev12 parses such imports. However, Roslyn discards them, rather than interpreting them as "UA{alias}" // (which will rarely work and never be correct). Debug.WriteLine("Import string '{0}' has syntactically invalid target '{1}'", importString, target); continue; } if (externAlias != null) { IdentifierNameSyntax externAliasSyntax; if (!TryParseIdentifierNameSyntax(externAlias, out externAliasSyntax)) { Debug.WriteLine("Import string '{0}' has syntactically invalid extern alias '{1}'", importString, externAlias); continue; } // This is the case that requires the binder to already know about extern aliases. targetSyntax = SyntaxHelpers.PrependExternAlias(externAliasSyntax, targetSyntax); } var unusedDiagnostics = DiagnosticBag.GetInstance(); var namespaceSymbol = binder.BindNamespaceOrType(targetSyntax, unusedDiagnostics).ExpressionSymbol as NamespaceSymbol; unusedDiagnostics.Free(); if ((object)namespaceSymbol == null) { // Namespace is unrecognized. The import may have been // valid in the original source but unnecessary. continue; // Don't add anything for this import. } if (!TryAddImport(alias, targetSyntax, namespaceSymbol, usingsBuilder, usingAliases, binder, importString)) { continue; } break; } case ImportTargetKind.Assembly: { // Handled in first pass (above). break; } default: { throw ExceptionUtilities.UnexpectedValue(kind); } } } return Imports.FromCustomDebugInfo(binder.Compilation, usingAliases, usingsBuilder.ToImmutableAndFree(), externs); }