@@ -293,20 +293,6 @@ let scopeSorter (scope1: PdbMethodScope) (scope2: PdbMethodScope) =
293293 elif ( scope1.EndOffset - scope1.StartOffset) < ( scope2.EndOffset - scope2.StartOffset) then 1
294294 else 0
295295
296- let collectScopes scope =
297- let list = List< PdbMethodScope>()
298- let rec toList scope parent =
299- let nested =
300- match parent with
301- | Some p -> scope.StartOffset <> p.StartOffset || scope.EndOffset <> p.EndOffset
302- | None -> true
303-
304- if nested then list.Add scope
305- scope.Children |> Seq.iter( fun s -> toList s ( if nested then Some scope else parent))
306-
307- toList scope None
308- list.ToArray() |> Array.sortWith< PdbMethodScope> scopeSorter
309-
310296type PortablePdbGenerator ( embedAllSource : bool , embedSourceList : string list , sourceLink : string , checksumAlgorithm , showTimes , info : PdbData , pathMap : PathMap ) =
311297
312298 let docs =
@@ -527,30 +513,50 @@ type PortablePdbGenerator (embedAllSource: bool, embedSourceList: string list, s
527513 importScopesTable.Add( imports, result)
528514 result
529515
530- let writeMethodScopes methToken scope =
531- for s in collectScopes scope do
516+ let flattenScopes rootScope =
517+ let list = List< PdbMethodScope>()
518+ let rec flattenScopes scope parent =
519+
520+ list.Add scope
521+ for nestedScope in scope.Children do
522+ let isNested =
523+ match parent with
524+ | Some p -> nestedScope.StartOffset >= p.StartOffset && nestedScope.EndOffset <= p.EndOffset
525+ | None -> true
526+
527+ flattenScopes nestedScope ( if isNested then Some scope else parent)
528+
529+ flattenScopes rootScope None
530+
531+ list.ToArray()
532+ |> Array.sortWith< PdbMethodScope> scopeSorter
533+
534+ let writeMethodScopes methToken rootScope =
535+
536+ let flattenedScopes = flattenScopes rootScope
532537
533- // Get or create the import scope for this method
534- let importScopeHandle =
538+ // Get or create the import scope for this method
539+ let importScopeHandle =
535540#if EMIT_ IMPORT_ SCOPES
536- match s.Imports with
537- | None -> Unchecked.defaultof<_>
538- | Some imports -> getImportScopeIndex imports
541+ match s.Imports with
542+ | None -> Unchecked.defaultof<_>
543+ | Some imports -> getImportScopeIndex imports
539544#else
540- getImportScopeIndex |> ignore // make sure this code counts as used
541- Unchecked.defaultof<_>
545+ getImportScopeIndex |> ignore // make sure this code counts as used
546+ Unchecked.defaultof<_>
542547#endif
543548
549+ for scope in flattenedScopes do
544550 let lastRowNumber = MetadataTokens.GetRowNumber( LocalVariableHandle.op_ Implicit lastLocalVariableHandle)
545551 let nextHandle = MetadataTokens.LocalVariableHandle( lastRowNumber + 1 )
546552
547553 metadata.AddLocalScope( MetadataTokens.MethodDefinitionHandle( methToken),
548554 importScopeHandle,
549555 nextHandle,
550556 Unchecked.defaultof< LocalConstantHandle>,
551- s .StartOffset, s .EndOffset - s .StartOffset ) |> ignore
557+ scope .StartOffset, scope .EndOffset - scope .StartOffset ) |> ignore
552558
553- for localVariable in s .Locals do
559+ for localVariable in scope .Locals do
554560 lastLocalVariableHandle <- metadata.AddLocalVariable( LocalVariableAttributes.None, localVariable.Index, metadata.GetOrAddString( localVariable.Name))
555561
556562 let emitMethod minfo =
@@ -957,7 +963,8 @@ let logDebugInfo (outfile: string) (info: PdbData) =
957963 fprintfn sw " ENTRYPOINT\r\n %b \r\n " info.EntryPoint.IsSome
958964 fprintfn sw " DOCUMENTS"
959965 for i, doc in Seq.zip [ 0 .. info.Documents.Length-1 ] info.Documents do
960- fprintfn sw " [%d ] %s " i doc.File
966+ // File names elided because they are ephemeral during testing
967+ fprintfn sw " [%d ] <elided-for-testing>" i // doc.File
961968 fprintfn sw " Type: %A " doc.DocumentType
962969 fprintfn sw " Language: %A " doc.Language
963970 fprintfn sw " Vendor: %A " doc.Vendor
@@ -987,3 +994,62 @@ let logDebugInfo (outfile: string) (info: PdbData) =
987994 | None -> ()
988995 | Some rootscope -> writeScope " " rootscope
989996 fprintfn sw " "
997+
998+ let rec allNamesOfScope acc ( scope : PdbMethodScope ) =
999+ let acc = ( acc, scope.Locals) ||> Array.fold ( fun z l -> Set.add l.Name z)
1000+ let acc = ( acc, scope.Children) ||> allNamesOfScopes
1001+ acc
1002+ and allNamesOfScopes acc ( scopes : PdbMethodScope []) =
1003+ ( acc, scopes) ||> Array.fold allNamesOfScope
1004+
1005+ let rec pushShadowedLocals ( localsToPush : PdbLocalVar []) ( scope : PdbMethodScope ) =
1006+ // Check if child scopes are properly nested
1007+ if scope.Children |> Array.forall ( fun child ->
1008+ child.StartOffset >= scope.StartOffset && child.EndOffset <= scope.EndOffset) then
1009+
1010+ let children = scope.Children |> Array.sortWith scopeSorter
1011+
1012+ // Find all the names defined in this scope
1013+ let scopeNames = set [| for n in scope.Locals -> n.Name |]
1014+
1015+ // Rename if necessary as we push
1016+ let rename , unprocessed = localsToPush |> Array.partition ( fun l -> scopeNames.Contains l.Name)
1017+ let renamed = [| for l in rename -> { l with Name = l.Name + " (shadowed)" } |]
1018+
1019+ let localsToPush2 = [| yield ! renamed; yield ! unprocessed; yield ! scope.Locals |]
1020+ let newChildren , splits = children |> Array.map ( pushShadowedLocals localsToPush2) |> Array.unzip
1021+
1022+ // Check if a rename in any of the children forces a split
1023+ if splits |> Array.exists id then
1024+ let results =
1025+ [|
1026+ // First fill in the gaps between the children with an adjusted version of this scope.
1027+ let gaps =
1028+ [| yield ( scope.StartOffset, scope.StartOffset)
1029+ for newChild in children do
1030+ yield ( newChild.StartOffset, newChild.EndOffset)
1031+ yield ( scope.EndOffset, scope.EndOffset) |]
1032+
1033+ for ((_, a),( b,_)) in Array.pairwise gaps do
1034+ if a < b then
1035+ yield { scope with Locals= localsToPush2; Children = [| |]; StartOffset = a; EndOffset = b}
1036+
1037+ yield ! Array.concat newChildren
1038+ |]
1039+ let results2 = results |> Array.sortWith scopeSorter
1040+ results2, true
1041+ else
1042+ let splitsParent = renamed.Length > 0
1043+ [| { scope with Locals= localsToPush2 } |], splitsParent
1044+ else
1045+ [| scope |], false
1046+
1047+ // Check to see if a scope has a local with the same name as any of its children
1048+ //
1049+ // If so, do not emit 'scope' itself. Instead,
1050+ // 1. Emit a copy of 'scope' in each true gap, with all locals
1051+ // 2. Adjust each child scope to also contain the locals from 'scope',
1052+ // adding the text " (shadowed)" to the names of those with name conflicts.
1053+ let unshadowScopes rootScope =
1054+ let result , _ = pushShadowedLocals [| |] rootScope
1055+ result
0 commit comments