@joebigelow / wix / commits / 0bf10d98

Improve error reporting of duplicate symbols

Virtual symbols provide more interesting ways to have (and avoid) conflicts. Adding additional messages and cleaning up the existing messages should help users know what options they have to address conflicts. This also puts all the conflict resolution in ReportConflictingSymbolsCommand instead of spreading it across reference resolution as well.

Rob Mensching committed Dec 16, 2023 at 09:03 UTC 0bf10d9873577f8c943cae1f50dedf68565847ee
12 files changed +251 -78
src/api/wix/WixToolset.Data/ErrorMessages.cs
-17
@@ -323,21 +323,6 @@ namespace WixToolset.Data
323 return Message(null, Ids.DuplicateSourcesForOutput, "Multiple source files ({0}) have resulted in the same output file '{1}'. This is likely because the source files only differ in extension or path. Rename the source files to avoid this problem.", sourceList, outputFile);
324 }
325
326 - public static Message DuplicateSymbol(SourceLineNumber sourceLineNumbers, string symbolName)
327 - {
328 - return Message(sourceLineNumbers, Ids.DuplicateSymbol, "Duplicate symbol '{0}' found. This typically means that an Id is duplicated. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.", symbolName);
329 - }
330 -
331 - public static Message DuplicateSymbol(SourceLineNumber sourceLineNumbers, string symbolName, string referencingSourceLineNumber)
332 - {
333 - return Message(sourceLineNumbers, Ids.DuplicateSymbol, "Duplicate symbol '{0}' referenced by {1}. This typically means that an Id is duplicated. Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.", symbolName, referencingSourceLineNumber);
334 - }
335 -
336 - public static Message DuplicateSymbol2(SourceLineNumber sourceLineNumbers)
337 - {
338 - return Message(sourceLineNumbers, Ids.DuplicateSymbol2, "Location of symbol related to previous error.");
339 - }
340 -
326 public static Message DuplicateTransform(string transform)
327 {
328 return Message(null, Ids.DuplicateTransform, "The transform {0} was included twice on the command line. Each transform can be applied to a patch only once.", transform);
@@ -2369,8 +2354,6 @@ namespace WixToolset.Data
2354 InvalidDateTimeFormat = 88,
2355 MultipleEntrySections = 89,
2356 MultipleEntrySections2 = 90,
2372 - DuplicateSymbol = 91,
2373 - DuplicateSymbol2 = 92,
2357 MissingEntrySection = 93,
2358 UnresolvedReference = 94,
2359 MultiplePrimaryReferences = 95,
src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs
+2 -4
@@ -36,7 +36,7 @@ namespace WixToolset.Core.Link
36 /// <summary>
37 /// Gets the collection of possibly conflicting symbols.
38 /// </summary>
39 - public IEnumerable<SymbolWithSection> PossibleConflicts { get; private set; }
39 + public IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; private set; }
40
41 /// <summary>
42 /// Gets the collection of redundant symbols that should not be included
@@ -140,9 +140,7 @@ namespace WixToolset.Core.Link
140 {
141 if (symbolWithSection.Overrides is null)
142 {
143 - var fullName = symbolWithSection.GetFullName();
144 -
145 - this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol.SourceLineNumbers, fullName));
143 + this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol));
144 }
145 }
146
src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs
+44 -17
@@ -9,7 +9,7 @@ namespace WixToolset.Core.Link
9
10 internal class ReportConflictingSymbolsCommand
11 {
12 - public ReportConflictingSymbolsCommand(IMessaging messaging, IEnumerable<SymbolWithSection> possibleConflicts, IEnumerable<IntermediateSection> resolvedSections)
12 + public ReportConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, ISet<IntermediateSection> resolvedSections)
13 {
14 this.Messaging = messaging;
15 this.PossibleConflicts = possibleConflicts;
@@ -18,35 +18,62 @@ namespace WixToolset.Core.Link
18
19 private IMessaging Messaging { get; }
20
21 - private IEnumerable<SymbolWithSection> PossibleConflicts { get; }
21 + private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; }
22
23 - private IEnumerable<IntermediateSection> ResolvedSections { get; }
23 + private ISet<IntermediateSection> ResolvedSections { get; }
24
25 public void Execute()
26 {
27 - // Do a quick check if there are any possibly conflicting symbols that don't come from tables that allow
28 - // overriding. Hopefully the symbols with possible conflicts list is usually very short list (empty should
29 - // be the most common). If we find any matches, we'll do a more costly check to see if the possible conflicting
27 + // Do a quick check if there are any possibly conflicting symbols. Hopefully the symbols with possible conflicts
28 + // list is a very short list (empty should be the most common).
29 + //
30 + // If we have conflicts then we'll do a more costly check to see if the possible conflicting
31 // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate
32 // (aka: conflicting) symbol.
32 - var illegalDuplicates = this.PossibleConflicts.Where(s => s.Symbol.Definition.Type != SymbolDefinitionType.WixAction && s.Symbol.Definition.Type != SymbolDefinitionType.WixVariable).ToList();
33 - if (0 < illegalDuplicates.Count)
33 + if (0 < this.PossibleConflicts.Count)
34 {
35 - var referencedSections = new HashSet<IntermediateSection>(this.ResolvedSections);
36 -
37 - foreach (var referencedDuplicate in illegalDuplicates.Where(s => referencedSections.Contains(s.Section)))
35 + foreach (var referencedDuplicate in this.PossibleConflicts.Where(s => this.ResolvedSections.Contains(s.Section)))
36 {
39 - var actuallyReferencedDuplicates = referencedDuplicate.PossiblyConflicts.Where(s => referencedSections.Contains(s.Section)).ToList();
37 + var actuallyReferencedDuplicates = referencedDuplicate.PossiblyConflicts.Where(s => this.ResolvedSections.Contains(s.Section)).ToList();
38
41 - if (actuallyReferencedDuplicates.Any())
39 + if (actuallyReferencedDuplicates.Count > 0)
40 {
43 - var fullName = referencedDuplicate.GetFullName();
41 + var conflicts = actuallyReferencedDuplicates.Append(referencedDuplicate).ToList();
42 + var virtualConflicts = conflicts.Where(s => s.Access == AccessModifier.Virtual).ToList();
43 + var overrideConflicts = conflicts.Where(s => s.Access == AccessModifier.Override).ToList();
44 + var otherConflicts = conflicts.Where(s => s.Access != AccessModifier.Virtual && s.Access != AccessModifier.Override).ToList();
45 +
46 + IEnumerable<SymbolWithSection> reportDuplicates = actuallyReferencedDuplicates;
47 +
48 + // If multiple symbols are virtual, use the duplicate virtual symbol message.
49 + if (virtualConflicts.Count > 1)
50 + {
51 + var first = virtualConflicts[0];
52 + var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
53
45 - this.Messaging.Write(ErrorMessages.DuplicateSymbol(referencedDuplicate.Symbol.SourceLineNumbers, fullName));
54 + reportDuplicates = virtualConflicts.Skip(1);
55 +
56 + this.Messaging.Write(LinkerErrors.DuplicateVirtualSymbol(first.Symbol, referencingSourceLineNumber));
57 + }
58 + else if (virtualConflicts.Count == 1 && otherConflicts.Count > 0)
59 + {
60 + var first = otherConflicts[0];
61 + var referencingSourceLineNumber = first.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
62 +
63 + reportDuplicates = virtualConflicts;
64 +
65 + this.Messaging.Write(LinkerErrors.VirtualSymbolMustBeOverridden(first.Symbol, referencingSourceLineNumber));
66 + }
67 + else
68 + {
69 + var referencingSourceLineNumber = referencedDuplicate.DirectReferences.FirstOrDefault()?.SourceLineNumbers;
70 +
71 + this.Messaging.Write(LinkerErrors.DuplicateSymbol(referencedDuplicate.Symbol, referencingSourceLineNumber));
72 + }
73
47 - foreach (var duplicate in actuallyReferencedDuplicates)
74 + foreach (var duplicate in reportDuplicates)
75 {
49 - this.Messaging.Write(ErrorMessages.DuplicateSymbol2(duplicate.Symbol.SourceLineNumbers));
76 + this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol));
77 }
78 }
79 }
src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs
+27 -30
@@ -27,9 +27,9 @@ namespace WixToolset.Core.Link
27 this.BuildingMergeModule = (SectionType.Module == entrySection.Type);
28 }
29
30 - public IEnumerable<SymbolWithSection> ReferencedSymbolWithSections => this.referencedSymbols;
30 + public IReadOnlyCollection<SymbolWithSection> ReferencedSymbolWithSections => this.referencedSymbols;
31
32 - public IEnumerable<IntermediateSection> ResolvedSections => this.resolvedSections;
32 + public ISet<IntermediateSection> ResolvedSections => this.resolvedSections;
33
34 private bool BuildingMergeModule { get; }
35
@@ -63,22 +63,25 @@ namespace WixToolset.Core.Link
63 // symbols provided. Then recursively call this method to process the
64 // located symbol's section. All in all this is a very simple depth-first
65 // search of the references per-section.
66 - foreach (var wixSimpleReferenceRow in section.Symbols.OfType<WixSimpleReferenceSymbol>())
66 + foreach (var reference in section.Symbols.OfType<WixSimpleReferenceSymbol>())
67 {
68 // If we're building a Merge Module, ignore all references to the Media table
69 // because Merge Modules don't have Media tables.
70 - if (this.BuildingMergeModule && wixSimpleReferenceRow.Table == "Media")
70 + if (this.BuildingMergeModule && reference.Table == "Media")
71 {
72 continue;
73 }
74
75 // See if the symbol (and any of its duplicates) are appropriately accessible.
76 - if (this.symbolsWithSections.TryGetValue(wixSimpleReferenceRow.SymbolicName, out var symbolWithSection))
76 + if (this.symbolsWithSections.TryGetValue(reference.SymbolicName, out var symbolWithSection))
77 {
78 var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection);
79 if (accessible.Count == 1)
80 {
81 var accessibleSymbol = accessible[0];
82 +
83 + accessibleSymbol.AddDirectReference(reference);
84 +
85 if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section)
86 {
87 this.RecursivelyResolveReferences(accessibleSymbol.Section);
@@ -86,32 +89,34 @@ namespace WixToolset.Core.Link
89 }
90 else if (accessible.Count == 0)
91 {
89 - this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbolWithSection.Access));
92 + this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName, symbolWithSection.Access));
93 }
91 - else // display errors for the duplicate symbols.
94 + else // multiple symbols referenced creates conflicting symbols.
95 {
93 - var accessibleSymbol = accessible[0];
94 - var accessibleFullName = accessibleSymbol.GetFullName();
95 - var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers?.ToString();
96 -
97 - if (String.IsNullOrEmpty(referencingSourceLineNumber))
98 - {
99 - this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName));
100 - }
101 - else
96 + // Remember the direct reference to the symbol for the error reporting later,
97 + // but do NOT continue resolving references found in these conflicting symbols.
98 + foreach (var conflict in accessible)
99 {
103 - this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName, referencingSourceLineNumber));
104 - }
100 + // This should NEVER happen.
101 + if (!conflict.PossiblyConflicts.Any())
102 + {
103 + throw new InvalidOperationException("If a reference can reference multiple symbols, those symbols MUST have already been recognized as possible conflicts.");
104 + }
105
106 - foreach (var accessibleDuplicate in accessible.Skip(1))
107 - {
108 - this.Messaging.Write(ErrorMessages.DuplicateSymbol2(accessibleDuplicate.Symbol.SourceLineNumbers));
106 + conflict.AddDirectReference(reference);
107 +
108 + this.referencedSymbols.Add(conflict);
109 +
110 + if (conflict.Section != null)
111 + {
112 + this.resolvedSections.Add(conflict.Section);
113 + }
114 }
115 }
116 }
117 else
118 {
114 - this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName));
119 + this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName));
120 }
121 }
122 }
@@ -133,14 +138,6 @@ namespace WixToolset.Core.Link
138
139 foreach (var dupe in symbolWithSection.PossiblyConflicts)
140 {
136 - //// don't count overridable WixActionSymbols
137 - //var symbolAction = symbolWithSection.Symbol as WixActionSymbol;
138 - //var dupeAction = dupe.Symbol as WixActionSymbol;
139 - //if (symbolAction?.Overridable != dupeAction?.Overridable)
140 - //{
141 - // continue;
142 - //}
143 -
141 if (this.AccessibleSymbol(referencingSection, dupe))
142 {
143 accessibleSymbols.Add(dupe);
src/wix/WixToolset.Core/Link/SymbolWithSection.cs
+21
@@ -6,12 +6,14 @@ namespace WixToolset.Core.Link
6 using System.Collections.Generic;
7 using System.Linq;
8 using WixToolset.Data;
9 + using WixToolset.Data.Symbols;
10
11 /// <summary>
12 /// Symbol with section representing a single unique symbol.
13 /// </summary>
14 internal class SymbolWithSection
15 {
16 + private List<WixSimpleReferenceSymbol> directReferences;
17 private HashSet<SymbolWithSection> possibleConflicts;
18
19 /// <summary>
@@ -43,6 +45,11 @@ namespace WixToolset.Core.Link
45 /// <value>Section for the symbol.</value>
46 public IntermediateSection Section { get; }
47
48 + /// <summary>
49 + /// Gets any duplicates of this symbol with sections that are possible conflicts.
50 + /// </summary>
51 + public IEnumerable<WixSimpleReferenceSymbol> DirectReferences => this.directReferences ?? Enumerable.Empty<WixSimpleReferenceSymbol>();
52 +
53 /// <summary>
54 /// Gets any duplicates of this symbol with sections that are possible conflicts.
55 /// </summary>
@@ -67,6 +74,20 @@ namespace WixToolset.Core.Link
74 this.possibleConflicts.Add(symbolWithSection);
75 }
76
77 + /// <summary>
78 + /// Adds a reference that directly points to this symbol.
79 + /// </summary>
80 + /// <param name="reference">The direct reference.</param>
81 + public void AddDirectReference(WixSimpleReferenceSymbol reference)
82 + {
83 + if (null == this.directReferences)
84 + {
85 + this.directReferences = new List<WixSimpleReferenceSymbol>();
86 + }
87 +
88 + this.directReferences.Add(reference);
89 + }
90 +
91 /// <summary>
92 /// Override a virtual symbol.
93 /// </summary>
src/wix/WixToolset.Core/LinkerErrors.cs
+66 -2
@@ -11,6 +11,41 @@ namespace WixToolset.Core
11 return Message(null, Ids.DuplicateBindPathVariableOnCommandLine, "", argument, bindName, bindValue, collisionValue);
12 }
13
14 + public static Message DuplicateSymbol(IntermediateSymbol symbol)
15 + {
16 + return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "Duplicate {0} with identifier '{1}' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.", symbol.Definition.Name, symbol.Id.Id);
17 + }
18 +
19 + public static Message DuplicateSymbol(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
20 + {
21 + if (referencingSourceLineNumber is null)
22 + {
23 + return DuplicateSymbol(symbol);
24 + }
25 +
26 + return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "Duplicate {0} with identifier '{1}' referenced by {2}. Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
27 + }
28 +
29 + public static Message DuplicateVirtualSymbol(IntermediateSymbol symbol)
30 + {
31 + return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "The virtual {0} with identifier '{1}' is duplicated. Ensure identifiers of a given type (Directory, File, etc.) are unique or did you mean to make one an override for the virtual symbol?", symbol.Definition.Name, symbol.Id.Id);
32 + }
33 +
34 + public static Message DuplicateVirtualSymbol(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
35 + {
36 + if (referencingSourceLineNumber is null)
37 + {
38 + return DuplicateVirtualSymbol(symbol);
39 + }
40 +
41 + return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol, "The virtual {0} with identifier '{1}' is duplicated. Ensure identifiers of a given type (Directory, File, etc.) are unique or did you mean to make one an override for the virtual symbol? Referenced from {2}", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
42 + }
43 +
44 + public static Message DuplicateSymbol2(IntermediateSymbol symbol)
45 + {
46 + return Message(symbol.SourceLineNumbers, Ids.DuplicateSymbol2, "Location of symbol related to previous error.");
47 + }
48 +
49 public static Message OrphanedPayload(SourceLineNumber sourceLineNumbers, string payloadId)
50 {
51 return Message(sourceLineNumbers, Ids.OrphanedPayload, "Found orphaned Payload '{0}'. Make sure to reference it from a Package, the BootstrapperApplication, or the Bundle or move it into its own Fragment so it only gets linked in when actually used.", payloadId);
@@ -46,9 +81,34 @@ namespace WixToolset.Core
81 return Message(sourceLineNumbers, Ids.UncompressedPayloadInContainer, "The payload '{0}' is uncompressed and cannot be added to container '{1}'. Remove its Compressed attribute and provide a @SourceFile value to allow it to be added to a container.", payloadId, containerId);
82 }
83
49 - public static Message VirtualSymbolNotFoundForOverride(SourceLineNumber sourceLineNumbers, string id)
84 + public static Message VirtualSymbolNotFoundForOverride(IntermediateSymbol symbol)
85 + {
86 + return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolNotFoundForOverride, "Could not find a virtual symbol to override with the {0} symbol '{1}'. Remove the override access modifier or include the code with the virtual symbol.", symbol.Definition.Name, symbol.Id.Id);
87 + }
88 +
89 + public static Message VirtualSymbolNotFoundForOverride(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
90 + {
91 + if (referencingSourceLineNumber is null)
92 + {
93 + return VirtualSymbolNotFoundForOverride(symbol);
94 + }
95 +
96 + return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolNotFoundForOverride, "Could not find a virtual symbol to override with the {0} symbol '{1}'. Remove the override access modifier or include the code with the virtual symbol. Referenced from {2}", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
97 + }
98 +
99 + public static Message VirtualSymbolMustBeOverridden(IntermediateSymbol symbol)
100 {
51 - return Message(sourceLineNumbers, Ids.VirtualSymbolNotFoundForOverride, "Did not find virtual symbol for override symbol '{0}'",id);
101 + return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolMustBeOverridden, "The {0} symbol '{1}' conflicts with a virtual symbol. Use the 'override' access modifier to override the virtual symbol or use a different Id to avoid the conflict.", symbol.Definition.Name, symbol.Id.Id);
102 + }
103 +
104 + public static Message VirtualSymbolMustBeOverridden(IntermediateSymbol symbol, SourceLineNumber referencingSourceLineNumber)
105 + {
106 + if (referencingSourceLineNumber is null)
107 + {
108 + return VirtualSymbolMustBeOverridden(symbol);
109 + }
110 +
111 + return Message(symbol.SourceLineNumbers, Ids.VirtualSymbolMustBeOverridden, "The {0} symbol '{1}' conflicts with a virtual symbol. Use the 'override' access modifier to override the virtual symbol or use a different Id to avoid the conflict. Referenced from {2}", symbol.Definition.Name, symbol.Id.Id, referencingSourceLineNumber);
112 }
113
114 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
@@ -58,6 +118,9 @@ namespace WixToolset.Core
118
119 public enum Ids
120 {
121 + DuplicateSymbol = 91,
122 + DuplicateSymbol2 = 92,
123 +
124 OrphanedPayload = 7000,
125 PackageInMultipleContainers = 7001,
126 PayloadSharedWithBA = 7002,
@@ -67,6 +130,7 @@ namespace WixToolset.Core
130 BAContainerCannotContainRemotePayload = 7006,
131 DuplicateBindPathVariableOnCommandLine = 7007,
132 VirtualSymbolNotFoundForOverride = 7008,
133 + VirtualSymbolMustBeOverridden = 7009,
134 } // last available is 7099. 7100 is WindowsInstallerBackendWarnings.
135 }
136 }
src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs
+37 -4
@@ -78,8 +78,8 @@ namespace WixToolsetTest.CoreIntegration
78 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs");
79 WixAssert.CompareLineByLine(new[]
80 {
81 - @"ln 8: Duplicate symbol 'Directory:TestFolder' referenced by <sourceFolder>\DuplicateCrossFragmentReference.wxs(4). This typically means that an Id is duplicated. Ensure all your identifiers of a given type (Directory, File, etc.) are unique or use an access modifier to scope the identfier.",
82 - "ln 12: Location of symbol related to previous error."
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."
83 }, errors);
84 }
85
@@ -89,7 +89,7 @@ namespace WixToolsetTest.CoreIntegration
89 var errors = BuildForFailure("TestData", "AccessModifier", "OverrideWithoutVirtualSymbol.wxs");
90 WixAssert.CompareLineByLine(new[]
91 {
92 - "ln 5: Did not find virtual symbol for override symbol 'Directory:TestFolder'",
92 + "ln 5: Could not find a virtual symbol to override with the Directory symbol 'TestFolder'. Remove the override access modifier or include the code with the virtual symbol.",
93 }, errors);
94 }
95
@@ -99,7 +99,40 @@ namespace WixToolsetTest.CoreIntegration
99 var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs");
100 WixAssert.CompareLineByLine(new[]
101 {
102 - "ln 14: Duplicate symbol 'Directory:TestFolder' found. This typically means that an Id is duplicated. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
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."
104 + }, errors);
105 + }
106 +
107 + [Fact]
108 + public void CannotCompileDuplicatedVirtual()
109 + {
110 + var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedVirtualSymbol.wxs");
111 + WixAssert.CompareLineByLine(new[]
112 + {
113 + "ln 6: The virtual Directory with identifier 'TestFolder' is duplicated. Ensure identifiers of a given type (Directory, File, etc.) are unique or did you mean to make one an override for the virtual symbol?",
114 + "ln 10: Location of symbol related to previous error."
115 + }, errors);
116 + }
117 +
118 + [Fact]
119 + public void CannotCompilePublicWithVirtualSymbol()
120 + {
121 + var errors = BuildForFailure("TestData", "AccessModifier", "VirtualSymbolWithoutOverride.wxs");
122 + WixAssert.CompareLineByLine(new[]
123 + {
124 + "ln 9: 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.",
125 + "ln 5: Location of symbol related to previous error."
126 + }, errors);
127 + }
128 +
129 + [Fact]
130 + public void CannotCompilePublicAndOverrideWithVirtualSymbol()
131 + {
132 + var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatePublicOverrideVirtualSymbol.wxs");
133 + WixAssert.CompareLineByLine(new[]
134 + {
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."
137 }, errors);
138 }
src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs
+11 -3
@@ -4,8 +4,8 @@ namespace WixToolsetTest.CoreIntegration
4 {
5 using System.IO;
6 using System.Linq;
7 - using WixInternal.TestSupport;
7 using WixInternal.Core.TestPackage;
8 + using WixInternal.TestSupport;
9 using WixToolset.Data;
10 using Xunit;
11
@@ -97,8 +97,16 @@ namespace WixToolsetTest.CoreIntegration
97 "-o", msiPath
98 }, out var messages);
99
100 - Assert.Equal(2, messages.Where(m => m.Id == (int)ErrorMessages.Ids.DuplicateSymbol).Count());
101 - Assert.Equal(2, messages.Where(m => m.Id == (int)ErrorMessages.Ids.DuplicateSymbol2).Count());
100 + var errors = messages.Where(m => m.Level == MessageLevel.Error)
101 + .Select(m => $"ln {m.SourceLineNumbers.LineNumber}: {m}".Replace(baseFolder, "<baseFolder>").Replace(folder, "<sourceFolder>"))
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."
109 + }, errors);
110 }
111 }
112
src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs
+1 -1
@@ -66,7 +66,7 @@ namespace WixToolsetTest.CoreIntegration
66
67 WixAssert.CompareLineByLine(new[]
68 {
69 - "Duplicate symbol 'WixChainItem:collision' found. This typically means that an Id is duplicated. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
69 + "Duplicate WixChainItem with identifier 'collision' found. Access modifiers (global, library, file, section) cannot prevent these conflicts. Ensure all your identifiers of a given type (Directory, File, etc.) are unique.",
70 "Location of symbol related to previous error.",
71 }, result.Messages.Select(m => m.ToString()).ToArray());
72
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs new
+17
@@ -0,0 +1,17 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Package Name="Duplicated Override Virtual Symbol" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4 +
5 + <StandardDirectory Id="ProgramFilesFolder">
6 + <Directory Id="override TestFolder" Name="Override Test Folder" />
7 + </StandardDirectory>
8 +
9 + <StandardDirectory Id="ProgramFilesFolder">
10 + <Directory Id="virtual TestFolder" Name="Test Folder" />
11 + </StandardDirectory>
12 +
13 + <StandardDirectory Id="ProgramFilesFolder">
14 + <Directory Id="TestFolder" Name="Collision Test Folder" />
15 + </StandardDirectory>
16 + </Package>
17 +</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs new
+13
@@ -0,0 +1,13 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Package Name="Duplicated Override Virtual Symbol" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
4 +
5 + <StandardDirectory Id="ProgramFilesFolder">
6 + <Directory Id="virtual TestFolder" Name="First Virtual Test Folder" />
7 + </StandardDirectory>
8 +
9 + <StandardDirectory Id="ProgramFilesFolder">
10 + <Directory Id="virtual TestFolder" Name="Second Virtual Test Folder" />
11 + </StandardDirectory>
12 + </Package>
13 +</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs new
+12
@@ -0,0 +1,12 @@
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 + <StandardDirectory Id="ProgramFilesFolder">
5 + <Directory Id="virtual TestFolder" Name="Test Folder" />
6 + </StandardDirectory>
7 +
8 + <StandardDirectory Id="ProgramFilesFolder">
9 + <Directory Id="TestFolder" Name="Missing Override Access Modifier" />
10 + </StandardDirectory>
11 + </Package>
12 +</Wix>