internal override ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo> GetLocalInfo( Cci.IMethodDefinition methodDef, ImmutableArray <LocalDefinition> localDefs) { if (localDefs.IsEmpty) { return(ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo> .Empty); } // Find declarators in current method syntax. var declarators = GetLocalVariableDeclaratorsVisitor.GetDeclarators((MethodSymbol)methodDef); // Create a map from declarator to declarator index. var declaratorToIndex = CreateDeclaratorToIndexMap(declarators); return(localDefs.SelectAsArray(localDef => GetLocalInfo(declaratorToIndex, localDef))); }
internal override bool TryGetPreviousLocals( Microsoft.CodeAnalysis.Emit.EmitBaseline baseline, IMethodSymbol method, out ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo> previousLocals, out GetPreviousLocalSlot getPreviousLocalSlot) { previousLocals = default(ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo>); getPreviousLocalSlot = NoPreviousLocalSlot; MethodHandle handle; if (!this.TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method, out handle)) { // Unrecognized method. Must have been added in the current compilation. return(false); } MethodDefinitionEntry methodEntry; if (!this.methodMap.TryGetValue((MethodSymbol)method, out methodEntry)) { // Not part of changeset. No need to preserve locals. return(false); } if (!methodEntry.PreserveLocalVariables) { // Not necessary to preserve locals. return(false); } var previousMethod = (MethodSymbol)methodEntry.PreviousMethod; var methodIndex = (uint)MetadataTokens.GetRowNumber(handle); SymbolMatcher map; // Check if method has changed previously. If so, we already have a map. if (baseline.LocalsForMethodsAddedOrChanged.TryGetValue(methodIndex, out previousLocals)) { map = this.mapToPrevious; } else { // Method has not changed since initial generation. Generate a map // using the local names provided with the initial metadata. var localNames = baseline.LocalNames(methodIndex); Debug.Assert(!localNames.IsDefault); var localInfo = default(ImmutableArray <MetadataDecoder.LocalInfo>); try { Debug.Assert(this.module.HasIL); var methodIL = this.module.GetMethodILOrThrow(handle); if (!methodIL.LocalSignature.IsNil) { var signature = this.module.MetadataReader.GetLocalSignature(methodIL.LocalSignature); localInfo = this.metadataDecoder.DecodeLocalSignatureOrThrow(signature); } else { localInfo = ImmutableArray <MetadataDecoder.LocalInfo> .Empty; } } catch (UnsupportedSignatureContent) { } catch (BadImageFormatException) { } if (localInfo.IsDefault) { // TODO: Report error that metadata is not supported. return(false); } else { // The signature may have more locals than names if trailing locals are unnamed. // (Locals in the middle of the signature may be unnamed too but since localNames // is indexed by slot, unnamed locals before the last named local will be represented // as null values in the array.) Debug.Assert(localInfo.Length >= localNames.Length); previousLocals = GetLocalSlots(previousMethod, localNames, localInfo); Debug.Assert(previousLocals.Length == localInfo.Length); } map = this.mapToMetadata; } // Find declarators in previous method syntax. // The locals are indices into this list. var previousDeclarators = GetLocalVariableDeclaratorsVisitor.GetDeclarators(previousMethod); // Create a map from declarator to declarator offset. var previousDeclaratorToOffset = new Dictionary <SyntaxNode, int>(); for (int offset = 0; offset < previousDeclarators.Length; offset++) { previousDeclaratorToOffset.Add(previousDeclarators[offset], offset); } // Create a map from local info to slot. var previousLocalInfoToSlot = new Dictionary <Microsoft.CodeAnalysis.Emit.EncLocalInfo, int>(); for (int slot = 0; slot < previousLocals.Length; slot++) { var localInfo = previousLocals[slot]; Debug.Assert(!localInfo.IsDefault); if (localInfo.IsInvalid) { // Unrecognized or deleted local. continue; } previousLocalInfoToSlot.Add(localInfo, slot); } var syntaxMap = methodEntry.SyntaxMap; if (syntaxMap == null) { // If there was no syntax map, the syntax structure has not changed, // so we can map from current to previous syntax by declarator index. Debug.Assert(methodEntry.PreserveLocalVariables); // Create a map from declarator to declarator index. var currentDeclarators = GetLocalVariableDeclaratorsVisitor.GetDeclarators((MethodSymbol)method); var currentDeclaratorToIndex = CreateDeclaratorToIndexMap(currentDeclarators); syntaxMap = currentSyntax => { var currentIndex = currentDeclaratorToIndex[(CSharpSyntaxNode)currentSyntax]; return(previousDeclarators[currentIndex]); }; } getPreviousLocalSlot = (object identity, Cci.ITypeReference typeRef, LocalSlotConstraints constraints) => { var local = (LocalSymbol)identity; var syntaxRefs = local.DeclaringSyntaxReferences; Debug.Assert(!syntaxRefs.IsDefault); if (!syntaxRefs.IsDefaultOrEmpty) { var currentSyntax = syntaxRefs[0].GetSyntax(); var previousSyntax = (CSharpSyntaxNode)syntaxMap(currentSyntax); if (previousSyntax != null) { int offset; if (previousDeclaratorToOffset.TryGetValue(previousSyntax, out offset)) { var previousType = map.MapReference(typeRef); if (previousType != null) { var localKey = new Microsoft.CodeAnalysis.Emit.EncLocalInfo(offset, previousType, constraints, (int)local.TempKind); int slot; // Should report a warning if the type of the local has changed // and the previous value will be dropped. (Bug #781309.) if (previousLocalInfoToSlot.TryGetValue(localKey, out slot)) { return(slot); } } } } } return(-1); }; return(true); }