/// <summary> /// Returns comments for the class method. May return null object is comments for method /// are missing in XML documentation file. /// Returned comments tags: /// Summary, Remarks, Parameters (if present), Responses (if present), Returns /// </summary> /// <param name="methodInfo"></param> /// <param name="nullIfNoComment">Return null if comment for method is not available</param> /// <returns></returns> public MethodComments GetMethodComments(MethodBase methodInfo, bool nullIfNoComment) { var methodNode = GetXmlMemberNode(methodInfo.MethodId(), methodInfo?.ReflectedType); if (nullIfNoComment && methodNode == null) { return(null); } var comments = new MethodComments(); return(GetComments(methodInfo, comments, methodNode)); }
protected MethodComments GetComments(MethodBase methodInfo, MethodComments comments, XPathNavigator node) { if (node == null) { return(comments); } GetCommonComments(comments, node); comments.Parameters = GetParametersComments(node); comments.TypeParameters = GetNamedComments(node, TypeParamXPath, NameAttribute); comments.Returns = GetReturnsComment(node); comments.Responses = GetNamedComments(node, ResponsesXPath, CodeAttribute); comments = ResolveInheritdocComments(comments, methodInfo); return(comments); }
private MethodComments ResolveInheritdocComments(MethodComments comments, MethodBase methodInfo) { if (!NeedsResolving(comments) || comments?.Parameters?.Count > 0 || !string.IsNullOrEmpty(comments?.Returns) || comments?.Responses?.Count > 0 || comments?.TypeParameters?.Count > 0) { return(comments); } // If an explicit cref attribute is specified, the documentation from // the specified namespace/type/member is inherited. if (GetCrefComments(comments.Inheritdoc.Cref, methodInfo.ReflectedType, comments, (node) => GetComments(methodInfo, comments, node))) { return(comments); } // For constructors: // - Search backwards up the type inheritance chain for a constructor // with a matching signature. // - If a match is found, its documentation is inherited. if (methodInfo.IsConstructor) { var baseClass = methodInfo.ReflectedType.BaseType; var constructorSignature = methodInfo.GetParameters() .Select(p => p.ParameterType).ToArray(); while (baseClass != null) { var baseConstructor = baseClass.GetConstructor( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Any, constructorSignature, null); if (baseConstructor != null) { var newComments = GetMethodComments(baseConstructor); if (newComments == null) { return(comments); } newComments.Inheritdoc = comments.Inheritdoc; return(newComments); } baseClass = baseClass.BaseType; } return(comments); } // For virtual members and interface implementations: // - If the member is an override, documentation is inherited from the // member it overrides. // - If the member is part of an interface, documentation is inherited // from the interface member being implemented. var interfaceDeclaration = methodInfo.ReflectedType .GetTypeInfo() .ImplementedInterfaces .Select(ii => methodInfo.ReflectedType.GetInterfaceMap(ii)) .SelectMany(map => Enumerable.Range(0, map.TargetMethods.Length) .Where(n => map.TargetMethods[n] == methodInfo) .Select(n => map.InterfaceMethods[n])) .FirstOrDefault(); if (interfaceDeclaration != null) { var newComments = GetMethodComments(interfaceDeclaration); if (newComments == null) { return(comments); } newComments.Inheritdoc = comments.Inheritdoc; return(newComments); } if (methodInfo.IsVirtual) { var baseMethod = (methodInfo as MethodInfo)?.GetBaseDefinition(); if (baseMethod != null) { var newComments = GetMethodComments(baseMethod); if (newComments == null) { return(comments); } newComments.Inheritdoc = comments.Inheritdoc; return(newComments); } return(comments); } return(comments); }