internal static void ForceCompleteMemberByLocation(SourceLocation locationOpt, CancellationToken cancellationToken, Symbol member) { if (locationOpt == null || member.IsDefinedInSourceTree(locationOpt.SourceTree, locationOpt.SourceSpan, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); member.ForceComplete(locationOpt, cancellationToken); } }
/// <summary> /// Compile documentation comments on the symbol and write them to the stream if one is provided. /// </summary> public override void DefaultVisit(Symbol symbol) { _cancellationToken.ThrowIfCancellationRequested(); if (symbol.IsImplicitlyDeclared || symbol.IsAccessor()) { return; } if (_filterTree != null && !symbol.IsDefinedInSourceTree(_filterTree, _filterSpanWithinTree)) { return; } bool isPartialMethodDefinitionPart = symbol.IsPartialDefinition(); // CONSIDER: ignore this if isForSingleSymbol? if (isPartialMethodDefinitionPart) { MethodSymbol implementationPart = ((MethodSymbol)symbol).PartialImplementationPart; if ((object)implementationPart != null) { Visit(implementationPart); } } DocumentationMode maxDocumentationMode; ImmutableArray<DocumentationCommentTriviaSyntax> docCommentNodes; if (!TryGetDocumentationCommentNodes(symbol, out maxDocumentationMode, out docCommentNodes)) { // If the XML in any of the doc comments is invalid, skip all further processing (for this symbol) and // just write a comment saying that info was lost for this symbol. string message = ErrorFacts.GetMessage(MessageID.IDS_XMLIGNORED, CultureInfo.CurrentUICulture); WriteLine(string.Format(CultureInfo.CurrentUICulture, message, symbol.GetDocumentationCommentId())); return; } // If there are no doc comments, then no further work is required (other than to report a diagnostic if one is required). if (docCommentNodes.IsEmpty) { if (maxDocumentationMode >= DocumentationMode.Diagnose && RequiresDocumentationComment(symbol)) { // Report the error at a location in the tree that was parsing doc comments. Location location = GetLocationInTreeReportingDocumentationCommentDiagnostics(symbol); if (location != null) { _diagnostics.Add(ErrorCode.WRN_MissingXMLComment, location, symbol); } } return; } _cancellationToken.ThrowIfCancellationRequested(); bool reportParameterOrTypeParameterDiagnostics = GetLocationInTreeReportingDocumentationCommentDiagnostics(symbol) != null; string withUnprocessedIncludes; bool haveParseError; HashSet<TypeParameterSymbol> documentedTypeParameters; HashSet<ParameterSymbol> documentedParameters; ImmutableArray<CSharpSyntaxNode> includeElementNodes; if (!TryProcessDocumentationCommentTriviaNodes( symbol, isPartialMethodDefinitionPart, docCommentNodes, reportParameterOrTypeParameterDiagnostics, out withUnprocessedIncludes, out haveParseError, out documentedTypeParameters, out documentedParameters, out includeElementNodes)) { return; } if (haveParseError) { // If the XML in any of the doc comments is invalid, skip all further processing (for this symbol) and // just write a comment saying that info was lost for this symbol. string message = ErrorFacts.GetMessage(MessageID.IDS_XMLIGNORED, CultureInfo.CurrentUICulture); WriteLine(string.Format(CultureInfo.CurrentUICulture, message, symbol.GetDocumentationCommentId())); return; } // If there are no include elements, then there's nothing to expand. if (!includeElementNodes.IsDefaultOrEmpty) { _cancellationToken.ThrowIfCancellationRequested(); // NOTE: we are expanding include elements AFTER formatting the comment, since the included text is pure // XML, not XML mixed with documentation comment trivia (e.g. ///). If we expanded them before formatting, // the formatting engine would have trouble determining what prefix to remove from each line. TextWriter expanderWriter = isPartialMethodDefinitionPart ? null : _writer; // Don't actually write partial method definition parts. IncludeElementExpander.ProcessIncludes(withUnprocessedIncludes, symbol, includeElementNodes, _compilation, ref documentedParameters, ref documentedTypeParameters, ref _includedFileCache, expanderWriter, _diagnostics, _cancellationToken); } else if (_writer != null && !isPartialMethodDefinitionPart) { // CONSIDER: The output would look a little different if we ran the XDocument through an XmlWriter. In particular, // formatting inside tags (e.g. <__tag___attr__=__"value"__>) would be normalized. Whitespace in elements would // (or should) not be affected. If we decide that this difference matters, we can run the XDocument through an XmlWriter. // Otherwise, just writing out the string saves a bunch of processing and does a better job of preserving whitespace. Write(withUnprocessedIncludes); } if (reportParameterOrTypeParameterDiagnostics) { _cancellationToken.ThrowIfCancellationRequested(); if (documentedParameters != null) { foreach (ParameterSymbol parameter in GetParameters(symbol)) { if (!documentedParameters.Contains(parameter)) { Location location = parameter.Locations[0]; Debug.Assert(location.SourceTree.ReportDocumentationCommentDiagnostics()); //Should be the same tree as for the symbol. // NOTE: parameter name, since the parameter would be displayed as just its type. _diagnostics.Add(ErrorCode.WRN_MissingParamTag, location, parameter.Name, symbol); } } } if (documentedTypeParameters != null) { foreach (TypeParameterSymbol typeParameter in GetTypeParameters(symbol)) { if (!documentedTypeParameters.Contains(typeParameter)) { Location location = typeParameter.Locations[0]; Debug.Assert(location.SourceTree.ReportDocumentationCommentDiagnostics()); //Should be the same tree as for the symbol. _diagnostics.Add(ErrorCode.WRN_MissingTypeParamTag, location, typeParameter, symbol); } } } } }
private bool IsSyntacticallyFilteredOut(Symbol symbol) { // TODO: it would be nice to be more precise than this: we only want to // warn about the base class if it is listed in the filter tree, not if // any part of the type is in the filter tree. return _filterTree != null && !symbol.IsDefinedInSourceTree(_filterTree, _filterSpanWithinTree); }