Beispiel #1
0
        // Returns the name and sets link if one could be found (or null if not)
        // First checks for "href" attribute and then checks for "cref"
        private string GetRefNameAndLink(XElement element, out string link)
        {
            // Check for href
            XAttribute hrefAttribute = element.Attribute("href");

            if (hrefAttribute != null)
            {
                link = $"<a href=\"{hrefAttribute.Value}\">{element.Value}</a>";
                return(element.Value);
            }

            // Check for cref
            string cref = element.Attribute("cref")?.Value;

            if (cref != null)
            {
                IDocument crefDoc;
                ISymbol   crefSymbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(cref, _compilation);
                if (crefSymbol != null && _symbolToDocument.TryGetValue(crefSymbol, out crefDoc))
                {
                    string name = crefDoc.String(CodeAnalysisKeys.DisplayName);
                    link = $"<code><a href=\"{_context.GetLink(crefDoc.FilePath(Keys.WritePath))}\">{WebUtility.HtmlEncode(name)}</a></code>";
                    return(name);
                }
            }
            link = null;
            return(cref?.Substring(cref.IndexOf(':') + 1) ?? string.Empty);
        }
Beispiel #2
0
        private async Task <ImmutableArray <UnusedSymbolInfo> > AnalyzeProject(Project project, CancellationToken cancellationToken)
        {
            WriteLine($"Analyze '{project.Name}'", Verbosity.Minimal);

            Compilation compilation = await project.GetCompilationAsync(cancellationToken);

            INamedTypeSymbol generatedCodeAttribute = compilation.GetTypeByMetadataName("System.CodeDom.Compiler.GeneratedCodeAttribute");

            ImmutableHashSet <ISymbol> ignoredSymbols = Options.IgnoredSymbols
                                                        .Select(f => DocumentationCommentId.GetFirstSymbolForDeclarationId(f, compilation))
                                                        .Where(f => f != null)
                                                        .ToImmutableHashSet();

            return(await UnusedSymbolFinder.FindUnusedSymbolsAsync(project, compilation, Predicate, ignoredSymbols, cancellationToken : cancellationToken).ConfigureAwait(false));

            bool Predicate(ISymbol symbol)
            {
                return((UnusedSymbolKinds & GetUnusedSymbolKinds(symbol)) != 0 &&
                       IsVisible(symbol) &&
                       (!Options.IgnoreObsolete ||
                        !symbol.HasAttribute(MetadataNames.System_ObsoleteAttribute)) &&
                       (Options.IncludeGeneratedCode ||
                        !GeneratedCodeUtility.IsGeneratedCode(symbol, generatedCodeAttribute, MefWorkspaceServices.Default.GetService <ISyntaxFactsService>(project.Language).IsComment, cancellationToken)));
            }
        }
Beispiel #3
0
        bool ParseDocSection(XElement item)
        {
            switch (item.Name.ToString())
            {
            case "summary":
                // in case when there is more than one summary, make the behavior the same as VS
                if (_Summary == null)
                {
                    _Summary = item;
                }
                break;

            case "remarks":
                _Remarks = item; break;

            case "returns":
                _Returns = item; break;

            case "param":
                (_Parameters ?? (_Parameters = new List <XElement>())).Add(item); break;

            case "typeparam":
                (_TypeParameters ?? (_TypeParameters = new List <XElement>())).Add(item); break;

            case "exception":
                (_Exceptions ?? (_Exceptions = new List <XElement>())).Add(item); break;

            case "example":
                (_Examples ?? (_Examples = new List <XElement>())).Add(item); break;

            case "seealso":
                (_SeeAlsos ?? (_SeeAlsos = new List <XElement>())).Add(item); break;

            case "see":
                (_Sees ?? (_Sees = new List <XElement>())).Add(item); break;

            case "preliminary":
                _Preliminary = true; break;

            case "inheritdoc":
                if (Config.Instance.QuickInfoOptions.MatchFlags(QuickInfoOptions.DocumentationFromInheritDoc))
                {
                    var cref = item.Attribute("cref");
                    if (cref != null && String.IsNullOrEmpty(cref.Value) == false)
                    {
                        var s = DocumentationCommentId.GetFirstSymbolForDeclarationId(cref.Value, _Compilation);
                        if (s != null)
                        {
                            _ExplicitInheritDoc = new XmlDoc(s, _Compilation);
                        }
                    }
                }
                break;

            default:
                return(false);
            }
            return(true);
        }
Beispiel #4
0
        private void CheckDeclarationId <TSymbol>(string expectedId, Compilation compilation, Func <TSymbol, bool> test)
            where TSymbol : ISymbol
        {
            var symbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(expectedId, compilation);

            Assert.Equal(true, symbol is TSymbol);
            Assert.Equal(true, test((TSymbol)symbol));
        }
        private static TSymbol CheckDeclarationId <TSymbol>(string expectedId, Compilation compilation, Func <TSymbol, bool> test)
            where TSymbol : ISymbol
        {
            var symbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(expectedId, compilation);

            Assert.True(symbol is TSymbol);
            Assert.True(test((TSymbol)symbol));

            return((TSymbol)symbol);
        }
        private static void CheckDeclarationId(string expectedId, INamespaceOrTypeSymbol symbol, Compilation compilation)
        {
            var id = DocumentationCommentId.CreateDeclarationId(symbol);

            Assert.Equal(expectedId, id);

            var sym = DocumentationCommentId.GetFirstSymbolForDeclarationId(id, compilation);

            Assert.Equal(symbol, sym);
        }
Beispiel #7
0
        internal void RenderXmlDocSymbol(string symbol, InlineCollection inlines, SymbolKind symbolKind)
        {
            switch (symbolKind)
            {
            case SymbolKind.Parameter:
                inlines.Add(symbol.Render(false, _SymbolFormatter.Parameter == null, _SymbolFormatter.Parameter));
                return;

            case SymbolKind.TypeParameter:
                inlines.Add(symbol.Render(_SymbolFormatter.TypeParameter == null, false, _SymbolFormatter.TypeParameter));
                return;

            case SymbolKind.DynamicType:
                // highlight keywords
                inlines.Add(symbol.Render(_SymbolFormatter.Keyword));
                return;
            }
            var s = DocumentationCommentId.GetFirstSymbolForDeclarationId(symbol, _Compilation);

            if (s != null)
            {
                _SymbolFormatter.Format(inlines, s, null, false);
                return;
            }
            if (symbol.Length > 2 && symbol[1] == ':')
            {
                switch (symbol[0])
                {
                case 'T':
                    inlines.Add(symbol.Substring(2).Render(false, true, _SymbolFormatter.Class));
                    return;

                case 'M':
                    inlines.Add(symbol.Substring(2).Render(false, true, _SymbolFormatter.Method));
                    return;

                case 'P':
                    inlines.Add(symbol.Substring(2).Render(false, true, _SymbolFormatter.Property));
                    return;

                case 'F':
                    inlines.Add(symbol.Substring(2).Render(false, true, _SymbolFormatter.Field));
                    return;

                case 'E':
                    inlines.Add(symbol.Substring(2).Render(false, true, _SymbolFormatter.Delegate));
                    return;

                case '!':
                    inlines.Add(symbol.Substring(2).Render(true, true, null));
                    return;
                }
            }
            inlines.Add(symbol);
        }
        protected override string GetDocumentationForSymbol(string documentationMemberID, CultureInfo preferredCulture, CancellationToken cancellationToken = default)
        {
            var symbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(documentationMemberID, _compilation);

            if (symbol != null)
            {
                return(symbol.GetDocumentationCommentXml(preferredCulture, cancellationToken: cancellationToken));
            }

            return(string.Empty);
        }
        internal ISymbol GetFirstSymbolForDeclarationId(string id)
        {
            if (Compilations.Length == 1)
                return DocumentationCommentId.GetFirstSymbolForDeclarationId(id, Compilations[0]);

            foreach (Compilation compilation in Compilations)
            {
                ISymbol symbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(id, compilation);

                if (symbol != null)
                    return symbol;
            }

            return null;
        }
        private static void AppendTextFromTagWithNameAttribute(FormatterState state, XElement element, Compilation compilation)
        {
            var nameAttribute = element.Attribute("name");

            if (nameAttribute == null)
            {
                return;
            }

            if (compilation != null && state.TryAppendSymbol(DocumentationCommentId.GetFirstSymbolForDeclarationId(nameAttribute.Value, compilation)))
            {
                return;
            }
            else
            {
                state.AppendString(TrimCrefPrefix(nameAttribute.Value));
            }
        }
Beispiel #11
0
            private IEnumerable <SymbolDisplayPart> RefToParts(string elementName, string refValue)
            {
                var semanticModel = _provider.SemanticModel;

                if (!(semanticModel is null))
                {
                    var symbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(refValue, semanticModel.Compilation);
                    if (!(symbol is null))
                    {
                        return(symbol.ToMinimalDisplayParts(semanticModel, _provider._position, _crefFormat));
                    }
                    if (TryProcessRef(elementName, refValue, out var part))
                    {
                        return(part.Enumerate());
                    }
                }
                return(_provider.CreatePart(SymbolDisplayPartKind.Text, TrimRefPrefix(refValue)).Enumerate());
            }
        internal static IEnumerable <SymbolDisplayPart> CrefToSymbolDisplayParts(string crefValue, int position, SemanticModel semanticModel, SymbolDisplayFormat format = null)
        {
            // first try to parse the symbol
            if (semanticModel != null)
            {
                var symbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(crefValue, semanticModel.Compilation);
                if (symbol != null)
                {
                    if (symbol.IsConstructor())
                    {
                        format = format.WithMemberOptions(SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeExplicitInterface);
                    }

                    return(symbol.ToMinimalDisplayParts(semanticModel, position, format));
                }
            }

            // if any of that fails fall back to just displaying the raw text
            return(SpecializedCollections.SingletonEnumerable(new SymbolDisplayPart(kind: SymbolDisplayPartKind.Text, symbol: null, text: TrimCrefPrefix(crefValue))));
        }
        private static void AppendTextFromSeeTag(FormatterState state, XElement element, Compilation compilation)
        {
            var crefAttribute = element.Attribute("cref");

            if (crefAttribute == null)
            {
                return;
            }

            var crefValue = crefAttribute.Value;

            if (compilation != null && state.TryAppendSymbol(DocumentationCommentId.GetFirstSymbolForDeclarationId(crefValue, compilation)))
            {
                return;
            }
            else
            {
                state.AppendString(TrimCrefPrefix(crefValue));
            }
        }
        private void BuildXmlDocumentation(ISymbol symbol, Compilation compilation, _VSOBJDESCOPTIONS options)
        {
            var documentationComment = symbol.GetDocumentationComment(expandIncludes: true, cancellationToken: CancellationToken.None);

            if (documentationComment == null)
            {
                return;
            }

            var formattingService = _project.LanguageServices.GetService <IDocumentationCommentFormattingService>();

            if (formattingService == null)
            {
                return;
            }

            var emittedDocs = false;

            if (documentationComment.SummaryText != null)
            {
                AddLineBreak();
                AddName(ServicesVSResources.Library_Summary);
                AddLineBreak();

                AddText(formattingService.Format(documentationComment.SummaryText, compilation));
                emittedDocs = true;
            }

            if (documentationComment.TypeParameterNames.Length > 0)
            {
                if (emittedDocs)
                {
                    AddLineBreak();
                }

                AddLineBreak();
                AddName(ServicesVSResources.Library_TypeParameters);

                foreach (var typeParameterName in documentationComment.TypeParameterNames)
                {
                    AddLineBreak();

                    var typeParameterText = documentationComment.GetTypeParameterText(typeParameterName);
                    if (typeParameterText != null)
                    {
                        AddParam(typeParameterName);
                        AddText(": ");

                        AddText(formattingService.Format(typeParameterText, compilation));
                        emittedDocs = true;
                    }
                }
            }

            if (documentationComment.ParameterNames.Length > 0)
            {
                if (emittedDocs)
                {
                    AddLineBreak();
                }

                AddLineBreak();
                AddName(ServicesVSResources.Library_Parameters);

                foreach (var parameterName in documentationComment.ParameterNames)
                {
                    AddLineBreak();

                    var parameterText = documentationComment.GetParameterText(parameterName);
                    if (parameterText != null)
                    {
                        AddParam(parameterName);
                        AddText(": ");

                        AddText(formattingService.Format(parameterText, compilation));
                        emittedDocs = true;
                    }
                }
            }

            if (ShowReturnsDocumentation(symbol) && documentationComment.ReturnsText != null)
            {
                if (emittedDocs)
                {
                    AddLineBreak();
                }

                AddLineBreak();
                AddName(ServicesVSResources.Library_Returns);
                AddLineBreak();

                AddText(formattingService.Format(documentationComment.ReturnsText, compilation));
                emittedDocs = true;
            }

            if (documentationComment.RemarksText != null)
            {
                if (emittedDocs)
                {
                    AddLineBreak();
                }

                AddLineBreak();
                AddName(ServicesVSResources.Library_Remarks);
                AddLineBreak();

                AddText(formattingService.Format(documentationComment.RemarksText, compilation));
                emittedDocs = true;
            }

            if (documentationComment.ExceptionTypes.Length > 0)
            {
                if (emittedDocs)
                {
                    AddLineBreak();
                }

                AddLineBreak();
                AddName(ServicesVSResources.Library_Exceptions);

                foreach (var exceptionType in documentationComment.ExceptionTypes)
                {
                    var exceptionTypeSymbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(exceptionType, compilation) as INamedTypeSymbol;
                    if (exceptionTypeSymbol != null)
                    {
                        AddLineBreak();

                        var exceptionTexts = documentationComment.GetExceptionTexts(exceptionType);
                        if (exceptionTexts.Length == 0)
                        {
                            AddTypeLink(exceptionTypeSymbol, LinkFlags.None);
                        }
                        else
                        {
                            foreach (var exceptionText in exceptionTexts)
                            {
                                AddTypeLink(exceptionTypeSymbol, LinkFlags.None);
                                AddText(": ");
                                AddText(formattingService.Format(exceptionText, compilation));
                            }
                        }

                        emittedDocs = true;
                    }
                }
            }
        }
Beispiel #15
0
        // Can be removed if https://github.com/dotnet/roslyn/issues/67 gets resolved
        // Modeled after Sandcastle implementation: http://tunnelvisionlabs.github.io/SHFB/docs-master/XMLCommentsGuide/html/86453FFB-B978-4A2A-9EB5-70E118CA8073.htm
        private void ProcessInheritDoc(XElement root, ISymbol currentSymbol, List <XElement> inheritDocElements, HashSet <string> inheritedSymbolCommentIds)
        {
            if (inheritDocElements.Count > 0)
            {
                // Gather the documents (first in the list takes precedence)
                List <ISymbol> inheritedSymbols = new List <ISymbol>();
                foreach (XElement inheritDocElement in inheritDocElements)
                {
                    // Remove from the parent
                    inheritDocElement.Remove();

                    // Locate the appropriate symbol
                    string inheritDocElementCref = inheritDocElement.Attribute("cref")?.Value;
                    if (inheritDocElementCref == null && inheritedSymbolCommentIds.Add(currentSymbol.GetDocumentationCommentId()))
                    {
                        INamedTypeSymbol currentTypeSymbol     = currentSymbol as INamedTypeSymbol;
                        IMethodSymbol    currentMethodSymbol   = currentSymbol as IMethodSymbol;
                        IPropertySymbol  currentPropertySymbol = currentSymbol as IPropertySymbol;
                        IEventSymbol     currentEventSymbol    = currentSymbol as IEventSymbol;
                        if (currentTypeSymbol != null)
                        {
                            // Types and interfaces, inherit from all base types
                            List <INamedTypeSymbol> baseTypeSymbols = AnalyzeSymbolVisitor.GetBaseTypes(currentTypeSymbol)
                                                                      .Where(x => inheritedSymbolCommentIds.Add(x.GetDocumentationCommentId()))
                                                                      .ToList();
                            if (baseTypeSymbols.Count > 0)
                            {
                                inheritedSymbols.AddRange(baseTypeSymbols);
                            }

                            // Then inherit from all interfaces
                            List <INamedTypeSymbol> interfaceSymbols = currentTypeSymbol.AllInterfaces
                                                                       .Where(x => inheritedSymbolCommentIds.Add(x.GetDocumentationCommentId()))
                                                                       .ToList();
                            if (interfaceSymbols.Count > 0)
                            {
                                inheritedSymbols.AddRange(interfaceSymbols);
                            }
                        }
                        else if (currentMethodSymbol != null && currentMethodSymbol.Name == currentMethodSymbol.ContainingType.Name)
                        {
                            // Constructor, check base type constructors for the same signature
                            string signature = AnalyzeSymbolVisitor.GetFullName(currentMethodSymbol);
                            signature = signature.Substring(signature.IndexOf('('));
                            foreach (INamedTypeSymbol baseTypeSymbol in AnalyzeSymbolVisitor.GetBaseTypes(currentMethodSymbol.ContainingType))
                            {
                                foreach (IMethodSymbol constructorSymbol in baseTypeSymbol.Constructors.Where(x => !x.IsImplicitlyDeclared))
                                {
                                    string constructorSignature = AnalyzeSymbolVisitor.GetFullName(constructorSymbol);
                                    constructorSignature = constructorSignature.Substring(constructorSignature.IndexOf('('));
                                    if (signature == constructorSignature &&
                                        inheritedSymbolCommentIds.Add(constructorSymbol.GetDocumentationCommentId()))
                                    {
                                        inheritedSymbols.Add(constructorSymbol);
                                    }
                                }
                            }
                        }
                        else if (currentMethodSymbol != null)
                        {
                            PopulateInheritedMemberSymbols(currentMethodSymbol, x => x.OverriddenMethod, inheritedSymbolCommentIds, inheritedSymbols);
                        }
                        else if (currentPropertySymbol != null)
                        {
                            PopulateInheritedMemberSymbols(currentPropertySymbol, x => x.OverriddenProperty, inheritedSymbolCommentIds, inheritedSymbols);
                        }
                        else if (currentEventSymbol != null)
                        {
                            PopulateInheritedMemberSymbols(currentEventSymbol, x => x.OverriddenEvent, inheritedSymbolCommentIds, inheritedSymbols);
                        }
                    }
                    else if (inheritDocElementCref != null)
                    {
                        // Explicit cref
                        if (inheritedSymbolCommentIds.Add(inheritDocElementCref))
                        {
                            ISymbol inheritedSymbol = DocumentationCommentId.GetFirstSymbolForDeclarationId(inheritDocElementCref, _compilation);
                            if (inheritedSymbol != null)
                            {
                                inheritedSymbols.Add(inheritedSymbol);
                            }
                        }
                    }
                }

                // Add the inherited comments
                foreach (ISymbol inheritedSymbol in inheritedSymbols)
                {
                    string inheritedXml = inheritedSymbol.GetDocumentationCommentXml(expandIncludes: true);
                    if (!string.IsNullOrEmpty(inheritedXml))
                    {
                        XElement inheritedRoot = GetRootElement(inheritedXml);
                        if (inheritedRoot != null)
                        {
                            // Inherit elements other than <inheritdoc>
                            List <XElement> inheritedInheritDocElements = new List <XElement>();
                            foreach (XElement inheritedElement in inheritedRoot.Elements())
                            {
                                if (inheritedElement.Name == "inheritdoc")
                                {
                                    inheritedInheritDocElements.Add(inheritedElement);
                                }
                                else
                                {
                                    string inheritedElementCref = inheritedElement.Attribute("cref")?.Value;
                                    string inheritedElementName = inheritedElement.Attribute("name")?.Value;
                                    bool   inherit = true;
                                    foreach (XElement rootElement in root.Elements(inheritedElement.Name))
                                    {
                                        if (inheritedElementCref == null && inheritedElementName == null)
                                        {
                                            // Don't inherit if the name is the same and there's no distinguishing attributes
                                            inherit = false;
                                            break;
                                        }
                                        if (inheritedElementCref != null && inheritedElementCref == rootElement.Attribute("cref")?.Value)
                                        {
                                            // Don't inherit if the cref attribute is the same
                                            inherit = false;
                                            break;
                                        }
                                        if (inheritedElementName != null && inheritedElementName == rootElement.Attribute("name")?.Value)
                                        {
                                            // Don't inherit if the name attribute is the same
                                            inherit = false;
                                            break;
                                        }
                                    }
                                    if (inherit)
                                    {
                                        root.Add(inheritedElement);
                                    }
                                }
                            }

                            // Recursively inherit <inheritdoc>
                            if (inheritedInheritDocElements.Count > 0)
                            {
                                ProcessInheritDoc(root, inheritedSymbol, inheritedInheritDocElements, inheritedSymbolCommentIds);
                            }
                        }
                    }
                }
            }
        }
 internal ISymbol GetFirstSymbolForDeclarationId(string id)
 {
     return(DocumentationCommentId.GetFirstSymbolForDeclarationId(id, Compilation));
 }