/// <summary> /// Two things are happening to declared symbols at the time we write the definition to HTML stream. /// First, the symbol is added to DeclaredSymbols (to be later written to D.txt for each project). /// Second, the redirect from SymbolId to local file path is added to A.txt (metadata to source redirect). /// </summary> /// <param name="declaredSymbol">Declared symbol. Can be null for files.</param> /// <param name="symbolId">ID of the declared symbol.</param> /// <param name="documentRelativeFilePath">Project-local path to the file where the symbol is defined.</param> /// <param name="positionInFile">Exact byte position in the HTML file stream being generated where the 16-char /// symbol ID starts, to later be back patched to 0000000000000000 if the symbol has no references.</param> public void AddDeclaredSymbol( ISymbol declaredSymbol, string symbolId, string documentRelativeFilePath, long positionInFile) { if (declaredSymbol != null) { if (declaredSymbol.Kind == SymbolKind.Local || declaredSymbol.Kind == SymbolKind.Parameter || declaredSymbol.Kind == SymbolKind.TypeParameter) { return; } // We care about indexing even private symbols for NavigateTo lock (DeclaredSymbols) { var declaredSymbolName = declaredSymbol.Name; if (declaredSymbolName != ".ctor" && declaredSymbolName != ".cctor" && !DeclaredSymbols.ContainsKey(declaredSymbol)) { DeclaredSymbols.Add(declaredSymbol, symbolId); } } } AddDeclaredSymbolToRedirectMap(SymbolIDToListOfLocationsMap, symbolId, documentRelativeFilePath, positionInFile); }
private void GenerateDeclarations() { Log.Write("Declarations..."); var lines = new List <string>(); if (DeclaredSymbols != null) { foreach (var declaredSymbol in DeclaredSymbols .OrderBy(s => SymbolIdService.GetName(s.Key)) .ThenBy(s => s.Value)) { lines.Add(string.Join(";", SymbolIdService.GetName(declaredSymbol.Key), // symbol name declaredSymbol.Value, // 8-byte symbol ID SymbolKindText.GetSymbolKind(declaredSymbol.Key), // kind (e.g. "class") Markup.EscapeSemicolons(SymbolIdService.GetDisplayString(declaredSymbol.Key)), // symbol full name and signature SymbolIdService.GetGlyphNumber(declaredSymbol.Key))); // icon number } } if (OtherFiles != null) { foreach (var document in OtherFiles.OrderBy(d => d)) { lines.Add(string.Join(";", Path.GetFileName(document), SymbolIdService.GetId(document), "file", Markup.EscapeSemicolons(document), Serialization.GetIconForExtension(document))); } } Serialization.WriteDeclaredSymbols(ProjectDestinationFolder, lines); }
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); }