/// <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 methodDebugInfo = default(MethodDebugInfo); if (typedSymReader != null) { try { var cdi = typedSymReader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (cdi != null) { CustomDebugInfoReader.GetCSharpDynamicLocalInfo( cdi, methodToken, methodVersion, localNames.FirstOrDefault(), out dynamicLocalMap, out dynamicLocalConstantMap); inScopeHoistedLocalIndices = CustomDebugInfoReader.GetCSharpInScopeHoistedLocalIndices( cdi, methodToken, methodVersion, ilOffset); } // TODO (acasey): switch on the type of typedSymReader and call the appropriate helper. (GH #702) methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion); } 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, methodDebugInfo)); }