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
176
177
178
179
180
181
182
183
184
|
// 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.Core.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 readonly IntermediateSection entrySection;
private readonly IDictionary<string, TupleWithSection> tuplesWithSections;
private HashSet<TupleWithSection> referencedTuples;
private HashSet<IntermediateSection> resolvedSections;
public ResolveReferencesCommand(IMessaging messaging, IntermediateSection entrySection, IDictionary<string, TupleWithSection> tuplesWithSections)
{
this.Messaging = messaging;
this.entrySection = entrySection;
this.tuplesWithSections = tuplesWithSections;
this.BuildingMergeModule = (SectionType.Module == entrySection.Type);
}
public IEnumerable<TupleWithSection> ReferencedTupleWithSections => this.referencedTuples;
public IEnumerable<IntermediateSection> ResolvedSections => this.resolvedSections;
private bool BuildingMergeModule { get; }
private IMessaging Messaging { get; }
/// <summary>
/// Resolves all the simple references in a section.
/// </summary>
public void Execute()
{
this.resolvedSections = new HashSet<IntermediateSection>();
this.referencedTuples = new HashSet<TupleWithSection>();
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
// tuples provided. Then recursively call this method to process the
// located tuple'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.tuplesWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var tupleWithSection))
{
this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName));
}
else // see if the tuple (and any of its duplicates) are appropriately accessible.
{
var accessible = this.DetermineAccessibleTuples(section, tupleWithSection);
if (!accessible.Any())
{
this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, tupleWithSection.Access));
}
else if (1 == accessible.Count)
{
var accessibleTuple = accessible[0];
this.referencedTuples.Add(accessibleTuple);
if (null != accessibleTuple.Section)
{
this.RecursivelyResolveReferences(accessibleTuple.Section);
}
}
else // display errors for the duplicate tuples.
{
var accessibleTuple = accessible[0];
var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers?.ToString();
if (String.IsNullOrEmpty(referencingSourceLineNumber))
{
this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleTuple.Tuple.SourceLineNumbers, accessibleTuple.Name));
}
else
{
this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleTuple.Tuple.SourceLineNumbers, accessibleTuple.Name, referencingSourceLineNumber));
}
foreach (var accessibleDuplicate in accessible.Skip(1))
{
this.Messaging.Write(ErrorMessages.DuplicateSymbol2(accessibleDuplicate.Tuple.SourceLineNumbers));
}
}
}
}
}
/// <summary>
/// Determine if the tuple and any of its duplicates are accessbile by referencing section.
/// </summary>
/// <param name="referencingSection">Section referencing the tuple.</param>
/// <param name="tupleWithSection">Tuple being referenced.</param>
/// <returns>List of tuples accessible by referencing section.</returns>
private List<TupleWithSection> DetermineAccessibleTuples(IntermediateSection referencingSection, TupleWithSection tupleWithSection)
{
var accessibleTuples = new List<TupleWithSection>();
if (this.AccessibleTuple(referencingSection, tupleWithSection))
{
accessibleTuples.Add(tupleWithSection);
}
foreach (var dupe in tupleWithSection.PossiblyConflicts)
{
// don't count overridable WixActionTuples
var tupleAction = tupleWithSection.Tuple as WixActionTuple;
var dupeAction = dupe.Tuple as WixActionTuple;
if (tupleAction?.Overridable != dupeAction?.Overridable)
{
continue;
}
if (this.AccessibleTuple(referencingSection, dupe))
{
accessibleTuples.Add(dupe);
}
}
foreach (var dupe in tupleWithSection.Redundants)
{
if (this.AccessibleTuple(referencingSection, dupe))
{
accessibleTuples.Add(dupe);
}
}
return accessibleTuples;
}
/// <summary>
/// Determine if a single tuple is accessible by the referencing section.
/// </summary>
/// <param name="referencingSection">Section referencing the tuple.</param>
/// <param name="tupleWithSection">Tuple being referenced.</param>
/// <returns>True if tuple is accessible.</returns>
private bool AccessibleTuple(IntermediateSection referencingSection, TupleWithSection tupleWithSection)
{
switch (tupleWithSection.Access)
{
case AccessModifier.Public:
return true;
case AccessModifier.Internal:
return tupleWithSection.Section.CompilationId.Equals(referencingSection.CompilationId) || (null != tupleWithSection.Section.LibraryId && tupleWithSection.Section.LibraryId.Equals(referencingSection.LibraryId));
case AccessModifier.Protected:
return tupleWithSection.Section.CompilationId.Equals(referencingSection.CompilationId);
case AccessModifier.Private:
return referencingSection == tupleWithSection.Section;
default:
throw new ArgumentOutOfRangeException(nameof(tupleWithSection.Access));
}
}
}
}
|