// // LovalVariableDeclarationSpace.cs // // Author: // Simon Lindgren // // Copyright (c) 2013 Simon Lindgren // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using ICSharpCode.NRefactory.Utils; using System.Collections.Generic; using System.Linq; using System; namespace ICSharpCode.NRefactory.CSharp.Analysis { /// /// Represents a declaration space. (ยง3.3) /// public class LocalDeclarationSpace { /// /// Maps from variable name to the declarations in this declaration space. /// /// /// This maps from variable name /// MultiDictionary declarations = new MultiDictionary (); public LocalDeclarationSpace() { Children = new List (); } /// /// The child declaration spaces. /// public IList Children { get; private set; } /// /// The parent declaration space. /// /// The parent. public LocalDeclarationSpace Parent { get; private set; } /// /// The names declared in this declaration space, excluding child spaces. /// /// The declared names. public ICollection DeclaredNames { get { return declarations.Keys; } } /// /// Get all nodes declaring the name specified in . /// /// The declaring nodes. /// The declaration name. public IEnumerable GetNameDeclarations(string name) { return declarations [name].Concat(Children.SelectMany(child => child.GetNameDeclarations(name))); } /// /// Adds a child declaration space. /// /// The to add. public void AddChildSpace(LocalDeclarationSpace child) { if (child == null) throw new ArgumentNullException("child"); if (Children.Contains(child)) throw new InvalidOperationException("the child was already added"); Children.Add(child); child.Parent = this; } /// /// Adds a new declaration to the declaration space. /// /// The name of the declared variable. /// A node associated with the declaration. public void AddDeclaration(string name, AstNode node) { if (name == null) throw new ArgumentNullException("name"); if (node == null) throw new ArgumentNullException("node"); declarations.Add(name, node); } /// /// Determines if the name exists in the this declaration space. /// /// true, if the name specified in is used in this variable declaration space, false otherwise. /// The name to look for. /// When true, child declaration spaces are included in the search. public bool ContainsName(string name, bool includeChildren) { if (name == null) throw new ArgumentNullException("name"); if (declarations.Keys.Contains(name)) return true; return includeChildren && Children.Any(child => child.ContainsName(name, true)); } /// /// Determines whether the name specified in is used in surrouding code. /// /// true if the name is used, false otherwise. /// The name to check. /// /// Contrary to , this method also checks parent declaration spaces /// for name conflicts. Typically, this will be the right method to use when determining if a name can be used. /// public bool IsNameUsed(string name) { if (name == null) throw new ArgumentNullException("name"); return IsNameUsedBySelfOrParent(name) || Children.Any(child => child.ContainsName(name, true)); } bool IsNameUsedBySelfOrParent(string name) { if (declarations.Keys.Contains(name)) return true; return Parent != null && Parent.IsNameUsedBySelfOrParent(name); } } }