Documentation ¶
Index ¶
- Constants
- Variables
- func IsContainer(symbolKind SymbolKind) bool
- func IsNotExist(err error) bool
- func RegisterMakeSymbolFormatter(unitType string, f MakeSymbolFormatter)
- func UniqueRefSymbols(refs []*Ref, m map[RefSymbolKey]int) map[RefSymbolKey]int
- type Doc
- type DocPage
- type DocPageKey
- type Docs
- type GoInterfaceMethod
- type MakeSymbolFormatter
- type Propagate
- type Qualification
- type Ref
- type RefKey
- type RefSet
- type RefSymbolKey
- type Refs
- type RepositoryListingSymbol
- type SID
- type StatType
- type Stats
- type Symbol
- type SymbolFormatter
- type SymbolKey
- type SymbolKind
- type SymbolPath
- type SymbolPrintFormatter
- type Symbols
- type TreePath
Constants ¶
const ( // An Unqualified name is just the symbol's name. // // Examples: // // Go method `MyMethod` // Python method `my_method` // JavaScript method `myMethod` Unqualified Qualification = "" // A ScopeQualified name is the language-specific description of the // symbol's defining scope plus the symbol's unqualified name. It should // uniquely describe the symbol among all other symbols defined in the same // logical package (but this is not strictly defined or enforced). // // Examples: // // Go method `(*MyType).MyMethod` // Python method `MyClass.my_method` // JavaScript method `MyConstructor.prototype.myMethod` ScopeQualified = "scope" // A DepQualified name is the package/module name (as seen by an external // library that imports/depends on the symbol's package/module) plus the // symbol's scope-qualified name. If there are nested packages, it should // describe enough of the package hierarchy to distinguish it from other // similarly named symbols (but this is not strictly defined or enforced). // // Examples: // // Go method `(*mypkg.MyType).MyMethod` // Python method `mypkg.MyClass.my_method` // CommonJS method `mymodule.MyConstructor.prototype.myMethod` DepQualified = "dep" // A RepositoryWideQualified name is the full package/module name(s) plus // the symbol's scope-qualified name. It should describe enough of the // package hierarchy so that it is unique in its repository. // RepositoryWideQualified differs from DepQualified in that the former // includes the full nested package/module path from the repository root // (e.g., 'a/b.C' for a Go func C in the repository 'github.com/user/a' // subdirectory 'b'), while DepQualified would only be the last directory // component (e.g., 'b.C' in that example). // // Examples: // // Go method `(*mypkg/subpkg.MyType).MyMethod` // Python method `mypkg.subpkg.MyClass.my_method` (unless mypkg =~ subpkg) // CommonJS method `mypkg.mymodule.MyConstructor.prototype.myMethod` (unless mypkg =~ mymodule) RepositoryWideQualified = "repo-wide" // A LanguageWideQualified name is the library/repository name plus the // package-qualified symbol name. It should describe the symbol so that it // is logically unique among all symbols that could reasonably exist for the // language that the symbol is written in (but this is not strictly defined // or enforced). // // Examples: // // Go method `(*github.com/user/repo/mypkg.MyType).MyMethod` // Python method `mylib.MyClass.my_method` (if mylib =~ mypkg, as for Django, etc.) // CommonJS method `mylib.MyConstructor.prototype.myMethod` (if mylib =~ mymod, as for caolan/async, etc.) LanguageWideQualified = "lang-wide" )
const ( // StatXRefs is the number of external references to a symbol (i.e., // references from other repositories). It is only computed for abstract // symbols (see the docs for SymbolKey) because it is not easy to determine // which specific commit a ref references (for external refs). StatXRefs = "xrefs" // StatRRefs is the number of references to a symbol from the same // repository in which the symbol is defined. It is inclusive of the // StatURefs count. It is only computed for concrete symbols (see the docs // for SymbolKey) because otherwise it would count 1 rref for each unique // revision of the repository that we have processed. (It is easy to // determine which specific commit an internal ref references; we just // assume it references a symbol in the same commit.) StatRRefs = "rrefs" // StatURefs is the number of references to a symbol from the same source // unit in which the symbol is defined. It is included in the StatRRefs // count. It is only computed for concrete symbols (see the docs for // SymbolKey) because otherwise it would count 1 uref for each revision of // the repository that we have processed. StatURefs = "urefs" // StatAuthors is the number of distinct resolved people who contributed // code to a symbol's definition (according to a VCS "blame" of the // version). It is only computed for concrete symbols (see the docs for // SymbolKey). StatAuthors = "authors" // StatClients is the number of distinct resolved people who have committed // refs that reference a symbol. It is only computed for abstract symbols // (see the docs for SymbolKey) because it is not easy to determine which // specific commit a ref references. StatClients = "clients" // StatDependents is the number of distinct repositories that contain refs // that reference a symbol. It is only computed for abstract symbols (see // the docs for SymbolKey) because it is not easy to determine which // specific commit a ref references. StatDependents = "dependents" // StatExportedElements is the number of exported symbols whose path is a // descendant of this symbol's path (and that is in the same repository and // source unit). It is only computed for concrete symbols (see the docs for // SymbolKey) because otherwise it would count 1 exported element for each // revision of the repository that we have processed. StatExportedElements = "exported_elements" // StatInterfaces is the number of interfaces that a symbol implements (in // its own repository or other repositories). TODO(sqs): it is not currently // being computed. StatInterfaces = "interfaces" // StatImplementations is the number of implementations of an interface // symbol (in its own repository or other repositories). TODO(sqs): it is // not currently being computed. StatImplementations = "implementations" )
const ( Const SymbolKind = "const" Field = "field" Func = "func" Module = "module" Package = "package" Type = "type" Var = "var" )
Variables ¶
var AllStatTypes = []StatType{StatXRefs, StatRRefs, StatURefs, StatAuthors, StatClients, StatDependents, StatExportedElements, StatInterfaces, StatImplementations}
var AllSymbolKinds = []SymbolKind{Const, Field, Func, Module, Package, Type, Var}
var ErrSymbolNotExist = errors.New("symbol does not exist")
var MakeSymbolFormatters = make(map[string]MakeSymbolFormatter)
MakeSymbolFormatter holds MakeSymbolFormatters that toolchains have registered with RegisterMakeSymbolFormatter.
Functions ¶
func IsContainer ¶
func IsContainer(symbolKind SymbolKind) bool
func IsNotExist ¶
func RegisterMakeSymbolFormatter ¶
func RegisterMakeSymbolFormatter(unitType string, f MakeSymbolFormatter)
RegisterMakeSymbolFormatter makes a SymbolFormatter constructor function (MakeSymbolFormatter) available for symbols with the specified unitType. If Register is called twice with the same unitType or if sf is nil, it panics
func UniqueRefSymbols ¶
func UniqueRefSymbols(refs []*Ref, m map[RefSymbolKey]int) map[RefSymbolKey]int
UniqueRefSymbols groups refs by the RefSymbolKey field and returns a map of how often each RefSymbolKey appears. If m is non-nil, counts are incremented and a new map is not created.
Types ¶
type DocPage ¶
type DocPage struct { DocPageKey // Note: the contents of these fields is unsanitized. Any sanitization should be done in the UI. Title string // Doc title Body string // HTML tags with the data-sg-doc-symbol attribute will be linked to symbol pages and vice-versa in the UI Toc string // Table of contents in conjunction (in sidebar) with body SymbolPaths *db_common.StringSlice // symbols within the scope of this documentation page }
type DocPageKey ¶
type GoInterfaceMethod ¶
type GoInterfaceMethod struct { // OfSymbolPath refers to the Go interface symbol that defines this method, or the Go // type symbol that implements this method. OfSymbolPath SymbolPath `db:"of_symbol_path"` // OfSymbolUnit refers to the unit containing the symbol denoted in OfSymbolPath. OfSymbolUnit string `db:"of_symbol_unit"` // Repo refers to the repository in which this method was defined. Repo repo.URI // Key is the canonical signature of the method for the implements // operation. If a type's methods' keys are a superset of an interface's, // then the type implements the interface. CanonicalSignature string `db:"canonical_signature"` // Name is the method's name. Name string }
GoInterfaceMethod represents a Go interface method defined by an Go interface symbol or implemented by a Go type symbol. It is used for finding all implementations of an interface.
type MakeSymbolFormatter ¶
type MakeSymbolFormatter func(*Symbol) SymbolFormatter
A MakeSymbolFormatter is a function, typically implemented by toolchains, that creates a SymbolFormatter for a symbol.
type Propagate ¶
type Propagate struct { // Src is the symbol whose type/value is being propagated to the dst symbol. SrcRepo repo.URI SrcPath SymbolPath SrcUnit string SrcUnitType string // Dst is the symbol that is receiving a propagated type/value from the src symbol. DstRepo repo.URI DstPath SymbolPath DstUnit string DstUnitType string }
Propagate describes type/value propagation in code. A Propagate entry from A (src) to B (dst) indicates that the type/value of A propagates to B. In Tern, this is indicated by A having a "fwd" property whose value is an array that includes B.
## Motivation & example
For example, consider the following JavaScript code:
var a = Foo; var b = a;
Foo, a, and b are each their own symbol. We could resolve all of them to the symbol of their original type (perhaps Foo), but there are occasions when you do want to see only the definition of a or b and examples thereof. Therefore, we need to represent them as distinct symbols.
Even though Foo, a, and b are distinct symbols, there are propagation relationships between them that are important to represent. The type of Foo propagates to both a and b, and the type of a propagates to b. In this case, we would have 3 Propagates: Propagate{Src: "Foo", Dst: "a"}, Propagate{Src: "Foo", Dst: "b"}, and Propagate{Src: "a", Dst: "b"}. (The propagation relationships could be described by just the first and last Propagates, but we explicitly include all paths as a denormalization optimization to avoid requiring an unbounded number of DB queries to determine which symbols a type propagates to or from.)
## Directionality
Propagation is unidirectional, in the general case. In the example above, if Foo referred to a JavaScript object and if the code were evaluated, any *runtime* type changes (e.g., setting a property) on Foo, a, and b would be reflected on all of the others. But this doesn't hold for static analysis; it's not always true that if a property "a.x" or "b.x" exists, then "Foo.x" exists. The simplest example is when Foo is an external definition. Perhaps this example file (which uses Foo as a library) modifies Foo to add a new property, but other libraries that use Foo would never see that property because they wouldn't be executed in the same context as this example file. So, in general, we cannot say that Foo receives all types applied to symbols that Foo propagates to.
## Hypothetical Python example
Consider the following 2 Python files:
"""file1.py""" class Foo(object): end """file2.py""" from .file1 import Foo Foo2 = Foo
In this example, there would be one Propagate: Propagate{Src: "file1/Foo", Dst: "file2/Foo2}.
type Qualification ¶
type Qualification string
A Qualification specifies how much to qualify names when formatting symbols and their type information.
type Ref ¶
type Ref struct { SymbolRepo repo.URI `db:"symbol_repo"` SymbolUnitType string `db:"symbol_unit_type"` SymbolUnit string `db:"symbol_unit"` SymbolPath SymbolPath `db:"symbol_path"` // Def is true if this ref is to a definition of the target symbol. Def bool Repo repo.URI // CommitID is the immutable commit ID (not the branch name) of the VCS // revision that this ref was found in. CommitID string `db:"commit_id" json:",omitempty"` UnitType string `db:"unit_type" json:",omitempty"` Unit string `json:",omitempty"` File string Start int End int }
Ref represents a reference from source code to a symbol.
func (*Ref) RefSymbolKey ¶
func (r *Ref) RefSymbolKey() RefSymbolKey
func (*Ref) SetFromSymbolKey ¶
type RefKey ¶
type RefKey struct { SymbolRepo repo.URI `db:"symbol_repo" json:",omitempty"` SymbolUnitType string `db:"symbol_unit_type" json:",omitempty"` SymbolUnit string `db:"symbol_unit" json:",omitempty"` SymbolPath SymbolPath `db:"symbol_path" json:",omitempty"` Def bool `json:",omitempty"` Repo repo.URI `json:",omitempty"` UnitType string `db:"unit_type" json:",omitempty"` Unit string `json:",omitempty"` File string `json:",omitempty"` CommitID string `db:"commit_id" json:",omitempty"` Start int `json:",omitempty"` End int `json:",omitempty"` }
func (*RefKey) RefSymbolKey ¶
func (r *RefKey) RefSymbolKey() RefSymbolKey
type RefSet ¶
type RefSet struct {
// contains filtered or unexported fields
}
RefSet is a set of Refs. It can used to determine whether a grapher emits duplicate refs.
func (*RefSet) AddAndCheckUnique ¶
AddAndCheckUnique adds ref to the set of seen refs, and returns whether the ref already existed in the set.
type RefSymbolKey ¶
type RefSymbolKey struct { SymbolRepo repo.URI `db:"symbol_repo" json:",omitempty"` SymbolUnitType string `db:"symbol_unit_type" json:",omitempty"` SymbolUnit string `db:"symbol_unit" json:",omitempty"` SymbolPath SymbolPath `db:"symbol_path" json:",omitempty"` }
type RepositoryListingSymbol ¶
type RepositoryListingSymbol struct { // Name is the full name shown on the page. Name string // NameLabel is a label displayed next to the Name, such as "(main package)" // to denote that a package is a Go main package. NameLabel string // Language is the source language of the symbol, with any additional // specifiers, such as "JavaScript (node.js)". Language string // SortKey is the key used to lexicographically sort all of the symbols on // the page. SortKey string }
RepositoryListingSymbol holds rendered display text to show on the "package" listing page of a repository.
type StatType ¶
type StatType string
StatType is the name of a symbol statistic (see below for a listing).
func (StatType) IsAbstract ¶
type Symbol ¶
type Symbol struct { // SID is a unique, sequential ID for a symbol. It is regenerated each time // the symbol is emitted by the grapher and saved to the database. The SID // is used as an optimization (e.g., joins are faster on SID than on // SymbolKey). SID SID `db:"sid" json:",omitempty" elastic:"type:integer,index:no"` // SymbolKey is the natural unique key for a symbol. It is stable // (subsequent runs of a grapher will emit the same symbols with the same // SymbolKeys). SymbolKey // TreePath is a structurally significant path descriptor for a symbol. For // many languages, it may be identical or similar to SymbolKey.Path. // However, it has the following constraints, which allow it to define a // symbol tree. // // A tree-path is a chain of '/'-delimited components. A component is either a // symbol name or a ghost component. // - A symbol name satifies the regex [^/-][^/]* // - A ghost component satisfies the regex -[^/]* // Any prefix of a tree-path that terminates in a symbol name must be a valid // tree-path for some symbol. // The following regex captures the children of a tree-path X: X(/-[^/]*)*(/[^/-][^/]*) TreePath TreePath `db:"treepath" json:",omitempty"` // Kind is the language-independent kind of this symbol. Kind SymbolKind `elastic:"type:string,index:analyzed"` Name string // Callable is true if this symbol may be called or invoked, such as in the // case of functions or methods. Callable bool `db:"callable"` File string `elastic:"type:string,index:no"` DefStart int `db:"def_start" elastic:"type:integer,index:no"` DefEnd int `db:"def_end" elastic:"type:integer,index:no"` Exported bool `elastic:"type:boolean,index:not_analyzed"` // Test is whether this symbol is defined in test code (as opposed to main // code). For example, definitions in Go *_test.go files have Test = true. Test bool `elastic:"type:boolean,index:not_analyzed" json:",omitempty"` // Data contains additional language- and toolchain-specific information // about the symbol. Data is used to construct function signatures, // import/require statements, language-specific type descriptions, etc. Data types.JsonText `json:",omitempty" elastic:"type:object,enabled:false"` }
func (*Symbol) Fmt ¶
func (s *Symbol) Fmt() SymbolPrintFormatter
func (*Symbol) HasImplementations ¶
HasImplementations returns true if this symbol is a Go interface and false otherwise. It is used for the interface implementations queries. TODO(sqs): run this through the golang toolchain instead of doing it here.
type SymbolFormatter ¶
type SymbolFormatter interface { // Name formats the symbol's name with the specified level of qualification. Name(qual Qualification) string // Type is the type of the symbol s, if s is not itself a type. If s is // itself a type, then Type returns its underlying type. // // Outputs: // // TYPE OF s RESULT // ------------ ----------------------------------------------------------------- // named type the named type's name // primitive the primitive's name // function `(arg1, arg2, ..., argN)` with language-specific type annotations // package empty // anon. type the leading keyword (or similar) of the anonymous type definition // // These rules are not strictly defined or enforced. Language toolchains // should freely bend the rules (after noting important exceptions here) to // produce sensible output. Type(qual Qualification) string // NameAndTypeSeparator is the string that should be inserted between the // symbol's name and type. This is typically empty for functions (so that // they are formatted with the left paren immediately following the name, // like `F(a)`) and a single space for other symbols (e.g., `MyVar string`). NameAndTypeSeparator() string // Language is the name of the programming language that s is in; e.g., // "Python" or "Go". Language() string // DefKeyword is the language keyword used to define the symbol (e.g., // 'class', 'type', 'func'). DefKeyword() string // Kind is the language-specific kind of this symbol (e.g., 'package', 'field', 'CommonJS module'). Kind() string }
SymbolFormatter formats a symbol.
type SymbolKey ¶
type SymbolKey struct { // Repo is the VCS repository that defines this symbol. Its Elasticsearch mapping is defined // separately. Repo repo.URI `json:",omitempty"` // CommitID is the ID of the VCS commit that this symbol was defined in. The // CommitID is always a full commit ID (40 hexadecimal characters for git // and hg), never a branch or tag name. CommitID string `db:"commit_id" json:",omitempty"` // UnitType is the type name of the source unit (obtained from unit.Type(u)) // that this symbol was defined in. UnitType string `db:"unit_type" json:",omitempty"` // Unit is the name of the source unit (obtained from u.Name()) that this // symbol was defined in. Unit string `json:",omitempty"` // Path is a unique identifier for the symbol, relative to the source unit. // It should remain stable across commits as long as the symbol is the // "same" symbol. Its Elasticsearch mapping is defined separately (because // it is a multi_field, which the struct tag can't currently represent). // // Path encodes no structural semantics. Its only meaning is to be a stable // unique identifier within a given source unit. In many languages, it is // convenient to use the namespace hierarchy (with some modifications) as // the Path, but this may not always be the case. I.e., don't rely on Path // to find parents or children or any other structural propreties of the // symbol hierarchy). See Symbol.TreePath instead. Path SymbolPath }
SymbolKey specifies a symbol, either concretely or abstractly. A concrete symbol key has a non-empty CommitID and refers to a symbol defined in a specific commit. An abstract symbol key has an empty CommitID and is considered to refer to symbols from any number of commits (so long as the Repo, UnitType, Unit, and Path match).
You can think of CommitID as the time dimension. With an empty CommitID, you are referring to a symbol that may or may not exist at various times. With a non-empty CommitID, you are referring to a specific definition of a symbol at the time specified by the CommitID.
type SymbolKind ¶
type SymbolKind string
func (*SymbolKind) Scan ¶
func (x *SymbolKind) Scan(v interface{}) error
func (SymbolKind) Valid ¶
func (k SymbolKind) Valid() bool
Returns true iff k is a known symbol kind.
type SymbolPath ¶
type SymbolPath string
func (*SymbolPath) Scan ¶
func (x *SymbolPath) Scan(v interface{}) error
type SymbolPrintFormatter ¶
type SymbolPrintFormatter interface { SymbolFormatter fmt.Formatter }
func PrintFormatter ¶
func PrintFormatter(s *Symbol) SymbolPrintFormatter
Formatter creates a string formatter for a symbol.
The verbs:
%n qualified name %w language keyword used to define the symbol (e.g., 'class', 'type', 'func') %k language-specific kind of this symbol (e.g., 'package', 'field', 'CommonJS module') %t type
The flags:
' ' (in `% t`) prepend the language-specific delimiter between a symbol's name and type
See SymbolFormatter for more information.