Ensure virtual symbols are included when overridden but not referenced
Rob Mensching committed
Mar 8, 2024 at 13:58 UTC
6a3a695b5ac3758fbf4a7836f65d7f85fdd121e0
13 files changed
+322
-156
src/ext/UI/test/WixToolsetTest.UI/UIExtensionFixture.cs
+6
-6
@@ -125,7 +125,7 @@ namespace WixToolsetTest.UI
125
}, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray());
126
}
127
128
- [Fact(Skip = "Linker problem")]
128
+ [Fact]
129
public void CanBuildUsingWixUIFeatureTree()
130
{
131
var folder = TestData.Get(@"TestData", "WixUI_FeatureTree");
@@ -161,7 +161,7 @@ namespace WixToolsetTest.UI
161
}, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray());
162
}
163
164
- [Fact(Skip = "Linker problem")]
164
+ [Fact]
165
public void CanBuildWithWixUIInstallDirWithCustomizedEula()
166
{
167
var folder = TestData.Get(@"TestData", "WixUI_InstallDir");
@@ -274,7 +274,7 @@ namespace WixToolsetTest.UI
274
}
275
}
276
277
- [Fact(Skip = "Linker problem")]
277
+ [Fact]
278
public void CanBuildUsingWixUIMondo()
279
{
280
var folder = TestData.Get(@"TestData", "WixUI_Mondo");
@@ -307,7 +307,7 @@ namespace WixToolsetTest.UI
307
}, results.Where(result => result.StartsWith("ControlEvent:") && result.Contains("DoAction")).ToArray());
308
WixAssert.CompareLineByLine(new[]
309
{
310
- "InstallUISequence:WelcomeDlg\tInstalled AND PATCH\t1295",
310
+ "InstallUISequence:WelcomeDlg\tNOT Installed OR PATCH\t1297",
311
}, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray());
312
}
313
@@ -325,7 +325,7 @@ namespace WixToolsetTest.UI
325
}, results.Where(s => s.StartsWith("Control:ErrorDlg\tY")).Select(s => s.Split('\t')[9]).ToArray());
326
}
327
328
- [Fact(Skip = "Linker problem")]
328
+ [Fact]
329
public void CanBuildWithInstallDirAndRemovedDialog()
330
{
331
var folder = TestData.Get(@"TestData", "InstallDir_NoLicense");
@@ -366,7 +366,7 @@ namespace WixToolsetTest.UI
366
}, results.Where(r => r.StartsWith("InstallUISequence:AdvancedWelcome") || r.StartsWith("InstallUISequence:Welcome")).ToArray());
367
}
368
369
- [Fact(Skip = "Linker problem")]
369
+ [Fact]
370
public void CanBuildWithInstallDirAndAddedDialog()
371
{
372
var folder = TestData.Get(@"TestData", "InstallDir_SpecialDlg");
src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
+11
-36
@@ -45,10 +45,9 @@ namespace WixToolset.Core.Link
45
public ISet<IntermediateSymbol> IdenticalDirectorySymbols { get; private set; }
46
47
/// <summary>
48
- /// Gets the collection of overridden symbols that should not be included
49
- /// in the final output.
48
+ /// Gets the collection of symbols that are marked as overrides.
49
/// </summary>
51
- public ISet<IntermediateSymbol> OverriddenSymbols { get; private set; }
50
+ public IReadOnlyCollection<SymbolWithSection> OverrideSymbols { get; private set; }
51
52
public void Execute()
53
{
@@ -56,7 +55,6 @@ namespace WixToolset.Core.Link
55
var possibleConflicts = new HashSet<SymbolWithSection>();
56
var identicalDirectorySymbols = new HashSet<IntermediateSymbol>();
57
var overrideSymbols = new List<SymbolWithSection>();
59
- var overriddenSymbols = new HashSet<IntermediateSymbol>();
58
59
if (!Enum.TryParse(this.ExpectedOutputType.ToString(), out SectionType expectedEntrySectionType))
60
{
@@ -92,34 +90,15 @@ namespace WixToolset.Core.Link
90
91
if (!symbolsByName.TryGetValue(fullName, out var existingSymbol))
92
{
95
- if (symbolWithSection.Access == AccessModifier.Override)
96
- {
97
- overrideSymbols.Add(symbolWithSection);
98
- }
99
-
93
symbolsByName.Add(fullName, symbolWithSection);
94
}
102
- else // uh-oh, duplicate symbols.
95
+ else // duplicate symbol ids MAY be a problem, but not always (e.g. identical directories and virtual symbols that get overridden) so we do NOT report errors here.
96
{
104
- if (AccessModifier.Virtual == existingSymbol.Access && AccessModifier.Override == symbolWithSection.Access)
105
- {
106
- symbolWithSection.OverrideVirtualSymbol(existingSymbol);
107
- symbolsByName[fullName] = symbolWithSection; // replace the virtual symbol with the override symbol.
108
-
109
- overrideSymbols.Add(symbolWithSection);
110
- overriddenSymbols.Add(existingSymbol.Symbol);
111
- }
112
- else if (AccessModifier.Override == existingSymbol.Access && AccessModifier.Virtual == symbolWithSection.Access)
113
- {
114
- existingSymbol.OverrideVirtualSymbol(symbolWithSection);
115
-
116
- overriddenSymbols.Add(symbolWithSection.Symbol);
117
- }
97
// If the duplicate symbols are both private directories, there is a chance that they
98
// point to identical symbols. Identical directory symbols are redundant and will not cause
99
// conflicts.
121
- else if (AccessModifier.Section == existingSymbol.Access && AccessModifier.Section == symbolWithSection.Access &&
122
- SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol))
100
+ if (AccessModifier.Section == existingSymbol.Access && AccessModifier.Section == symbolWithSection.Access &&
101
+ SymbolDefinitionType.Directory == existingSymbol.Symbol.Definition.Type && existingSymbol.Symbol.IsIdentical(symbolWithSection.Symbol))
102
{
103
// Ensure identical symbols are tracked to ensure that only one symbol will end up in linked intermediate.
104
identicalDirectorySymbols.Add(existingSymbol.Symbol);
@@ -129,25 +108,21 @@ namespace WixToolset.Core.Link
108
{
109
symbolWithSection.AddPossibleConflict(existingSymbol);
110
existingSymbol.AddPossibleConflict(symbolWithSection);
132
- possibleConflicts.Add(symbolWithSection);
111
+ possibleConflicts.Add(existingSymbol);
112
}
113
}
135
- }
136
- }
114
138
- // Ensure override symbols actually overrode a virtual symbol.
139
- foreach (var symbolWithSection in overrideSymbols)
140
- {
141
- if (symbolWithSection.Overrides is null)
142
- {
143
- this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol));
115
+ if (symbolWithSection.Access == AccessModifier.Override)
116
+ {
117
+ overrideSymbols.Add(symbolWithSection);
118
+ }
119
}
120
}
121
122
this.SymbolsByName = symbolsByName;
123
this.PossibleConflicts = possibleConflicts;
124
this.IdenticalDirectorySymbols = identicalDirectorySymbols;
150
- this.OverriddenSymbols = overriddenSymbols;
125
+ this.OverrideSymbols = overrideSymbols;
126
}
127
}
128
}
src/wix/WixToolset.Core/Link/ProcessConflictingSymbolsCommand.cs
new
+159
@@ -0,0 +1,159 @@
1
+// 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.
2
+
3
+namespace WixToolset.Core.Link
4
+{
5
+ using System.Collections.Generic;
6
+ using System.Linq;
7
+ using WixToolset.Data;
8
+ using WixToolset.Data.Symbols;
9
+ using WixToolset.Extensibility.Services;
10
+
11
+ internal class ProcessConflictingSymbolsCommand
12
+ {
13
+ public ProcessConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, IReadOnlyCollection<SymbolWithSection> overrideSymbols, ISet<IntermediateSection> resolvedSections)
14
+ {
15
+ this.Messaging = messaging;
16
+ this.PossibleConflicts = possibleConflicts;
17
+ this.OverrideSymbols = overrideSymbols;
18
+ this.ResolvedSections = resolvedSections;
19
+ }
20
+
21
+ private IMessaging Messaging { get; }
22
+
23
+ private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; }
24
+
25
+ private ISet<IntermediateSection> ResolvedSections { get; }
26
+
27
+ private IReadOnlyCollection<SymbolWithSection> OverrideSymbols { get; }
28
+
29
+ /// <summary>
30
+ /// Gets the collection of overridden symbols that should not be included
31
+ /// in the final output.
32
+ /// </summary>
33
+ public ISet<IntermediateSymbol> OverriddenSymbols { get; private set; }
34
+
35
+ public void Execute()
36
+ {
37
+ var overriddenSymbols = new HashSet<IntermediateSymbol>();
38
+
39
+ foreach (var symbolWithConflicts in this.PossibleConflicts)
40
+ {
41
+ var conflicts = YieldReferencedConflicts(symbolWithConflicts, this.ResolvedSections).ToList();
42
+
43
+ if (conflicts.Count > 1)
44
+ {
45
+ IEnumerable<SymbolWithSection> reportDuplicates;
46
+
47
+ var virtualConflicts = conflicts.Where(s => s.Access == AccessModifier.Virtual).ToList();
48
+
49
+ // No virtual symbols, just plain old duplicate errors. This is the easy case.
50
+ if (virtualConflicts.Count == 0)
51
+ {
52
+ var first = conflicts[0];
53
+ reportDuplicates = conflicts.Skip(1);
54
+
55
+ var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
56
+
57
+ this.Messaging.Write(LinkerErrors.DuplicateSymbol(first.Symbol, referencingSourceLineNumber));
58
+ }
59
+ else // there are virtual symbols, which complicates conflict resolution and may not be an error at all.
60
+ {
61
+ var firstVirtualSymbol = virtualConflicts[0];
62
+ var overrideConflicts = conflicts.Where(s => s.Access == AccessModifier.Override).ToList();
63
+
64
+ // If there is a single virtual symbol, there may be a single override symbol to make this a success case.
65
+ // All other scenarios are errors.
66
+ if (virtualConflicts.Count == 1)
67
+ {
68
+ var otherConflicts = conflicts.Where(s => s.Access != AccessModifier.Virtual && s.Access != AccessModifier.Override).ToList();
69
+
70
+ if (otherConflicts.Count > 0)
71
+ {
72
+ var first = otherConflicts[0];
73
+ var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
74
+
75
+ reportDuplicates = virtualConflicts;
76
+
77
+ switch (first.Symbol)
78
+ {
79
+ case WixActionSymbol action:
80
+ this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(action));
81
+ break;
82
+ default:
83
+ this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(first.Symbol, referencingSourceLineNumber));
84
+ break;
85
+ }
86
+ }
87
+ else if (overrideConflicts.Count > 1) // multiple overrides report as normal duplicates.
88
+ {
89
+ var first = overrideConflicts[0];
90
+ var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
91
+
92
+ reportDuplicates = overrideConflicts.Skip(1);
93
+
94
+ this.Messaging.Write(LinkerErrors.DuplicateSymbol(first.Symbol, referencingSourceLineNumber));
95
+ }
96
+ else // the single virtual symbol is overridden by a single override symbol. This is a success case.
97
+ {
98
+ var overrideSymbol = overrideConflicts[0];
99
+
100
+ overriddenSymbols.Add(firstVirtualSymbol.Symbol);
101
+
102
+ reportDuplicates = Enumerable.Empty<SymbolWithSection>();
103
+ }
104
+ }
105
+ else // multiple symbols are virtual, use the duplicate virtual symbol message.
106
+ {
107
+ var first = virtualConflicts[0];
108
+ var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
109
+
110
+ reportDuplicates = virtualConflicts.Skip(1);
111
+
112
+ this.Messaging.Write(LinkerErrors.DuplicateVirtualSymbol(first.Symbol, referencingSourceLineNumber));
113
+ }
114
+
115
+ // Always point the override symbols at the first virtual symbol to prevent error being reported about missing overrides.
116
+ // There may have been errors reported above, but there was at least one virtual symbol to satisfy the overrides so we
117
+ // don't want extra errors in this case.
118
+ foreach (var overrideSymbol in overrideConflicts)
119
+ {
120
+ overrideSymbol.OverrideVirtualSymbol(firstVirtualSymbol);
121
+ }
122
+ }
123
+
124
+ foreach (var duplicate in reportDuplicates)
125
+ {
126
+ this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol));
127
+ }
128
+ }
129
+ }
130
+
131
+ // Ensure referenced override symbols actually overrode a virtual symbol.
132
+ foreach (var referencedOverrideSymbol in this.OverrideSymbols.Where(s => this.ResolvedSections.Contains(s.Section)))
133
+ {
134
+ if (referencedOverrideSymbol.Overrides is null)
135
+ {
136
+ this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(referencedOverrideSymbol.Symbol));
137
+ }
138
+ }
139
+
140
+ this.OverriddenSymbols = overriddenSymbols;
141
+ }
142
+
143
+ private static IEnumerable<SymbolWithSection> YieldReferencedConflicts(SymbolWithSection symbolWithConflicts, ISet<IntermediateSection> resolvedSections)
144
+ {
145
+ if (resolvedSections.Contains(symbolWithConflicts.Section))
146
+ {
147
+ yield return symbolWithConflicts;
148
+ }
149
+
150
+ foreach (var possibleConflict in symbolWithConflicts.PossiblyConflicts)
151
+ {
152
+ if (resolvedSections.Contains(possibleConflict.Section))
153
+ {
154
+ yield return possibleConflict;
155
+ }
156
+ }
157
+ }
158
+ }
159
+}
src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs
deleted
-92
@@ -1,92 +0,0 @@
1
-// 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.
2
-
3
-namespace WixToolset.Core.Link
4
-{
5
- using System.Collections.Generic;
6
- using System.Linq;
7
- using WixToolset.Data;
8
- using WixToolset.Data.Symbols;
9
- using WixToolset.Extensibility.Services;
10
-
11
- internal class ReportConflictingSymbolsCommand
12
- {
13
- public ReportConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, ISet<IntermediateSection> resolvedSections)
14
- {
15
- this.Messaging = messaging;
16
- this.PossibleConflicts = possibleConflicts;
17
- this.ResolvedSections = resolvedSections;
18
- }
19
-
20
- private IMessaging Messaging { get; }
21
-
22
- private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; }
23
-
24
- private ISet<IntermediateSection> ResolvedSections { get; }
25
-
26
- public void Execute()
27
- {
28
- // Do a quick check if there are any possibly conflicting symbols. Hopefully the symbols with possible conflicts
29
- // list is a very short list (empty should be the most common).
30
- //
31
- // If we have conflicts then we'll do a more costly check to see if the possible conflicting
32
- // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate
33
- // (aka: conflicting) symbol.
34
- if (0 < this.PossibleConflicts.Count)
35
- {
36
- foreach (var referencedDuplicate in this.PossibleConflicts.Where(s => this.ResolvedSections.Contains(s.Section)))
37
- {
38
- var actuallyReferencedDuplicates = referencedDuplicate.PossiblyConflicts.Where(s => this.ResolvedSections.Contains(s.Section)).ToList();
39
-
40
- if (actuallyReferencedDuplicates.Count > 0)
41
- {
42
- var conflicts = actuallyReferencedDuplicates.Append(referencedDuplicate).ToList();
43
- var virtualConflicts = conflicts.Where(s => s.Access == AccessModifier.Virtual).ToList();
44
- var overrideConflicts = conflicts.Where(s => s.Access == AccessModifier.Override).ToList();
45
- var otherConflicts = conflicts.Where(s => s.Access != AccessModifier.Virtual && s.Access != AccessModifier.Override).ToList();
46
-
47
- IEnumerable<SymbolWithSection> reportDuplicates = actuallyReferencedDuplicates;
48
-
49
- // If multiple symbols are virtual, use the duplicate virtual symbol message.
50
- if (virtualConflicts.Count > 1)
51
- {
52
- var first = virtualConflicts[0];
53
- var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
54
-
55
- reportDuplicates = virtualConflicts.Skip(1);
56
-
57
- this.Messaging.Write(LinkerErrors.DuplicateVirtualSymbol(first.Symbol, referencingSourceLineNumber));
58
- }
59
- else if (virtualConflicts.Count == 1 && otherConflicts.Count > 0)
60
- {
61
- var first = otherConflicts[0];
62
- var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
63
-
64
- reportDuplicates = virtualConflicts;
65
-
66
- switch (first.Symbol)
67
- {
68
- case WixActionSymbol action:
69
- this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(action));
70
- break;
71
- default:
72
- this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(first.Symbol, referencingSourceLineNumber));
73
- break;
74
- }
75
- }
76
- else
77
- {
78
- var referencingSourceLineNumber = referencedDuplicate.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
79
-
80
- this.Messaging.Write(LinkerErrors.DuplicateSymbol(referencedDuplicate.Symbol, referencingSourceLineNumber));
81
- }
82
-
83
- foreach (var duplicate in reportDuplicates)
84
- {
85
- this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol));
86
- }
87
- }
88
- }
89
- }
90
- }
91
- }
92
-}
src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs
+59
-4
@@ -76,6 +76,7 @@ namespace WixToolset.Core.Link
76
if (this.symbolsWithSections.TryGetValue(reference.SymbolicName, out var symbolWithSection))
77
{
78
var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection);
79
+
80
if (accessible.Count == 1)
81
{
82
var accessibleSymbol = accessible[0];
@@ -91,7 +92,7 @@ namespace WixToolset.Core.Link
92
{
93
this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName, symbolWithSection.Access));
94
}
94
- else // multiple symbols referenced creates conflicting symbols.
95
+ else // multiple accessible symbols referenced creates conflicting symbols.
96
{
97
// Remember the direct reference to the symbol for the error reporting later,
98
// but do NOT continue resolving references found in these conflicting symbols.
@@ -122,7 +123,7 @@ namespace WixToolset.Core.Link
123
}
124
125
/// <summary>
125
- /// Determine if the symbol and any of its duplicates are accessbile by referencing section.
126
+ /// Determine if the symbol and any of its duplicates are accessbile by the referencing section.
127
/// </summary>
128
/// <param name="referencingSection">Section referencing the symbol.</param>
129
/// <param name="symbolWithSection">Symbol being referenced.</param>
@@ -130,23 +131,77 @@ namespace WixToolset.Core.Link
131
private List<SymbolWithSection> DetermineAccessibleSymbols(IntermediateSection referencingSection, SymbolWithSection symbolWithSection)
132
{
133
var accessibleSymbols = new List<SymbolWithSection>();
134
+ List<SymbolWithSection> virtualSymbols = null;
135
136
if (this.AccessibleSymbol(referencingSection, symbolWithSection))
137
{
136
- accessibleSymbols.Add(symbolWithSection);
138
+ AddSymbolToCorrectCollection(symbolWithSection, accessibleSymbols, ref virtualSymbols);
139
}
140
141
foreach (var dupe in symbolWithSection.PossiblyConflicts)
142
{
143
if (this.AccessibleSymbol(referencingSection, dupe))
144
{
143
- accessibleSymbols.Add(dupe);
145
+ AddSymbolToCorrectCollection(dupe, accessibleSymbols, ref virtualSymbols);
146
+ }
147
+ }
148
+
149
+ // If a virtual symbol is accessible we have some extra work to do.
150
+ if (virtualSymbols != null)
151
+ {
152
+ // If there are multiple virtual symbols accessible that's an error case so add them all and
153
+ // they'll be reported as conflicts later.
154
+ if (virtualSymbols.Count > 1)
155
+ {
156
+ accessibleSymbols.AddRange(virtualSymbols);
157
+ }
158
+ else
159
+ {
160
+ var overrode = false;
161
+
162
+ // If there are any override symbols, skip adding the virtual symbols because they are "overridden".
163
+ foreach (var overrideSymbol in accessibleSymbols.Where(symbol => symbol.Access == AccessModifier.Override))
164
+ {
165
+ overrideSymbol.OverrideVirtualSymbol(virtualSymbols[0]);
166
+
167
+ overrode = true;
168
+ }
169
+
170
+ // If there are no overriding symbols, add the virtual symbol (there is only one but we'll add the collection just in case)
171
+ // so it will be reported as a conflict later.
172
+ if (!overrode)
173
+ {
174
+ accessibleSymbols.AddRange(virtualSymbols);
175
+ }
176
}
177
}
178
179
return accessibleSymbols;
180
}
181
182
+ /// <summary>
183
+ /// Add a symbol to the correct collection based on its access.
184
+ /// </summary>
185
+ /// <param name="symbolWithSection"></param>
186
+ /// <param name="accessibleSymbols">Collection of non-virtual symbol that was accessible.</param>
187
+ /// <param name="virtualSymbols">Collection of virtual symbol that was accessible</param>
188
+ private static void AddSymbolToCorrectCollection(SymbolWithSection symbolWithSection, List<SymbolWithSection> accessibleSymbols, ref List<SymbolWithSection> virtualSymbols)
189
+ {
190
+ if (symbolWithSection.Access == AccessModifier.Virtual)
191
+ {
192
+ if (virtualSymbols == null)
193
+ {
194
+ virtualSymbols = new List<SymbolWithSection>();
195
+ }
196
+
197
+ virtualSymbols.Add(symbolWithSection);
198
+ }
199
+ else
200
+ {
201
+ accessibleSymbols.Add(symbolWithSection);
202
+ }
203
+ }
204
+
205
/// <summary>
206
/// Determine if a single symbol is accessible by the referencing section.
207
/// </summary>
src/wix/WixToolset.Core/Linker.cs
+6
-3
@@ -190,10 +190,13 @@ namespace WixToolset.Core
190
}
191
}
192
193
- // Report duplicates that would ultimately end up being primary key collisions.
193
+ // Process conflicts that may be overridden virtual symbols (that's okay) or end up as primary key collisions (those need to be reported as errors).
194
+ ISet<IntermediateSymbol> overriddenSymbols;
195
{
195
- var reportDupes = new ReportConflictingSymbolsCommand(this.Messaging, find.PossibleConflicts, resolve.ResolvedSections);
196
+ var reportDupes = new ProcessConflictingSymbolsCommand(this.Messaging, find.PossibleConflicts, find.OverrideSymbols, resolve.ResolvedSections);
197
reportDupes.Execute();
198
+
199
+ overriddenSymbols = reportDupes.OverriddenSymbols;
200
}
201
202
if (this.Messaging.EncounteredError)
@@ -222,7 +225,7 @@ namespace WixToolset.Core
225
continue;
226
}
227
}
225
- else if (find.OverriddenSymbols.Contains(symbol))
228
+ else if (overriddenSymbols.Contains(symbol))
229
{
230
// Skip the symbols that were overridden.
231
continue;
src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs
+19
-6
@@ -62,6 +62,18 @@ namespace WixToolsetTest.CoreIntegration
62
}, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Access.AsString() + ":" + d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
63
}
64
65
+ [Fact]
66
+ public void CanCompileVirtualSymbolThatDoesNotGetOverridden()
67
+ {
68
+ var dirSymbols = BuildToGetDirectorySymbols("TestData", "AccessModifier", "VirtualSymbolThatDoesNotGetOverridden.wxs");
69
+ WixAssert.CompareLineByLine(new[]
70
+ {
71
+ "virtual:ProgramFilesFolder:TARGETDIR:PFiles",
72
+ "virtual:TARGETDIR::SourceDir",
73
+ "virtual:TestFolder:ProgramFilesFolder:Used",
74
+ }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => d.Id.Access.AsString() + ":" + d.Id.Id + ":" + d.ParentDirectoryRef + ":" + d.Name).ToArray());
75
+ }
76
+
77
[Fact]
78
public void CannotCompileInvalidCrossFragmentReference()
79
{
@@ -78,8 +90,9 @@ namespace WixToolsetTest.CoreIntegration
90
var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs");
91
WixAssert.CompareLineByLine(new[]
92
{
81
- "ln 12: Duplicate Directory with identifier 'TestFolder' referenced by <sourceFolder>\\DuplicateCrossFragmentReference.wxs(4). Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.",
82
- "ln 8: Location of symbol related to previous error."
93
+ "ln 8: Duplicate Directory with identifier 'TestFolder' referenced by <sourceFolder>\\DuplicateCrossFragmentReference.wxs(4). Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.",
94
+ "ln 12: Location of symbol related to previous error.",
95
+ "ln 16: Location of symbol related to previous error."
96
}, errors);
97
}
98
@@ -99,8 +112,8 @@ namespace WixToolsetTest.CoreIntegration
112
var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs");
113
WixAssert.CompareLineByLine(new[]
114
{
102
- "ln 14: Duplicate Directory with identifier 'TestFolder' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
103
- "ln 6: Location of symbol related to previous error."
115
+ "ln 6: Duplicate Directory with identifier 'TestFolder' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
116
+ "ln 14: Location of symbol related to previous error."
117
}, errors);
118
}
119
@@ -132,8 +145,8 @@ namespace WixToolsetTest.CoreIntegration
145
var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatePublicOverrideVirtualSymbol.wxs");
146
WixAssert.CompareLineByLine(new[]
147
{
135
- "ln 14: Duplicate Directory with identifier 'TestFolder' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
136
- "ln 6: Location of symbol related to previous error."
148
+ "ln 14: The Directory symbol 'TestFolder' conflicts with a virtual symbol. Use the 'override' access modifier to override the virtual symbol or use a different Id to avoid the conflict.",
149
+ "ln 10: Location of symbol related to previous error."
150
}, errors);
151
}
152
src/wix/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs
+11
-4
@@ -4,9 +4,9 @@ namespace WixToolsetTest.CoreIntegration
4
{
5
using System.IO;
6
using System.Linq;
7
+ using WixInternal.Core.TestPackage;
8
using WixInternal.TestSupport;
9
using WixToolset.Core;
9
- using WixInternal.Core.TestPackage;
10
using WixToolset.Data;
11
using WixToolset.Data.Symbols;
12
using WixToolset.Extensibility.Data;
@@ -101,7 +101,7 @@ namespace WixToolsetTest.CoreIntegration
101
[Fact]
102
public void VariableRedefinitionIsAWarning()
103
{
104
- var folder = TestData.Get(@"TestData\Variables");
104
+ var folder = TestData.Get(@"TestData", "Variables");
105
106
using (var fs = new DisposableFileSystem())
107
{
@@ -121,8 +121,15 @@ namespace WixToolsetTest.CoreIntegration
121
122
result.AssertSuccess();
123
124
- var warning = result.Messages.Where(message => message.Id == (int)WarningMessages.Ids.VariableDeclarationCollision);
125
- Assert.Single(warning);
124
+ var warning = result.Messages.Where(m => m.Level == MessageLevel.Warning || m.Level == MessageLevel.Error)
125
+ .Select(m => $"ln {m.SourceLineNumbers.LineNumber}: {m.Level.ToString().ToLowerInvariant()}: {m}".Replace(baseFolder, "<baseFolder>"))
126
+ .ToArray();
127
+ WixAssert.CompareLineByLine(new[]
128
+ {
129
+ "ln 5: warning: The variable 'Bar' with value 'Baz' was previously declared with value 'Bar'.",
130
+ "ln 24: warning: It is no longer necessary to define the standard directory 'TARGETDIR'. Use the StandardDirectory element instead.",
131
+ "ln 25: warning: It is no longer necessary to define the standard directory 'ProgramFilesFolder'. Use the StandardDirectory element instead."
132
+ }, warning);
133
}
134
}
135
src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
+3
-4
@@ -102,10 +102,9 @@ namespace WixToolsetTest.CoreIntegration
102
.ToArray();
103
WixAssert.CompareLineByLine(new[]
104
{
105
- "ln 8: Duplicate Registry with identifier 'regJnkjRU9YGaMJhQOqKmivWKf_VdY' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
106
- "ln 7: Location of symbol related to previous error.",
107
- "ln 9: Duplicate Registry with identifier 'regJnkjRU9YGaMJhQOqKmivWKf_VdY' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
108
- "ln 7: Location of symbol related to previous error."
105
+ "ln 7: Duplicate Registry with identifier 'regJnkjRU9YGaMJhQOqKmivWKf_VdY' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
106
+ "ln 8: Location of symbol related to previous error.",
107
+ "ln 9: Location of symbol related to previous error."
108
}, errors);
109
}
110
}
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicateCrossFragmentReference.wxs
+4
@@ -11,4 +11,8 @@
11
<Fragment>
12
<Directory Id="TestFolder" Name="Dupe 2" />
13
</Fragment>
14
+
15
+ <Fragment>
16
+ <Directory Id="TestFolder" Name="Dupe 3" />
17
+ </Fragment>
18
</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/OverrideVirtualSymbolWithFragments.wxs
+13
@@ -2,8 +2,21 @@
2
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
<Package Name="Override Virtual Symbol With Fragments" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4
<DirectoryRef Id="TestFolder" />
5
+
6
+ <PropertyRef Id="A" />
7
+ <PropertyRef Id="B" />
8
</Package>
9
10
+ <Fragment>
11
+ <Property Id="A" Secure="true"/>
12
+ <DirectoryRef Id="TestFolder" />
13
+ </Fragment>
14
+
15
+ <Fragment>
16
+ <Property Id="B" Secure="true"/>
17
+ <DirectoryRef Id="TestFolder" />
18
+ </Fragment>
19
+
20
<Fragment>
21
<StandardDirectory Id="ProgramFilesFolder">
22
<Directory Id="override TestFolder" Name="Override Test Folder Includes Another" />
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolThatDoesNotGetOverridden.wxs
new
+30
@@ -0,0 +1,30 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
+ <Package Name="Override Without Virtual Symbol" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4
+ <PropertyRef Id="DoesGetReferenced" />
5
+ </Package>
6
+
7
+ <Fragment>
8
+ <Property Id="DoesNotGetReferenced1" Value="Does Not Get Referenced" />
9
+
10
+ <StandardDirectory Id="ProgramFilesFolder">
11
+ <Directory Id="override TestFolder" Name="IsNotUsed1" />
12
+ </StandardDirectory>
13
+ </Fragment>
14
+
15
+ <Fragment>
16
+ <Property Id="DoesNotGetReferenced2" Value="Does Not Get Referenced" />
17
+
18
+ <StandardDirectory Id="ProgramFilesFolder">
19
+ <Directory Id="override TestFolder" Name="IsNotUsed2" />
20
+ </StandardDirectory>
21
+ </Fragment>
22
+
23
+ <Fragment>
24
+ <Property Id="DoesGetReferenced" Value="Is Referenced" />
25
+
26
+ <StandardDirectory Id="ProgramFilesFolder">
27
+ <Directory Id="virtual TestFolder" Name="Used" />
28
+ </StandardDirectory>
29
+ </Fragment>
30
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/Variables/Package.wxs
+1
-1
@@ -22,7 +22,7 @@
22
23
<Fragment>
24
<Directory Id="override TARGETDIR" Name="SourceDir">
25
- <Directory Id="override ProgramFilesFolder">
25
+ <Directory Id="ProgramFilesFolder">
26
<Directory Id="INSTALLFOLDER" Name="MsiPackage" />
27
</Directory>
28
</Directory>