1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Link
{
using System;
using System.Collections.Generic;
using System.Linq;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility.Services;
/// <summary>
/// Resolves all the simple references in a section.
/// </summary>
internal class ResolveReferencesCommand
{
private IntermediateSection entrySection;
private IDictionary<string, Symbol> symbols;
private HashSet<Symbol> referencedSymbols;
private HashSet<IntermediateSection> resolvedSections;
public ResolveReferencesCommand(IMessaging messaging, IntermediateSection entrySection, IDictionary<string, Symbol> symbols)
{
this.Messaging = messaging;
this.entrySection = entrySection;
this.symbols = symbols;
}
public bool BuildingMergeModule { private get; set; }
public IEnumerable<Symbol> ReferencedSymbols { get { return this.referencedSymbols; } }
public IEnumerable<IntermediateSection> ResolvedSections { get { return this.resolvedSections; } }
private IMessaging Messaging { get; }
/// <summary>
/// Resolves all the simple references in a section.
/// </summary>
public void Execute()
{
this.resolvedSections = new HashSet<IntermediateSection>();
this.referencedSymbols = new HashSet<Symbol>();
this.RecursivelyResolveReferences(this.entrySection);
}
/// <summary>
/// Recursive helper function to resolve all references of passed in section.
/// </summary>
/// <param name="section">Section with references to resolve.</param>
/// <remarks>Note: recursive function.</remarks>
private void RecursivelyResolveReferences(IntermediateSection section)
{
// If we already resolved this section, move on to the next.
if (!this.resolvedSections.Add(section))
{
return;
}
// Process all of the references contained in this section using the collection of
// symbols provided. Then recursively call this method to process the
// located symbol's section. All in all this is a very simple depth-first
// search of the references per-section.
foreach (var wixSimpleReferenceRow in section.Tuples.OfType<WixSimpleReferenceTuple>())
{
// If we're building a Merge Module, ignore all references to the Media table
// because Merge Modules don't have Media tables.
if (this.BuildingMergeModule && wixSimpleReferenceRow.Table== "Media")
{
continue;
}
if (!this.symbols.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbol))
{
this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName));
}
else // see if the symbol (and any of its duplicates) are appropriately accessible.
{
IList<Symbol> accessible = DetermineAccessibleSymbols(section, symbol);
if (!accessible.Any())
{
this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbol.Access));
}
else if (1 == accessible.Count)
{
var accessibleSymbol = accessible[0];
this.referencedSymbols.Add(accessibleSymbol);
if (null != accessibleSymbol.Section)
{
RecursivelyResolveReferences(accessibleSymbol.Section);
}
}
else // display errors for the duplicate symbols.
{
var accessibleSymbol = accessible[0];
var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers.ToString();
if (String.IsNullOrEmpty(referencingSourceLineNumber))
{
this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Row.SourceLineNumbers, accessibleSymbol.Name));
}
else
{
this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Row.SourceLineNumbers, accessibleSymbol.Name, referencingSourceLineNumber));
}
foreach (Symbol accessibleDuplicate in accessible.Skip(1))
{
this.Messaging.Write(ErrorMessages.DuplicateSymbol2(accessibleDuplicate.Row.SourceLineNumbers));
}
}
}
}
}
/// <summary>
/// Determine if the symbol and any of its duplicates are accessbile by referencing section.
/// </summary>
/// <param name="referencingSection">Section referencing the symbol.</param>
/// <param name="symbol">Symbol being referenced.</param>
/// <returns>List of symbols accessible by referencing section.</returns>
private IList<Symbol> DetermineAccessibleSymbols(IntermediateSection referencingSection, Symbol symbol)
{
List<Symbol> symbols = new List<Symbol>();
if (AccessibleSymbol(referencingSection, symbol))
{
symbols.Add(symbol);
}
foreach (Symbol dupe in symbol.PossiblyConflictingSymbols)
{
if (AccessibleSymbol(referencingSection, dupe))
{
symbols.Add(dupe);
}
}
foreach (Symbol dupe in symbol.RedundantSymbols)
{
if (AccessibleSymbol(referencingSection, dupe))
{
symbols.Add(dupe);
}
}
return symbols;
}
/// <summary>
/// Determine if a single symbol is accessible by the referencing section.
/// </summary>
/// <param name="referencingSection">Section referencing the symbol.</param>
/// <param name="symbol">Symbol being referenced.</param>
/// <returns>True if symbol is accessible.</returns>
private bool AccessibleSymbol(IntermediateSection referencingSection, Symbol symbol)
{
switch (symbol.Access)
{
case AccessModifier.Public:
return true;
case AccessModifier.Internal:
return symbol.Section.CompilationId.Equals(referencingSection.CompilationId) || (null != symbol.Section.LibraryId && symbol.Section.LibraryId.Equals(referencingSection.LibraryId));
case AccessModifier.Protected:
return symbol.Section.CompilationId.Equals(referencingSection.CompilationId);
case AccessModifier.Private:
return referencingSection == symbol.Section;
default:
throw new ArgumentOutOfRangeException(nameof(symbol.Access));
}
}
}
}
|