diff options
author | Rob Mensching <rob@firegiant.com> | 2023-12-16 09:03:44 -0800 |
---|---|---|
committer | Rob Mensching <rob@firegiant.com> | 2023-12-16 14:32:21 -0800 |
commit | 0bf10d9873577f8c943cae1f50dedf68565847ee (patch) | |
tree | f62be6f9a0909bde26eda675ad48e08c48d1e8e2 | |
parent | eff9d4204880535f821827e5aece5068402358f6 (diff) | |
download | wix-0bf10d9873577f8c943cae1f50dedf68565847ee.tar.gz wix-0bf10d9873577f8c943cae1f50dedf68565847ee.tar.bz2 wix-0bf10d9873577f8c943cae1f50dedf68565847ee.zip |
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.
12 files changed, 251 insertions, 78 deletions
diff --git a/src/api/wix/WixToolset.Data/ErrorMessages.cs b/src/api/wix/WixToolset.Data/ErrorMessages.cs index 889d1762..e149d54a 100644 --- a/src/api/wix/WixToolset.Data/ErrorMessages.cs +++ b/src/api/wix/WixToolset.Data/ErrorMessages.cs | |||
@@ -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); | 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 | } | 324 | } |
325 | 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 | |||
341 | public static Message DuplicateTransform(string transform) | 326 | public static Message DuplicateTransform(string transform) |
342 | { | 327 | { |
343 | 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); | 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 | |||
2369 | InvalidDateTimeFormat = 88, | 2354 | InvalidDateTimeFormat = 88, |
2370 | MultipleEntrySections = 89, | 2355 | MultipleEntrySections = 89, |
2371 | MultipleEntrySections2 = 90, | 2356 | MultipleEntrySections2 = 90, |
2372 | DuplicateSymbol = 91, | ||
2373 | DuplicateSymbol2 = 92, | ||
2374 | MissingEntrySection = 93, | 2357 | MissingEntrySection = 93, |
2375 | UnresolvedReference = 94, | 2358 | UnresolvedReference = 94, |
2376 | MultiplePrimaryReferences = 95, | 2359 | MultiplePrimaryReferences = 95, |
diff --git a/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs index e614d4eb..f9d6ab59 100644 --- a/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs +++ b/src/wix/WixToolset.Core/Link/FindEntrySectionAndLoadSymbolsCommand.cs | |||
@@ -36,7 +36,7 @@ namespace WixToolset.Core.Link | |||
36 | /// <summary> | 36 | /// <summary> |
37 | /// Gets the collection of possibly conflicting symbols. | 37 | /// Gets the collection of possibly conflicting symbols. |
38 | /// </summary> | 38 | /// </summary> |
39 | public IEnumerable<SymbolWithSection> PossibleConflicts { get; private set; } | 39 | public IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; private set; } |
40 | 40 | ||
41 | /// <summary> | 41 | /// <summary> |
42 | /// Gets the collection of redundant symbols that should not be included | 42 | /// Gets the collection of redundant symbols that should not be included |
@@ -140,9 +140,7 @@ namespace WixToolset.Core.Link | |||
140 | { | 140 | { |
141 | if (symbolWithSection.Overrides is null) | 141 | if (symbolWithSection.Overrides is null) |
142 | { | 142 | { |
143 | var fullName = symbolWithSection.GetFullName(); | 143 | this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol)); |
144 | |||
145 | this.Messaging.Write(LinkerErrors.VirtualSymbolNotFoundForOverride(symbolWithSection.Symbol.SourceLineNumbers, fullName)); | ||
146 | } | 144 | } |
147 | } | 145 | } |
148 | 146 | ||
diff --git a/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs index 3a07d366..2851fa60 100644 --- a/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs +++ b/src/wix/WixToolset.Core/Link/ReportConflictingSymbolsCommand.cs | |||
@@ -9,7 +9,7 @@ namespace WixToolset.Core.Link | |||
9 | 9 | ||
10 | internal class ReportConflictingSymbolsCommand | 10 | internal class ReportConflictingSymbolsCommand |
11 | { | 11 | { |
12 | public ReportConflictingSymbolsCommand(IMessaging messaging, IEnumerable<SymbolWithSection> possibleConflicts, IEnumerable<IntermediateSection> resolvedSections) | 12 | public ReportConflictingSymbolsCommand(IMessaging messaging, IReadOnlyCollection<SymbolWithSection> possibleConflicts, ISet<IntermediateSection> resolvedSections) |
13 | { | 13 | { |
14 | this.Messaging = messaging; | 14 | this.Messaging = messaging; |
15 | this.PossibleConflicts = possibleConflicts; | 15 | this.PossibleConflicts = possibleConflicts; |
@@ -18,35 +18,62 @@ namespace WixToolset.Core.Link | |||
18 | 18 | ||
19 | private IMessaging Messaging { get; } | 19 | private IMessaging Messaging { get; } |
20 | 20 | ||
21 | private IEnumerable<SymbolWithSection> PossibleConflicts { get; } | 21 | private IReadOnlyCollection<SymbolWithSection> PossibleConflicts { get; } |
22 | 22 | ||
23 | private IEnumerable<IntermediateSection> ResolvedSections { get; } | 23 | private ISet<IntermediateSection> ResolvedSections { get; } |
24 | 24 | ||
25 | public void Execute() | 25 | public void Execute() |
26 | { | 26 | { |
27 | // Do a quick check if there are any possibly conflicting symbols that don't come from tables that allow | 27 | // Do a quick check if there are any possibly conflicting symbols. Hopefully the symbols with possible conflicts |
28 | // overriding. Hopefully the symbols with possible conflicts list is usually very short list (empty should | 28 | // list is a very short list (empty should be the most common). |
29 | // be the most common). If we find any matches, we'll do a more costly check to see if the possible conflicting | 29 | // |
30 | // If we have conflicts then we'll do a more costly check to see if the possible conflicting | ||
30 | // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate | 31 | // symbols are in sections we actually referenced. From the resulting set, show an error for each duplicate |
31 | // (aka: conflicting) symbol. | 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 < this.PossibleConflicts.Count) |
33 | if (0 < illegalDuplicates.Count) | ||
34 | { | 34 | { |
35 | var referencedSections = new HashSet<IntermediateSection>(this.ResolvedSections); | 35 | foreach (var referencedDuplicate in this.PossibleConflicts.Where(s => this.ResolvedSections.Contains(s.Section))) |
36 | |||
37 | foreach (var referencedDuplicate in illegalDuplicates.Where(s => referencedSections.Contains(s.Section))) | ||
38 | { | 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(); |
40 | 38 | ||
41 | if (actuallyReferencedDuplicates.Any()) | 39 | if (actuallyReferencedDuplicates.Count > 0) |
42 | { | 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; | ||
44 | 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 | } | ||
46 | 73 | ||
47 | foreach (var duplicate in actuallyReferencedDuplicates) | 74 | foreach (var duplicate in reportDuplicates) |
48 | { | 75 | { |
49 | this.Messaging.Write(ErrorMessages.DuplicateSymbol2(duplicate.Symbol.SourceLineNumbers)); | 76 | this.Messaging.Write(LinkerErrors.DuplicateSymbol2(duplicate.Symbol)); |
50 | } | 77 | } |
51 | } | 78 | } |
52 | } | 79 | } |
diff --git a/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs index 0edbf39c..0e7a7a52 100644 --- a/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs +++ b/src/wix/WixToolset.Core/Link/ResolveReferencesCommand.cs | |||
@@ -27,9 +27,9 @@ namespace WixToolset.Core.Link | |||
27 | this.BuildingMergeModule = (SectionType.Module == entrySection.Type); | 27 | this.BuildingMergeModule = (SectionType.Module == entrySection.Type); |
28 | } | 28 | } |
29 | 29 | ||
30 | public IEnumerable<SymbolWithSection> ReferencedSymbolWithSections => this.referencedSymbols; | 30 | public IReadOnlyCollection<SymbolWithSection> ReferencedSymbolWithSections => this.referencedSymbols; |
31 | 31 | ||
32 | public IEnumerable<IntermediateSection> ResolvedSections => this.resolvedSections; | 32 | public ISet<IntermediateSection> ResolvedSections => this.resolvedSections; |
33 | 33 | ||
34 | private bool BuildingMergeModule { get; } | 34 | private bool BuildingMergeModule { get; } |
35 | 35 | ||
@@ -63,22 +63,25 @@ namespace WixToolset.Core.Link | |||
63 | // symbols provided. Then recursively call this method to process the | 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 | 64 | // located symbol's section. All in all this is a very simple depth-first |
65 | // search of the references per-section. | 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 | { | 67 | { |
68 | // If we're building a Merge Module, ignore all references to the Media table | 68 | // If we're building a Merge Module, ignore all references to the Media table |
69 | // because Merge Modules don't have Media tables. | 69 | // because Merge Modules don't have Media tables. |
70 | if (this.BuildingMergeModule && wixSimpleReferenceRow.Table == "Media") | 70 | if (this.BuildingMergeModule && reference.Table == "Media") |
71 | { | 71 | { |
72 | continue; | 72 | continue; |
73 | } | 73 | } |
74 | 74 | ||
75 | // See if the symbol (and any of its duplicates) are appropriately accessible. | 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 | { | 77 | { |
78 | var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection); | 78 | var accessible = this.DetermineAccessibleSymbols(section, symbolWithSection); |
79 | if (accessible.Count == 1) | 79 | if (accessible.Count == 1) |
80 | { | 80 | { |
81 | var accessibleSymbol = accessible[0]; | 81 | var accessibleSymbol = accessible[0]; |
82 | |||
83 | accessibleSymbol.AddDirectReference(reference); | ||
84 | |||
82 | if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section) | 85 | if (this.referencedSymbols.Add(accessibleSymbol) && null != accessibleSymbol.Section) |
83 | { | 86 | { |
84 | this.RecursivelyResolveReferences(accessibleSymbol.Section); | 87 | this.RecursivelyResolveReferences(accessibleSymbol.Section); |
@@ -86,32 +89,34 @@ namespace WixToolset.Core.Link | |||
86 | } | 89 | } |
87 | else if (accessible.Count == 0) | 90 | else if (accessible.Count == 0) |
88 | { | 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)); |
90 | } | 93 | } |
91 | else // display errors for the duplicate symbols. | 94 | else // multiple symbols referenced creates conflicting symbols. |
92 | { | 95 | { |
93 | var accessibleSymbol = accessible[0]; | 96 | // Remember the direct reference to the symbol for the error reporting later, |
94 | var accessibleFullName = accessibleSymbol.GetFullName(); | 97 | // but do NOT continue resolving references found in these conflicting symbols. |
95 | var referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers?.ToString(); | 98 | foreach (var conflict in accessible) |
96 | |||
97 | if (String.IsNullOrEmpty(referencingSourceLineNumber)) | ||
98 | { | ||
99 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName)); | ||
100 | } | ||
101 | else | ||
102 | { | 99 | { |
103 | this.Messaging.Write(ErrorMessages.DuplicateSymbol(accessibleSymbol.Symbol.SourceLineNumbers, accessibleFullName, referencingSourceLineNumber)); | 100 | // This should NEVER happen. |
104 | } | 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 | 105 | ||
106 | foreach (var accessibleDuplicate in accessible.Skip(1)) | 106 | conflict.AddDirectReference(reference); |
107 | { | 107 | |
108 | this.Messaging.Write(ErrorMessages.DuplicateSymbol2(accessibleDuplicate.Symbol.SourceLineNumbers)); | 108 | this.referencedSymbols.Add(conflict); |
109 | |||
110 | if (conflict.Section != null) | ||
111 | { | ||
112 | this.resolvedSections.Add(conflict.Section); | ||
113 | } | ||
109 | } | 114 | } |
110 | } | 115 | } |
111 | } | 116 | } |
112 | else | 117 | else |
113 | { | 118 | { |
114 | this.Messaging.Write(ErrorMessages.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName)); | 119 | this.Messaging.Write(ErrorMessages.UnresolvedReference(reference.SourceLineNumbers, reference.SymbolicName)); |
115 | } | 120 | } |
116 | } | 121 | } |
117 | } | 122 | } |
@@ -133,14 +138,6 @@ namespace WixToolset.Core.Link | |||
133 | 138 | ||
134 | foreach (var dupe in symbolWithSection.PossiblyConflicts) | 139 | foreach (var dupe in symbolWithSection.PossiblyConflicts) |
135 | { | 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 | |||
144 | if (this.AccessibleSymbol(referencingSection, dupe)) | 141 | if (this.AccessibleSymbol(referencingSection, dupe)) |
145 | { | 142 | { |
146 | accessibleSymbols.Add(dupe); | 143 | accessibleSymbols.Add(dupe); |
diff --git a/src/wix/WixToolset.Core/Link/SymbolWithSection.cs b/src/wix/WixToolset.Core/Link/SymbolWithSection.cs index 979aa44f..5bdf8360 100644 --- a/src/wix/WixToolset.Core/Link/SymbolWithSection.cs +++ b/src/wix/WixToolset.Core/Link/SymbolWithSection.cs | |||
@@ -6,12 +6,14 @@ namespace WixToolset.Core.Link | |||
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Linq; | 7 | using System.Linq; |
8 | using WixToolset.Data; | 8 | using WixToolset.Data; |
9 | using WixToolset.Data.Symbols; | ||
9 | 10 | ||
10 | /// <summary> | 11 | /// <summary> |
11 | /// Symbol with section representing a single unique symbol. | 12 | /// Symbol with section representing a single unique symbol. |
12 | /// </summary> | 13 | /// </summary> |
13 | internal class SymbolWithSection | 14 | internal class SymbolWithSection |
14 | { | 15 | { |
16 | private List<WixSimpleReferenceSymbol> directReferences; | ||
15 | private HashSet<SymbolWithSection> possibleConflicts; | 17 | private HashSet<SymbolWithSection> possibleConflicts; |
16 | 18 | ||
17 | /// <summary> | 19 | /// <summary> |
@@ -46,6 +48,11 @@ namespace WixToolset.Core.Link | |||
46 | /// <summary> | 48 | /// <summary> |
47 | /// Gets any duplicates of this symbol with sections that are possible conflicts. | 49 | /// Gets any duplicates of this symbol with sections that are possible conflicts. |
48 | /// </summary> | 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> | ||
49 | public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>(); | 56 | public IEnumerable<SymbolWithSection> PossiblyConflicts => this.possibleConflicts ?? Enumerable.Empty<SymbolWithSection>(); |
50 | 57 | ||
51 | /// <summary> | 58 | /// <summary> |
@@ -68,6 +75,20 @@ namespace WixToolset.Core.Link | |||
68 | } | 75 | } |
69 | 76 | ||
70 | /// <summary> | 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> | ||
71 | /// Override a virtual symbol. | 92 | /// Override a virtual symbol. |
72 | /// </summary> | 93 | /// </summary> |
73 | /// <param name="virtualSymbolWithSection">Virtual symbol with section that is being overridden.</param> | 94 | /// <param name="virtualSymbolWithSection">Virtual symbol with section that is being overridden.</param> |
diff --git a/src/wix/WixToolset.Core/LinkerErrors.cs b/src/wix/WixToolset.Core/LinkerErrors.cs index 78cd76f0..c234087e 100644 --- a/src/wix/WixToolset.Core/LinkerErrors.cs +++ b/src/wix/WixToolset.Core/LinkerErrors.cs | |||
@@ -11,6 +11,41 @@ namespace WixToolset.Core | |||
11 | return Message(null, Ids.DuplicateBindPathVariableOnCommandLine, "", argument, bindName, bindValue, collisionValue); | 11 | return Message(null, Ids.DuplicateBindPathVariableOnCommandLine, "", argument, bindName, bindValue, collisionValue); |
12 | } | 12 | } |
13 | 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 | |||
14 | public static Message OrphanedPayload(SourceLineNumber sourceLineNumbers, string payloadId) | 49 | public static Message OrphanedPayload(SourceLineNumber sourceLineNumbers, string payloadId) |
15 | { | 50 | { |
16 | 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); | 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 | |||
46 | 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); | 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); |
47 | } | 82 | } |
48 | 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) | ||
50 | { | 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); | ||
52 | } | 112 | } |
53 | 113 | ||
54 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) | 114 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) |
@@ -58,6 +118,9 @@ namespace WixToolset.Core | |||
58 | 118 | ||
59 | public enum Ids | 119 | public enum Ids |
60 | { | 120 | { |
121 | DuplicateSymbol = 91, | ||
122 | DuplicateSymbol2 = 92, | ||
123 | |||
61 | OrphanedPayload = 7000, | 124 | OrphanedPayload = 7000, |
62 | PackageInMultipleContainers = 7001, | 125 | PackageInMultipleContainers = 7001, |
63 | PayloadSharedWithBA = 7002, | 126 | PayloadSharedWithBA = 7002, |
@@ -67,6 +130,7 @@ namespace WixToolset.Core | |||
67 | BAContainerCannotContainRemotePayload = 7006, | 130 | BAContainerCannotContainRemotePayload = 7006, |
68 | DuplicateBindPathVariableOnCommandLine = 7007, | 131 | DuplicateBindPathVariableOnCommandLine = 7007, |
69 | VirtualSymbolNotFoundForOverride = 7008, | 132 | VirtualSymbolNotFoundForOverride = 7008, |
133 | VirtualSymbolMustBeOverridden = 7009, | ||
70 | } // last available is 7099. 7100 is WindowsInstallerBackendWarnings. | 134 | } // last available is 7099. 7100 is WindowsInstallerBackendWarnings. |
71 | } | 135 | } |
72 | } | 136 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs index d0e31760..5e40114f 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/AccessModifierFixture.cs | |||
@@ -78,8 +78,8 @@ namespace WixToolsetTest.CoreIntegration | |||
78 | var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs"); | 78 | var errors = BuildForFailure("TestData", "AccessModifier", "DuplicateCrossFragmentReference.wxs"); |
79 | WixAssert.CompareLineByLine(new[] | 79 | WixAssert.CompareLineByLine(new[] |
80 | { | 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.", | 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 12: Location of symbol related to previous error." | 82 | "ln 8: Location of symbol related to previous error." |
83 | }, errors); | 83 | }, errors); |
84 | } | 84 | } |
85 | 85 | ||
@@ -89,7 +89,7 @@ namespace WixToolsetTest.CoreIntegration | |||
89 | var errors = BuildForFailure("TestData", "AccessModifier", "OverrideWithoutVirtualSymbol.wxs"); | 89 | var errors = BuildForFailure("TestData", "AccessModifier", "OverrideWithoutVirtualSymbol.wxs"); |
90 | WixAssert.CompareLineByLine(new[] | 90 | WixAssert.CompareLineByLine(new[] |
91 | { | 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); | 93 | }, errors); |
94 | } | 94 | } |
95 | 95 | ||
@@ -99,7 +99,40 @@ namespace WixToolsetTest.CoreIntegration | |||
99 | var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs"); | 99 | var errors = BuildForFailure("TestData", "AccessModifier", "DuplicatedOverrideVirtualSymbol.wxs"); |
100 | WixAssert.CompareLineByLine(new[] | 100 | WixAssert.CompareLineByLine(new[] |
101 | { | 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.", | ||
103 | "ln 6: Location of symbol related to previous error." | 136 | "ln 6: Location of symbol related to previous error." |
104 | }, errors); | 137 | }, errors); |
105 | } | 138 | } |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs index 7bf10e3f..9931a45a 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/RegistryFixture.cs | |||
@@ -4,8 +4,8 @@ namespace WixToolsetTest.CoreIntegration | |||
4 | { | 4 | { |
5 | using System.IO; | 5 | using System.IO; |
6 | using System.Linq; | 6 | using System.Linq; |
7 | using WixInternal.TestSupport; | ||
8 | using WixInternal.Core.TestPackage; | 7 | using WixInternal.Core.TestPackage; |
8 | using WixInternal.TestSupport; | ||
9 | using WixToolset.Data; | 9 | using WixToolset.Data; |
10 | using Xunit; | 10 | using Xunit; |
11 | 11 | ||
@@ -97,8 +97,16 @@ namespace WixToolsetTest.CoreIntegration | |||
97 | "-o", msiPath | 97 | "-o", msiPath |
98 | }, out var messages); | 98 | }, out var messages); |
99 | 99 | ||
100 | Assert.Equal(2, messages.Where(m => m.Id == (int)ErrorMessages.Ids.DuplicateSymbol).Count()); | 100 | var errors = messages.Where(m => m.Level == MessageLevel.Error) |
101 | Assert.Equal(2, messages.Where(m => m.Id == (int)ErrorMessages.Ids.DuplicateSymbol2).Count()); | 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); | ||
102 | } | 110 | } |
103 | } | 111 | } |
104 | 112 | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs index 8d8ac801..54375f67 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs | |||
@@ -66,7 +66,7 @@ namespace WixToolsetTest.CoreIntegration | |||
66 | 66 | ||
67 | WixAssert.CompareLineByLine(new[] | 67 | WixAssert.CompareLineByLine(new[] |
68 | { | 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.", | 70 | "Location of symbol related to previous error.", |
71 | }, result.Messages.Select(m => m.ToString()).ToArray()); | 71 | }, result.Messages.Select(m => m.ToString()).ToArray()); |
72 | 72 | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs new file mode 100644 index 00000000..7ecf4445 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatePublicOverrideVirtualSymbol.wxs | |||
@@ -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> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs new file mode 100644 index 00000000..e97d0b57 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/DuplicatedVirtualSymbol.wxs | |||
@@ -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> | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs new file mode 100644 index 00000000..3db854f5 --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/AccessModifier/VirtualSymbolWithoutOverride.wxs | |||
@@ -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> | ||