/// <summary> /// C# compiler uses complecated logic to generate docIds for Eii properties. Need to have special logic here. /// </summary> /// <param name="property">Value to process</param> /// <returns>DocId for property member wchich needs to be equal to docId generated by compiler's /doc flag </returns> protected override string EiiPropertyProcessing(PropertyReference property) { string name; PropertyDefinition propertyDef = property as PropertyDefinition; MethodDefinition method = null; if (propertyDef != null) { method = propertyDef.GetMethod ?? propertyDef.SetMethod; } if (method != null && !DocUtils.IsExplicitlyImplemented(method)) { name = property.Name; } else { DocUtils.GetInfoForExplicitlyImplementedMethod(method, out var iface, out var ifaceMethod); AddTypeCount = false; name = string.Join("#", new string[] { GetTypeName(iface).Replace(".", "#"), DocUtils.GetMember(property.Name) }); AddTypeCount = true; } return(name); }
protected override string GetPropertyName(PropertyReference property) { string name = null; PropertyDefinition propertyDef = property as PropertyDefinition; MethodDefinition method = null; if (propertyDef != null) { method = propertyDef.GetMethod ?? propertyDef.SetMethod; } if (method != null && !DocUtils.IsExplicitlyImplemented(method)) { name = property.Name; } else { TypeReference iface; MethodReference ifaceMethod; DocUtils.GetInfoForExplicitlyImplementedMethod(method, out iface, out ifaceMethod); AddTypeCount = false; name = string.Join("#", new string[] { GetTypeName(iface).Replace(".", "#"), DocUtils.GetMember(property.Name) }); AddTypeCount = true; } StringBuilder buf = new StringBuilder(); buf.Append(GetName(property.DeclaringType)); buf.Append('.'); buf.Append(name); IList <ParameterDefinition> parameters = property.Parameters; if (parameters.Count > 0) { genDeclType = property.DeclaringType; buf.Append('('); IList <GenericParameter> genArgs = property.DeclaringType.GenericParameters; AppendParameter(buf, genArgs, parameters[0]); for (int i = 1; i < parameters.Count; ++i) { buf.Append(','); AppendParameter(buf, genArgs, parameters[i]); } buf.Append(')'); genDeclType = null; } return(buf.ToString()); }
private static IEnumerable <MemberReference> GetReflectionMembersCore(TypeDefinition type, string docName, string memberType) { // In case of dropping the namespace, we have to remove the dropped NS // so that docName will match what's in the assembly/type if (MDocUpdater.HasDroppedNamespace(type) && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) { int droppedNsLength = MDocUpdater.droppedNamespace.Length; docName = docName.Substring(droppedNsLength + 1, docName.Length - droppedNsLength - 1); } // need to worry about 4 forms of //@MemberName values: // 1. "Normal" (non-generic) member names: GetEnumerator // - Lookup as-is. // 2. Explicitly-implemented interface member names: System.Collections.IEnumerable.Current // - try as-is, and try type.member (due to "kludge" for property // support. // 3. "Normal" Generic member names: Sort<T> (CSC) // - need to remove generic parameters --> "Sort" // 4. Explicitly-implemented interface members for generic interfaces: // -- System.Collections.Generic.IEnumerable<T>.Current // - Try as-is, and try type.member, *keeping* the generic parameters. // --> System.Collections.Generic.IEnumerable<T>.Current, IEnumerable<T>.Current // 5. As of 2008-01-02, gmcs will do e.g. 'IFoo`1[A].Method' instead of // 'IFoo<A>.Method' for explicitly implemented methods; don't interpret // this as (1) or (2). if (docName.IndexOf('<') == -1 && docName.IndexOf('[') == -1) { int memberCount = 0; // Cases 1 & 2 foreach (MemberReference mi in type.GetMembers(docName)) { memberCount++; yield return(mi); } if (memberCount == 0 && CountChars(docName, '.') > 0) { Func <MemberReference, bool> verifyInterface = (member) => { var meth = member as MethodDefinition; if (meth == null && member is PropertyReference) { var propertyDefinition = ((PropertyReference)member).Resolve(); meth = propertyDefinition.GetMethod ?? propertyDefinition.SetMethod; } return(meth != null && (member.Name.Equals(".ctor") || DocUtils.IsExplicitlyImplemented(meth))); }; // might be a property; try only type.member instead of // namespace.type.member. var typeMember = DocUtils.GetTypeDotMember(docName); var memberName = DocUtils.GetMember(docName); foreach (MemberReference mi in type.GetMembers(typeMember).Where(verifyInterface)) { memberCount++; yield return(mi); } // some VB libraries use just the member name foreach (MemberReference mi in type.GetMembers(memberName).Where(verifyInterface)) { memberCount++; yield return(mi); } // some VB libraries use a `typemember` naming convention foreach (MemberReference mi in type.GetMembers(typeMember.Replace(".", "")).Where(verifyInterface)) { memberCount++; yield return(mi); } // if we still haven't found the member, there are some VB libraries // that use a different interface name for implementation. if (memberCount == 0) { foreach (MemberReference mi in type .GetMembers() .Where(m => m.Name.StartsWith("I", StringComparison.InvariantCultureIgnoreCase) && m.Name.EndsWith(memberName, StringComparison.InvariantCultureIgnoreCase)) .Where(verifyInterface)) { memberCount++; yield return(mi); } } if (memberCount == 0 && memberType == "Property") { foreach (MemberReference mr in type.GetMembers().Where(x => x is PropertyDefinition)) { var method = ((PropertyDefinition)mr).GetMethod ?? ((PropertyDefinition)mr).SetMethod; if (method?.Overrides != null && method.Overrides.Any()) { DocUtils.GetInfoForExplicitlyImplementedMethod(method, out TypeReference iface, out MethodReference ifaceMethod); var newName = DocUtils.GetMemberForProperty(ifaceMethod.Name); if (newName == memberName && verifyInterface(mr) && docName.Contains(iface.Name)) { yield return(mr); } } } } } yield break; } // cases 3 & 4 int numLt = 0; int numDot = 0; int startLt, startType, startMethod; startLt = startType = startMethod = -1; for (int i = 0; i < docName.Length; ++i) { switch (docName[i]) { case '<': if (numLt == 0) { startLt = i; } ++numLt; break; case '>': --numLt; if (numLt == 0 && (i + 1) < docName.Length) { // there's another character in docName, so this <...> sequence is // probably part of a generic type -- case 4. startLt = -1; } break; case '.': startType = startMethod; startMethod = i; ++numDot; break; } } string refName = startLt == -1 ? docName : docName.Substring(0, startLt); // case 3 foreach (MemberReference mi in type.GetMembers(refName)) { yield return(mi); } // case 4 foreach (MemberReference mi in type.GetMembers(refName.Substring(startType + 1))) { yield return(mi); } // If we _still_ haven't found it, we've hit another generic naming issue: // post Mono 1.1.18, gmcs generates [[FQTN]] instead of <TypeName> for // explicitly-implemented METHOD names (not properties), e.g. // "System.Collections.Generic.IEnumerable`1[[Foo, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GetEnumerator" // instead of "System.Collections.Generic.IEnumerable<Foo>.GetEnumerator", // which the XML docs will contain. // // Alas, we can't derive the Mono name from docName, so we need to iterate // over all member names, convert them into CSC format, and compare... :-( if (numDot == 0) { yield break; } foreach (MemberReference mi in type.GetMembers()) { if (MDocUpdater.GetMemberName(mi) == docName) { yield return(mi); } } }