private INamedTypeSymbol GetCompletionListType(ITypeSymbol type, INamedTypeSymbol within, Compilation compilation)
        {
            // PERF: None of the SpecialTypes include <completionlist> tags,
            // so we don't even need to load the documentation.
            if (type.IsSpecialType())
            {
                return(null);
            }

            // PERF: Avoid parsing XML unless the text contains the word "completionlist".
            string xmlText = type.GetDocumentationCommentXml();

            if (xmlText == null || !xmlText.Contains(DocumentationCommentXmlNames.CompletionListElementName))
            {
                return(null);
            }

            var documentation = Shared.Utilities.DocumentationComment.FromXmlFragment(xmlText);

            var completionListType = documentation.CompletionListCref != null
                ? DocumentationCommentId.GetSymbolsForDeclarationId(documentation.CompletionListCref, compilation).OfType <INamedTypeSymbol>().FirstOrDefault()
                : null;

            return(completionListType != null && completionListType.IsAccessibleWithin(within)
                ? completionListType
                : null);
        }
Пример #2
0
        private async Task <ISymbol> GetSymbolAsync(Solution solution, ProjectId projectId, string symbolId, CancellationToken cancellationToken)
        {
            var project = solution.GetProject(projectId);

            if (project.SupportsCompilation)
            {
                var comp = await solution.GetProject(projectId).GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                var symbols = DocumentationCommentId.GetSymbolsForDeclarationId(symbolId, comp).ToList();

                if (symbols.Count == 1)
                {
                    return(symbols[0]);
                }
                else if (symbols.Count > 1)
                {
#if false
                    // if we have multiple matches, use the same index that it appeared as in the original solution.
                    var originalComp = await this.originalSolution.GetProject(projectId).GetCompilationAsync(cancellationToken).ConfigureAwait(false);

                    var originalSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(symbolId, originalComp).ToList();
                    var index           = originalSymbols.IndexOf(originalSymbol);
                    if (index >= 0 && index <= symbols.Count)
                    {
                        return(symbols[index]);
                    }
#else
                    return(symbols[0]);
#endif
                }
            }

            return(null);
        }
Пример #3
0
        /// <summary>
        /// Gets the current symbol for a source symbol.
        /// </summary>
        public async Task <ISymbol> GetCurrentSymbolAsync(ISymbol symbol, CancellationToken cancellationToken = default)
        {
            var symbolId = DocumentationCommentId.CreateDeclarationId(symbol);

            // check to see if symbol is from current solution
            var project = _currentSolution.GetProject(symbol.ContainingAssembly, cancellationToken);

            if (project != null)
            {
                return(await GetSymbolAsync(_currentSolution, project.Id, symbolId, cancellationToken).ConfigureAwait(false));
            }

            // check to see if it is from original solution
            project = _originalSolution.GetProject(symbol.ContainingAssembly, cancellationToken);
            if (project != null)
            {
                return(await GetSymbolAsync(_currentSolution, project.Id, symbolId, cancellationToken).ConfigureAwait(false));
            }

            // try to find symbol from any project (from current solution) with matching assembly name
            foreach (var projectId in this.GetProjectsForAssembly(symbol.ContainingAssembly))
            {
                var currentSymbol = await GetSymbolAsync(_currentSolution, projectId, symbolId, cancellationToken).ConfigureAwait(false);

                if (currentSymbol != null)
                {
                    return(currentSymbol);
                }
            }

            return(null);
        }
        // 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);
        }
        public static SymbolNamesOption Create(ImmutableArray <string> symbolNames, Compilation compilation, string optionalPrefix)
        {
            if (symbolNames.IsEmpty)
            {
                return(Empty);
            }

            var namesBuilder = PooledHashSet <string> .GetInstance();

            var symbolsBuilder = PooledHashSet <ISymbol> .GetInstance();

            foreach (var name in symbolNames)
            {
                if (name.Equals(".ctor", StringComparison.Ordinal) ||
                    name.Equals(".cctor", StringComparison.Ordinal) ||
                    !name.Contains(".") && !name.Contains(":"))
                {
                    namesBuilder.Add(name);
                }
                else
                {
                    var nameWithPrefix = (string.IsNullOrEmpty(optionalPrefix) || name.StartsWith(optionalPrefix, StringComparison.Ordinal)) ?
                                         name :
                                         optionalPrefix + name;

#pragma warning disable CA1307 // Specify StringComparison - https://github.com/dotnet/roslyn-analyzers/issues/1552
                    // Documentation comment ID for constructors uses '#ctor', but '#' is a comment start token for editorconfig.
                    // We instead search for a '..ctor' in editorconfig and replace it with a '.#ctor' here.
                    // Similarly, handle static constructors ".cctor"
                    nameWithPrefix = nameWithPrefix.Replace("..ctor", ".#ctor");
                    nameWithPrefix = nameWithPrefix.Replace("..cctor", ".#cctor");
#pragma warning restore

                    foreach (var symbol in DocumentationCommentId.GetSymbolsForDeclarationId(nameWithPrefix, compilation))
                    {
                        if (symbol != null)
                        {
                            if (symbol is INamespaceSymbol namespaceSymbol &&
                                namespaceSymbol.ConstituentNamespaces.Length > 1)
                            {
                                foreach (var constituentNamespace in namespaceSymbol.ConstituentNamespaces)
                                {
                                    symbolsBuilder.Add(constituentNamespace);
                                }
                            }

                            symbolsBuilder.Add(symbol);
                        }
                    }
                }
            }

            if (namesBuilder.Count == 0 && symbolsBuilder.Count == 0)
            {
                return(Empty);
            }

            return(new SymbolNamesOption(namesBuilder.ToImmutableAndFree(), symbolsBuilder.ToImmutableAndFree()));
        }
Пример #6
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);
        }
Пример #7
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 void CheckDeclarationIdExact <TSymbol>(string expectedId, Compilation compilation, Func <TSymbol, bool> test)
            where TSymbol : ISymbol
        {
            var symbol = CheckDeclarationId(expectedId, compilation, test);

            var id = DocumentationCommentId.CreateDeclarationId(symbol);

            Assert.Equal(expectedId, id);
        }
Пример #9
0
        private bool IsSuppressed(SyntaxNodeAnalysisContext syntaxNodeContext, ISymbol symbol, string diagnosticId)
        {
            var analyzersSettings = syntaxNodeContext.GetSettings(CancellationToken.None);
            var possibleSymbols   = GetPossibleSymbols(symbol).ToList();

            return(analyzersSettings.Suppressions.Where(suppression => suppression.Rules.Contains(diagnosticId))
                   .SelectMany(suppression => DocumentationCommentId.GetSymbolsForDeclarationId(suppression.Target, syntaxNodeContext.Compilation))
                   .Any(possibleSymbols.Contains));
        }
        private static void CheckReferenceId(string expectedId, INamespaceOrTypeSymbol symbol, Compilation compilation)
        {
            var id = DocumentationCommentId.CreateReferenceId(symbol);

            Assert.Equal(expectedId, id);

            var sym = DocumentationCommentId.GetSymbolsForReferenceId(id, compilation).FirstOrDefault();

            Assert.Equal(symbol, sym);
        }
        protected static bool ShouldFindReferencesInGlobalSuppressions(ISymbol symbol, [NotNullWhen(returnValue: true)] out string?documentationCommentId)
        {
            if (!SupportsGlobalSuppression(symbol))
            {
                documentationCommentId = null;
                return(false);
            }

            documentationCommentId = DocumentationCommentId.CreateDeclarationId(symbol);
            return(documentationCommentId != null);
        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);
        }
        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);
        }
Пример #14
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);
        }
Пример #15
0
        private static string CreateSuppressionTarget(ISymbol symbol)
        {
            var actualSymbol = symbol;

            if (actualSymbol is IMethodSymbol methodSymbol && methodSymbol.ReducedFrom != null)
            {
                actualSymbol = methodSymbol.ReducedFrom;
            }

            return(DocumentationCommentId.CreateDeclarationId(actualSymbol));
        }
        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);
        }
Пример #17
0
        private INamedTypeSymbol GetCompletionListType(ITypeSymbol type, INamedTypeSymbol within, Compilation compilation)
        {
            var documentation = type.GetDocumentationComment();

            var completionListType = documentation.CompletionListCref != null
                ? DocumentationCommentId.GetSymbolsForDeclarationId(documentation.CompletionListCref, compilation).OfType <INamedTypeSymbol>().FirstOrDefault()
                : null;

            return(completionListType != null && completionListType.IsAccessibleWithin(within)
                ? completionListType
                : null);
        }
        internal ISymbol GetFirstSymbolForReferenceId(string id)
        {
            if (Compilations.Length == 1)
                return DocumentationCommentId.GetFirstSymbolForReferenceId(id, Compilations[0]);

            foreach (Compilation compilation in Compilations)
            {
                ISymbol symbol = DocumentationCommentId.GetFirstSymbolForReferenceId(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));
            }
        }
Пример #20
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());
            }
Пример #21
0
        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);
        }
            public void AnalyzeAssemblyOrModuleAttribute(SyntaxNode attributeSyntax, SemanticModel model, Action <Diagnostic> reportDiagnostic, CancellationToken cancellationToken)
            {
                if (!_state.IsSuppressMessageAttributeWithNamedArguments(attributeSyntax, model, cancellationToken, out var namedAttributeArguments))
                {
                    return;
                }

                if (!SuppressMessageAttributeState.HasValidScope(namedAttributeArguments, out var targetScope))
                {
                    reportDiagnostic(Diagnostic.Create(s_invalidScopeDescriptor, attributeSyntax.GetLocation()));
                    return;
                }

                if (!_state.HasValidTarget(namedAttributeArguments, targetScope, out var targetHasDocCommentIdFormat,
                                           out var targetSymbolString, out var targetValueOperation, out var resolvedSymbols))
                {
                    reportDiagnostic(Diagnostic.Create(s_invalidOrMissingTargetDescriptor, attributeSyntax.GetLocation()));
                    return;
                }

                // We want to flag valid target which uses legacy format to update to Roslyn based DocCommentId format.
                if (resolvedSymbols.Length > 0 && !targetHasDocCommentIdFormat)
                {
                    RoslynDebug.Assert(!string.IsNullOrEmpty(targetSymbolString));
                    RoslynDebug.Assert(targetValueOperation != null);

                    var properties = ImmutableDictionary <string, string?> .Empty;
                    if (resolvedSymbols.Length == 1)
                    {
                        // We provide a code fix for the case where the target resolved to a single symbol.
                        var docCommentId = DocumentationCommentId.CreateDeclarationId(resolvedSymbols[0]);
                        if (!string.IsNullOrEmpty(docCommentId))
                        {
                            // Suppression target has an optional "~" prefix to distinguish it from legacy FxCop suppressions.
                            // IDE suppression code fixes emit this prefix, so we we also add this prefix to new suppression target string.
                            properties = properties.Add(DocCommentIdKey, "~" + docCommentId);
                        }
                    }

                    reportDiagnostic(Diagnostic.Create(LegacyFormatTargetDescriptor, targetValueOperation.Syntax.GetLocation(), properties !, targetSymbolString));
                    return;
                }
            }
        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));
            }
        }
        public void TupleParameterMethod(string methodCode, string expectedDocId)
        {
            string code = $@"
class C
{{
    {methodCode}
}}";

            var comp = CreateCompilation(code);

            comp.VerifyDiagnostics();

            var symbol      = comp.GetSymbolsWithName("DoStuff").Single();
            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);

            Assert.Equal(expectedDocId, actualDocId);
            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);

            Assert.Equal(new[] { symbol }, foundSymbols);
        }
        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))));
        }
Пример #26
0
            static void ProcessSymbolName(NameParts parts, Compilation compilation, string?optionalPrefix, PooledDictionary <ISymbol, TValue> symbolsBuilder)
            {
                var nameWithPrefix = (string.IsNullOrEmpty(optionalPrefix) || parts.SymbolName.StartsWith(optionalPrefix, StringComparison.Ordinal))
                    ? parts.SymbolName
                    : optionalPrefix + parts.SymbolName;

#pragma warning disable CA1307 // Specify StringComparison - https://github.com/dotnet/roslyn-analyzers/issues/1552
                // Documentation comment ID for constructors uses '#ctor', but '#' is a comment start token for editorconfig.
                // We instead search for a '..ctor' in editorconfig and replace it with a '.#ctor' here.
                // Similarly, handle static constructors ".cctor"
                nameWithPrefix = nameWithPrefix.Replace("..ctor", ".#ctor");
                nameWithPrefix = nameWithPrefix.Replace("..cctor", ".#cctor");
#pragma warning restore

                foreach (var symbol in DocumentationCommentId.GetSymbolsForDeclarationId(nameWithPrefix, compilation))
                {
                    if (symbol == null)
                    {
                        continue;
                    }

                    if (symbol is INamespaceSymbol namespaceSymbol &&
                        namespaceSymbol.ConstituentNamespaces.Length > 1)
                    {
                        foreach (var constituentNamespace in namespaceSymbol.ConstituentNamespaces)
                        {
                            if (!symbolsBuilder.ContainsKey(constituentNamespace))
                            {
                                symbolsBuilder.Add(constituentNamespace, parts.AssociatedValue);
                            }
                        }
                    }

                    if (!symbolsBuilder.ContainsKey(symbol))
                    {
                        symbolsBuilder.Add(symbol, parts.AssociatedValue);
                    }
                }
            }
        public void DynamicParameterMethod()
        {
            string code = @"
class C
{
    int DoStuff(dynamic dynamic) => 0;
}";

            var comp = CreateCSharpCompilation(code);

            var symbol = comp.GetSymbolsWithName("DoStuff").Single();

            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);

            var expectedDocId = "M:C.DoStuff(System.Object)~System.Int32";

            Assert.Equal(expectedDocId, actualDocId);

            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);

            Assert.Equal(new[] { symbol }, foundSymbols);
        }
Пример #28
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).ConfigureAwait(false));

            bool Predicate(ISymbol symbol)
            {
                return((UnusedSymbolKinds & GetUnusedSymbolKinds(symbol)) != 0 &&
                       IsVisible(symbol) &&
                       (Options.IncludeGeneratedCode ||
                        !GeneratedCodeUtility.IsGeneratedCode(symbol, generatedCodeAttribute, SyntaxFactsServiceFactory.Instance.GetService(project.Language).IsComment, cancellationToken)));
            }
        }
        public void TupleReturnMethod()
        {
            string code = @"
class C
{
    (int i, int) DoStuff() => default;
}";

            var comp = CreateCompilation(code);

            comp.VerifyDiagnostics();

            var symbol = comp.GetSymbolsWithName("DoStuff").Single();

            var actualDocId = DocumentationCommentId.CreateDeclarationId(symbol);

            string expectedDocId = "M:C.DoStuff~System.ValueTuple{System.Int32,System.Int32}";

            Assert.Equal(expectedDocId, actualDocId);

            var foundSymbols = DocumentationCommentId.GetSymbolsForDeclarationId(expectedDocId, comp);

            Assert.Equal(new[] { symbol }, foundSymbols);
        }
Пример #30
0
        private IImmutableSet <ISymbol> ReadWhitelist()
        {
            var query =
                from additionalFile in AnalyzerOptions.AdditionalFiles
                where StringComparer.Ordinal.Equals(Path.GetFileName(additionalFile.Path), ImmutableTypesFileName)
                let sourceText = additionalFile.GetText(CancellationToken)
                                 where sourceText != null
                                 from line in sourceText.Lines
                                 let text = line.ToString()
                                            where !string.IsNullOrWhiteSpace(text)
                                            select text;

            var entries = query.ToList();

            entries.Add("System.Guid");
            entries.Add("System.TimeSpan");
            entries.Add("System.DateTimeOffset");
            entries.Add("System.Uri");
            entries.Add("System.Nullable`1");
            entries.Add("System.Collections.Generic.KeyValuePair`2");
            var result = new HashSet <ISymbol>(SymbolEqualityComparer.Default);

            foreach (var entry in entries)
            {
                var symbols = DocumentationCommentId.GetSymbolsForDeclarationId($"T:{entry}", Compilation);
                if (symbols.IsDefaultOrEmpty)
                {
                    continue;
                }
                foreach (var symbol in symbols)
                {
                    result.Add(symbol);
                }
            }
            return(result.ToImmutableHashSet(SymbolEqualityComparer.Default));
        }