Exemplo n.º 1
0
        private ISymbol GetSymbolForRange(Classification.Range r)
        {
            var position = r.ClassifiedSpan.TextSpan.Start;
            var token    = Root.FindToken(position, findInsideTrivia: true);

            return(SemanticModel.GetDeclaredSymbol(token.Parent));
        }
Exemplo n.º 2
0
        private void AddReferencesToOverriddenMembers(
            Classification.Range range,
            SyntaxToken token,
            ISymbol declaredSymbol)
        {
            if (!declaredSymbol.IsOverride)
            {
                return;
            }

            IMethodSymbol method = declaredSymbol as IMethodSymbol;

            if (method != null)
            {
                var overriddenMethod = method.OverriddenMethod;
                if (overriddenMethod != null)
                {
                    ProcessReference(
                        range,
                        overriddenMethod,
                        ReferenceKind.Override);
                    projectGenerator.AddBaseMember(method, overriddenMethod);
                }
            }

            IPropertySymbol property = declaredSymbol as IPropertySymbol;

            if (property != null)
            {
                var overriddenProperty = property.OverriddenProperty;
                if (overriddenProperty != null)
                {
                    ProcessReference(
                        range,
                        overriddenProperty,
                        ReferenceKind.Override);
                    projectGenerator.AddBaseMember(property, overriddenProperty);
                }
            }

            IEventSymbol eventSymbol = declaredSymbol as IEventSymbol;

            if (eventSymbol != null)
            {
                var overriddenEvent = eventSymbol.OverriddenEvent;
                if (overriddenEvent != null)
                {
                    ProcessReference(
                        range,
                        overriddenEvent,
                        ReferenceKind.Override);
                    projectGenerator.AddBaseMember(eventSymbol, overriddenEvent);
                }
            }
        }
        private HtmlElementInfo ProcessReference(Classification.Range range, SyntaxToken token, bool isLargeFile = false)
        {
            ClassifiedSpan classifiedSpan = range.ClassifiedSpan;
            var            kind           = ReferenceKind.Reference;
            var            node           = GetBindableParent(token);

            if (token.RawKind == (int)Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.NewKeyword &&
                node is Microsoft.CodeAnalysis.VisualBasic.Syntax.ObjectCreationExpressionSyntax)
            {
                // don't count New in New Foo() as a reference to the constructor
                return(null);
            }

            if (token.ToString() == "[" &&
                token.Parent is Microsoft.CodeAnalysis.CSharp.Syntax.BracketedArgumentListSyntax &&
                token.Parent.Parent is Microsoft.CodeAnalysis.CSharp.Syntax.ElementAccessExpressionSyntax)
            {
                node = token.Parent.Parent;
            }

            if (node == null)
            {
                return(null);
            }

            var symbol = GetSymbol(node);

            if (symbol == null)
            {
                return(null);
            }

            //Diagnostics(classifiedSpan, token, symbol);

            kind = DetermineReferenceKind(token, node, symbol);

            return(ProcessReference(range, symbol, kind, isLargeFile));
        }
        private void AddReferencesToImplementedMembers(
            Classification.Range range,
            SyntaxToken token,
            ISymbol declaredSymbol)
        {
            var declaringType = declaredSymbol.ContainingType;
            var interfaces    = declaringType.AllInterfaces;

            foreach (var implementedInterface in interfaces)
            {
                foreach (var member in implementedInterface.GetMembers())
                {
                    if (declaringType.FindImplementationForInterfaceMember(member) == declaredSymbol)
                    {
                        ProcessReference(
                            range,
                            member,
                            ReferenceKind.InterfaceMemberImplementation);
                        projectGenerator.AddImplementedInterfaceMember(declaredSymbol, member);
                    }
                }
            }
        }
        private string GetClassAttribute(string rangeText, Classification.Range range)
        {
            string classificationType = range.ClassificationType;

            if (classificationType == null ||
                classificationType == Constants.ClassificationPunctuation)
            {
                return(null);
            }

            if (range.ClassificationType == Constants.ClassificationLiteral ||
                range.ClassificationType == Constants.ClassificationUnknown)
            {
                return(classificationType);
            }

            if (range.ClassificationType != Constants.ClassificationIdentifier &&
                range.ClassificationType != Constants.ClassificationTypeName &&
                rangeText != "this" &&
                rangeText != "base" &&
                rangeText != "var" &&
                rangeText != "New" &&
                rangeText != "new" &&
                rangeText != "[" &&
                rangeText != "partial" &&
                rangeText != "Partial")
            {
                return(classificationType);
            }

            if (range.ClassificationType == Constants.ClassificationKeyword)
            {
                return(classificationType);
            }

            var position = range.ClassifiedSpan.TextSpan.Start;
            var token    = Root.FindToken(position, findInsideTrivia: true);

            var declaredSymbol = SemanticModel.GetDeclaredSymbol(token.Parent);

            if (declaredSymbol is IParameterSymbol && rangeText == "this")
            {
                return(classificationType);
            }

            if (declaredSymbol != null)
            {
                return(ClassFromSymbol(declaredSymbol, classificationType));
            }

            var node = GetBindableParent(token);

            if (token.ToString() == "[" &&
                token.Parent is Microsoft.CodeAnalysis.CSharp.Syntax.BracketedArgumentListSyntax &&
                token.Parent.Parent is Microsoft.CodeAnalysis.CSharp.Syntax.ElementAccessExpressionSyntax)
            {
                node = token.Parent.Parent;
            }

            if (node == null)
            {
                return(classificationType);
            }

            var symbol = GetSymbol(node);

            if (symbol == null)
            {
                return(classificationType);
            }

            return(ClassFromSymbol(symbol, classificationType));
        }
        private HtmlElementInfo ProcessReference(Classification.Range range, ISymbol symbol, ReferenceKind kind, bool isLargeFile = false)
        {
            ClassifiedSpan classifiedSpan = range.ClassifiedSpan;
            var            methodSymbol   = symbol as IMethodSymbol;

            if (methodSymbol != null && methodSymbol.ReducedFrom != null)
            {
                symbol = methodSymbol.ReducedFrom;
            }

            HtmlElementInfo result = null;

            if (symbol.IsImplicitlyDeclared)
            {
                if (methodSymbol?.MethodKind == MethodKind.Constructor &&
                    symbol.ContainingSymbol != null)
                {
                    return(ProcessReference(range, symbol.ContainingSymbol, ReferenceKind.Instantiation));
                }
            }

            if (symbol.Kind == SymbolKind.Local ||
                symbol.Kind == SymbolKind.Parameter ||
                symbol.Kind == SymbolKind.TypeParameter)
            {
                if (isLargeFile)
                {
                    return(null);
                }

                return(HighlightReference(symbol));
            }

            if (methodSymbol?.MethodKind == MethodKind.Constructor &&
                methodSymbol.ContainingType != null)
            {
                ProcessReference(range, methodSymbol.ContainingType, ReferenceKind.Instantiation);
            }

            if ((symbol.Kind == SymbolKind.Event ||
                 symbol.Kind == SymbolKind.Field ||
                 symbol.Kind == SymbolKind.Method ||
                 symbol.Kind == SymbolKind.NamedType ||
                 symbol.Kind == SymbolKind.Property) &&
                symbol.Locations.Length >= 1)
            {
                var    typeSymbol = symbol as ITypeSymbol;
                string symbolId   = SymbolIdService.GetId(symbol);
                var    location   = symbol.Locations[0];
                string destinationAssemblyName = null;
                if (location.IsInSource)
                {
                    result = GenerateHyperlink(symbol, symbolId, location.SourceTree, out destinationAssemblyName);
                }
                else if (location.IsInMetadata && location.MetadataModule != null)
                {
                    var metadataModule = location.MetadataModule;
                    result = GenerateHyperlink(symbolId, symbol, metadataModule, isLargeFile, out destinationAssemblyName);
                }

                if (result == null)
                {
                    return(result);
                }

                if (result.Attributes == null ||
                    !result.Attributes.TryGetValue("href", out string target) ||
                    !target.Contains("@"))
                {
                    // only register a reference to the symbol if it's not a symbol from an external assembly.
                    // if this links to a symbol in a different index, link target contain @.
                    projectGenerator.AddReference(
                        this.documentDestinationFilePath,
                        Text,
                        destinationAssemblyName,
                        symbol,
                        symbolId,
                        classifiedSpan.TextSpan.Start,
                        classifiedSpan.TextSpan.End,
                        kind);
                }
            }

            // don't make this and var into hyperlinks in large files to save space
            if (isLargeFile && (range.Text == "this" || range.Text == "var"))
            {
                result = null;
            }

            return(result);
        }
        private HtmlElementInfo TryProcessGuid(Classification.Range range)
        {
            var text      = range.Text;
            var spanStart = range.ClassifiedSpan.TextSpan.Start;
            var spanEnd   = range.ClassifiedSpan.TextSpan.End;

            if (text.StartsWith("@"))
            {
                text = text.Substring(1);
                spanStart++;
            }

            if (text.StartsWith("\"") && text.EndsWith("\"") && text.Length >= 2)
            {
                spanStart++;
                spanEnd--;
                text = text.Substring(1, text.Length - 2);
            }

            // quick check to reject non-Guids even before trying to parse
            if (text.Length != 32 && text.Length != 36 && text.Length != 38)
            {
                return(null);
            }

            if (!Guid.TryParse(text, out Guid guid))
            {
                return(null);
            }

            var symbolId = guid.ToString();

            var referencesFilePath = Path.Combine(
                SolutionDestinationFolder,
                Constants.GuidAssembly,
                Constants.ReferencesFileName,
                symbolId + ".html");
            string href = Paths.MakeRelativeToFile(referencesFilePath, documentDestinationFilePath);

            href = href.Replace('\\', '/');

            var link = new HtmlElementInfo
            {
                Name       = "a",
                Attributes =
                {
                    { "href",   href },
                    { "target", "n"  },
                },
                DeclaredSymbolId = symbolId
            };

            projectGenerator.AddReference(
                this.documentDestinationFilePath,
                Text,
                Constants.GuidAssembly,
                null,
                symbolId,
                spanStart,
                spanEnd,
                ReferenceKind.GuidUsage);

            return(link);
        }
        private HtmlElementInfo GenerateLinks(Classification.Range range, bool isLargeFile = false)
        {
            var text = range.Text;

            if (range.ClassificationType == Constants.ClassificationLiteral)
            {
                return(TryProcessGuid(range));
            }

            if (range.ClassificationType != Constants.ClassificationIdentifier &&
                range.ClassificationType != Constants.ClassificationTypeName &&
                text != "this" &&
                text != "base" &&
                text != "string" &&
                text != "var" &&
                text != "New" &&
                text != "new" &&
                text != "[" &&
                text != "partial" &&
                text != "Partial")
            {
                return(null);
            }

            var position = range.ClassifiedSpan.TextSpan.Start;
            var token    = Root.FindToken(position, findInsideTrivia: true);

            if (IsZeroLengthArrayAllocation(token))
            {
                projectGenerator.AddReference(
                    this.documentDestinationFilePath,
                    Text,
                    "mscorlib",
                    null,
                    "EmptyArrayAllocation",
                    range.ClassifiedSpan.TextSpan.Start,
                    range.ClassifiedSpan.TextSpan.End,
                    ReferenceKind.EmptyArrayAllocation);
                return(null);
            }

            // now that we've passed the empty array allocation check, disable all further new keywords
            if (range.ClassificationType == Constants.ClassificationKeyword && text == "new")
            {
                return(null);
            }

            var declaredSymbol = SemanticModel.GetDeclaredSymbol(token.Parent);

            if (declaredSymbol is IParameterSymbol && text == "this")
            {
                // it's a 'this' in the first parameter of an extension method - we don't want it to
                // hyperlink to anything
                return(null);
            }

            if (declaredSymbol != null)
            {
                if (token.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PartialKeyword) ||
                    token.IsKind(Microsoft.CodeAnalysis.VisualBasic.SyntaxKind.PartialKeyword))
                {
                    if (declaredSymbol is INamedTypeSymbol)
                    {
                        return(TryProcessPartialKeyword((INamedTypeSymbol)declaredSymbol));
                    }

                    return(null);
                }

                var explicitlyImplementedMember = GetExplicitlyImplementedMember(declaredSymbol);
                if (explicitlyImplementedMember == null)
                {
                    if (token.Span.Contains(position) &&
                        (declaredSymbol.Kind == SymbolKind.Event ||
                         declaredSymbol.Kind == SymbolKind.Field ||
                         declaredSymbol.Kind == SymbolKind.Local ||
                         declaredSymbol.Kind == SymbolKind.Method ||
                         declaredSymbol.Kind == SymbolKind.NamedType ||
                         declaredSymbol.Kind == SymbolKind.Parameter ||
                         declaredSymbol.Kind == SymbolKind.Property ||
                         declaredSymbol.Kind == SymbolKind.TypeParameter
                        ) &&
                        DeclaredSymbols.Add(declaredSymbol))
                    {
                        if ((declaredSymbol.Kind == SymbolKind.Method ||
                             declaredSymbol.Kind == SymbolKind.Property ||
                             declaredSymbol.Kind == SymbolKind.Event) &&
                            !declaredSymbol.IsStatic)
                        {
                            // declarations of overridden members are also "references" to their
                            // base members. This is needed for "Find Overridding Members" and
                            // "Find Implementations"
                            AddReferencesToOverriddenMembers(range, token, declaredSymbol);
                            AddReferencesToImplementedMembers(range, token, declaredSymbol);
                        }

                        return(ProcessDeclaredSymbol(declaredSymbol, isLargeFile));
                    }
                }
                else
                {
                    projectGenerator.AddImplementedInterfaceMember(
                        declaredSymbol,
                        explicitlyImplementedMember);
                    return(ProcessReference(
                               range,
                               explicitlyImplementedMember,
                               ReferenceKind.InterfaceMemberImplementation));
                }
            }
            else
            {
                return(ProcessReference(range, token, isLargeFile));
            }

            return(null);
        }
        private string GenerateRange(StreamWriter writer, Classification.Range range, int lineCount = 0)
        {
            var html = range.Text;

            html = Markup.HtmlEscape(html);
            bool            isLargeFile         = IsLargeFile(lineCount);
            string          classAttributeValue = GetClassAttribute(html, range);
            HtmlElementInfo hyperlinkInfo       = GenerateLinks(range, isLargeFile);

            if (hyperlinkInfo == null)
            {
                if (classAttributeValue == null || isLargeFile)
                {
                    return(html);
                }

                if (classAttributeValue == "k")
                {
                    return("<b>" + html + "</b>");
                }
            }

            var sb = new StringBuilder();

            var elementName = "span";

            if (hyperlinkInfo != null)
            {
                elementName = hyperlinkInfo.Name;
            }

            sb.Append("<" + elementName);
            bool overridingClassAttributeSpecified = false;

            if (hyperlinkInfo != null)
            {
                foreach (var attribute in hyperlinkInfo.Attributes)
                {
                    AddAttribute(sb, attribute.Key, attribute.Value);
                    if (attribute.Key == "class")
                    {
                        overridingClassAttributeSpecified = true;
                    }
                }
            }

            if (!overridingClassAttributeSpecified)
            {
                AddAttribute(sb, "class", classAttributeValue);
            }

            sb.Append('>');

            html = AddIdSpanForImplicitConstructorIfNecessary(hyperlinkInfo, html);

            sb.Append(html);
            sb.Append("</" + elementName + ">");

            html = sb.ToString();

            if (hyperlinkInfo != null && hyperlinkInfo.DeclaredSymbol != null)
            {
                writer.Flush();
                long streamPosition = writer.BaseStream.Length;

                streamPosition += html.IndexOf(hyperlinkInfo.Attributes["id"] + ".html");
                projectGenerator.AddDeclaredSymbol(
                    hyperlinkInfo.DeclaredSymbol,
                    hyperlinkInfo.DeclaredSymbolId,
                    documentRelativeFilePathWithoutHtmlExtension,
                    streamPosition);
            }

            return(html);
        }