// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; using System.Threading; namespace ICSharpCode.SharpDevelop.Dom { public class DefaultProjectContent : IProjectContent { readonly List referencedContents = new List(); // we use a list of Dictionaries because we need multiple dictionaries: // each uses another StringComparer // (C#: StringComparer.InvariantCulture, VB: StringComparer.InvariantCultureCaseInsensitive) // new dictionaries are added to the list when required List> classLists = new List>(); List> namespaces = new List>(); XmlDoc xmlDoc = new XmlDoc(); IUsing defaultImports; bool isDisposed; public IUsing DefaultImports { get { return defaultImports; } set { defaultImports = value; } } public virtual object Project { get { return null; } } /// /// Gets if the project content is representing the current version of the assembly. /// This property always returns true for ParseProjectContents but might return false /// for ReflectionProjectContent/CecilProjectContent if the file was changed. /// public virtual bool IsUpToDate { get { return true; } } public List> ClassLists { get { if (classLists.Count == 0) { classLists.Add(new Dictionary(language.NameComparer)); } return classLists; } } public ICollection NamespaceNames { get { return Namespaces[0].Keys; } } protected List> Namespaces { get { if (namespaces.Count == 0) { namespaces.Add(new Dictionary(language.NameComparer)); } return namespaces; } } // NamespaceStruct behaves like a reference type because it only consists of readonly references! protected struct NamespaceStruct { public readonly List Classes; public readonly List SubNamespaces; public NamespaceStruct(string name) // struct must have a parameter { this.Classes = new List(); this.SubNamespaces = new List(); } public NamespaceStruct MergeWith(NamespaceStruct other) { NamespaceStruct newStruct = new NamespaceStruct(null); newStruct.Classes.AddRange(this.Classes); newStruct.Classes.AddRange(other.Classes); newStruct.SubNamespaces.AddRange(this.SubNamespaces); newStruct.SubNamespaces.AddRange(other.SubNamespaces); return newStruct; } } /// /// Gets the class dictionary that uses the name comparison rules of . /// protected Dictionary GetClasses(LanguageProperties language) { for (int i = 0; i < classLists.Count; ++i) { if (classLists[i].Comparer == language.NameComparer) return classLists[i]; } Dictionary d; if (classLists.Count > 0) { Dictionary oldList = classLists[0]; d = new Dictionary(oldList.Count, language.NameComparer); foreach (KeyValuePair pair in oldList) { // don't use d.Add(), the new name language might treat two names as equal // that were unequal in the old dictionary d[pair.Key] = pair.Value; } } else { d = new Dictionary(language.NameComparer); } classLists.Add(d); return d; } /// /// Gets the namespace dictionary that uses the name comparison rules of . /// protected Dictionary GetNamespaces(LanguageProperties language) { for (int i = 0; i < namespaces.Count; ++i) { if (namespaces[i].Comparer == language.NameComparer) return namespaces[i]; } Dictionary d; if (namespaces.Count > 0) { Dictionary oldList = namespaces[0]; d = new Dictionary(oldList.Count, language.NameComparer); foreach (KeyValuePair pair in oldList) { NamespaceStruct ns; if (d.TryGetValue(pair.Key, out ns)) { // we got a name conflict due to the new NameComparer. // This happens if a C# assembly contains the namespace "a" and "A", // and now we're trying to get a dictionary for use in VB. d[pair.Key] = ns.MergeWith(pair.Value); } else { d.Add(pair.Key, pair.Value); } } } else { d = new Dictionary(language.NameComparer); } namespaces.Add(d); return d; } public XmlDoc XmlDoc { get { return xmlDoc; } protected set { xmlDoc = value; } } public ICollection Classes { get { lock (namespaces) { List list = new List(ClassLists[0].Count + 10); foreach (IClass c in ClassLists[0].Values) { if (c is GenericClassContainer) { GenericClassContainer gcc = (GenericClassContainer)c; list.AddRange(gcc.RealClasses); } else { list.Add(c); } } return list; } } } SystemTypes systemTypes; /// /// Gets a class that allows to conveniently access commonly used types in the system /// namespace. /// public virtual SystemTypes SystemTypes { get { if (systemTypes == null) { systemTypes = new SystemTypes(this); } return systemTypes; } } public ICollection ReferencedContents { get { return referencedContents; } } LanguageProperties language = LanguageProperties.CSharp; /// /// Gets/Sets the properties of the language this project content was written in. /// public LanguageProperties Language { [DebuggerStepThrough] get { return language; } set { if (value == null) throw new ArgumentNullException(); language = value; } } public string GetXmlDocumentation(string memberTag) { CheckNotDisposed(); string desc = xmlDoc.GetDocumentation(memberTag); if (desc != null) { return desc; } lock (referencedContents) { foreach (IProjectContent referencedContent in referencedContents) { desc = referencedContent.XmlDoc.GetDocumentation(memberTag); if (desc != null) { return desc; } } } return null; } public virtual void Dispose() { xmlDoc.Dispose(); isDisposed = true; } [Conditional("DEBUG")] void CheckNotDisposed() { // TODO: this is broken - we are accessing project contents even after // they have been unloaded, e.g. on other threads if (!isDisposed) { // throw new ObjectDisposedException(); } } public void AddClassToNamespaceList(IClass addClass) { lock (namespaces) { AddClassToNamespaceListInternal(addClass); } DomCache.Clear(); } /// /// Container class that is used when multiple classes with different type parameter /// count have the same class name. /// /// The GenericClassContainer is only used internally to hold the class list, it is never returned by any public API. /// private sealed class GenericClassContainer : DefaultClass { public GenericClassContainer(string fullyQualifiedName) : base(DefaultCompilationUnit.DummyCompilationUnit, fullyQualifiedName) {} IClass[] realClasses = new IClass[4]; public IEnumerable RealClasses { get { foreach (IClass c in realClasses) { if (c != null) yield return c; } } } public int RealClassCount { get { int count = 0; foreach (IClass c in realClasses) { if (c != null) count += 1; } return count; } } public IClass Get(int typeParameterCount) { if (realClasses.Length > typeParameterCount) return realClasses[typeParameterCount]; else return null; } public IClass GetBest(int typeParameterCount) { IClass c; for (int i = typeParameterCount; i < realClasses.Length; i++) { c = Get(i); if (c != null) return c; } for (int i = typeParameterCount - 1; i >= 0; i--) { c = Get(i); if (c != null) return c; } return null; } public void Set(IClass c) { int typeParameterCount = c.TypeParameters.Count; if (realClasses.Length <= typeParameterCount) { IClass[] newArray = new IClass[typeParameterCount + 2]; realClasses.CopyTo(newArray, 0); realClasses = newArray; } realClasses[typeParameterCount] = c; } public void Remove(int typeParameterCount) { if (realClasses.Length > typeParameterCount) realClasses[typeParameterCount] = null; } } protected void AddClassToNamespaceListInternal(IClass addClass) { // Freeze the class when adding it to the project content addClass.Freeze(); Debug.Assert(!(addClass is CompoundClass)); Debug.Assert(!addClass.HasCompoundClass); string fullyQualifiedName = addClass.FullyQualifiedName; IClass existingClass = GetClassInternal(fullyQualifiedName, addClass.TypeParameters.Count, language); if (existingClass != null && existingClass.TypeParameters.Count == addClass.TypeParameters.Count) { LoggingService.Debug("Adding existing class " + addClass.Name + " from " + Path.GetFileName(addClass.CompilationUnit.FileName)); CompoundClass compound = existingClass as CompoundClass; if (compound != null) { // mark the class as partial // (VB allows specifying the 'partial' modifier only on one part) addClass.HasCompoundClass = true; // add the new class to the compound class List newParts = new List(compound.Parts); newParts.Add(addClass); // construct a replacement CompoundClass with the new part list addClass = CompoundClass.Create(newParts); LoggingService.Debug("Added new part (old part count=" + compound.Parts.Count +", new part count=" + newParts.Count + ")"); } else { // Instead of overwriting a class with another, treat both parts as partial. // This fixes SD2-1217. if (!(addClass.IsPartial || language.ImplicitPartialClasses)) { LoggingService.Info("Duplicate class " + fullyQualifiedName + ", creating compound"); } else { LoggingService.Debug("Creating compound for " + fullyQualifiedName); } // Merge existing non-partial class with addClass addClass.HasCompoundClass = true; existingClass.HasCompoundClass = true; addClass = CompoundClass.Create(new[] { addClass, existingClass }); } } AddClassToNamespaceListInternal2(addClass); } void AddClassToNamespaceListInternal2(IClass addClass) { bool isReplacingExistingClass = false; string fullyQualifiedName = addClass.FullyQualifiedName; IClass oldDictionaryClass; if (GetClasses(language).TryGetValue(fullyQualifiedName, out oldDictionaryClass)) { isReplacingExistingClass = true; GenericClassContainer gcc = oldDictionaryClass as GenericClassContainer; if (gcc != null) { gcc.Set(addClass); return; } else if (oldDictionaryClass.TypeParameters.Count != addClass.TypeParameters.Count) { gcc = new GenericClassContainer(fullyQualifiedName); gcc.Set(addClass); gcc.Set(oldDictionaryClass); addClass = gcc; } } foreach (Dictionary classes in ClassLists) { classes[fullyQualifiedName] = addClass; } string nSpace = addClass.Namespace; if (nSpace == null) { nSpace = String.Empty; } CreateNamespace(nSpace); List classList = GetNamespaces(this.language)[nSpace].Classes; if (isReplacingExistingClass) { for (int i = 0; i < classList.Count; i++) { if (classList[i].FullyQualifiedName == fullyQualifiedName) { classList[i] = addClass; return; } } } classList.Add(addClass); } void CreateNamespace(string nSpace) { Dictionary dict = GetNamespaces(this.language); if (dict.ContainsKey(nSpace)) return; NamespaceStruct namespaceStruct = new NamespaceStruct(nSpace); dict.Add(nSpace, namespaceStruct); // use the same namespaceStruct for all dictionaries foreach (Dictionary otherDict in namespaces) { if (otherDict == dict) continue; NamespaceStruct existingNamespaceStruct; if (otherDict.TryGetValue(nSpace, out existingNamespaceStruct)) otherDict[nSpace] = existingNamespaceStruct.MergeWith(namespaceStruct); else otherDict.Add(nSpace, namespaceStruct); } if (nSpace.Length == 0) return; // add to parent namespace int pos = nSpace.LastIndexOf('.'); string parent; string subNs; if (pos < 0) { parent = ""; subNs = nSpace; } else { parent = nSpace.Substring(0, pos); subNs = nSpace.Substring(pos + 1); } CreateNamespace(parent); dict[parent].SubNamespaces.Add(subNs); } /// /// Removes the specified namespace from all namespace lists if the namespace is empty. /// void RemoveEmptyNamespace(string nSpace) { if (nSpace == null || nSpace.Length == 0) return; Dictionary dict = GetNamespaces(this.language); if (!dict.ContainsKey(nSpace)) return; // remove only if really empty if (dict[nSpace].Classes.Count > 0 || dict[nSpace].SubNamespaces.Count > 0) return; // remove the namespace from all dictionaries foreach (Dictionary anyDict in namespaces) { anyDict.Remove(nSpace); } // remove the namespace from parent's SubNamespaces list int pos = nSpace.LastIndexOf('.'); string parent; string subNs; if (pos < 0) { parent = ""; subNs = nSpace; } else { parent = nSpace.Substring(0, pos); subNs = nSpace.Substring(pos + 1); } dict[parent].SubNamespaces.Remove(subNs); RemoveEmptyNamespace(parent); // remove parent if also empty } List assemblyAttributes = new List(); public virtual IList GetAssemblyAttributes() { lock (namespaces) { return assemblyAttributes.ToArray(); } } public void RemoveCompilationUnit(ICompilationUnit unit) { lock (namespaces) { foreach (IClass c in unit.Classes) { RemoveClass(c); } foreach (IAttribute attr in unit.Attributes) assemblyAttributes.Remove(attr); } DomCache.Clear(); } public void UpdateCompilationUnit(ICompilationUnit oldUnit, ICompilationUnit parserOutput, string fileName) { parserOutput.Freeze(); lock (namespaces) { if (oldUnit != null) { foreach (IClass c in oldUnit.Classes) RemoveClass(c); foreach (IAttribute attr in oldUnit.Attributes) assemblyAttributes.Remove(attr); } foreach (IClass c in parserOutput.Classes) { AddClassToNamespaceListInternal(c); } assemblyAttributes.AddRange(parserOutput.Attributes); } DomCache.Clear(); } protected void RemoveClass(IClass @class) { string fullyQualifiedName = @class.FullyQualifiedName; int typeParameterCount = @class.TypeParameters.Count; if (@class.HasCompoundClass) { LoggingService.Debug("Removing part " + @class.CompilationUnit.FileName + " from compound class " + @class.FullyQualifiedName); // remove a part of a partial class // Use "as" cast to fix SD2-680: the stored class might be a part not marked as partial CompoundClass compound = GetClassInternal(fullyQualifiedName, typeParameterCount, language) as CompoundClass; if (compound == null) { LoggingService.Warn("compound class not found"); return; } typeParameterCount = compound.TypeParameters.Count; List newParts = new List(compound.Parts); newParts.Remove(@class); if (newParts.Count > 1) { LoggingService.Debug("Part removed, old part count = " + compound.Parts.Count + ", new part count=" + newParts.Count); AddClassToNamespaceListInternal2(CompoundClass.Create(newParts)); return; } else if (newParts.Count == 1) { LoggingService.Debug("Second-to-last part removed (old part count = " + compound.Parts.Count + "), overwriting compound with last part"); newParts[0].HasCompoundClass = false; AddClassToNamespaceListInternal2(newParts[0]); return; } else { // newParts.Count == 0 // this should not be possible, the compound should have been destroyed when there was only 1 part left LoggingService.Warn("All parts removed, remove compound"); @class = compound; // all parts removed, remove compound class } } IClass classInDictionary; if (!GetClasses(language).TryGetValue(fullyQualifiedName, out classInDictionary)) { return; } GenericClassContainer gcc = classInDictionary as GenericClassContainer; if (gcc != null) { gcc.Remove(typeParameterCount); if (gcc.RealClassCount > 0) { return; } } foreach (Dictionary classes in ClassLists) { classes.Remove(fullyQualifiedName); } string nSpace = @class.Namespace; if (nSpace == null) { nSpace = String.Empty; } // Remove class from namespace lists List classList = GetNamespaces(this.language)[nSpace].Classes; for (int i = 0; i < classList.Count; i++) { if (language.NameComparer.Equals(classList[i].FullyQualifiedName, fullyQualifiedName)) { classList.RemoveAt(i); break; } } if (classList.Count == 0) { RemoveEmptyNamespace(nSpace); } } #region Default Parser Layer dependent functions public IClass GetClass(string typeName, int typeParameterCount) { return GetClass(typeName, typeParameterCount, language, GetClassOptions.Default); } protected IClass GetClassInternal(string typeName, int typeParameterCount, LanguageProperties language) { CheckNotDisposed(); #if DEBUG if (System.Text.RegularExpressions.Regex.IsMatch (typeName, "`[0-9]+$")) Debug.Assert(false, "how did a Reflection type name get here?"); #endif lock (namespaces) { IClass c; if (GetClasses(language).TryGetValue(typeName, out c)) { GenericClassContainer gcc = c as GenericClassContainer; if (gcc != null) { return gcc.GetBest(typeParameterCount); } return c; } return null; } } bool IsAccessibleClass(IClass c) { // check the outermost class (which is either public or internal) while (c.DeclaringType != null) c = c.DeclaringType; return c.IsPublic || c.ProjectContent.InternalsVisibleTo(this); } public IClass GetClass(string typeName, int typeParameterCount, LanguageProperties language, GetClassOptions options) { IClass c = GetClassInternal(typeName, typeParameterCount, language); if (c != null && c.TypeParameters.Count == typeParameterCount) { return c; } // Search in references: if ((options & GetClassOptions.LookInReferences) != 0) { lock (referencedContents) { foreach (IProjectContent content in referencedContents) { // Look for the class in the referenced content. // Don't do a inner-class search in the recursive call - one search // done by this GetClass call is sufficient. IClass contentClass = content.GetClass( typeName, typeParameterCount, language, options & ~(GetClassOptions.LookInReferences | GetClassOptions.LookForInnerClass)); if (contentClass != null) { if (contentClass.TypeParameters.Count == typeParameterCount && IsAccessibleClass(contentClass)) { return contentClass; } else { c = contentClass; } } } } } if ((options & GetClassOptions.LookForInnerClass) != 0) { // not found -> maybe nested type -> trying to find class that contains this one. int lastIndex = typeName.LastIndexOf('.'); if (lastIndex > 0) { string outerName = typeName.Substring(0, lastIndex); IClass upperClass = GetClass(outerName, typeParameterCount, language, options); if (upperClass != null) { foreach (IClass upperBaseClass in upperClass.ClassInheritanceTree) { IList innerClasses = upperBaseClass.InnerClasses; if (innerClasses != null) { string innerName = typeName.Substring(lastIndex + 1); foreach (IClass innerClass in innerClasses) { if (language.NameComparer.Equals(innerClass.Name, innerName)) { if (innerClass.TypeParameters.Count == typeParameterCount) { return innerClass; } else { // store match c = innerClass; } } } } } } } } if ((options & GetClassOptions.ExactMatch) == GetClassOptions.ExactMatch) { return null; } else { // no matching class found - we'll return a class with different type paramter count return c; } } public List GetNamespaceContents(string nameSpace) { List namespaceList = new List(); AddNamespaceContents(namespaceList, nameSpace, language, true); return namespaceList; } public List GetAllContents() { List list = new List(); AddAllContents(list, this.language, true); return list; } /// /// Adds the contents of all namespaces in this project to the . /// /// If true, contents of referenced projects will be added as well (not recursive - just 1 level deep). public void AddAllContents(List list, LanguageProperties language, bool lookInReferences) { if (lookInReferences) { lock (referencedContents) { foreach (IProjectContent content in referencedContents) { content.AddAllContents(list, language, false); } } } lock (namespaces) { Dictionary dict = GetNamespaces(language); foreach (var namespaceStruct in dict.Values) { AddNamespaceStructContents(list, namespaceStruct, language, lookInReferences); } } } /// /// Adds the contents of the specified to the . /// /// If true, contents of referenced projects will be added as well (not recursive - just 1 level deep). public void AddNamespaceContents(List list, string nameSpace, LanguageProperties language, bool lookInReferences) { if (nameSpace == null) { return; } if (lookInReferences) { lock (referencedContents) { foreach (IProjectContent content in referencedContents) { content.AddNamespaceContents(list, nameSpace, language, false); } } } lock (namespaces) { Dictionary dict = GetNamespaces(language); if (dict.ContainsKey(nameSpace)) { NamespaceStruct ns = dict[nameSpace]; AddNamespaceStructContents(list, ns, language, lookInReferences); } } } void AddNamespaceStructContents(List list, NamespaceStruct ns, LanguageProperties language, bool lookInReferences) { int newCapacity = list.Count + ns.Classes.Count + ns.SubNamespaces.Count; if (list.Capacity < newCapacity) list.Capacity = Math.Max(list.Count * 2, newCapacity); foreach (IClass c in ns.Classes) { if (c is GenericClassContainer) { foreach (IClass realClass in ((GenericClassContainer)c).RealClasses) { AddNamespaceContentsClass(list, realClass, language, lookInReferences); } } else { AddNamespaceContentsClass(list, c, language, lookInReferences); } } foreach (string subns in ns.SubNamespaces) { NamespaceEntry subnsEntry = new NamespaceEntry(subns); if (!list.Contains(subnsEntry)) // PERF list.Add(subnsEntry); } } void AddNamespaceContentsClass(List list, IClass c, LanguageProperties language, bool lookInReferences) { if (c.IsInternal && !lookInReferences) { // internal class and we are looking at it from another project content return; } if (language.ShowInNamespaceCompletion(c)) list.Add(c); if (language.ImportModules && c.ClassType == ClassType.Module) { foreach (IMember m in c.Methods) { if (m.IsAccessible(null, false)) list.Add(m); } foreach (IMember m in c.Events) { if (m.IsAccessible(null, false)) list.Add(m); } foreach (IMember m in c.Fields) { if (m.IsAccessible(null, false)) list.Add(m); } foreach (IMember m in c.Properties) { if (m.IsAccessible(null, false)) list.Add(m); } } } public bool NamespaceExists(string name) { return NamespaceExists(name, language, true); } public bool NamespaceExists(string name, LanguageProperties language, bool lookInReferences) { if (name == null) { return false; } if (lookInReferences) { lock (referencedContents) { foreach (IProjectContent content in referencedContents) { if (content.NamespaceExists(name, language, false)) { return true; } } } } lock (namespaces) { return GetNamespaces(language).ContainsKey(name); } } bool MatchesRequest(SearchTypeRequest request, ref SearchTypeResult result) { if (result.NamespaceResult != null) return request.TypeParameterCount == 0; else { IReturnType rt = result.Result; if (rt == null) return false; if (rt.TypeArgumentCount != request.TypeParameterCount) return false; IClass c = rt.GetUnderlyingClass(); if (c != null) return IsAccessibleClass(c); else return true; } } public SearchTypeResult SearchType(SearchTypeRequest request) { string name = request.Name; if (string.IsNullOrEmpty(name)) { return SearchTypeResult.Empty; } // 'result' holds the fall-back result if no result with the right type parameter count is found. SearchTypeResult result = SearchTypeResult.Empty; if (name.IndexOf('.') < 0) { for (IClass outerClass = request.CurrentType; outerClass != null; outerClass = outerClass.DeclaringType) { // Try inner classes (in full inheritance tree) // Don't use loop with cur = cur.BaseType because of inheritance cycles foreach (IClass baseClass in outerClass.ClassInheritanceTree) { if (baseClass.ClassType == ClassType.Class || baseClass.ClassType == ClassType.Struct || baseClass.ClassType == ClassType.Module) { foreach (IClass innerClass in baseClass.InnerClasses) { if (language.NameComparer.Equals(innerClass.Name, name)) { result = new SearchTypeResult(innerClass); if (MatchesRequest(request, ref result)) { return result; } } } } } } } for (IUsingScope usingScope = request.CurrentUsingScope; usingScope != null; usingScope = usingScope.Parent) { string fullname; if (string.IsNullOrEmpty(usingScope.NamespaceName)) { // Try if name is already the full type name fullname = name; } else { fullname = usingScope.NamespaceName + "." + name; } IClass c = GetClass(fullname, request.TypeParameterCount); if (c != null) { result = new SearchTypeResult(c); if (MatchesRequest(request, ref result)) { return result; } } if (NamespaceExists(fullname)) { result = new SearchTypeResult(fullname, null); if (MatchesRequest(request, ref result)) { return result; } } // prefer aliases over imported types foreach (IUsing u in usingScope.Usings) { if (u.HasAliases) { if (SearchTypeInUsing(u, request, ref result)) return result; } } foreach (IUsing u in usingScope.Usings) { if (!u.HasAliases) { if (SearchTypeInUsing(u, request, ref result)) return result; } } } if (defaultImports != null) { if (SearchTypeInUsing(defaultImports, request, ref result)) return result; } return result; } bool SearchTypeInUsing(IUsing u, SearchTypeRequest request, ref SearchTypeResult result) { foreach (IReturnType r in u.SearchType(request.Name, request.TypeParameterCount)) { result = new SearchTypeResult(r, u); if (MatchesRequest(request, ref result)) { return true; } } string nsResult = u.SearchNamespace(request.Name); if (nsResult != null) { result = new SearchTypeResult(nsResult, null); if (MatchesRequest(request, ref result)) { return true; } } return false; } /// /// Gets the position of a member in this project content (not a referenced one). /// /// The full class name in Reflection syntax (always case sensitive, ` for generics) /// Whether to search in referenced project contents. public IClass GetClassByReflectionName(string className, bool lookInReferences) { if (className == null) throw new ArgumentNullException("className"); int typeParameterCount; className = ReflectionLayer.ReflectionClass.ConvertReflectionNameToFullName(className, out typeParameterCount); GetClassOptions options = GetClassOptions.Default; if (!lookInReferences) options &= ~GetClassOptions.LookInReferences; return GetClass(className, typeParameterCount, LanguageProperties.CSharp, options); } /// /// Gets the position of a member in this project content (not a referenced one). /// /// The member name in Reflection syntax (always case sensitive, ` for generics). /// member name = [ExplicitInterface .] MemberName [`TypeArgumentCount] [(Parameters)] public static IMember GetMemberByReflectionName(IClass curClass, string fullMemberName) { if (curClass == null) return null; int pos = fullMemberName.IndexOf('('); if (pos > 0) { // is method call int colonPos = fullMemberName.LastIndexOf(':'); if (colonPos > 0) { fullMemberName = fullMemberName.Substring(0, colonPos); } string interfaceName = null; string memberName = fullMemberName.Substring(0, pos); int pos2 = memberName.LastIndexOf('.'); if (pos2 > 0) { interfaceName = memberName.Substring(0, pos2); memberName = memberName.Substring(pos2 + 1); } // put class name in front of full member name because we'll compare against it later fullMemberName = curClass.DotNetName + "." + fullMemberName; IMethod firstMethod = null; foreach (IMethod m in curClass.Methods) { if (m.Name == memberName) { if (firstMethod == null) firstMethod = m; StringBuilder dotnetName = new StringBuilder(m.DotNetName); dotnetName.Append('('); for (int i = 0; i < m.Parameters.Count; i++) { if (i > 0) dotnetName.Append(','); if (m.Parameters[i].ReturnType != null) { dotnetName.Append(m.Parameters[i].ReturnType.DotNetName); } } dotnetName.Append(')'); if (dotnetName.ToString() == fullMemberName) { return m; } } } return firstMethod; } else { string interfaceName = null; string memberName = fullMemberName; pos = memberName.LastIndexOf('.'); if (pos > 0) { interfaceName = memberName.Substring(0, pos); memberName = memberName.Substring(pos + 1); } // get first method with that name, but prefer method without parameters IMethod firstMethod = null; foreach (IMethod m in curClass.Methods) { if (m.Name == memberName) { if (firstMethod == null || m.Parameters.Count == 0) firstMethod = m; } } if (firstMethod != null) return firstMethod; return curClass.SearchMember(memberName, LanguageProperties.CSharp); } } public FilePosition GetPosition(IEntity d) { IMember m = d as IMember; IClass c = d as IClass; if (m != null) { return new FilePosition(m.DeclaringType.CompilationUnit, m.Region.BeginLine, m.Region.BeginColumn); } else if (c != null) { return new FilePosition(c.CompilationUnit, c.Region.BeginLine, c.Region.BeginColumn); } else { return FilePosition.Empty; } } #endregion public void AddReferencedContent(IProjectContent pc) { if (pc != null) { lock (this.ReferencedContents) { this.ReferencedContents.Add(pc); } } } public event EventHandler ReferencedContentsChanged; protected virtual void OnReferencedContentsChanged(EventArgs e) { systemTypes = null; // re-create system types DomCache.Clear(); if (ReferencedContentsChanged != null) { ReferencedContentsChanged(this, e); } } public bool InternalsVisibleTo(IProjectContent otherProjectContent) { return this == otherProjectContent; } public static readonly IProjectContent DummyProjectContent = new DummyContent(); private class DummyContent : DefaultProjectContent { public override string ToString() { return "[DummyProjectContent]"; } public override SystemTypes SystemTypes { get { return HostCallback.GetCurrentProjectContent().SystemTypes; } } } /// public virtual string AssemblyName { get { return null; } } } }