From d3d3649a68cb1fa589fdd987a6690dbd5d671f0d Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sun, 17 Sep 2017 15:35:20 -0700 Subject: Initial code commit --- .../Link/ResolveReferencesCommand.cs | 178 +++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/WixToolset.Core/Link/ResolveReferencesCommand.cs (limited to 'src/WixToolset.Core/Link/ResolveReferencesCommand.cs') diff --git a/src/WixToolset.Core/Link/ResolveReferencesCommand.cs b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs new file mode 100644 index 00000000..5a985f3f --- /dev/null +++ b/src/WixToolset.Core/Link/ResolveReferencesCommand.cs @@ -0,0 +1,178 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Link +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Rows; + + /// + /// Resolves all the simple references in a section. + /// + internal class ResolveReferencesCommand : ICommand + { + private Section entrySection; + private IDictionary symbols; + private HashSet referencedSymbols; + private HashSet
resolvedSections; + + public ResolveReferencesCommand(Section entrySection, IDictionary symbols) + { + this.entrySection = entrySection; + this.symbols = symbols; + } + + public bool BuildingMergeModule { private get; set; } + + public IEnumerable ReferencedSymbols { get { return this.referencedSymbols; } } + + public IEnumerable
ResolvedSections { get { return this.resolvedSections; } } + + /// + /// Resolves all the simple references in a section. + /// + public void Execute() + { + this.resolvedSections = new HashSet
(); + this.referencedSymbols = new HashSet(); + + this.RecursivelyResolveReferences(this.entrySection); + } + + /// + /// Recursive helper function to resolve all references of passed in section. + /// + /// Section with references to resolve. + /// Note: recursive function. + private void RecursivelyResolveReferences(Section section) + { + // If we already resolved this section, move on to the next. + if (!this.resolvedSections.Add(section)) + { + return; + } + + // Process all of the references contained in this section using the collection of + // symbols provided. Then recursively call this method to process the + // located symbol's section. All in all this is a very simple depth-first + // search of the references per-section. + Table wixSimpleReferenceTable; + if (section.Tables.TryGetTable("WixSimpleReference", out wixSimpleReferenceTable)) + { + foreach (WixSimpleReferenceRow wixSimpleReferenceRow in wixSimpleReferenceTable.Rows) + { + Debug.Assert(wixSimpleReferenceRow.Section == section); + + // If we're building a Merge Module, ignore all references to the Media table + // because Merge Modules don't have Media tables. + if (this.BuildingMergeModule && "Media" == wixSimpleReferenceRow.TableName) + { + continue; + } + + Symbol symbol; + if (!this.symbols.TryGetValue(wixSimpleReferenceRow.SymbolicName, out symbol)) + { + Messaging.Instance.OnMessage(WixErrors.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName)); + } + else // see if the symbol (and any of its duplicates) are appropriately accessible. + { + IList accessible = DetermineAccessibleSymbols(section, symbol); + if (!accessible.Any()) + { + Messaging.Instance.OnMessage(WixErrors.UnresolvedReference(wixSimpleReferenceRow.SourceLineNumbers, wixSimpleReferenceRow.SymbolicName, symbol.Access)); + } + else if (1 == accessible.Count) + { + Symbol accessibleSymbol = accessible[0]; + this.referencedSymbols.Add(accessibleSymbol); + + if (null != accessibleSymbol.Section) + { + RecursivelyResolveReferences(accessibleSymbol.Section); + } + } + else // display errors for the duplicate symbols. + { + Symbol accessibleSymbol = accessible[0]; + string referencingSourceLineNumber = wixSimpleReferenceRow.SourceLineNumbers.ToString(); + if (String.IsNullOrEmpty(referencingSourceLineNumber)) + { + Messaging.Instance.OnMessage(WixErrors.DuplicateSymbol(accessibleSymbol.Row.SourceLineNumbers, accessibleSymbol.Name)); + } + else + { + Messaging.Instance.OnMessage(WixErrors.DuplicateSymbol(accessibleSymbol.Row.SourceLineNumbers, accessibleSymbol.Name, referencingSourceLineNumber)); + } + + foreach (Symbol accessibleDuplicate in accessible.Skip(1)) + { + Messaging.Instance.OnMessage(WixErrors.DuplicateSymbol2(accessibleDuplicate.Row.SourceLineNumbers)); + } + } + } + } + } + } + + /// + /// Determine if the symbol and any of its duplicates are accessbile by referencing section. + /// + /// Section referencing the symbol. + /// Symbol being referenced. + /// List of symbols accessible by referencing section. + private IList DetermineAccessibleSymbols(Section referencingSection, Symbol symbol) + { + List symbols = new List(); + + if (AccessibleSymbol(referencingSection, symbol)) + { + symbols.Add(symbol); + } + + foreach (Symbol dupe in symbol.PossiblyConflictingSymbols) + { + if (AccessibleSymbol(referencingSection, dupe)) + { + symbols.Add(dupe); + } + } + + foreach (Symbol dupe in symbol.RedundantSymbols) + { + if (AccessibleSymbol(referencingSection, dupe)) + { + symbols.Add(dupe); + } + } + + return symbols; + } + + /// + /// Determine if a single symbol is accessible by the referencing section. + /// + /// Section referencing the symbol. + /// Symbol being referenced. + /// True if symbol is accessible. + private bool AccessibleSymbol(Section referencingSection, Symbol symbol) + { + switch (symbol.Access) + { + case AccessModifier.Public: + return true; + case AccessModifier.Internal: + return symbol.Row.Section.IntermediateId.Equals(referencingSection.IntermediateId) || (null != symbol.Row.Section.LibraryId && symbol.Row.Section.LibraryId.Equals(referencingSection.LibraryId)); + case AccessModifier.Protected: + return symbol.Row.Section.IntermediateId.Equals(referencingSection.IntermediateId); + case AccessModifier.Private: + return referencingSection == symbol.Section; + default: + throw new InvalidOperationException(); + } + } + } +} -- cgit v1.2.3-55-g6feb