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; }
internal static PENamedTypeSymbol GetType(this CSharpCompilation compilation, Guid moduleVersionId, int typeToken, out MetadataDecoder metadataDecoder) { var module = compilation.GetModule(moduleVersionId); var reader = module.Module.MetadataReader; var typeHandle = (TypeDefinitionHandle)MetadataTokens.Handle(typeToken); var type = GetType(module, typeHandle); metadataDecoder = new MetadataDecoder(module, type); return type; }
private EvaluationContext( MethodContextReuseConstraints? methodContextReuseConstraints, CSharpCompilation compilation, MetadataDecoder metadataDecoder, MethodSymbol currentFrame, ImmutableArray<LocalSymbol> locals, InScopeHoistedLocals inScopeHoistedLocals, MethodDebugInfo methodDebugInfo) { Debug.Assert(inScopeHoistedLocals != null); this.MethodContextReuseConstraints = methodContextReuseConstraints; this.Compilation = compilation; _metadataDecoder = metadataDecoder; _currentFrame = currentFrame; _locals = locals; _inScopeHoistedLocals = inScopeHoistedLocals; _methodDebugInfo = methodDebugInfo; }
private EvaluationContext( ImmutableArray<MetadataBlock> metadataBlocks, MethodScope methodScope, CSharpCompilation compilation, MetadataDecoder metadataDecoder, MethodSymbol currentFrame, ImmutableArray<LocalSymbol> locals, ImmutableSortedSet<int> inScopeHoistedLocalIndices, ImmutableArray<ImmutableArray<string>> importStringGroups, ImmutableArray<string> externAliasStrings) { Debug.Assert(inScopeHoistedLocalIndices != null); Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault); this.MetadataBlocks = metadataBlocks; this.MethodScope = methodScope; this.Compilation = compilation; _metadataDecoder = metadataDecoder; _currentFrame = currentFrame; _locals = locals; _inScopeHoistedLocalIndices = inScopeHoistedLocalIndices; _importStringGroups = importStringGroups; _externAliasStrings = externAliasStrings; }
private static void GetConstants( ArrayBuilder<LocalSymbol> builder, MethodSymbol method, IEnumerable<ISymUnmanagedScope> scopes, MetadataDecoder metadataDecoder, ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap, SourceAssemblySymbol containingAssembly) { foreach (var scope in scopes) { foreach (var constant in scope.GetConstants()) { string name = constant.GetName(); object rawValue = constant.GetValue(); var signature = constant.GetSignature(); var info = metadataDecoder.GetLocalInfo(signature); Debug.Assert(!info.IsByRef); Debug.Assert(!info.IsPinned); var type = info.Type; var constantValue = PdbHelpers.GetConstantValue(type.EnumUnderlyingType(), rawValue); ImmutableArray<bool> dynamicFlags; if (dynamicLocalConstantMap != null && dynamicLocalConstantMap.TryGetValue(name, out dynamicFlags)) { type = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags( type, containingAssembly, RefKind.None, dynamicFlags); } builder.Add(new EELocalConstantSymbol(method, name, type, constantValue)); } } }
internal static EvaluationContext CreateMethodContext( CSharpCompilation compilation, object symReader, Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, int localSignatureToken) { Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition); var typedSymReader = (ISymUnmanagedReader)symReader; var allScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance(); var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance(); typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes); var methodContextReuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive); allScopes.Free(); var localNames = containingScopes.GetLocalNames(); var inScopeHoistedLocals = InScopeHoistedLocals.Empty; var methodDebugInfo = default(MethodDebugInfo); if (typedSymReader != null) { try { // TODO (https://github.com/dotnet/roslyn/issues/702): switch on the type of typedSymReader and call the appropriate helper. methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion, localNames.FirstOrDefault()); var inScopeHoistedLocalIndices = methodDebugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref methodContextReuseConstraints); inScopeHoistedLocals = new CSharpInScopeHoistedLocals(inScopeHoistedLocalIndices); } catch (InvalidOperationException) { // bad CDI, ignore } } var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle); Debug.Assert((object)currentFrame != null); var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame); var localInfo = metadataDecoder.GetLocalInfo(localSignatureToken); var localBuilder = ArrayBuilder<LocalSymbol>.GetInstance(); var sourceAssembly = compilation.SourceAssembly; GetLocals(localBuilder, currentFrame, localNames, localInfo, methodDebugInfo.DynamicLocalMap, sourceAssembly); GetConstants(localBuilder, currentFrame, containingScopes, metadataDecoder, methodDebugInfo.DynamicLocalConstantMap, sourceAssembly); containingScopes.Free(); var locals = localBuilder.ToImmutableAndFree(); return new EvaluationContext( methodContextReuseConstraints, compilation, metadataDecoder, currentFrame, locals, inScopeHoistedLocals, methodDebugInfo); }
private void CompileTimeAndRuntimeAssemblies( ImmutableArray<MetadataReference> compileReferences, ImmutableArray<MetadataReference> runtimeReferences, string storageAssemblyName) { var source = @"class C { static void M(LibraryA.A a, LibraryB.B b, Windows.Data.Text.TextSegment t, Windows.Storage.StorageFolder f) { } }"; var compilation0 = CreateCompilationWithMscorlib(source, compileReferences, TestOptions.DebugDll); WithRuntimeInstance(compilation0, runtimeReferences, runtime => { var context = CreateMethodContext(runtime, "C.M"); string error; var testData = new CompilationTestData(); context.CompileExpression("(object)a ?? (object)b ?? (object)t ?? f", out error, testData); Assert.Null(error); testData.GetMethodData("<>x.<>m0").VerifyIL( @"{ // Code size 17 (0x11) .maxstack 2 IL_0000: ldarg.0 IL_0001: dup IL_0002: brtrue.s IL_0010 IL_0004: pop IL_0005: ldarg.1 IL_0006: dup IL_0007: brtrue.s IL_0010 IL_0009: pop IL_000a: ldarg.2 IL_000b: dup IL_000c: brtrue.s IL_0010 IL_000e: pop IL_000f: ldarg.3 IL_0010: ret }"); testData = new CompilationTestData(); var result = context.CompileExpression("default(Windows.Storage.StorageFolder)", out error, testData); Assert.Null(error); var methodData = testData.GetMethodData("<>x.<>m0"); methodData.VerifyIL( @"{ // Code size 2 (0x2) .maxstack 1 IL_0000: ldnull IL_0001: ret }"); // Check return type is from runtime assembly. var assemblyReference = AssemblyMetadata.CreateFromImage(result.Assembly).GetReference(); var compilation = CSharpCompilation.Create( assemblyName: ExpressionCompilerUtilities.GenerateUniqueName(), references: runtimeReferences.Concat(ImmutableArray.Create<MetadataReference>(assemblyReference))); var assembly = ImmutableArray.CreateRange(result.Assembly); using (var metadata = ModuleMetadata.CreateFromImage(ImmutableArray.CreateRange(assembly))) { var reader = metadata.MetadataReader; var typeDef = reader.GetTypeDef("<>x"); var methodHandle = reader.GetMethodDefHandle(typeDef, "<>m0"); var module = (PEModuleSymbol)compilation.GetMember("<>x").ContainingModule; var metadataDecoder = new MetadataDecoder(module); SignatureHeader signatureHeader; BadImageFormatException metadataException; var parameters = metadataDecoder.GetSignatureForMethod(methodHandle, out signatureHeader, out metadataException); Assert.Equal(parameters.Length, 5); var actualReturnType = parameters[0].Type; Assert.Equal(actualReturnType.TypeKind, TypeKind.Class); // not error var expectedReturnType = compilation.GetMember("Windows.Storage.StorageFolder"); Assert.Equal(expectedReturnType, actualReturnType); Assert.Equal(storageAssemblyName, actualReturnType.ContainingAssembly.Name); } }); }
private static void GetConstants( ArrayBuilder<LocalSymbol> builder, MethodSymbol method, ImmutableArray<NamedLocalConstant> constants, MetadataDecoder metadataDecoder, ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap, SourceAssemblySymbol containingAssembly) { foreach (var constant in constants) { var info = metadataDecoder.GetLocalInfo(constant.Signature); Debug.Assert(!info.IsByRef); Debug.Assert(!info.IsPinned); var type = info.Type; ImmutableArray<bool> dynamicFlags; if (dynamicLocalConstantMap.TryGetValue(constant.Name, out dynamicFlags)) { type = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags( type, containingAssembly, RefKind.None, dynamicFlags); } var constantValue = ReinterpretConstantValue(constant.Value, type.SpecialType); builder.Add(new EELocalConstantSymbol(method, constant.Name, type, constantValue)); } }
/// <summary> /// Create a context for evaluating expressions within a method scope. /// </summary> /// <param name="previous">Previous context, if any, for possible re-use.</param> /// <param name="metadataBlocks">Module metadata</param> /// <param name="symReader"><see cref="ISymUnmanagedReader"/> for PDB associated with <paramref name="moduleVersionId"/></param> /// <param name="moduleVersionId">Module containing method</param> /// <param name="methodToken">Method metadata token</param> /// <param name="methodVersion">Method version.</param> /// <param name="ilOffset">IL offset of instruction pointer in method</param> /// <param name="localSignatureToken">Method local signature token</param> /// <returns>Evaluation context</returns> internal static EvaluationContext CreateMethodContext( CSharpMetadataContext previous, ImmutableArray<MetadataBlock> metadataBlocks, object symReader, Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, int localSignatureToken) { Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition); var typedSymReader = (ISymUnmanagedReader)symReader; var scopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance(); typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, scopes); var scope = scopes.GetMethodScope(methodToken, methodVersion); // Re-use the previous compilation if possible. CSharpCompilation compilation; if (metadataBlocks.HaveNotChanged(previous)) { // Re-use entire context if method scope has not changed. var previousContext = previous.EvaluationContext; if ((scope != null) && (previousContext != null) && scope.Equals(previousContext.MethodScope)) { return previousContext; } compilation = previous.Compilation; } else { compilation = metadataBlocks.ToCompilation(); } var localNames = scopes.GetLocalNames(); var dynamicLocalMap = ImmutableDictionary<int, ImmutableArray<bool>>.Empty; var dynamicLocalConstantMap = ImmutableDictionary<string, ImmutableArray<bool>>.Empty; var inScopeHoistedLocalIndices = ImmutableSortedSet<int>.Empty; var groupedImportStrings = default(ImmutableArray<ImmutableArray<string>>); var externAliasStrings = default(ImmutableArray<string>); if (typedSymReader != null) { try { var cdi = typedSymReader.GetCustomDebugInfo(methodToken, methodVersion); if (cdi != null) { CustomDebugInfoReader.GetCSharpDynamicLocalInfo( cdi, methodToken, methodVersion, localNames.FirstOrDefault(), out dynamicLocalMap, out dynamicLocalConstantMap); inScopeHoistedLocalIndices = CustomDebugInfoReader.GetCSharpInScopeHoistedLocalIndices( cdi, methodToken, methodVersion, ilOffset); } groupedImportStrings = typedSymReader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings); } catch (InvalidOperationException) { // bad CDI, ignore } } var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle); Debug.Assert((object)currentFrame != null); var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame); var localInfo = metadataDecoder.GetLocalInfo(localSignatureToken); var localBuilder = ArrayBuilder<LocalSymbol>.GetInstance(); var sourceAssembly = compilation.SourceAssembly; GetLocals(localBuilder, currentFrame, localNames, localInfo, dynamicLocalMap, sourceAssembly); GetConstants(localBuilder, currentFrame, scopes.GetConstantSignatures(), metadataDecoder, dynamicLocalConstantMap, sourceAssembly); scopes.Free(); var locals = localBuilder.ToImmutableAndFree(); return new EvaluationContext( metadataBlocks, scope, compilation, metadataDecoder, currentFrame, locals, inScopeHoistedLocalIndices, groupedImportStrings, externAliasStrings); }
private static PENamedTypeSymbol GetType(PEModuleSymbol module, TypeDefinitionHandle typeHandle) { var metadataDecoder = new MetadataDecoder(module); return (PENamedTypeSymbol)metadataDecoder.GetTypeOfToken(typeHandle); }
private static EvaluationContext CreateMethodContext( CSharpCompilation compilation, object symReader, Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, int localSignatureToken) { var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var localSignatureHandle = (localSignatureToken != 0) ? (StandaloneSignatureHandle)MetadataTokens.Handle(localSignatureToken) : default(StandaloneSignatureHandle); var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle); Debug.Assert((object)currentFrame != null); var sourceAssembly = compilation.SourceAssembly; var symbolProvider = new CSharpEESymbolProvider(sourceAssembly, (PEModuleSymbol)currentFrame.ContainingModule, currentFrame); var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame); var localInfo = metadataDecoder.GetLocalInfo(localSignatureHandle); var typedSymReader = (ISymUnmanagedReader3)symReader; var inScopeHoistedLocals = InScopeHoistedLocals.Empty; var debugInfo = MethodDebugInfo<TypeSymbol, LocalSymbol>.ReadMethodDebugInfo(typedSymReader, symbolProvider, methodToken, methodVersion, ilOffset, isVisualBasicMethod: false); var reuseSpan = debugInfo.ReuseSpan; var localsBuilder = ArrayBuilder<LocalSymbol>.GetInstance(); MethodDebugInfo<TypeSymbol, LocalSymbol>.GetLocals(localsBuilder, symbolProvider, debugInfo.LocalVariableNames, localInfo, debugInfo.DynamicLocalMap); if (!debugInfo.HoistedLocalScopeRecords.IsDefaultOrEmpty) { inScopeHoistedLocals = new CSharpInScopeHoistedLocals(debugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref reuseSpan)); } localsBuilder.AddRange(debugInfo.LocalConstants); return new EvaluationContext( new MethodContextReuseConstraints(moduleVersionId, methodToken, methodVersion, reuseSpan), compilation, currentFrame, localsBuilder.ToImmutableAndFree(), inScopeHoistedLocals, debugInfo); }
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 Binder CreateBinderChain( CSharpCompilation compilation, PEModuleSymbol module, NamespaceSymbol @namespace, ImmutableArray<ImmutableArray<ImportRecord>> importRecordGroups, MetadataDecoder metadataDecoder) { var stack = ArrayBuilder<string>.GetInstance(); while ((object)@namespace != null) { stack.Push(@namespace.Name); @namespace = @namespace.ContainingNamespace; } Binder binder = new BuckStopsHereBinder(compilation); var hasImports = !importRecordGroups.IsDefaultOrEmpty; var numImportStringGroups = hasImports ? importRecordGroups.Length : 0; var currentStringGroup = numImportStringGroups - 1; // PERF: We used to call compilation.GetCompilationNamespace on every iteration, // but that involved walking up to the global namespace, which we have to do // anyway. Instead, we'll inline the functionality into our own walk of the // namespace chain. @namespace = compilation.GlobalNamespace; while (stack.Count > 0) { var namespaceName = stack.Pop(); if (namespaceName.Length > 0) { // We're re-getting the namespace, rather than using the one containing // the current frame method, because we want the merged namespace. @namespace = @namespace.GetNestedNamespace(namespaceName); Debug.Assert((object)@namespace != null, $"We worked backwards from symbols to names, but no symbol exists for name '{namespaceName}'"); } else { Debug.Assert((object)@namespace == (object)compilation.GlobalNamespace); } Imports imports = null; if (hasImports) { if (currentStringGroup < 0) { Debug.WriteLine($"No import string group for namespace '{@namespace}'"); break; } var importsBinder = new InContainerBinder(@namespace, binder); imports = BuildImports(compilation, module, importRecordGroups[currentStringGroup], importsBinder, metadataDecoder); currentStringGroup--; } binder = new InContainerBinder(@namespace, binder, imports); } stack.Free(); if (currentStringGroup >= 0) { // CONSIDER: We could lump these into the outermost namespace. It's probably not worthwhile since // the usings are already for the wrong method. Debug.WriteLine($"Found {currentStringGroup + 1} import string groups without corresponding namespaces"); } return binder; }
/// <summary> /// Create a context to compile expressions within a method scope. /// </summary> internal CompilationContext( CSharpCompilation compilation, MetadataDecoder metadataDecoder, MethodSymbol currentFrame, ImmutableArray<LocalSymbol> locals, InScopeHoistedLocals inScopeHoistedLocals, MethodDebugInfo methodDebugInfo, CSharpSyntaxNode syntax) { Debug.Assert(string.IsNullOrEmpty(methodDebugInfo.DefaultNamespaceName)); Debug.Assert((syntax == null) || (syntax is ExpressionSyntax) || (syntax is LocalDeclarationStatementSyntax)); // TODO: syntax.SyntaxTree should probably be added to the compilation, // but it isn't rooted by a CompilationUnitSyntax so it doesn't work (yet). _currentFrame = currentFrame; _syntax = syntax; _methodNotType = !locals.IsDefault; // NOTE: Since this is done within CompilationContext, it will not be cached. // CONSIDER: The values should be the same everywhere in the module, so they // could be cached. // (Catch: what happens in a type context without a method def?) this.Compilation = GetCompilationWithExternAliases(compilation, methodDebugInfo.ExternAliasRecords); _metadataDecoder = metadataDecoder; // Each expression compile should use a unique compilation // to ensure expression-specific synthesized members can be // added (anonymous types, for instance). Debug.Assert(this.Compilation != compilation); this.NamespaceBinder = CreateBinderChain( this.Compilation, (PEModuleSymbol)currentFrame.ContainingModule, currentFrame.ContainingNamespace, methodDebugInfo.ImportRecordGroups, _metadataDecoder); if (_methodNotType) { _locals = locals; ImmutableArray<string> displayClassVariableNamesInOrder; GetDisplayClassVariables( currentFrame, _locals, inScopeHoistedLocals, out displayClassVariableNamesInOrder, out _displayClassVariables, out _hoistedParameterNames); Debug.Assert(displayClassVariableNamesInOrder.Length == _displayClassVariables.Count); _localsForBinding = GetLocalsForBinding(_locals, displayClassVariableNamesInOrder, _displayClassVariables); } else { _locals = ImmutableArray<LocalSymbol>.Empty; _displayClassVariables = ImmutableDictionary<string, DisplayClassVariable>.Empty; _localsForBinding = ImmutableArray<LocalSymbol>.Empty; } // Assert that the cheap check for "this" is equivalent to the expensive check for "this". Debug.Assert( _displayClassVariables.ContainsKey(GeneratedNames.ThisProxyFieldName()) == _displayClassVariables.Values.Any(v => v.Kind == DisplayClassVariableKind.This)); }
private static Binder ExtendBinderChain( InspectionContext inspectionContext, CSharpCompilation compilation, MetadataDecoder metadataDecoder, CSharpSyntaxNode syntax, EEMethodSymbol method, Binder binder, bool hasDisplayClassThis, bool methodNotType) { var substitutedSourceMethod = GetSubstitutedSourceMethod(method.SubstitutedSourceMethod, hasDisplayClassThis); var substitutedSourceType = substitutedSourceMethod.ContainingType; var stack = ArrayBuilder<NamedTypeSymbol>.GetInstance(); for (var type = substitutedSourceType; (object)type != null; type = type.ContainingType) { stack.Add(type); } while (stack.Count > 0) { substitutedSourceType = stack.Pop(); binder = new InContainerBinder(substitutedSourceType, binder); if (substitutedSourceType.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceType.TypeArguments, binder); } } stack.Free(); if (substitutedSourceMethod.Arity > 0) { binder = new WithTypeArgumentsBinder(substitutedSourceMethod.TypeArguments, binder); } if (methodNotType) { // Method locals and parameters shadow pseudo-variables. binder = new PlaceholderLocalBinder(inspectionContext, new EETypeNameDecoder(compilation, metadataDecoder.ModuleSymbol), syntax, method, binder); } binder = new EEMethodBinder(method, substitutedSourceMethod, binder); if (methodNotType) { binder = new SimpleLocalScopeBinder(method.LocalsForBinding, binder); } return binder; }
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); }