Copyright 2017 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package render

import (
	
	
	
	
	

	
	
	
)
This logic creates data structures needed to map some string (e.g., "io.EOF")to the package that contains those identifiers.
The identifierResolver.toHTML method is the primary API used by other logicin this package. The identifierResolver is essentially comprised of:
* packageIDs: a collection of top-level identifiers in the package being rendered and any related packages.
* declIDs: a collection of parameters related to the specific declaration being rendered. We collect declaration parameters because they provide a useful heuristic for further linking (e.g., "r.Read" can be linked if we know the type of r).
This logic is unused when doing non-HTML formatting.
forEachPackageDecl iterates though every top-level declaration in a package.
func ( *doc.Package,  func( ast.Decl)) {
	for ,  := range .Consts {
		(.Decl)
	}
	for ,  := range .Vars {
		(.Decl)
	}
	for ,  := range .Funcs {
		(.Decl)
	}
	for ,  := range .Types {
		(.Decl)
		for ,  := range .Consts {
			(.Decl)
		}
		for ,  := range .Vars {
			(.Decl)
		}
		for ,  := range .Funcs {
			(.Decl)
		}
		for ,  := range .Methods {
			(.Decl)
		}
	}
}
packageIDs is a collection of top-level package identifiers in the package being rendered and any related packages.
name is the name of the package being rendered. E.g., "json"
impPaths maps package names to their import paths. E.g., impPaths["json"] == "encoding/json"
	impPaths map[string]string // map[name]pkgPath
pkgIDs is the set of all top-level identifiers in this package and any related package. E.g., pkgIDs["json"]["Encoder.Encode"] == true
	pkgIDs map[string]map[string]bool // map[name]map[topLevelID]bool
topLevelDecls is the set of all AST declarations for the this package.
	topLevelDecls map[interface{}]bool // map[T]bool where T is *ast.FuncDecl | *ast.GenDecl | *ast.TypeSpec | *ast.ValueSpec
}
newPackageIDs returns a packageIDs that collects all top-level identifiers for the given package pkg and any related packages.
func ( *doc.Package,  ...*doc.Package) *packageIDs {
	 := &packageIDs{
		name:          .Name,
		impPaths:      make(map[string]string),
		pkgIDs:        make(map[string]map[string]bool),
		topLevelDecls: make(map[interface{}]bool),
	}
Collect top-level declaration IDs for pkg and related packages.
	for ,  := range append([]*doc.Package{}, ...) {
		if ,  := .pkgIDs[.Name];  {
			continue // package name conflicts, ignore this package
		}
		.impPaths[.Name] = .ImportPath
		.pkgIDs[.Name] = make(map[string]bool)
		forEachPackageDecl(, func( ast.Decl) {
			for ,  := range generateAnchorPoints() {
				.pkgIDs[.Name][.ID.String()] = true // E.g., ["io"]["Reader.Read"]
			}
		})
	}
Collect AST objects for accurate linking of Go source code.
	forEachPackageDecl(, func( ast.Decl) {
		.topLevelDecls[] = true
		if ,  := .(*ast.GenDecl);  != nil {
			for ,  := range .Specs {
				.topLevelDecls[] = true
			}
		}
	})
	return 
}
declIDs is a collection of identifiers that are related to the ast.Decl currently being processed. Using Decl-level variables allows us to provide greater accuracy in linking when comments refer to the variable names. For example, we can link "r.Read" to "io.Reader.Read" because we know that variable "r" is of type "io.Reader", which has a "Read" method.
recvType is the type of the receiver for any methods. E.g., "Reader"
paramTypes is a mapping of parameter names in a ast.FuncDecl to the type of that parameter. E.g., paramTypes["r"] == "io.Reader"
	paramTypes map[string]string // map[varName]typeName
}

func ( ast.Decl) *declIDs {
	 := &declIDs{paramTypes: make(map[string]string)}

	switch decl := .(type) {
Note that go/doc.New automatically splits type declaration blocks into individual specifications. If there are multiple, it okay to skip this logic, since all of this information is just to improve the heuristics of toHTML.
		if .Tok == token.TYPE && len(.Specs) == 1 {
			.recvType = .Specs[0].(*ast.TypeSpec).Name.String()
		}
Obtain receiver variable and type names.
		if .Recv != nil && len(.Recv.List) > 0 {
			 := .Recv.List[0]
			.recvType, _ = nodeName(.Type) // E.g., "Reader"
			if len(.Names) == 1 && .recvType != "" {
				,  := nodeName(.Names[0]) // E.g., "r"
				if  != "" {
					.paramTypes[] = .recvType
				}
			}
		}
Add mapping of variable names to types names for parameters and results.
		for ,  := range []*ast.FieldList{.Type.Params, .Type.Results} {
			if  == nil {
				continue
			}
			for ,  := range .List {
				,  := nodeName(.Type) // E.g., "context.Context"
				if  == "" {
					continue
				}
				for ,  := range .Names {
					,  := nodeName() // E.g., "ctx"
					if  != "" {
						.paramTypes[] = 
					}
				}
			}
		}
	}
	return 
}

type identifierResolver struct {
	*packageIDs
	*declIDs
packageURL is a function for producing URLs from package paths. E.g., packageURL("builtin") == "/pkg/builtin/index.html"
toURL returns a URL to locate the given package, and optionally a specific identifier in that package. The pkgPath may be empty, indicating that this is an anchor only URL. The id may be empty, indicating that this refers to the package itself.
func ( identifierResolver) (,  string) ( string) {
	if  != "" {
		 = "/" + 
		if .packageURL != nil {
			 = .packageURL()
		}
	}
	if  != "" {
		 += "#" + 
	}
	return 
}
toHTML formats a dot-delimited word as HTML with each ID segment converted to be a link to the relevant declaration.
extraSuffix is extra identifier segments that can't be matched probably because we lack type information.
	var  safehtml.HTML // E.g., ".Get" for an unknown Get method
	 := strings.Split(, ".")
Skip any standalone unexported identifier.
	if !isExported() && len() == 1 {
		return safehtml.HTMLEscaped()
	}
Generate variations on the original word.
	var  []string
	if ,  := .paramTypes[[0]];  {
		 = append(, +[len([0]):]) // E.g., "r.Read" => "io.Reader.Read"
	} else if .recvType != "" {
		 = append(, .recvType+"."+) // E.g., "Read" => "Reader.Read"
	}
	 = append(, )

	var  string
	for ,  := range  {
		if , ,  := .lookup();  {
			 =  // direct match
			goto 
		}
		if , ,  := .lookup(strings.TrimSuffix(, "s"));  {
			 = [:len()-len("s")] // E.g., "Caches" => "Cache"
			goto 
		}
		if , ,  := .lookup(strings.TrimSuffix(, "es"));  {
			 = [:len()-len("es")] // E.g., "Boxes" => "Box"
			goto 
		}
Repeatedly truncate the last segment, searching for a partial match.
		,  := len(), len()
		for  >= 0 &&  >= 0 {
			 := isExported([:]) || strings.Contains([:], ".")
			if , ,  := .lookup([:]);  &&  {
				 = [:]
				 = strings.Split([:], ".")
				 = safehtml.HTMLEscaped([:])
				goto 
			}
			 = strings.LastIndexByte([:], '.')
			 = strings.LastIndexByte([:], '.')
		}
	}
	return safehtml.HTMLEscaped() // no match found

altWord contains a modified dot-separated identifier. origIDs contains the segments of the original identifier. It is possible for Split(altWord, ".") to be longer than origIDs if an implicit type was prepended. E.g., altWord="io.Reader.Read", origIDs=["r", "Read"]
Skip past implicit prefix selectors. E.g., i=3, altWord[i:]="Reader.Read"
	var  int
	for strings.Count([:], ".")+1 != len() {
		 += strings.IndexByte([:], '.') + 1
	}

	var  []safehtml.HTML
Advance to the next segment in altWord. E.g., i=9, altWord[:i]="io.Reader", s="r" E.g., i=14, altWord[:i]="io.Reader.Read", s="Read"
		if  := strings.IndexByte([+1:], '.');  >= 0 {
			 += 1 + 
		} else {
			 = len()
		}

		, ,  := .lookup([:])
		 := .toURL(, )
		,  := LinkTemplate.ExecuteToHTML(Link{Href: , Text: })
		if  != nil {
			 = safehtml.HTMLEscaped("[" + .Error() + "]")
		}
		 = append(, )
		 = append(, safehtml.HTMLEscaped("."))
	}
	if len() == 0 {
		return 
Replace final dot with extraSuffix.
	[len()-1] = 
	return safehtml.HTMLConcat(...)
}
Link is the data passed to LinkTemplate.
type Link struct {
	Href, Text string
	Class      string // class for "a" tag; optional
}

var LinkTemplate = template.Must(template.New("link").Parse(
	`<a {{with .Class}}class="{{.}}" {{end}}href="{{.Href}}">{{.Text}}</a>`))
lookup looks up a dot-separated identifier. E.g., "pkg", "pkg.Var", "Recv.Method", "Struct.Field", "pkg.Struct.Field"
func ( identifierResolver) ( string) (,  string,  bool) {
	if .pkgIDs[.name][] {
		return "", , true // ID refers to local top-level declaration
	}
	if  := .impPaths[];  != "" {
		return , "", true // ID refers to a package
	}
	if  := strings.IndexByte(, '.');  >= 0 {
		,  := [:], [+1:]
		if .pkgIDs[][] {
			if  == .name {
				 = ""
			}
			return .impPaths[], , true // ID refers to a different package's top-level declaration
		}
	}
	return "", "", false // not found
}

func ( ast.Node) (string, *ast.Ident) {
	switch n := .(type) {
	case *ast.Ident:
		return .String(), 
	case *ast.StarExpr:
		return (.X)
	case *ast.SelectorExpr:
		if ,  := (.X);  != "" {
			return  + "." + .Sel.String(), .Sel
		}
		return .Sel.String(), .Sel
	default:
		return "", nil
	}
}

func ( string) bool {
	,  := utf8.DecodeRuneInString()
	return unicode.IsUpper()