private string AddIdSpanForImplicitConstructorIfNecessary(HtmlElementInfo hyperlinkInfo, string html) { if (hyperlinkInfo != null && hyperlinkInfo.DeclaredSymbol != null) { INamedTypeSymbol namedTypeSymbol = hyperlinkInfo.DeclaredSymbol as INamedTypeSymbol; if (namedTypeSymbol != null) { var implicitInstanceConstructor = namedTypeSymbol.Constructors.FirstOrDefault(c => !c.IsStatic && c.IsImplicitlyDeclared); if (implicitInstanceConstructor != null) { var symbolId = SymbolIdService.GetId(implicitInstanceConstructor); html = Markup.Tag("span", html, new Dictionary <string, string> { { "id", symbolId } }); projectGenerator.AddDeclaredSymbol( implicitInstanceConstructor, symbolId, documentRelativeFilePathWithoutHtmlExtension, 0); } } } return(html); }
private void GenerateXamlFile(string xamlFile) { var projectSourceFolder = Path.GetDirectoryName(ProjectFilePath); if (!Path.IsPathRooted(xamlFile)) { xamlFile = Path.Combine(Path.GetDirectoryName(ProjectFilePath), xamlFile); } xamlFile = Path.GetFullPath(xamlFile); var sourceXmlFile = xamlFile; if (!File.Exists(sourceXmlFile)) { return; } var relativePath = Paths.MakeRelativeToFolder(sourceXmlFile, projectSourceFolder); relativePath = relativePath.Replace("..", "parent"); var destinationHtmlFile = Path.Combine(ProjectDestinationFolder, relativePath) + ".html"; var xamlSupport = new XamlSupport(this); xamlSupport.GenerateXaml(sourceXmlFile, destinationHtmlFile, relativePath); OtherFiles.Add(relativePath); AddDeclaredSymbolToRedirectMap(SymbolIDToListOfLocationsMap, SymbolIdService.GetId(relativePath), relativePath, 0); }
private static string GetAssemblyFromSymbol(ISymbol symbol) { ITypeSymbol type = (ITypeSymbol)GetTypeFromSymbol(symbol); string metadataName = type.MetadataName; if (type.ContainingNamespace != null) { var namespaceName = type.ContainingNamespace.ToDisplayString(QualifiedNameOnlyFormat); if (!string.IsNullOrEmpty(namespaceName)) { metadataName = namespaceName + "." + metadataName; } } var forwardedTo = symbol.ContainingAssembly.ResolveForwardedType(metadataName); if (forwardedTo != null) { symbol = forwardedTo; } var assembly = SymbolIdService.GetAssemblyId(symbol.ContainingAssembly); return(assembly); }
public void GenerateBaseMembers() { Log.Write("Base members..."); var assemblyReferencesDataFolder = Path.Combine( this.SolutionGenerator.SolutionDestinationFolder, this.AssemblyName, Constants.ReferencesFileName); Directory.CreateDirectory(assemblyReferencesDataFolder); lock (this.BaseMembers) { var lines = new List <string>(this.BaseMembers.Count); foreach (var kvp in this.BaseMembers.OrderBy(b => SymbolIdService.GetId(b.Key))) { var fromMemberId = SymbolIdService.GetId(kvp.Key); var line = fromMemberId + ";" + SymbolIdService.GetAssemblyId(kvp.Value.ContainingAssembly) + ";" + SymbolIdService.GetId(kvp.Value); lines.Add(line); // just make sure the references file for this symbol exists, so that even if symbols // that aren't referenced anywhere get a reference file with a base member link if there // is a base member for the symbol var referencesFile = Path.Combine(assemblyReferencesDataFolder, fromMemberId + ".txt"); File.AppendAllText(referencesFile, ""); } var fileName = Path.Combine(ProjectDestinationFolder, Constants.BaseMembersFileName + ".txt"); File.WriteAllLines(fileName, lines); } }
public HtmlElementInfo GenerateHyperlinkToReferences(ISymbol symbol, bool isLargeFile = false) { string symbolId = SymbolIdService.GetId(symbol); string referencesFilePath = Path.Combine(ProjectDestinationFolder, Constants.ReferencesFileName, symbolId + ".html"); string href = Paths.MakeRelativeToFile(referencesFilePath, documentDestinationFilePath); href = href.Replace('\\', '/'); var result = new HtmlElementInfo { Name = "a", Attributes = { ["id"] = symbolId, ["href"] = href, ["target"] = "n", }, DeclaredSymbol = symbol, DeclaredSymbolId = symbolId }; if (!isLargeFile) { var dataGlyph = string.Format("{0},{1}", SymbolIdService.GetGlyphNumber(symbol), GetSymbolDepth(symbol)); result.Attributes.Add("data-glyph", dataGlyph); } return(result); }
public DeclaredSymbolInfo(ISymbol symbol, string assemblyName = null) { ID = SymbolIdService.GetIdULong(symbol); Name = SymbolIdService.GetName(symbol); Kind = SymbolKindText.GetSymbolKind(symbol); Description = SymbolIdService.GetDisplayString(symbol); Glyph = SymbolIdService.GetGlyphNumber(symbol); AssemblyName = assemblyName; }
private void GenerateProjectFile() { var projectExtension = Path.GetExtension(ProjectFilePath); if (!File.Exists(ProjectFilePath) || ".dll".Equals(projectExtension, StringComparison.OrdinalIgnoreCase) || ".winmd".Equals(projectExtension, StringComparison.OrdinalIgnoreCase)) { return; } ProjectCollection projectCollection = null; try { var title = Path.GetFileName(ProjectFilePath); var destinationFileName = Path.Combine(ProjectDestinationFolder, title) + ".html"; AddDeclaredSymbolToRedirectMap(SymbolIDToListOfLocationsMap, SymbolIdService.GetId(title), title, 0); // ProjectCollection caches the environment variables it reads at startup // and doesn't re-get them later. We need a new project collection to read // the latest set of environment variables. projectCollection = new ProjectCollection(); this.msbuildProject = new Project( ProjectFilePath, null, null, projectCollection, ProjectLoadSettings.IgnoreMissingImports); var msbuildSupport = new MSBuildSupport(this); msbuildSupport.Generate(ProjectFilePath, destinationFileName, msbuildProject, true); GenerateXmlFiles(msbuildProject); GenerateXamlFiles(msbuildProject); GenerateResxFiles(msbuildProject); GenerateTypeScriptFiles(msbuildProject); OtherFiles.Add(title); } catch (Exception ex) { Log.Exception("Exception during Project file generation: " + ProjectFilePath + "\r\n" + ex.ToString()); } finally { if (projectCollection != null) { projectCollection.UnloadAllProjects(); projectCollection.Dispose(); } } }
private void AddFileToRedirectMap(string filePath) { lock (SymbolIDToListOfLocationsMap) { SymbolIDToListOfLocationsMap.Add( SymbolIdService.GetId(filePath), new List <Tuple <string, long> > { Tuple.Create(filePath, 0L) }); } }
public HtmlElementInfo GenerateHyperlink( ISymbol symbol, string symbolId, SyntaxTree syntaxTree, out string assemblyName) { string href = null; assemblyName = SymbolIdService.GetAssemblyId(GetAssemblyFromSymbol(symbol)); // if it's in a different assembly, use the URL to a redirecting file for that assembly if (assemblyName != Document.Project.AssemblyName) { href = GetAbsoluteLink(symbolId, assemblyName); } else // it's in the same assembly, we can just use the direct path without redirects { string referencedSymbolDestinationFilePath = null; if (symbol.Locations.Length > 1) { referencedSymbolDestinationFilePath = Path.Combine( SolutionDestinationFolder, assemblyName, Constants.PartialResolvingFileName, symbolId); } else { var referenceRelativeFilePath = Paths.GetRelativePathInProject(syntaxTree, Document.Project); referencedSymbolDestinationFilePath = Path.Combine(projectGenerator.ProjectDestinationFolder, referenceRelativeFilePath); } href = Paths.MakeRelativeToFile(referencedSymbolDestinationFilePath, documentDestinationFilePath) + ".html"; if (referencedSymbolDestinationFilePath + ".html" == documentDestinationFilePath) { href = ""; } else { href = href.Replace('\\', '/'); } href = href + "#" + symbolId; } return(new HtmlElementInfo { Name = "a", Attributes = { { "href", href }, } }); }
private void GenerateXmlFile(string filePath) { if (File.Exists(filePath = NormalizeFilePath(filePath))) { var relativePath = AddOtherFileRelativeToProject(filePath); var destinationHtmlFile = Path.Combine(ProjectDestinationFolder, relativePath) + ".html"; new XmlSupport(this).Generate(filePath, destinationHtmlFile, relativePath); AddDeclaredSymbolToRedirectMap(SymbolIDToListOfLocationsMap, SymbolIdService.GetId(relativePath), relativePath, 0); } }
private string GetProjectDestinationPath(Project project, string solutionDestinationPath) { var assemblyName = project.AssemblyName; if (assemblyName == "<Error>") { return(null); } AssemblyName = SymbolIdService.GetAssemblyId(assemblyName); string subfolder = Path.Combine(solutionDestinationPath, AssemblyName); return(subfolder); }
public static IEnumerable <string> GetReferencePaths(IAssemblySymbol assemblySymbol) { foreach (var referenceIdentity in GetReferences(assemblySymbol)) { var resolved = Resolve(referenceIdentity.Name); if (!string.IsNullOrEmpty(resolved)) { yield return(resolved); } else { Log.Message(SymbolIdService.GetAssemblyId(assemblySymbol) + " references an assembly that cannot be resolved: " + referenceIdentity.Name); } } }
private static string GetSymbolName(ISymbol symbol, string symbolId) { string symbolName = null; if (symbol != null) { symbolName = SymbolIdService.GetName(symbol); if (symbolName == ".ctor") { symbolName = SymbolIdService.GetName(symbol.ContainingType) + " .ctor"; } } else { symbolName = symbolId; } return(symbolName); }
private string GetAssemblyFromSymbol(ISymbol symbol) { ITypeSymbol type = (ITypeSymbol)GetTypeFromSymbol(symbol); string metadataName = type.MetadataName; if (type.ContainingNamespace != null) { var namespaceName = type.ContainingNamespace.ToDisplayString(QualifiedNameOnlyFormat); if (!string.IsNullOrEmpty(namespaceName)) { metadataName = namespaceName + "." + metadataName; } } var forwardedTo = symbol.ContainingAssembly.ResolveForwardedType(metadataName); if (forwardedTo != null) { symbol = forwardedTo; } type = (ITypeSymbol)GetTypeFromSymbol(symbol); var forwardKey = ValueTuple.Create(type.ContainingAssembly.Name, (type?.OriginalDefinition ?? type).GetDocumentationCommentId()); string forwardedToAssembly; if (projectGenerator.SolutionGenerator.TypeForwards.TryGetValue(forwardKey, out forwardedToAssembly)) { lock (projectGenerator.ForwardedReferenceAssemblies) { projectGenerator.ForwardedReferenceAssemblies.Add( type.ContainingAssembly.Name + "->" + forwardedToAssembly); } return(forwardedToAssembly); } var assembly = SymbolIdService.GetAssemblyId(symbol.ContainingAssembly); return(assembly); }
private HtmlElementInfo TryProcessPartialKeyword(INamedTypeSymbol symbol) { if (symbol.Locations.Length > 1) { string symbolId = SymbolIdService.GetId(symbol); string partialFilePath = Path.Combine(ProjectDestinationFolder, Constants.PartialResolvingFileName, symbolId + ".html"); string href = Paths.MakeRelativeToFile(partialFilePath, documentDestinationFilePath); href = href.Replace('\\', '/'); var result = new HtmlElementInfo() { Name = "a", Attributes = { { "href", href }, { "target", "s" }, } }; return(result); } return(null); }
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 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 void Diagnostics(ClassifiedSpan classifiedSpan, SyntaxToken token, ISymbol symbol) { var tokenText = token.ToString(); if (!(symbol is INamedTypeSymbol) || classifiedSpan.ClassificationType == "t" || tokenText == "this" || tokenText == "base" || tokenText == "var") { return; } if (tokenText == "SR" || tokenText == "SR2" || tokenText == "SRID" || tokenText == "Strings" || tokenText == "Res" || tokenText == "VisualStudioVersionInfo" || tokenText == "Error" || tokenText == "Resource" || tokenText == "Resources" || tokenText == "AssemblyRef" || tokenText == "ProjectResources") { return; } var symbolDisplayString = SymbolIdService.GetDisplayString(symbol); if (symbolDisplayString == "System.SR" || symbolDisplayString == "System.Web.SR" || symbolDisplayString == "ThisAssembly") { return; } if (!reportedSymbolDisplayStrings.Add(symbolDisplayString)) { return; } if (reportedDiagnostics) { return; } reportedDiagnostics = true; string message = this.documentDestinationFilePath + "\r\n" + token.ToString() + ", " + token.Span.Start + "\r\n" + (classifiedSpan.ClassificationType ?? "null classification type") + "\r\n" + symbolDisplayString; var diagnostics = this.SemanticModel.GetDiagnostics().Where(d => { var diagnostic = d.GetMessage(); if (diagnostic.Contains("The type or namespace name 'Resources'") || diagnostic.Contains("must declare a body because it is not marked abstract")) { return(false); } return(true); }); if (diagnostics.Any()) { var diagnosticsMessage = string.Join("\r\n", diagnostics.Select(d => d.ToString())); message = message + "\r\n" + diagnosticsMessage; } Log.Exception("Classification: " + message); }
private string ProcessAttributeValue(ClassifiedRange range, string text, bool isRootProject) { var node = range.Node; var attributeSyntax = node.GetParent(2) as XmlAttributeSyntax; if (attributeSyntax != null) { var parentElement = attributeSyntax.ParentElement; if (parentElement?.Name == "Output" && (attributeSyntax.Name == "ItemName" || attributeSyntax.Name == "PropertyName") && !text.Contains("%")) { if (attributeSyntax.Name == "ItemName") { return(ProcessItemName( range.LineText, range.LineNumber + 1, range.Column, text, isRootProject, isUsage: false)); } else { return(ProcessPropertyName( range.LineText, range.LineNumber + 1, range.Column, text, isRootProject, isUsage: false)); } } if (parentElement?.Name == "Target") { if (attributeSyntax.Name == "Name") { return(ProcessTargetName( range.LineText, range.LineNumber + 1, range.Column, text, isRootProject, isUsage: false)); } if (attributeSyntax.Name == "DependsOnTargets" || attributeSyntax.Name == "BeforeTargets" || attributeSyntax.Name == "AfterTargets") { return(ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList)); } } if (parentElement?.Name == "CallTarget" && attributeSyntax.Name == "Targets") { return(ProcessExpressions(range, text, isRootProject, ProcessSemicolonSeparatedList)); } if (parentElement?.Name == "UsingTask" && attributeSyntax.Name == "TaskName") { var taskName = attributeSyntax.Value; var assemblyFileAttribute = parentElement.Attributes.FirstOrDefault(a => a.Name == "AssemblyFile"); var assemblyNameAttribute = parentElement.Attributes.FirstOrDefault(a => a.Name == "AssemblyName"); string assemblyName = null; if (assemblyFileAttribute != null && !string.IsNullOrWhiteSpace(assemblyFileAttribute.Value)) { var assemblyFilePath = assemblyFileAttribute.Value; assemblyFilePath = project.ExpandString(assemblyFilePath); assemblyName = Path.GetFileNameWithoutExtension(assemblyFilePath); } else if (assemblyNameAttribute != null && !string.IsNullOrWhiteSpace(assemblyNameAttribute.Value)) { assemblyName = assemblyNameAttribute.Value; assemblyName = project.ExpandString(assemblyName); int comma = assemblyName.IndexOf(','); if (comma > -1) { assemblyName = assemblyName.Substring(0, comma); } } if (assemblyName != null) { var symbolId = SymbolIdService.GetId("T:" + taskName); ProjectGenerator.AddReference( destinationHtmlFilePath, range.LineText, range.Column, taskName.Length, range.LineNumber, isRootProject ? ProjectGenerator.AssemblyName : Constants.MSBuildFiles, assemblyName, null, symbolId, ReferenceKind.Instantiation); var url = string.Format("/{0}/A.html#{1}", assemblyName, symbolId); var result = string.Format("<a href=\"{0}\" class=\"msbuildlink\">{1}</a>", url, text); return(result); } } } return(ProcessExpressions(range, text, isRootProject)); }
public async Task Generate() { if (Configuration.CalculateRoslynSemantics) { this.Text = await Document.GetTextAsync(); this.Root = await Document.GetSyntaxRootAsync(); this.SemanticModel = await Document.GetSemanticModelAsync(); this.SemanticFactsService = WorkspaceHacks.GetSemanticFactsService(this.Document); this.SyntaxFactsService = WorkspaceHacks.GetSyntaxFactsService(this.Document); var semanticFactsServiceType = SemanticFactsService.GetType(); var isWrittenTo = semanticFactsServiceType.GetMethod("IsWrittenTo"); this.isWrittenToDelegate = (Func <SemanticModel, SyntaxNode, CancellationToken, bool>) Delegate.CreateDelegate(typeof(Func <SemanticModel, SyntaxNode, CancellationToken, bool>), SemanticFactsService, isWrittenTo); var syntaxFactsServiceType = SyntaxFactsService.GetType(); var getBindableParent = syntaxFactsServiceType.GetMethod("GetBindableParent"); this.getBindableParentDelegate = (Func <SyntaxToken, SyntaxNode>) Delegate.CreateDelegate(typeof(Func <SyntaxToken, SyntaxNode>), SyntaxFactsService, getBindableParent); this.DeclaredSymbols = new HashSet <ISymbol>(); Interlocked.Increment(ref projectGenerator.DocumentCount); Interlocked.Add(ref projectGenerator.LinesOfCode, Text.Lines.Count); Interlocked.Add(ref projectGenerator.BytesOfCode, Text.Length); } CalculateDocumentDestinationPath(); CalculateRelativePathToRoot(); // add the file itself as a "declared symbol", so that clicking on document in search // results redirects to the document ProjectGenerator.AddDeclaredSymbolToRedirectMap( this.projectGenerator.SymbolIDToListOfLocationsMap, SymbolIdService.GetId(this.Document), documentRelativeFilePathWithoutHtmlExtension, 0); if (File.Exists(documentDestinationFilePath)) { // someone already generated this file, likely a shared linked file from elsewhere return; } this.classifier = new Classification(); Log.Write(documentDestinationFilePath); try { var directoryName = Path.GetDirectoryName(documentDestinationFilePath); var sanitized = Paths.SanitizeFolder(directoryName); if (directoryName != sanitized) { Log.Exception("Illegal characters in path: " + directoryName + " Project: " + this.projectGenerator.AssemblyName); } if (Configuration.CreateFoldersOnDisk) { Directory.CreateDirectory(directoryName); } } catch (PathTooLongException) { // there's one case where a path is too long - we don't care enough about it return; } if (Configuration.WriteDocumentsToDisk) { using (var streamWriter = new StreamWriter( documentDestinationFilePath, append: false, encoding: Encoding.UTF8)) { await GenerateHtml(streamWriter); } } else { using (var memoryStream = new MemoryStream()) using (var streamWriter = new StreamWriter(memoryStream)) { await GeneratePre(streamWriter); } } }
private HtmlElementInfo GenerateLinks(ClassifiedRange range, string destinationHtmlFilePath, Dictionary <string, int> localSymbolIdMap) { HtmlElementInfo result = null; var localRelativePath = destinationHtmlFilePath.Substring( Path.Combine( Paths.SolutionDestinationFolder, Constants.TypeScriptFiles).Length); if (!string.IsNullOrEmpty(range.definitionSymbolId)) { var definitionSymbolId = SymbolIdService.GetId(range.definitionSymbolId); if (range.IsSymbolLocalOnly()) { var localId = GetLocalId(definitionSymbolId, localSymbolIdMap); result = new HtmlElementInfo { Name = "span", Attributes = { { "id", "r" + localId + " rd" }, { "class", "r" + localId + " r" } } }; return(result); } result = new HtmlElementInfo { Name = "a", Attributes = { { "id", definitionSymbolId }, { "href", "/TypeScriptFiles/" + Constants.ReferencesFileName + "/" + definitionSymbolId + ".html" }, { "target", "n" } } }; var searchString = range.searchString; if (!string.IsNullOrEmpty(searchString) && searchString.Length > 2) { lock (declarations) { searchString = searchString.StripQuotes(); if (IsWellFormed(searchString)) { var declaration = string.Join(";", searchString, // symbol name definitionSymbolId, // 8-byte symbol ID range.definitionKind, // kind (e.g. "class") Markup.EscapeSemicolons(range.fullName), // symbol full name and signature GetGlyph(range.definitionKind) // glyph number ); declarations.Add(declaration); } } } } if (range.hyperlinks == null || range.hyperlinks.Length == 0) { return(result); } var hyperlink = range.hyperlinks[0]; var symbolId = SymbolIdService.GetId(hyperlink.symbolId); if (range.IsSymbolLocalOnly() || localSymbolIdMap.ContainsKey(symbolId)) { var localId = GetLocalId(symbolId, localSymbolIdMap); result = new HtmlElementInfo { Name = "span", Attributes = { { "class", "r" + localId + " r" } } }; return(result); } var hyperlinkDestinationFile = Path.GetFullPath(hyperlink.sourceFile); hyperlinkDestinationFile = GetDestinationFilePath(hyperlinkDestinationFile); string href = ""; if (!string.Equals(hyperlinkDestinationFile, destinationHtmlFilePath, StringComparison.OrdinalIgnoreCase)) { href = Paths.MakeRelativeToFile(hyperlinkDestinationFile, destinationHtmlFilePath); href = href.Replace('\\', '/'); } href = href + "#" + symbolId; if (result == null) { result = new HtmlElementInfo { Name = "a", Attributes = { { "href", href }, { "target", "s" }, } }; } else if (!result.Attributes.ContainsKey("href")) { result.Attributes.Add("href", href); result.Attributes.Add("target", "s"); } lock (this.references) { var lineNumber = range.lineNumber + 1; var linkToReference = ".." + localRelativePath + "#" + lineNumber.ToString(); var start = range.column; var end = range.column + range.text.Length; var lineText = Markup.HtmlEscape(range.lineText, ref start, ref end); var reference = new Reference { FromAssemblyId = Constants.TypeScriptFiles, ToAssemblyId = Constants.TypeScriptFiles, FromLocalPath = localRelativePath.Substring(0, localRelativePath.Length - ".html".Length).Replace('\\', '/'), Kind = ReferenceKind.Reference, ToSymbolId = symbolId, ToSymbolName = range.text, ReferenceLineNumber = lineNumber, ReferenceLineText = lineText, ReferenceColumnStart = start, ReferenceColumnEnd = end, Url = linkToReference.Replace('\\', '/') }; if (!references.TryGetValue(symbolId, out List <Reference> bucket)) { bucket = new List <Reference>(); references.Add(symbolId, bucket); } bucket.Add(reference); } return(result); }