private ISymbol GetSymbolForRange(Classification.Range r) { var position = r.ClassifiedSpan.TextSpan.Start; var token = Root.FindToken(position, findInsideTrivia: true); return(SemanticModel.GetDeclaredSymbol(token.Parent)); }
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); }