@@ -293,20 +293,6 @@ let scopeSorter (scope1: PdbMethodScope) (scope2: PdbMethodScope) =
293
293
elif ( scope1.EndOffset - scope1.StartOffset) < ( scope2.EndOffset - scope2.StartOffset) then 1
294
294
else 0
295
295
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
-
310
296
type PortablePdbGenerator ( embedAllSource : bool , embedSourceList : string list , sourceLink : string , checksumAlgorithm , showTimes , info : PdbData , pathMap : PathMap ) =
311
297
312
298
let docs =
@@ -527,30 +513,50 @@ type PortablePdbGenerator (embedAllSource: bool, embedSourceList: string list, s
527
513
importScopesTable.Add( imports, result)
528
514
result
529
515
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
532
537
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 =
535
540
#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
539
544
#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<_>
542
547
#endif
543
548
549
+ for scope in flattenedScopes do
544
550
let lastRowNumber = MetadataTokens.GetRowNumber( LocalVariableHandle.op_ Implicit lastLocalVariableHandle)
545
551
let nextHandle = MetadataTokens.LocalVariableHandle( lastRowNumber + 1 )
546
552
547
553
metadata.AddLocalScope( MetadataTokens.MethodDefinitionHandle( methToken),
548
554
importScopeHandle,
549
555
nextHandle,
550
556
Unchecked.defaultof< LocalConstantHandle>,
551
- s .StartOffset, s .EndOffset - s .StartOffset ) |> ignore
557
+ scope .StartOffset, scope .EndOffset - scope .StartOffset ) |> ignore
552
558
553
- for localVariable in s .Locals do
559
+ for localVariable in scope .Locals do
554
560
lastLocalVariableHandle <- metadata.AddLocalVariable( LocalVariableAttributes.None, localVariable.Index, metadata.GetOrAddString( localVariable.Name))
555
561
556
562
let emitMethod minfo =
@@ -957,7 +963,8 @@ let logDebugInfo (outfile: string) (info: PdbData) =
957
963
fprintfn sw " ENTRYPOINT\r\n %b \r\n " info.EntryPoint.IsSome
958
964
fprintfn sw " DOCUMENTS"
959
965
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
961
968
fprintfn sw " Type: %A " doc.DocumentType
962
969
fprintfn sw " Language: %A " doc.Language
963
970
fprintfn sw " Vendor: %A " doc.Vendor
@@ -987,3 +994,62 @@ let logDebugInfo (outfile: string) (info: PdbData) =
987
994
| None -> ()
988
995
| Some rootscope -> writeScope " " rootscope
989
996
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