diff --git a/.github/workflows/codeqltest.yml b/.github/workflows/codeqltest.yml index ab25e15dcab..0d9275a0f2e 100644 --- a/.github/workflows/codeqltest.yml +++ b/.github/workflows/codeqltest.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Set up Go 1.16 + - name: Set up Go 1.17 uses: actions/setup-go@v1 with: - go-version: 1.16 + go-version: 1.17 id: go - name: Set up CodeQL CLI @@ -20,7 +20,7 @@ jobs: echo "Done" cd $HOME echo "Downloading CodeQL CLI..." - LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -1) + LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | grep -v beta | tail -1) gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST" echo "Done" echo "Unpacking CodeQL CLI..." @@ -59,10 +59,10 @@ jobs: name: Test MacOS runs-on: macOS-latest steps: - - name: Set up Go 1.16 + - name: Set up Go 1.17 uses: actions/setup-go@v1 with: - go-version: 1.16 + go-version: 1.17 id: go - name: Set up CodeQL CLI @@ -72,7 +72,7 @@ jobs: echo "Done" cd $HOME echo "Downloading CodeQL CLI..." - LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -1) + LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | grep -v beta | tail -1) gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-osx64.zip "$LATEST" echo "Done" echo "Unpacking CodeQL CLI..." @@ -99,10 +99,10 @@ jobs: name: Test Windows runs-on: windows-latest steps: - - name: Set up Go 1.16 + - name: Set up Go 1.17 uses: actions/setup-go@v1 with: - go-version: 1.16 + go-version: 1.17 id: go - name: Set up CodeQL CLI @@ -112,7 +112,7 @@ jobs: echo "Done" cd "$HOME" echo "Downloading CodeQL CLI..." - LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -1) + LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | grep -v beta | tail -1) gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-win64.zip "$LATEST" echo "Done" echo "Unpacking CodeQL CLI..." diff --git a/CODEOWNERS b/CODEOWNERS index 72a3954cfb5..d076d9576d4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,6 +1 @@ * @github/codeql-go - -# Documentation -**/*.qhelp @shati-patel -# Exclude experimental -**/experimental/**/*.qhelp @github/codeql-go diff --git a/change-notes/2021-05-06-xorm.md b/change-notes/2021-05-06-xorm.md new file mode 100644 index 00000000000..0398530b950 --- /dev/null +++ b/change-notes/2021-05-06-xorm.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added support for the `xorm.io/xorm` package diff --git a/change-notes/2021-07-28-insufficient-key-size.md b/change-notes/2021-07-28-insufficient-key-size.md new file mode 100644 index 00000000000..d3880bee73f --- /dev/null +++ b/change-notes/2021-07-28-insufficient-key-size.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Query "Use of a weak cryptographic key" (`go/insufficient-key-size`) is promoted from experimental status. This checks that any RSA keys which are generated have a size of at least 2048 bits. diff --git a/change-notes/2021-08-17-go-117.md b/change-notes/2021-08-17-go-117.md new file mode 100644 index 00000000000..640f771b5f0 --- /dev/null +++ b/change-notes/2021-08-17-go-117.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The extractor now supports Go 1.17 features and models the changed libraries. diff --git a/change-notes/2021-08-23-getPrimaryQlClasses.md b/change-notes/2021-08-23-getPrimaryQlClasses.md new file mode 100644 index 00000000000..30b00908a23 --- /dev/null +++ b/change-notes/2021-08-23-getPrimaryQlClasses.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added `AstNode.getPrimaryQlClasses()` predicate, which gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. diff --git a/codeql-extractor.yml b/codeql-extractor.yml index b258b193f56..e4da61ac7af 100644 --- a/codeql-extractor.yml +++ b/codeql-extractor.yml @@ -6,6 +6,8 @@ pull_request_triggers: - "**/glide.yaml" - "**/Gopkg.toml" column_kind: "utf8" +extra_env_vars: + CODEQL_REDUCE_FILES_FOLDERS_RELATIONS: "true" file_types: - name: go display_name: Go diff --git a/codeql-tools/pre-finalize.cmd b/codeql-tools/pre-finalize.cmd index 4abac249933..f8909ea54ef 100644 --- a/codeql-tools/pre-finalize.cmd +++ b/codeql-tools/pre-finalize.cmd @@ -1,6 +1,8 @@ @echo off SETLOCAL EnableDelayedExpansion +SET CODEQL_REDUCE_FILES_FOLDERS_RELATIONS=true + if NOT "%CODEQL_EXTRACTOR_GO_EXTRACT_HTML%"=="no" ( type NUL && "%CODEQL_DIST%/codeql.exe" database index-files ^ --working-dir=. ^ diff --git a/codeql-tools/pre-finalize.sh b/codeql-tools/pre-finalize.sh index 3a8b31c70a0..6151f552698 100755 --- a/codeql-tools/pre-finalize.sh +++ b/codeql-tools/pre-finalize.sh @@ -3,7 +3,7 @@ set -eu if [ "${CODEQL_EXTRACTOR_GO_EXTRACT_HTML:-yes}" != "no" ]; then - "$CODEQL_DIST/codeql" database index-files \ + CODEQL_REDUCE_FILES_FOLDERS_RELATIONS=true "$CODEQL_DIST/codeql" database index-files \ --working-dir=. \ --include-extension=.htm \ --include-extension=.html \ diff --git a/extractor/dbscheme/tables.go b/extractor/dbscheme/tables.go index 0a968fd8ecd..8da7312dfb8 100644 --- a/extractor/dbscheme/tables.go +++ b/extractor/dbscheme/tables.go @@ -896,16 +896,12 @@ var NumlinesTable = NewTable("numlines", var FilesTable = NewTable("files", EntityColumn(FileType, "id").Key(), StringColumn("name"), - StringColumn("simple"), - StringColumn("ext"), - IntColumn("fromSource"), ) // FoldersTable is the table defining folder entities var FoldersTable = NewTable("folders", EntityColumn(FolderType, "id").Key(), StringColumn("name"), - StringColumn("simple"), ) // ContainerParentTable is the table defining the parent-child relation among container entities diff --git a/extractor/extractor.go b/extractor/extractor.go index 704f80ebbed..4208a788d02 100644 --- a/extractor/extractor.go +++ b/extractor/extractor.go @@ -458,7 +458,7 @@ func (extraction *Extraction) extractError(tw *trap.Writer, err packages.Error, e error ) - if pos == "" { + if pos == "" || pos == "-" { // extract a dummy file wd, e := os.Getwd() if e != nil { @@ -590,15 +590,6 @@ func (extraction *Extraction) extractFile(ast *ast.File, pkg *packages.Package) return nil } -// stemAndExt splits a given file name into its stem (the part before the last '.') -// and extension (the part after the last '.') -func stemAndExt(base string) (string, string) { - if i := strings.LastIndexByte(base, '.'); i >= 0 { - return base[:i], base[i+1:] - } - return base, "" -} - // extractFileInfo extracts file-system level information for the given file, populating // the `files` and `containerparent` tables func (extraction *Extraction) extractFileInfo(tw *trap.Writer, file string) { @@ -627,9 +618,8 @@ func (extraction *Extraction) extractFileInfo(tw *trap.Writer, file string) { path = parentPath + "/" + component } if i == len(components)-1 { - stem, ext := stemAndExt(component) lbl := tw.Labeler.FileLabelFor(file) - dbscheme.FilesTable.Emit(tw, lbl, path, stem, ext, 0) + dbscheme.FilesTable.Emit(tw, lbl, path) dbscheme.ContainerParentTable.Emit(tw, parentLbl, lbl) dbscheme.HasLocationTable.Emit(tw, lbl, emitLocation(tw, lbl, 0, 0, 0, 0)) extraction.Lock.Lock() @@ -639,7 +629,7 @@ func (extraction *Extraction) extractFileInfo(tw *trap.Writer, file string) { break } lbl := tw.Labeler.GlobalID(util.EscapeTrapSpecialChars(path) + ";folder") - dbscheme.FoldersTable.Emit(tw, lbl, path, component) + dbscheme.FoldersTable.Emit(tw, lbl, path) if i > 0 { dbscheme.ContainerParentTable.Emit(tw, parentLbl, lbl) } diff --git a/go.mod b/go.mod index 50a9c825682..5d77091a50c 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,13 @@ module github.com/github/codeql-go -go 1.16 +go 1.17 require ( - golang.org/x/mod v0.3.0 - golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 + golang.org/x/mod v0.5.0 + golang.org/x/tools v0.1.5 +) + +require ( + golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/go.sum b/go.sum index b336fd3e273..57b82477ee7 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,27 @@ -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 h1:sEvmEcJVKBNUvgCUClbUQeHOAa9U0I2Ce1BooMvVCY4= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= diff --git a/ql/src/experimental/CWE-326/InsufficientKeySize.qhelp b/ql/src/Security/CWE-326/InsufficientKeySize.qhelp similarity index 96% rename from ql/src/experimental/CWE-326/InsufficientKeySize.qhelp rename to ql/src/Security/CWE-326/InsufficientKeySize.qhelp index c18341ca922..6547993458b 100644 --- a/ql/src/experimental/CWE-326/InsufficientKeySize.qhelp +++ b/ql/src/Security/CWE-326/InsufficientKeySize.qhelp @@ -26,7 +26,7 @@

- In the example below the key size is set to 2048 bits. + In the example below, the key size is set to 2048 bits.

diff --git a/ql/src/experimental/CWE-326/InsufficientKeySize.ql b/ql/src/Security/CWE-326/InsufficientKeySize.ql similarity index 83% rename from ql/src/experimental/CWE-326/InsufficientKeySize.ql rename to ql/src/Security/CWE-326/InsufficientKeySize.ql index ab5637f2914..6e1096f7708 100644 --- a/ql/src/experimental/CWE-326/InsufficientKeySize.ql +++ b/ql/src/Security/CWE-326/InsufficientKeySize.ql @@ -1,11 +1,13 @@ /** * @name Use of a weak cryptographic key - * @description Using weak cryptographic key can allow an attacker to compromise security. + * @description Using a weak cryptographic key can allow an attacker to compromise security. * @kind path-problem * @problem.severity error + * @security-severity 7.5 + * @precision high * @id go/weak-crypto-key * @tags security - * external/cwe/cwe-326 + * external/cwe/cwe-326 */ import go diff --git a/ql/src/experimental/CWE-326/InsufficientKeySizeBad.go b/ql/src/Security/CWE-326/InsufficientKeySizeBad.go similarity index 100% rename from ql/src/experimental/CWE-326/InsufficientKeySizeBad.go rename to ql/src/Security/CWE-326/InsufficientKeySizeBad.go diff --git a/ql/src/experimental/CWE-326/InsufficientKeySizeGood.go b/ql/src/Security/CWE-326/InsufficientKeySizeGood.go similarity index 100% rename from ql/src/experimental/CWE-326/InsufficientKeySizeGood.go rename to ql/src/Security/CWE-326/InsufficientKeySizeGood.go diff --git a/ql/src/codeql-suites/go-developer-happiness.qls b/ql/src/codeql-suites/go-developer-happiness.qls new file mode 100644 index 00000000000..0b2a2b1ae9e --- /dev/null +++ b/ql/src/codeql-suites/go-developer-happiness.qls @@ -0,0 +1,8 @@ +- description: Experimental queries showing how we use CodeQL internally for developer happiness +- qlpack: codeql-go +- include: + id: go/examples/database-call-in-loop +- include: + id: go/examples/deferinloop +- include: + id: go/examples/gorm-error-not-checked diff --git a/ql/src/experimental/CWE-400/DatabaseCallInLoop.go b/ql/src/experimental/CWE-400/DatabaseCallInLoop.go new file mode 100644 index 00000000000..138bbbcd9d4 --- /dev/null +++ b/ql/src/experimental/CWE-400/DatabaseCallInLoop.go @@ -0,0 +1,13 @@ +package main + +import "gorm.io/gorm" + +func getUsers(db *gorm.DB, names []string) []User { + res := make([]User, 0, len(names)) + for _, name := range names { + var user User + db.Where("name = ?", name).First(&user) + res = append(res, user) + } + return res +} diff --git a/ql/src/experimental/CWE-400/DatabaseCallInLoop.qhelp b/ql/src/experimental/CWE-400/DatabaseCallInLoop.qhelp new file mode 100644 index 00000000000..d9c8a50fae7 --- /dev/null +++ b/ql/src/experimental/CWE-400/DatabaseCallInLoop.qhelp @@ -0,0 +1,29 @@ + + + + +

Database calls in loops are slower than running a single query and consume more resources. This +can lead to denial of service attacks if the loop bounds can be controlled by an attacker.

+
+ + +

Ensure that where possible, database queries are not run in a loop, instead running a single query to get all relevant data.

+ +
+ + +

In the example below, users in a database are queried one by one in a loop:

+ + + +

This is corrected by running a single query that selects all of the users at once:

+ + + +
+ + + +
diff --git a/ql/src/experimental/CWE-400/DatabaseCallInLoop.ql b/ql/src/experimental/CWE-400/DatabaseCallInLoop.ql new file mode 100644 index 00000000000..2e4f25fe495 --- /dev/null +++ b/ql/src/experimental/CWE-400/DatabaseCallInLoop.ql @@ -0,0 +1,69 @@ +/** + * @name Database call in loop + * @description Detects database operations within loops. + * Doing operations in series can be slow and lead to N+1 situations. + * @kind path-problem + * @problem.severity warning + * @precision high + * @id go/examples/database-call-in-loop + */ + +import go + +class DatabaseAccess extends DataFlow::MethodCallNode { + DatabaseAccess() { + exists(string name | + this.getTarget().hasQualifiedName(Gorm::packagePath(), "DB", name) and + // all terminating Gorm methods + name = + [ + "Find", "Take", "Last", "Scan", "Row", "Rows", "ScanRows", "Pluck", "Count", "First", + "FirstOrInit", "FindOrCreate", "Update", "Updates", "UpdateColumn", "UpdateColumns", + "Save", "Create", "Delete", "Exec" + ] + ) + } +} + +class CallGraphNode extends Locatable { + CallGraphNode() { + this instanceof LoopStmt + or + this instanceof CallExpr + or + this instanceof FuncDef + } +} + +/** + * Holds if `pred` calls `succ`, i.e. is an edge in the call graph, + * This includes explicit edges from call -> callee, to produce better paths. + */ +predicate callGraphEdge(CallGraphNode pred, CallGraphNode succ) { + // Go from a loop to an enclosed expression. + pred.(LoopStmt).getBody().getAChild*() = succ.(CallExpr) + or + // Go from a call to the called function. + pred.(CallExpr) = succ.(FuncDef).getACall().asExpr() + or + // Go from a function to an enclosed loop. + pred.(FuncDef) = succ.(LoopStmt).getEnclosingFunction() + or + // Go from a function to an enclosed call. + pred.(FuncDef) = succ.(CallExpr).getEnclosingFunction() +} + +query predicate edges(CallGraphNode pred, CallGraphNode succ) { + callGraphEdge(pred, succ) and + // Limit the range of edges to only those that are relevant. + // This helps to speed up the query by reducing the size of the outputted path information. + exists(LoopStmt loop, DatabaseAccess dbAccess | + // is between a loop and a db access + callGraphEdge*(loop, pred) and + callGraphEdge*(succ, dbAccess.asExpr()) + ) +} + +from LoopStmt loop, DatabaseAccess dbAccess +where edges*(loop, dbAccess.asExpr()) +select dbAccess, loop, dbAccess, "$@ is called in $@", dbAccess, dbAccess.toString(), loop, "a loop" diff --git a/ql/src/experimental/CWE-400/DatabaseCallInLoopGood.go b/ql/src/experimental/CWE-400/DatabaseCallInLoopGood.go new file mode 100644 index 00000000000..22928a6abc2 --- /dev/null +++ b/ql/src/experimental/CWE-400/DatabaseCallInLoopGood.go @@ -0,0 +1,9 @@ +package main + +import "gorm.io/gorm" + +func getUsersGood(db *gorm.DB, names []string) []User { + res := make([]User, 0, len(names)) + db.Where("name IN ?", names).Find(&res) + return res +} diff --git a/ql/src/experimental/InconsistentCode/DeferInLoop.go b/ql/src/experimental/InconsistentCode/DeferInLoop.go new file mode 100644 index 00000000000..1b57d1855b4 --- /dev/null +++ b/ql/src/experimental/InconsistentCode/DeferInLoop.go @@ -0,0 +1,14 @@ +package main + +import "os" + +func openFiles(filenames []string) { + for _, filename := range filenames { + file, err := os.Open(filename) + defer file.Close() + if err != nil { + // handle error + } + // work on file + } +} diff --git a/ql/src/experimental/InconsistentCode/DeferInLoop.qhelp b/ql/src/experimental/InconsistentCode/DeferInLoop.qhelp new file mode 100644 index 00000000000..ea31e6829ed --- /dev/null +++ b/ql/src/experimental/InconsistentCode/DeferInLoop.qhelp @@ -0,0 +1,32 @@ + + + + +

A deferred statement in a loop will not execute until the end of the function. This can lead to unintentionally holding resources open, like file handles or database transactions.

+
+ + +

Either run the deferred function manually, or create a subroutine that contains the defer.

+ +
+ + +

In the example below, the files opened in the loop are not closed until the end of the function:

+ + + +

The corrected version puts the loop body into a function.

+ + + +
+ + +
  • + Defer statements. +
  • + +
    +
    diff --git a/ql/examples/snippets/deferinloop.ql b/ql/src/experimental/InconsistentCode/DeferInLoop.ql similarity index 100% rename from ql/examples/snippets/deferinloop.ql rename to ql/src/experimental/InconsistentCode/DeferInLoop.ql diff --git a/ql/src/experimental/InconsistentCode/DeferInLoopGood.go b/ql/src/experimental/InconsistentCode/DeferInLoopGood.go new file mode 100644 index 00000000000..d28bc8e4cb9 --- /dev/null +++ b/ql/src/experimental/InconsistentCode/DeferInLoopGood.go @@ -0,0 +1,18 @@ +package main + +import "os" + +func openFile(filename string) { + file, err := os.Open(filename) + defer file.Close() + if err != nil { + // handle error + } + // work on file +} + +func openFilesGood(filenames []string) { + for _, filename := range filenames { + openFile(filename) + } +} diff --git a/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.go b/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.go new file mode 100644 index 00000000000..422e49b5f10 --- /dev/null +++ b/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.go @@ -0,0 +1,9 @@ +package main + +import "gorm.io/gorm" + +func getUserId(db *gorm.DB, name string) int64 { + var user User + db.Where("name = ?", name).First(&user) + return user.Id +} diff --git a/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.qhelp b/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.qhelp new file mode 100644 index 00000000000..499e38eeff2 --- /dev/null +++ b/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.qhelp @@ -0,0 +1,34 @@ + + + + +

    GORM errors are returned as a field of the return value instead of a separate return value.

    + +

    It is therefore very easy to miss that an error may occur and omit error handling routines.

    +
    + + +

    Ensure that GORM errors are checked.

    + +
    + + +

    In the example below, the error from the database query is never checked:

    + + + +

    The corrected version checks and handles the error before returning.

    + + + +
    + + +
  • + GORM Error Handling. +
  • + +
    +
    diff --git a/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.ql b/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.ql new file mode 100644 index 00000000000..15ab4450f6d --- /dev/null +++ b/ql/src/experimental/InconsistentCode/GORMErrorNotChecked.ql @@ -0,0 +1,35 @@ +/** + * @name GORM error not checked + * @description A call that interacts with the database using the GORM library + * without checking whether there was an error. + * @kind problem + * @problem.severity warning + * @id go/examples/gorm-error-not-checked + * @precision high + */ + +import go +import semmle.go.frameworks.SQL + +from DataFlow::MethodCallNode call +where + exists(string name | call.getTarget().hasQualifiedName(Gorm::packagePath(), "DB", name) | + name != "InstantSet" and + name != "LogMode" + ) and + // the value from the call does not: + not exists(DataFlow::Node succ | TaintTracking::localTaintStep*(call, succ) | + // get assigned to any variables + succ = any(Write w).getRhs() + or + // get returned + succ instanceof DataFlow::ResultNode + or + // have any methods chained on it + exists(DataFlow::MethodCallNode m | succ = m.getReceiver()) + or + // have its `Error` field read + exists(DataFlow::FieldReadNode fr | fr.readsField(succ, _, _, "Error")) + ) +select call, + "This call appears to interact with the database without checking whether an error was encountered." diff --git a/ql/src/experimental/InconsistentCode/GORMErrorNotCheckedGood.go b/ql/src/experimental/InconsistentCode/GORMErrorNotCheckedGood.go new file mode 100644 index 00000000000..551e06fb66a --- /dev/null +++ b/ql/src/experimental/InconsistentCode/GORMErrorNotCheckedGood.go @@ -0,0 +1,11 @@ +package main + +import "gorm.io/gorm" + +func getUserIdGood(db *gorm.DB, name string) int64 { + var user User + if err := db.Where("name = ?", name).First(&user).Error; err != nil { + // handle errors + } + return user.Id +} diff --git a/ql/src/experimental/frameworks/CleverGo.qll b/ql/src/experimental/frameworks/CleverGo.qll index 9ff5ea7da21..c061c416b88 100644 --- a/ql/src/experimental/frameworks/CleverGo.qll +++ b/ql/src/experimental/frameworks/CleverGo.qll @@ -25,46 +25,46 @@ private module CleverGo { | receiverName = "Context" and ( - // signature: func (*Context).BasicAuth() (username string, password string, ok bool) + // signature: func (*Context) BasicAuth() (username string, password string, ok bool) methodName = "BasicAuth" and out.isResult([0, 1]) or - // signature: func (*Context).Decode(v interface{}) (err error) + // signature: func (*Context) Decode(v interface{}) (err error) methodName = "Decode" and out.isParameter(0) or - // signature: func (*Context).DefaultQuery(key string, defaultVlue string) string + // signature: func (*Context) DefaultQuery(key string, defaultVlue string) string methodName = "DefaultQuery" and out.isResult() or - // signature: func (*Context).FormValue(key string) string + // signature: func (*Context) FormValue(key string) string methodName = "FormValue" and out.isResult() or - // signature: func (*Context).GetHeader(name string) string + // signature: func (*Context) GetHeader(name string) string methodName = "GetHeader" and out.isResult() or - // signature: func (*Context).PostFormValue(key string) string + // signature: func (*Context) PostFormValue(key string) string methodName = "PostFormValue" and out.isResult() or - // signature: func (*Context).QueryParam(key string) string + // signature: func (*Context) QueryParam(key string) string methodName = "QueryParam" and out.isResult() or - // signature: func (*Context).QueryParams() net/url.Values + // signature: func (*Context) QueryParams() net/url.Values methodName = "QueryParams" and out.isResult() or - // signature: func (*Context).QueryString() string + // signature: func (*Context) QueryString() string methodName = "QueryString" and out.isResult() ) or receiverName = "Params" and ( - // signature: func (Params).String(name string) string + // signature: func (Params) String(name string) string methodName = "String" and out.isResult() ) @@ -77,7 +77,7 @@ private module CleverGo { | interfaceName = "Decoder" and ( - // signature: func (Decoder).Decode(req *net/http.Request, v interface{}) error + // signature: func (Decoder) Decode(req *net/http.Request, v interface{}) error methodName = "Decode" and out.isParameter(1) ) @@ -135,31 +135,31 @@ private module CleverGo { // Taint-tracking models for package: clevergo.tech/clevergo@v0.5.2 ( // Receiver type: Application - // signature: func (*Application).RouteURL(name string, args ...string) (*net/url.URL, error) + // signature: func (*Application) RouteURL(name string, args ...string) (*net/url.URL, error) this.hasQualifiedName(packagePath(), "Application", "RouteURL") and inp.isParameter(_) and out.isResult(0) or // Receiver type: Context - // signature: func (*Context).Context() context.Context + // signature: func (*Context) Context() context.Context this.hasQualifiedName(packagePath(), "Context", "Context") and inp.isReceiver() and out.isResult() or // Receiver type: Params - // signature: func (Params).String(name string) string + // signature: func (Params) String(name string) string this.hasQualifiedName(packagePath(), "Params", "String") and inp.isReceiver() and out.isResult() or // Receiver interface: Decoder - // signature: func (Decoder).Decode(req *net/http.Request, v interface{}) error + // signature: func (Decoder) Decode(req *net/http.Request, v interface{}) error this.implements(packagePath(), "Decoder", "Decode") and inp.isParameter(0) and out.isParameter(1) or // Receiver interface: Renderer - // signature: func (Renderer).Render(w io.Writer, name string, data interface{}, c *Context) error + // signature: func (Renderer) Render(w io.Writer, name string, data interface{}, c *Context) error this.implements(packagePath(), "Renderer", "Render") and inp.isParameter(2) and out.isParameter(0) @@ -183,7 +183,7 @@ private module CleverGo { package = packagePath() and // Receiver type: Context ( - // signature: func (*Context).Redirect(code int, url string) error + // signature: func (*Context) Redirect(code int, url string) error this = any(Method m | m.hasQualifiedName(package, "Context", "Redirect")).getACall() and urlNode = this.getArgument(1) ) @@ -227,72 +227,72 @@ private module CleverGo { // Receiver type: Context receiverName = "Context" and ( - // signature: func (*Context).Error(code int, msg string) error + // signature: func (*Context) Error(code int, msg string) error methodName = "Error" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/plain" or - // signature: func (*Context).HTML(code int, html string) error + // signature: func (*Context) HTML(code int, html string) error methodName = "HTML" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/html" or - // signature: func (*Context).HTMLBlob(code int, bs []byte) error + // signature: func (*Context) HTMLBlob(code int, bs []byte) error methodName = "HTMLBlob" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/html" or - // signature: func (*Context).JSON(code int, data interface{}) error + // signature: func (*Context) JSON(code int, data interface{}) error methodName = "JSON" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "application/json" or - // signature: func (*Context).JSONBlob(code int, bs []byte) error + // signature: func (*Context) JSONBlob(code int, bs []byte) error methodName = "JSONBlob" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "application/json" or - // signature: func (*Context).JSONP(code int, data interface{}) error + // signature: func (*Context) JSONP(code int, data interface{}) error methodName = "JSONP" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "application/javascript" or - // signature: func (*Context).JSONPBlob(code int, bs []byte) error + // signature: func (*Context) JSONPBlob(code int, bs []byte) error methodName = "JSONPBlob" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "application/javascript" or - // signature: func (*Context).JSONPCallback(code int, callback string, data interface{}) error + // signature: func (*Context) JSONPCallback(code int, callback string, data interface{}) error methodName = "JSONPCallback" and bodyNode = bodySetterCall.getArgument(2) and contentTypeString = "application/javascript" or - // signature: func (*Context).JSONPCallbackBlob(code int, callback string, bs []byte) (err error) + // signature: func (*Context) JSONPCallbackBlob(code int, callback string, bs []byte) (err error) methodName = "JSONPCallbackBlob" and bodyNode = bodySetterCall.getArgument(2) and contentTypeString = "application/javascript" or - // signature: func (*Context).String(code int, s string) error + // signature: func (*Context) String(code int, s string) error methodName = "String" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/plain" or - // signature: func (*Context).StringBlob(code int, bs []byte) error + // signature: func (*Context) StringBlob(code int, bs []byte) error methodName = "StringBlob" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/plain" or - // signature: func (*Context).Stringf(code int, format string, a ...interface{}) error + // signature: func (*Context) Stringf(code int, format string, a ...interface{}) error methodName = "Stringf" and bodyNode = bodySetterCall.getArgument([1, any(int i | i >= 2)]) and contentTypeString = "text/plain" or - // signature: func (*Context).XML(code int, data interface{}) error + // signature: func (*Context) XML(code int, data interface{}) error methodName = "XML" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/xml" or - // signature: func (*Context).XMLBlob(code int, bs []byte) error + // signature: func (*Context) XMLBlob(code int, bs []byte) error methodName = "XMLBlob" and bodyNode = bodySetterCall.getArgument(1) and contentTypeString = "text/xml" @@ -335,12 +335,12 @@ private module CleverGo { // Receiver type: Context receiverName = "Context" and ( - // signature: func (*Context).Blob(code int, contentType string, bs []byte) (err error) + // signature: func (*Context) Blob(code int, contentType string, bs []byte) (err error) methodName = "Blob" and bodyNode = bodySetterCall.getArgument(2) and contentTypeNode = bodySetterCall.getArgument(1) or - // signature: func (*Context).Emit(code int, contentType string, body string) (err error) + // signature: func (*Context) Emit(code int, contentType string, body string) (err error) methodName = "Emit" and bodyNode = bodySetterCall.getArgument(2) and contentTypeNode = bodySetterCall.getArgument(1) @@ -378,11 +378,11 @@ private module CleverGo { // Receiver type: Context receiverName = "Context" and ( - // signature: func (*Context).Write(data []byte) (int, error) + // signature: func (*Context) Write(data []byte) (int, error) methodName = "Write" and bodyNode = bodySetterCall.getArgument(0) or - // signature: func (*Context).WriteString(data string) (int, error) + // signature: func (*Context) WriteString(data string) (int, error) methodName = "WriteString" and bodyNode = bodySetterCall.getArgument(0) ) @@ -425,7 +425,7 @@ private module CleverGo { // Receiver type: Context receiverName = "Context" and ( - // signature: func (*Context).SetHeader(key string, value string) + // signature: func (*Context) SetHeader(key string, value string) methodName = "SetHeader" and headerNameNode = headerSetterCall.getArgument(0) and headerValueNode = headerSetterCall.getArgument(1) @@ -471,19 +471,19 @@ private module CleverGo { // Receiver type: Context receiverName = "Context" and ( - // signature: func (*Context).SetContentTypeHTML() + // signature: func (*Context) SetContentTypeHTML() methodName = "SetContentTypeHTML" and valueString = "text/html" or - // signature: func (*Context).SetContentTypeJSON() + // signature: func (*Context) SetContentTypeJSON() methodName = "SetContentTypeJSON" and valueString = "application/json" or - // signature: func (*Context).SetContentTypeText() + // signature: func (*Context) SetContentTypeText() methodName = "SetContentTypeText" and valueString = "text/plain" or - // signature: func (*Context).SetContentTypeXML() + // signature: func (*Context) SetContentTypeXML() methodName = "SetContentTypeXML" and valueString = "text/xml" ) @@ -526,7 +526,7 @@ private module CleverGo { // Receiver type: Context receiverName = "Context" and ( - // signature: func (*Context).SetContentType(v string) + // signature: func (*Context) SetContentType(v string) methodName = "SetContentType" and valueNode = setterCall.getArgument(0) ) diff --git a/ql/src/experimental/frameworks/Fiber.qll b/ql/src/experimental/frameworks/Fiber.qll index 08a0d961d41..a3240a0b85a 100644 --- a/ql/src/experimental/frameworks/Fiber.qll +++ b/ql/src/experimental/frameworks/Fiber.qll @@ -138,7 +138,7 @@ private module Fiber { package = fiberPackagePath() and // Receiver type: Ctx ( - // signature: func (*Ctx).Redirect(location string, status ...int) + // signature: func (*Ctx) Redirect(location string, status ...int) this = any(Method m | m.hasQualifiedName(package, "Ctx", "Redirect")).getACall() and urlNode = this.getArgument(0) ) @@ -184,12 +184,12 @@ private module Fiber { // Receiver type: Ctx receiverName = "Ctx" and ( - // signature: func (*Ctx).Append(field string, values ...string) + // signature: func (*Ctx) Append(field string, values ...string) methodName = "Append" and headerNameNode = headerSetterCall.getArgument(0) and headerValueNode = headerSetterCall.getArgument(any(int i | i >= 1)) or - // signature: func (*Ctx).Set(key string, val string) + // signature: func (*Ctx) Set(key string, val string) methodName = "Set" and headerNameNode = headerSetterCall.getArgument(0) and headerValueNode = headerSetterCall.getArgument(1) @@ -231,12 +231,12 @@ private module Fiber { // Receiver type: Ctx receiverName = "Ctx" and ( - // signature: func (*Ctx).JSON(data interface{}) error + // signature: func (*Ctx) JSON(data interface{}) error methodName = "JSON" and bodyNode = bodySetterCall.getArgument(0) and contentTypeString = "application/json" or - // signature: func (*Ctx).JSONP(data interface{}, callback ...string) error + // signature: func (*Ctx) JSONP(data interface{}, callback ...string) error methodName = "JSONP" and bodyNode = bodySetterCall.getArgument(0) and contentTypeString = "application/javascript" @@ -274,27 +274,27 @@ private module Fiber { // Receiver type: Ctx receiverName = "Ctx" and ( - // signature: func (*Ctx).Format(body interface{}) + // signature: func (*Ctx) Format(body interface{}) methodName = "Format" and bodyNode = bodySetterCall.getArgument(0) or - // signature: func (*Ctx).Send(bodies ...interface{}) + // signature: func (*Ctx) Send(bodies ...interface{}) methodName = "Send" and bodyNode = bodySetterCall.getArgument(_) or - // signature: func (*Ctx).SendBytes(body []byte) + // signature: func (*Ctx) SendBytes(body []byte) methodName = "SendBytes" and bodyNode = bodySetterCall.getArgument(0) or - // signature: func (*Ctx).SendStream(stream io.Reader, size ...int) + // signature: func (*Ctx) SendStream(stream io.Reader, size ...int) methodName = "SendStream" and bodyNode = bodySetterCall.getArgument(0) or - // signature: func (*Ctx).SendString(body string) + // signature: func (*Ctx) SendString(body string) methodName = "SendString" and bodyNode = bodySetterCall.getArgument(0) or - // signature: func (*Ctx).Write(bodies ...interface{}) + // signature: func (*Ctx) Write(bodies ...interface{}) methodName = "Write" and bodyNode = bodySetterCall.getArgument(_) ) @@ -314,71 +314,71 @@ private module Fiber { | receiverName = "Ctx" and ( - // signature: func (*Ctx).BaseURL() string + // signature: func (*Ctx) BaseURL() string methodName = "BaseURL" and out.isResult() or - // signature: func (*Ctx).Body() string + // signature: func (*Ctx) Body() string methodName = "Body" and out.isResult() or - // signature: func (*Ctx).BodyParser(out interface{}) error + // signature: func (*Ctx) BodyParser(out interface{}) error methodName = "BodyParser" and out.isParameter(0) or - // signature: func (*Ctx).Cookies(key string, defaultValue ...string) string + // signature: func (*Ctx) Cookies(key string, defaultValue ...string) string methodName = "Cookies" and out.isResult() or - // signature: func (*Ctx).FormFile(key string) (*mime/multipart.FileHeader, error) + // signature: func (*Ctx) FormFile(key string) (*mime/multipart.FileHeader, error) methodName = "FormFile" and out.isResult(0) or - // signature: func (*Ctx).FormValue(key string) (value string) + // signature: func (*Ctx) FormValue(key string) (value string) methodName = "FormValue" and out.isResult() or - // signature: func (*Ctx).Get(key string, defaultValue ...string) string + // signature: func (*Ctx) Get(key string, defaultValue ...string) string methodName = "Get" and out.isResult() or - // signature: func (*Ctx).Hostname() string + // signature: func (*Ctx) Hostname() string methodName = "Hostname" and out.isResult() or - // signature: func (*Ctx).Method(override ...string) string + // signature: func (*Ctx) Method(override ...string) string methodName = "Method" and out.isResult() or - // signature: func (*Ctx).MultipartForm() (*mime/multipart.Form, error) + // signature: func (*Ctx) MultipartForm() (*mime/multipart.Form, error) methodName = "MultipartForm" and out.isResult(0) or - // signature: func (*Ctx).OriginalURL() string + // signature: func (*Ctx) OriginalURL() string methodName = "OriginalURL" and out.isResult() or - // signature: func (*Ctx).Params(key string, defaultValue ...string) string + // signature: func (*Ctx) Params(key string, defaultValue ...string) string methodName = "Params" and out.isResult() or - // signature: func (*Ctx).Path(override ...string) string + // signature: func (*Ctx) Path(override ...string) string methodName = "Path" and out.isResult() or - // signature: func (*Ctx).Query(key string, defaultValue ...string) string + // signature: func (*Ctx) Query(key string, defaultValue ...string) string methodName = "Query" and out.isResult() or - // signature: func (*Ctx).QueryParser(out interface{}) error + // signature: func (*Ctx) QueryParser(out interface{}) error methodName = "QueryParser" and out.isParameter(0) or - // signature: func (*Ctx).Range(size int) (rangeData Range, err error) + // signature: func (*Ctx) Range(size int) (rangeData Range, err error) methodName = "Range" and out.isResult(0) or - // signature: func (*Ctx).Subdomains(offset ...int) []string + // signature: func (*Ctx) Subdomains(offset ...int) []string methodName = "Subdomains" and out.isResult() ) diff --git a/ql/src/go.dbscheme b/ql/src/go.dbscheme index b37faf5d62c..2842941c6f9 100644 --- a/ql/src/go.dbscheme +++ b/ql/src/go.dbscheme @@ -133,9 +133,9 @@ locations_default(unique int id: @location_default, int file: @file ref, int beg numlines(int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, int num_comment: int ref); -files(unique int id: @file, string name: string ref, string simple: string ref, string ext: string ref, int fromSource: int ref); +files(unique int id: @file, string name: string ref); -folders(unique int id: @folder, string name: string ref, string simple: string ref); +folders(unique int id: @folder, string name: string ref); containerparent(int parent: @container ref, unique int child: @container ref); diff --git a/ql/src/go.dbscheme.stats b/ql/src/go.dbscheme.stats index 4a1886f84c2..b18e8556fb2 100644 --- a/ql/src/go.dbscheme.stats +++ b/ql/src/go.dbscheme.stats @@ -8175,18 +8175,6 @@ name 529 - - simple - 373 - - - ext - 3 - - - fromSource - 1 - @@ -8205,54 +8193,6 @@ - - id - simple - - - 12 - - - 1 - 2 - 529 - - - - - - - id - ext - - - 12 - - - 1 - 2 - 529 - - - - - - - id - fromSource - - - 12 - - - 1 - 2 - 529 - - - - - name id @@ -8269,301 +8209,6 @@ - - name - simple - - - 12 - - - 1 - 2 - 529 - - - - - - - name - ext - - - 12 - - - 1 - 2 - 529 - - - - - - - name - fromSource - - - 12 - - - 1 - 2 - 529 - - - - - - - simple - id - - - 12 - - - 1 - 2 - 301 - - - 2 - 3 - 47 - - - 3 - 22 - 25 - - - - - - - simple - name - - - 12 - - - 1 - 2 - 301 - - - 2 - 3 - 47 - - - 3 - 22 - 25 - - - - - - - simple - ext - - - 12 - - - 1 - 2 - 368 - - - 2 - 3 - 5 - - - - - - - simple - fromSource - - - 12 - - - 1 - 2 - 373 - - - - - - - ext - id - - - 12 - - - 1 - 2 - 1 - - - 14 - 15 - 1 - - - 514 - 515 - 1 - - - - - - - ext - name - - - 12 - - - 1 - 2 - 1 - - - 14 - 15 - 1 - - - 514 - 515 - 1 - - - - - - - ext - simple - - - 12 - - - 1 - 2 - 1 - - - 14 - 15 - 1 - - - 363 - 364 - 1 - - - - - - - ext - fromSource - - - 12 - - - 1 - 2 - 3 - - - - - - - fromSource - id - - - 12 - - - 529 - 530 - 1 - - - - - - - fromSource - name - - - 12 - - - 529 - 530 - 1 - - - - - - - fromSource - simple - - - 12 - - - 373 - 374 - 1 - - - - - - - fromSource - ext - - - 12 - - - 3 - 4 - 1 - - - - - @@ -8578,10 +8223,6 @@ name 210 - - simple - 178 - @@ -8600,22 +8241,6 @@ - - id - simple - - - 12 - - - 1 - 2 - 210 - - - - - name id @@ -8632,74 +8257,6 @@ - - name - simple - - - 12 - - - 1 - 2 - 210 - - - - - - - simple - id - - - 12 - - - 1 - 2 - 157 - - - 2 - 3 - 18 - - - 3 - 10 - 3 - - - - - - - simple - name - - - 12 - - - 1 - 2 - 157 - - - 2 - 3 - 18 - - - 3 - 10 - 3 - - - - - diff --git a/ql/src/semmle/go/AST.qll b/ql/src/semmle/go/AST.qll index 8468fba1276..6ce205aefae 100644 --- a/ql/src/semmle/go/AST.qll +++ b/ql/src/semmle/go/AST.qll @@ -81,6 +81,11 @@ class AstNode extends @node, Locatable { /** Gets the innermost function definition to which this AST node belongs, if any. */ FuncDef getEnclosingFunction() { result = getParent().parentInSameFunction*() } + /** + * Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs. + */ + final string getPrimaryQlClasses() { result = concat(getAPrimaryQlClass(), ",") } + /** * Gets the name of a primary CodeQL class to which this node belongs. * diff --git a/ql/src/semmle/go/Comments.qll b/ql/src/semmle/go/Comments.qll index 2a765c5e972..e072c0cb7ca 100644 --- a/ql/src/semmle/go/Comments.qll +++ b/ql/src/semmle/go/Comments.qll @@ -189,7 +189,7 @@ private Comment getInitialComment(File f, int i) { } /** - * A build constraint comment of the form `// +build ...`. + * A build constraint comment of the form `// +build ...` or `//go:build ...`. * * Examples: * @@ -203,17 +203,23 @@ class BuildConstraintComment extends LineComment { // a line comment preceding the package declaration, itself only preceded by // line comments exists(File f, int i | + // correctness of the placement of the build constraint is not checked here; + // this is more lax than the actual rules for build constraints this = getInitialComment(f, i) and not getInitialComment(f, [0 .. i - 1]) instanceof BlockComment ) and - // comment text starts with `+build` - getText().regexpMatch("\\s*\\+build.*") + ( + // comment text starts with `+build` or `go:build` + this.getText().regexpMatch("\\s*\\+build.*") + or + this.getText().regexpMatch("\\s*go:build.*") + ) } override string getAPrimaryQlClass() { result = "BuildConstraintComment" } /** Gets the body of this build constraint. */ - string getConstraintBody() { result = getText().splitAt("+build ", 1) } + string getConstraintBody() { result = getText().splitAt("build ", 1) } /** Gets a disjunct of this build constraint. */ string getADisjunct() { result = getConstraintBody().splitAt(" ") } diff --git a/ql/src/semmle/go/Files.qll b/ql/src/semmle/go/Files.qll index ed27c6b557b..28cb395beb3 100644 --- a/ql/src/semmle/go/Files.qll +++ b/ql/src/semmle/go/Files.qll @@ -155,7 +155,7 @@ abstract class Container extends @container { /** A folder. */ class Folder extends Container, @folder { - override string getAbsolutePath() { folders(this, result, _) } + override string getAbsolutePath() { folders(this, result) } /** Gets the file or subfolder in this folder that has the given `name`, if any. */ Container getChildContainer(string name) { @@ -182,7 +182,7 @@ class ExtractedOrExternalFile extends Container, @file, Documentable, ExprParent DeclParent, ScopeNode { override Location getLocation() { has_location(this, result) } - override string getAbsolutePath() { files(this, result, _, _, _) } + override string getAbsolutePath() { files(this, result) } /** Gets the number of lines in this file. */ int getNumberOfLines() { numlines(this, result, _, _) } @@ -222,6 +222,8 @@ class ExtractedOrExternalFile extends Container, @file, Documentable, ExprParent exists(BuildConstraintComment bcc | this = bcc.getFile() | forex(string disjunct | disjunct = bcc.getADisjunct() | disjunct.splitAt(",").(Architecture).getBitSize() = bitSize + or + disjunct.splitAt("/").(Architecture).getBitSize() = bitSize ) ) } diff --git a/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll b/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll index 341f92925db..5642a853513 100644 --- a/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll +++ b/ql/src/semmle/go/controlflow/ControlFlowGraphImpl.qll @@ -1184,6 +1184,14 @@ module CFG { } private class ConversionExprTree extends PostOrderTree, ConversionExpr { + override Completion getCompletion() { + // conversions of a slice to an array pointer are the only kind that may panic + this.getType().(PointerType).getBaseType() instanceof ArrayType and + result = Panic() + or + result = Done() + } + override ControlFlow::Node getNode() { result = MkExprNode(this) } override ControlFlowTree getChildTree(int i) { i = 0 and result = getOperand() } diff --git a/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll b/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll index eab96dac19e..c4aed4ddd1e 100644 --- a/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll +++ b/ql/src/semmle/go/dataflow/internal/DataFlowUtil.qll @@ -1219,7 +1219,7 @@ abstract class BarrierGuard extends Node { // Case: a function like "return someBarrierGuard(arg)" // or "return !someBarrierGuard(arg) && otherCond(...)" exists(boolean outcome | - not exists(DataFlow::Node otherRet | otherRet = outp.getEntryNode(fd) | otherRet != ret) and + ret = getUniqueOutputNode(fd, outp) and this.checks(arg.asExpr(), outcome) and // This predicate's contract is (p holds of ret ==> arg is checked), // (and we have (this has outcome ==> arg is checked)) @@ -1234,7 +1234,7 @@ abstract class BarrierGuard extends Node { Function f2, FunctionInput inp2, FunctionOutput outp2, CallNode c, DataFlow::Property outpProp | - not exists(DataFlow::Node otherRet | otherRet = outp.getEntryNode(fd) | otherRet != ret) and + ret = getUniqueOutputNode(fd, outp) and this.guardingFunction(f2, inp2, outp2, outpProp) and c = f2.getACall() and arg = inp2.getNode(c) and @@ -1252,6 +1252,10 @@ abstract class BarrierGuard extends Node { } } +DataFlow::Node getUniqueOutputNode(FuncDecl fd, FunctionOutput outp) { + result = unique(DataFlow::Node n | n = outp.getEntryNode(fd) | n) +} + /** * Holds if `ret` is a data-flow node whose value contributes to the output `res` of `fd`, * and that node may have Boolean value `b`. diff --git a/ql/src/semmle/go/frameworks/SQL.qll b/ql/src/semmle/go/frameworks/SQL.qll index f626fe097ca..b8c51750b8f 100644 --- a/ql/src/semmle/go/frameworks/SQL.qll +++ b/ql/src/semmle/go/frameworks/SQL.qll @@ -224,3 +224,33 @@ module Gorm { result = package(["github.com/jinzhu/gorm", "github.com/go-gorm/gorm", "gorm.io/gorm"], "") } } + +/** + * Provides classes for working with the [XORM](https://xorm.io/) package. + */ +module Xorm { + /** Gets the package name for Xorm. */ + string packagePath() { result = package(["xorm.io/xorm", "github.com/go-xorm/xorm"], "") } + + /** A model for sinks of XORM. */ + private class XormSink extends SQL::QueryString::Range { + XormSink() { + exists(Method meth, string type, string name, int n | + meth.hasQualifiedName(Xorm::packagePath(), type, name) and + this = meth.getACall().getArgument(n) and + type = ["Engine", "Session"] + | + name = + [ + "Query", "Exec", "QueryString", "QueryInterface", "SQL", "Where", "And", "Or", "Alias", + "NotIn", "In", "Select", "SetExpr", "OrderBy", "Having", "GroupBy" + ] and + n = 0 + or + name = ["SumInt", "Sum", "Sums", "SumsInt"] and n = 1 + or + name = "Join" and n = [0, 1, 2] + ) + } + } +} diff --git a/ql/src/semmle/go/frameworks/stdlib/ArchiveTar.qll b/ql/src/semmle/go/frameworks/stdlib/ArchiveTar.qll index 4b57dd6919c..baaf8ca603f 100644 --- a/ql/src/semmle/go/frameworks/stdlib/ArchiveTar.qll +++ b/ql/src/semmle/go/frameworks/stdlib/ArchiveTar.qll @@ -35,15 +35,15 @@ module ArchiveTar { MethodModels() { // Methods: - // signature: func (*Header).FileInfo() os.FileInfo + // signature: func (*Header) FileInfo() os.FileInfo hasQualifiedName("archive/tar", "Header", "FileInfo") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Reader).Next() (*Header, error) + // signature: func (*Reader) Next() (*Header, error) hasQualifiedName("archive/tar", "Reader", "Next") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Writer).WriteHeader(hdr *Header) error + // signature: func (*Writer) WriteHeader(hdr *Header) error hasQualifiedName("archive/tar", "Writer", "WriteHeader") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/ArchiveZip.qll b/ql/src/semmle/go/frameworks/stdlib/ArchiveZip.qll index e1e480b285f..8b25fd334fc 100644 --- a/ql/src/semmle/go/frameworks/stdlib/ArchiveZip.qll +++ b/ql/src/semmle/go/frameworks/stdlib/ArchiveZip.qll @@ -38,15 +38,27 @@ module ArchiveZip { FunctionOutput outp; MethodModels() { - // signature: func (*File).Open() (io.ReadCloser, error) + // signature: func (*File) Open() (io.ReadCloser, error) hasQualifiedName("archive/zip", "File", "Open") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Writer).Create(name string) (io.Writer, error) + // signature: func (*File) OpenRaw() (io.Reader, error) + hasQualifiedName("archive/zip", "File", "OpenRaw") and + (inp.isReceiver() and outp.isResult(0)) + or + // signature: func (*Writer) Copy(f *File) error + hasQualifiedName("archive/zip", "Writer", "Copy") and + (inp.isParameter(0) and outp.isReceiver()) + or + // signature: func (*Writer) Create(name string) (io.Writer, error) hasQualifiedName("archive/zip", "Writer", "Create") and (inp.isResult(0) and outp.isReceiver()) or - // signature: func (*Writer).CreateHeader(fh *FileHeader) (io.Writer, error) + // signature: func (*Writer) CreateRaw(fh *FileHeader) (io.Writer, error) + hasQualifiedName("archive/zip", "Writer", "CreateRaw") and + (inp.isResult(0) and outp.isReceiver()) + or + // signature: func (*Writer) CreateHeader(fh *FileHeader) (io.Writer, error) hasQualifiedName("archive/zip", "Writer", "CreateHeader") and (inp.isResult(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Bufio.qll b/ql/src/semmle/go/frameworks/stdlib/Bufio.qll index 4c81861a12c..dc0fa3a5cc6 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Bufio.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Bufio.qll @@ -79,39 +79,39 @@ module Bufio { FunctionOutput outp; MethodModels() { - // signature: func (*Reader).Peek(n int) ([]byte, error) + // signature: func (*Reader) Peek(n int) ([]byte, error) hasQualifiedName("bufio", "Reader", "Peek") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadBytes(delim byte) ([]byte, error) + // signature: func (*Reader) ReadBytes(delim byte) ([]byte, error) hasQualifiedName("bufio", "Reader", "ReadBytes") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadLine() (line []byte, isPrefix bool, err error) + // signature: func (*Reader) ReadLine() (line []byte, isPrefix bool, err error) hasQualifiedName("bufio", "Reader", "ReadLine") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadSlice(delim byte) (line []byte, err error) + // signature: func (*Reader) ReadSlice(delim byte) (line []byte, err error) hasQualifiedName("bufio", "Reader", "ReadSlice") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadString(delim byte) (string, error) + // signature: func (*Reader) ReadString(delim byte) (string, error) hasQualifiedName("bufio", "Reader", "ReadString") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).Reset(r io.Reader) + // signature: func (*Reader) Reset(r io.Reader) hasQualifiedName("bufio", "Reader", "Reset") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Scanner).Bytes() []byte + // signature: func (*Scanner) Bytes() []byte hasQualifiedName("bufio", "Scanner", "Bytes") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Scanner).Text() string + // signature: func (*Scanner) Text() string hasQualifiedName("bufio", "Scanner", "Text") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Writer).Reset(w io.Writer) + // signature: func (*Writer) Reset(w io.Writer) hasQualifiedName("bufio", "Writer", "Reset") and (inp.isReceiver() and outp.isParameter(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Bytes.qll b/ql/src/semmle/go/frameworks/stdlib/Bytes.qll index c87d69b4541..c2791b1eaa3 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Bytes.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Bytes.qll @@ -150,23 +150,23 @@ module Bytes { FunctionOutput outp; MethodModels() { - // signature: func (*Buffer).Bytes() []byte + // signature: func (*Buffer) Bytes() []byte hasQualifiedName("bytes", "Buffer", "Bytes") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Buffer).Next(n int) []byte + // signature: func (*Buffer) Next(n int) []byte hasQualifiedName("bytes", "Buffer", "Next") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Buffer).ReadBytes(delim byte) (line []byte, err error) + // signature: func (*Buffer) ReadBytes(delim byte) (line []byte, err error) hasQualifiedName("bytes", "Buffer", "ReadBytes") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Buffer).ReadString(delim byte) (line string, err error) + // signature: func (*Buffer) ReadString(delim byte) (line string, err error) hasQualifiedName("bytes", "Buffer", "ReadString") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).Reset(b []byte) + // signature: func (*Reader) Reset(b []byte) hasQualifiedName("bytes", "Reader", "Reset") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/CompressFlate.qll b/ql/src/semmle/go/frameworks/stdlib/CompressFlate.qll index dee4bf9aca3..a26ad967699 100644 --- a/ql/src/semmle/go/frameworks/stdlib/CompressFlate.qll +++ b/ql/src/semmle/go/frameworks/stdlib/CompressFlate.qll @@ -38,11 +38,11 @@ module CompressFlate { FunctionOutput outp; MethodModels() { - // signature: func (*Writer).Reset(dst io.Writer) + // signature: func (*Writer) Reset(dst io.Writer) hasQualifiedName("compress/flate", "Writer", "Reset") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (Resetter).Reset(r io.Reader, dict []byte) error + // signature: func (Resetter) Reset(r io.Reader, dict []byte) error implements("compress/flate", "Resetter", "Reset") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/CompressGzip.qll b/ql/src/semmle/go/frameworks/stdlib/CompressGzip.qll index 772ee24cded..366f8c7a634 100644 --- a/ql/src/semmle/go/frameworks/stdlib/CompressGzip.qll +++ b/ql/src/semmle/go/frameworks/stdlib/CompressGzip.qll @@ -34,11 +34,11 @@ module CompressGzip { FunctionOutput outp; MethodModels() { - // signature: func (*Reader).Reset(r io.Reader) error + // signature: func (*Reader) Reset(r io.Reader) error hasQualifiedName("compress/gzip", "Reader", "Reset") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Writer).Reset(w io.Writer) + // signature: func (*Writer) Reset(w io.Writer) hasQualifiedName("compress/gzip", "Writer", "Reset") and (inp.isReceiver() and outp.isParameter(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/CompressZlib.qll b/ql/src/semmle/go/frameworks/stdlib/CompressZlib.qll index 91f1b62318e..ab88b6319aa 100644 --- a/ql/src/semmle/go/frameworks/stdlib/CompressZlib.qll +++ b/ql/src/semmle/go/frameworks/stdlib/CompressZlib.qll @@ -42,11 +42,11 @@ module CompressZlib { FunctionOutput outp; MethodModels() { - // signature: func (*Writer).Reset(w io.Writer) + // signature: func (*Writer) Reset(w io.Writer) hasQualifiedName("compress/zlib", "Writer", "Reset") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (Resetter).Reset(r io.Reader, dict []byte) error + // signature: func (Resetter) Reset(r io.Reader, dict []byte) error implements("compress/zlib", "Resetter", "Reset") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/ContainerHeap.qll b/ql/src/semmle/go/frameworks/stdlib/ContainerHeap.qll index c62e5fe4725..ddd8c602c51 100644 --- a/ql/src/semmle/go/frameworks/stdlib/ContainerHeap.qll +++ b/ql/src/semmle/go/frameworks/stdlib/ContainerHeap.qll @@ -34,11 +34,11 @@ module ContainerHeap { FunctionOutput outp; MethodModels() { - // signature: func (Interface).Pop() interface{} + // signature: func (Interface) Pop() interface{} implements("container/heap", "Interface", "Pop") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Interface).Push(x interface{}) + // signature: func (Interface) Push(x interface{}) implements("container/heap", "Interface", "Push") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/ContainerList.qll b/ql/src/semmle/go/frameworks/stdlib/ContainerList.qll index 3b44e3c8bed..6efa1e96b8e 100644 --- a/ql/src/semmle/go/frameworks/stdlib/ContainerList.qll +++ b/ql/src/semmle/go/frameworks/stdlib/ContainerList.qll @@ -11,79 +11,79 @@ module ContainerList { FunctionOutput outp; MethodModels() { - // signature: func (*Element).Next() *Element + // signature: func (*Element) Next() *Element hasQualifiedName("container/list", "Element", "Next") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Element).Prev() *Element + // signature: func (*Element) Prev() *Element hasQualifiedName("container/list", "Element", "Prev") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*List).Back() *Element + // signature: func (*List) Back() *Element hasQualifiedName("container/list", "List", "Back") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*List).Front() *Element + // signature: func (*List) Front() *Element hasQualifiedName("container/list", "List", "Front") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*List).Init() *List + // signature: func (*List) Init() *List hasQualifiedName("container/list", "List", "Init") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*List).InsertAfter(v interface{}, mark *Element) *Element + // signature: func (*List) InsertAfter(v interface{}, mark *Element) *Element hasQualifiedName("container/list", "List", "InsertAfter") and ( inp.isParameter(0) and (outp.isReceiver() or outp.isResult()) ) or - // signature: func (*List).InsertBefore(v interface{}, mark *Element) *Element + // signature: func (*List) InsertBefore(v interface{}, mark *Element) *Element hasQualifiedName("container/list", "List", "InsertBefore") and ( inp.isParameter(0) and (outp.isReceiver() or outp.isResult()) ) or - // signature: func (*List).MoveAfter(e *Element, mark *Element) + // signature: func (*List) MoveAfter(e *Element, mark *Element) hasQualifiedName("container/list", "List", "MoveAfter") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*List).MoveBefore(e *Element, mark *Element) + // signature: func (*List) MoveBefore(e *Element, mark *Element) hasQualifiedName("container/list", "List", "MoveBefore") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*List).MoveToBack(e *Element) + // signature: func (*List) MoveToBack(e *Element) hasQualifiedName("container/list", "List", "MoveToBack") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*List).MoveToFront(e *Element) + // signature: func (*List) MoveToFront(e *Element) hasQualifiedName("container/list", "List", "MoveToFront") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*List).PushBack(v interface{}) *Element + // signature: func (*List) PushBack(v interface{}) *Element hasQualifiedName("container/list", "List", "PushBack") and ( inp.isParameter(0) and (outp.isReceiver() or outp.isResult()) ) or - // signature: func (*List).PushBackList(other *List) + // signature: func (*List) PushBackList(other *List) hasQualifiedName("container/list", "List", "PushBackList") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*List).PushFront(v interface{}) *Element + // signature: func (*List) PushFront(v interface{}) *Element hasQualifiedName("container/list", "List", "PushFront") and ( inp.isParameter(0) and (outp.isReceiver() or outp.isResult()) ) or - // signature: func (*List).PushFrontList(other *List) + // signature: func (*List) PushFrontList(other *List) hasQualifiedName("container/list", "List", "PushFrontList") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*List).Remove(e *Element) interface{} + // signature: func (*List) Remove(e *Element) interface{} hasQualifiedName("container/list", "List", "Remove") and (inp.isParameter(0) and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/ContainerRing.qll b/ql/src/semmle/go/frameworks/stdlib/ContainerRing.qll index 94b83b6faf2..7463c0455f6 100644 --- a/ql/src/semmle/go/frameworks/stdlib/ContainerRing.qll +++ b/ql/src/semmle/go/frameworks/stdlib/ContainerRing.qll @@ -11,23 +11,23 @@ module ContainerRing { FunctionOutput outp; MethodModels() { - // signature: func (*Ring).Link(s *Ring) *Ring + // signature: func (*Ring) Link(s *Ring) *Ring hasQualifiedName("container/ring", "Ring", "Link") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Ring).Move(n int) *Ring + // signature: func (*Ring) Move(n int) *Ring hasQualifiedName("container/ring", "Ring", "Move") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Ring).Next() *Ring + // signature: func (*Ring) Next() *Ring hasQualifiedName("container/ring", "Ring", "Next") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Ring).Prev() *Ring + // signature: func (*Ring) Prev() *Ring hasQualifiedName("container/ring", "Ring", "Prev") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Ring).Unlink(n int) *Ring + // signature: func (*Ring) Unlink(n int) *Ring hasQualifiedName("container/ring", "Ring", "Unlink") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Context.qll b/ql/src/semmle/go/frameworks/stdlib/Context.qll index d8e7a133726..d65aa5c68dd 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Context.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Context.qll @@ -46,7 +46,7 @@ module Context { FunctionOutput outp; MethodModels() { - // signature: func (Context).Value(key interface{}) interface{} + // signature: func (Context) Value(key interface{}) interface{} implements(packagePath(), "Context", "Value") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Crypto.qll b/ql/src/semmle/go/frameworks/stdlib/Crypto.qll index bf9e32086b2..f1517304f7c 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Crypto.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Crypto.qll @@ -11,7 +11,7 @@ module Crypto { FunctionOutput outp; MethodModels() { - // signature: func (Decrypter).Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error) + // signature: func (Decrypter) Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error) implements("crypto", "Decrypter", "Decrypt") and (inp.isParameter(1) and outp.isResult(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/CryptoCipher.qll b/ql/src/semmle/go/frameworks/stdlib/CryptoCipher.qll index 8575afd3adb..a4817fe03b0 100644 --- a/ql/src/semmle/go/frameworks/stdlib/CryptoCipher.qll +++ b/ql/src/semmle/go/frameworks/stdlib/CryptoCipher.qll @@ -11,11 +11,11 @@ module CryptoCipher { FunctionOutput outp; MethodModels() { - // signature: func (Block).Decrypt(dst []byte, src []byte) + // signature: func (Block) Decrypt(dst []byte, src []byte) implements("crypto/cipher", "Block", "Decrypt") and (inp.isParameter(1) and outp.isParameter(0)) or - // signature: func (AEAD).Open(dst []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) + // signature: func (AEAD) Open(dst []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) implements("crypto/cipher", "AEAD", "Open") and ( inp.isParameter(2) and diff --git a/ql/src/semmle/go/frameworks/stdlib/CryptoRsa.qll b/ql/src/semmle/go/frameworks/stdlib/CryptoRsa.qll index d43fd282baf..6b48847d6bf 100644 --- a/ql/src/semmle/go/frameworks/stdlib/CryptoRsa.qll +++ b/ql/src/semmle/go/frameworks/stdlib/CryptoRsa.qll @@ -30,7 +30,7 @@ module CryptoRsa { FunctionOutput outp; MethodModels() { - // signature: func (*PrivateKey).Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) + // signature: func (*PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) hasQualifiedName("crypto/rsa", "PrivateKey", "Decrypt") and (inp.isParameter(1) and outp.isResult(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/DatabaseSql.qll b/ql/src/semmle/go/frameworks/stdlib/DatabaseSql.qll index 85cf5adeeaf..fa6bf309fa7 100644 --- a/ql/src/semmle/go/frameworks/stdlib/DatabaseSql.qll +++ b/ql/src/semmle/go/frameworks/stdlib/DatabaseSql.qll @@ -128,15 +128,15 @@ module DatabaseSql { FunctionOutput outp; SqlMethodModels() { - // signature: func (*Row).Scan(dest ...interface{}) error + // signature: func (*Row) Scan(dest ...interface{}) error this.hasQualifiedName("database/sql", "Row", "Scan") and (inp.isReceiver() and outp.isParameter(_)) or - // signature: func (*Rows).Scan(dest ...interface{}) error + // signature: func (*Rows) Scan(dest ...interface{}) error this.hasQualifiedName("database/sql", "Rows", "Scan") and (inp.isReceiver() and outp.isParameter(_)) or - // signature: func (Scanner).Scan(src interface{}) error + // signature: func (Scanner) Scan(src interface{}) error this.implements("database/sql", "Scanner", "Scan") and (inp.isParameter(0) and outp.isReceiver()) or @@ -159,27 +159,27 @@ module DatabaseSql { FunctionOutput outp; SqlDriverMethodModels() { - // signature: func (NotNull).ConvertValue(v interface{}) (Value, error) + // signature: func (NotNull) ConvertValue(v interface{}) (Value, error) this.hasQualifiedName("database/sql/driver", "NotNull", "ConvertValue") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (Null).ConvertValue(v interface{}) (Value, error) + // signature: func (Null) ConvertValue(v interface{}) (Value, error) this.hasQualifiedName("database/sql/driver", "Null", "ConvertValue") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (ValueConverter).ConvertValue(v interface{}) (Value, error) + // signature: func (ValueConverter) ConvertValue(v interface{}) (Value, error) this.implements("database/sql/driver", "ValueConverter", "ConvertValue") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (Conn).Prepare(query string) (Stmt, error) + // signature: func (Conn) Prepare(query string) (Stmt, error) this.implements("database/sql/driver", "Conn", "Prepare") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (ConnPrepareContext).PrepareContext(ctx context.Context, query string) (Stmt, error) + // signature: func (ConnPrepareContext) PrepareContext(ctx context.Context, query string) (Stmt, error) this.implements("database/sql/driver", "ConnPrepareContext", "PrepareContext") and (inp.isParameter(1) and outp.isResult(0)) or - // signature: func (Valuer).Value() (Value, error) + // signature: func (Valuer) Value() (Value, error) this.implements("database/sql/driver", "Valuer", "Value") and (inp.isReceiver() and outp.isResult(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Encoding.qll b/ql/src/semmle/go/frameworks/stdlib/Encoding.qll index 732434489d1..767d2d64cd8 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Encoding.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Encoding.qll @@ -11,19 +11,19 @@ module Encoding { FunctionOutput outp; MethodModels() { - // signature: func (BinaryMarshaler).MarshalBinary() (data []byte, err error) + // signature: func (BinaryMarshaler) MarshalBinary() (data []byte, err error) implements("encoding", "BinaryMarshaler", "MarshalBinary") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (TextMarshaler).MarshalText() (text []byte, err error) + // signature: func (TextMarshaler) MarshalText() (text []byte, err error) implements("encoding", "TextMarshaler", "MarshalText") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (BinaryUnmarshaler).UnmarshalBinary(data []byte) error + // signature: func (BinaryUnmarshaler) UnmarshalBinary(data []byte) error implements("encoding", "BinaryUnmarshaler", "UnmarshalBinary") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (TextUnmarshaler).UnmarshalText(text []byte) error + // signature: func (TextUnmarshaler) UnmarshalText(text []byte) error implements("encoding", "TextUnmarshaler", "UnmarshalText") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/EncodingBase32.qll b/ql/src/semmle/go/frameworks/stdlib/EncodingBase32.qll index 2d9dd67ec11..d1eae83abc2 100644 --- a/ql/src/semmle/go/frameworks/stdlib/EncodingBase32.qll +++ b/ql/src/semmle/go/frameworks/stdlib/EncodingBase32.qll @@ -26,11 +26,11 @@ module EncodingBase32 { FunctionOutput outp; MethodModels() { - // signature: func (*Encoding).Decode(dst []byte, src []byte) (n int, err error) + // signature: func (*Encoding) Decode(dst []byte, src []byte) (n int, err error) hasQualifiedName("encoding/base32", "Encoding", "Decode") and (inp.isParameter(1) and outp.isParameter(0)) or - // signature: func (*Encoding).DecodeString(s string) ([]byte, error) + // signature: func (*Encoding) DecodeString(s string) ([]byte, error) hasQualifiedName("encoding/base32", "Encoding", "DecodeString") and (inp.isParameter(0) and outp.isResult(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/EncodingBase64.qll b/ql/src/semmle/go/frameworks/stdlib/EncodingBase64.qll index a70a4afe648..82a68b5d0c2 100644 --- a/ql/src/semmle/go/frameworks/stdlib/EncodingBase64.qll +++ b/ql/src/semmle/go/frameworks/stdlib/EncodingBase64.qll @@ -26,11 +26,11 @@ module EncodingBase64 { FunctionOutput outp; MethodModels() { - // signature: func (*Encoding).Decode(dst []byte, src []byte) (n int, err error) + // signature: func (*Encoding) Decode(dst []byte, src []byte) (n int, err error) hasQualifiedName("encoding/base64", "Encoding", "Decode") and (inp.isParameter(1) and outp.isParameter(0)) or - // signature: func (*Encoding).DecodeString(s string) ([]byte, error) + // signature: func (*Encoding) DecodeString(s string) ([]byte, error) hasQualifiedName("encoding/base64", "Encoding", "DecodeString") and (inp.isParameter(0) and outp.isResult(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/EncodingCsv.qll b/ql/src/semmle/go/frameworks/stdlib/EncodingCsv.qll index f5c0d32e2bb..481dce5a5fd 100644 --- a/ql/src/semmle/go/frameworks/stdlib/EncodingCsv.qll +++ b/ql/src/semmle/go/frameworks/stdlib/EncodingCsv.qll @@ -30,19 +30,19 @@ module EncodingCsv { FunctionOutput outp; MethodModels() { - // signature: func (*Reader).Read() (record []string, err error) + // signature: func (*Reader) Read() (record []string, err error) hasQualifiedName("encoding/csv", "Reader", "Read") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadAll() (records [][]string, err error) + // signature: func (*Reader) ReadAll() (records [][]string, err error) hasQualifiedName("encoding/csv", "Reader", "ReadAll") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Writer).Write(record []string) error + // signature: func (*Writer) Write(record []string) error hasQualifiedName("encoding/csv", "Writer", "Write") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Writer).WriteAll(records [][]string) error + // signature: func (*Writer) WriteAll(records [][]string) error hasQualifiedName("encoding/csv", "Writer", "WriteAll") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/EncodingGob.qll b/ql/src/semmle/go/frameworks/stdlib/EncodingGob.qll index 98958be76db..19f7c1c6004 100644 --- a/ql/src/semmle/go/frameworks/stdlib/EncodingGob.qll +++ b/ql/src/semmle/go/frameworks/stdlib/EncodingGob.qll @@ -30,27 +30,27 @@ module EncodingGob { FunctionOutput outp; MethodModels() { - // signature: func (*Decoder).Decode(e interface{}) error + // signature: func (*Decoder) Decode(e interface{}) error hasQualifiedName("encoding/gob", "Decoder", "Decode") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Decoder).DecodeValue(v reflect.Value) error + // signature: func (*Decoder) DecodeValue(v reflect.Value) error hasQualifiedName("encoding/gob", "Decoder", "DecodeValue") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Encoder).Encode(e interface{}) error + // signature: func (*Encoder) Encode(e interface{}) error hasQualifiedName("encoding/gob", "Encoder", "Encode") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Encoder).EncodeValue(value reflect.Value) error + // signature: func (*Encoder) EncodeValue(value reflect.Value) error hasQualifiedName("encoding/gob", "Encoder", "EncodeValue") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (GobDecoder).GobDecode([]byte) error + // signature: func (GobDecoder) GobDecode([]byte) error implements("encoding/gob", "GobDecoder", "GobDecode") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (GobEncoder).GobEncode() ([]byte, error) + // signature: func (GobEncoder) GobEncode() ([]byte, error) implements("encoding/gob", "GobEncoder", "GobEncode") and (inp.isReceiver() and outp.isResult(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/EncodingJson.qll b/ql/src/semmle/go/frameworks/stdlib/EncodingJson.qll index d05cc73c25f..6d58176d85a 100644 --- a/ql/src/semmle/go/frameworks/stdlib/EncodingJson.qll +++ b/ql/src/semmle/go/frameworks/stdlib/EncodingJson.qll @@ -81,31 +81,31 @@ module EncodingJson { FunctionOutput outp; MethodModels() { - // signature: func (*Decoder).Buffered() io.Reader + // signature: func (*Decoder) Buffered() io.Reader hasQualifiedName("encoding/json", "Decoder", "Buffered") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Decoder).Decode(v interface{}) error + // signature: func (*Decoder) Decode(v interface{}) error hasQualifiedName("encoding/json", "Decoder", "Decode") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Decoder).Token() (Token, error) + // signature: func (*Decoder) Token() (Token, error) hasQualifiedName("encoding/json", "Decoder", "Token") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Encoder).Encode(v interface{}) error + // signature: func (*Encoder) Encode(v interface{}) error hasQualifiedName("encoding/json", "Encoder", "Encode") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Encoder).SetIndent(prefix string, indent string) + // signature: func (*Encoder) SetIndent(prefix string, indent string) hasQualifiedName("encoding/json", "Encoder", "SetIndent") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (Marshaler).MarshalJSON() ([]byte, error) + // signature: func (Marshaler) MarshalJSON() ([]byte, error) implements("encoding/json", "Marshaler", "MarshalJSON") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (Unmarshaler).UnmarshalJSON([]byte) error + // signature: func (Unmarshaler) UnmarshalJSON([]byte) error implements("encoding/json", "Unmarshaler", "UnmarshalJSON") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/EncodingXml.qll b/ql/src/semmle/go/frameworks/stdlib/EncodingXml.qll index 84ddecdd498..14d2e63e961 100644 --- a/ql/src/semmle/go/frameworks/stdlib/EncodingXml.qll +++ b/ql/src/semmle/go/frameworks/stdlib/EncodingXml.qll @@ -82,67 +82,67 @@ module EncodingXml { FunctionOutput outp; MethodModels() { - // signature: func (CharData).Copy() CharData + // signature: func (CharData) Copy() CharData hasQualifiedName("encoding/xml", "CharData", "Copy") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Comment).Copy() Comment + // signature: func (Comment) Copy() Comment hasQualifiedName("encoding/xml", "Comment", "Copy") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Decoder).Decode(v interface{}) error + // signature: func (*Decoder) Decode(v interface{}) error hasQualifiedName("encoding/xml", "Decoder", "Decode") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Decoder).DecodeElement(v interface{}, start *StartElement) error + // signature: func (*Decoder) DecodeElement(v interface{}, start *StartElement) error hasQualifiedName("encoding/xml", "Decoder", "DecodeElement") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Decoder).RawToken() (Token, error) + // signature: func (*Decoder) RawToken() (Token, error) hasQualifiedName("encoding/xml", "Decoder", "RawToken") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Decoder).Token() (Token, error) + // signature: func (*Decoder) Token() (Token, error) hasQualifiedName("encoding/xml", "Decoder", "Token") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (Directive).Copy() Directive + // signature: func (Directive) Copy() Directive hasQualifiedName("encoding/xml", "Directive", "Copy") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Encoder).Encode(v interface{}) error + // signature: func (*Encoder) Encode(v interface{}) error hasQualifiedName("encoding/xml", "Encoder", "Encode") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Encoder).EncodeElement(v interface{}, start StartElement) error + // signature: func (*Encoder) EncodeElement(v interface{}, start StartElement) error hasQualifiedName("encoding/xml", "Encoder", "EncodeElement") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Encoder).EncodeToken(t Token) error + // signature: func (*Encoder) EncodeToken(t Token) error hasQualifiedName("encoding/xml", "Encoder", "EncodeToken") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Encoder).Indent(prefix string, indent string) + // signature: func (*Encoder) Indent(prefix string, indent string) hasQualifiedName("encoding/xml", "Encoder", "Indent") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (ProcInst).Copy() ProcInst + // signature: func (ProcInst) Copy() ProcInst hasQualifiedName("encoding/xml", "ProcInst", "Copy") and (inp.isReceiver() and outp.isResult()) or - // signature: func (StartElement).Copy() StartElement + // signature: func (StartElement) Copy() StartElement hasQualifiedName("encoding/xml", "StartElement", "Copy") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Marshaler).MarshalXML(e *Encoder, start StartElement) error + // signature: func (Marshaler) MarshalXML(e *Encoder, start StartElement) error this.implements("encoding/xml", "Marshaler", "MarshalXML") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (TokenReader).Token() (Token, error) + // signature: func (TokenReader) Token() (Token, error) this.implements("encoding/xml", "TokenReader", "Token") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (Unmarshaler).UnmarshalXML(d *Decoder, start StartElement) error + // signature: func (Unmarshaler) UnmarshalXML(d *Decoder, start StartElement) error this.implements("encoding/xml", "Unmarshaler", "UnmarshalXML") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Expvar.qll b/ql/src/semmle/go/frameworks/stdlib/Expvar.qll index 1132a4f2350..01fbda900f4 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Expvar.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Expvar.qll @@ -11,27 +11,27 @@ module Expvar { FunctionOutput outp; MethodModels() { - // signature: func (Func).Value() interface{} + // signature: func (Func) Value() interface{} hasQualifiedName("expvar", "Func", "Value") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Map).Get(key string) Var + // signature: func (*Map) Get(key string) Var hasQualifiedName("expvar", "Map", "Get") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Map).Set(key string, av Var) + // signature: func (*Map) Set(key string, av Var) hasQualifiedName("expvar", "Map", "Set") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*String).Set(value string) + // signature: func (*String) Set(value string) hasQualifiedName("expvar", "String", "Set") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*String).Value() string + // signature: func (*String) Value() string hasQualifiedName("expvar", "String", "Value") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Var).String() string + // signature: func (Var) String() string implements("expvar", "Var", "String") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Fmt.qll b/ql/src/semmle/go/frameworks/stdlib/Fmt.qll index f3151c579d3..41a833c122a 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Fmt.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Fmt.qll @@ -137,23 +137,23 @@ module Fmt { FunctionOutput outp; MethodModels() { - // signature: func (GoStringer).GoString() string + // signature: func (GoStringer) GoString() string implements("fmt", "GoStringer", "GoString") and (inp.isReceiver() and outp.isResult()) or - // signature: func (ScanState).Read(buf []byte) (n int, err error) + // signature: func (ScanState) Read(buf []byte) (n int, err error) implements("fmt", "ScanState", "Read") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (Stringer).String() string + // signature: func (Stringer) String() string implements("fmt", "Stringer", "String") and (inp.isReceiver() and outp.isResult()) or - // signature: func (ScanState).Token(skipSpace bool, f func(rune) bool) (token []byte, err error) + // signature: func (ScanState) Token(skipSpace bool, f func(rune) bool) (token []byte, err error) implements("fmt", "ScanState", "Token") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (State).Write(b []byte) (n int, err error) + // signature: func (State) Write(b []byte) (n int, err error) this.implements("fmt", "State", "Write") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll b/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll index 45a7532afdb..54f3b959593 100644 --- a/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll +++ b/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll @@ -68,11 +68,11 @@ module HtmlTemplate { FunctionOutput outp; MethodModels() { - // signature: func (*Template).Execute(wr io.Writer, data interface{}) error + // signature: func (*Template) Execute(wr io.Writer, data interface{}) error hasQualifiedName("html/template", "Template", "Execute") and (inp.isParameter(1) and outp.isParameter(0)) or - // signature: func (*Template).ExecuteTemplate(wr io.Writer, name string, data interface{}) error + // signature: func (*Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error hasQualifiedName("html/template", "Template", "ExecuteTemplate") and (inp.isParameter(2) and outp.isParameter(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Io.qll b/ql/src/semmle/go/frameworks/stdlib/Io.qll index 968f45dfe9b..ffd95a660e0 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Io.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Io.qll @@ -81,31 +81,31 @@ module Io { FunctionOutput outp; MethodModels() { - // signature: func (Reader).Read(p []byte) (n int, err error) + // signature: func (Reader) Read(p []byte) (n int, err error) implements("io", "Reader", "Read") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (ReaderAt).ReadAt(p []byte, off int64) (n int, err error) + // signature: func (ReaderAt) ReadAt(p []byte, off int64) (n int, err error) implements("io", "ReaderAt", "ReadAt") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (ReaderFrom).ReadFrom(r Reader) (n int64, err error) + // signature: func (ReaderFrom) ReadFrom(r Reader) (n int64, err error) implements("io", "ReaderFrom", "ReadFrom") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Writer).Write(p []byte) (n int, err error) + // signature: func (Writer) Write(p []byte) (n int, err error) implements("io", "Writer", "Write") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (WriterAt).WriteAt(p []byte, off int64) (n int, err error) + // signature: func (WriterAt) WriteAt(p []byte, off int64) (n int, err error) implements("io", "WriterAt", "WriteAt") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (StringWriter).WriteString(s string) (n int, err error) + // signature: func (StringWriter) WriteString(s string) (n int, err error) implements("io", "StringWriter", "WriteString") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (WriterTo).WriteTo(w Writer) (n int64, err error) + // signature: func (WriterTo) WriteTo(w Writer) (n int64, err error) implements("io", "WriterTo", "WriteTo") and (inp.isReceiver() and outp.isParameter(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/IoFs.qll b/ql/src/semmle/go/frameworks/stdlib/IoFs.qll index 310d6da5749..ea6f1be33b0 100644 --- a/ql/src/semmle/go/frameworks/stdlib/IoFs.qll +++ b/ql/src/semmle/go/frameworks/stdlib/IoFs.qll @@ -16,6 +16,10 @@ module IoFs { FunctionOutput outp; FunctionModels() { + //signature: func FileInfoToDirEntry(info FileInfo) DirEntry + this.hasQualifiedName(packagePath(), "FileInfoToDirEntry") and + (inp.isParameter(0) and outp.isResult()) + or //signature: func Glob(fsys FS, pattern string) (matches []string, err error) this.hasQualifiedName(packagePath(), "Glob") and (inp.isParameter(0) and outp.isResult(0)) @@ -60,35 +64,35 @@ module IoFs { FunctionOutput outp; MethodModels() { - //signature: func (DirEntry).Name() string + //signature: func (DirEntry) Name() string this.implements(packagePath(), "DirEntry", "Name") and (inp.isReceiver() and outp.isResult()) or - //signature: func (DirEntry).Info() (FileInfo, error) + //signature: func (DirEntry) Info() (FileInfo, error) this.implements(packagePath(), "DirEntry", "Info") and (inp.isReceiver() and outp.isResult(0)) or - //signature: func (FS).Open(name string) (File, error) + //signature: func (FS) Open(name string) (File, error) this.implements(packagePath(), "FS", "Open") and (inp.isReceiver() and outp.isResult(0)) or - //signature: func (GlobFS).Glob(pattern string) ([]string, error) + //signature: func (GlobFS) Glob(pattern string) ([]string, error) this.implements(packagePath(), "GlobFS", "Glob") and (inp.isReceiver() and outp.isResult(0)) or - //signature: func (ReadDirFS).ReadDir(name string) ([]DirEntry, error) + //signature: func (ReadDirFS) ReadDir(name string) ([]DirEntry, error) this.implements(packagePath(), "ReadDirFS", "ReadDir") and (inp.isReceiver() and outp.isResult(0)) or - //signature: func (ReadFileFS).ReadFile(name string) ([]byte, error) + //signature: func (ReadFileFS) ReadFile(name string) ([]byte, error) this.implements(packagePath(), "ReadFileFS", "ReadFile") and (inp.isReceiver() and outp.isResult(0)) or - //signature: func (SubFS).Sub(dir string) (FS, error) + //signature: func (SubFS) Sub(dir string) (FS, error) this.implements(packagePath(), "SubFS", "Sub") and (inp.isReceiver() and outp.isResult(0)) or - //signature: func (File).Read([]byte) (int, error) + //signature: func (File) Read([]byte) (int, error) this.implements(packagePath(), "File", "Read") and (inp.isReceiver() and outp.isParameter(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Log.qll b/ql/src/semmle/go/frameworks/stdlib/Log.qll index f6b2dcfbd03..9d4c677be50 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Log.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Log.qll @@ -51,51 +51,51 @@ module Log { FunctionOutput outp; MethodModels() { - // signature: func (*Logger).Fatal(v ...interface{}) + // signature: func (*Logger) Fatal(v ...interface{}) hasQualifiedName("log", "Logger", "Fatal") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Fatalf(format string, v ...interface{}) + // signature: func (*Logger) Fatalf(format string, v ...interface{}) hasQualifiedName("log", "Logger", "Fatalf") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Fatalln(v ...interface{}) + // signature: func (*Logger) Fatalln(v ...interface{}) hasQualifiedName("log", "Logger", "Fatalln") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Panic(v ...interface{}) + // signature: func (*Logger) Panic(v ...interface{}) hasQualifiedName("log", "Logger", "Panic") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Panicf(format string, v ...interface{}) + // signature: func (*Logger) Panicf(format string, v ...interface{}) hasQualifiedName("log", "Logger", "Panicf") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Panicln(v ...interface{}) + // signature: func (*Logger) Panicln(v ...interface{}) hasQualifiedName("log", "Logger", "Panicln") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Print(v ...interface{}) + // signature: func (*Logger) Print(v ...interface{}) hasQualifiedName("log", "Logger", "Print") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Printf(format string, v ...interface{}) + // signature: func (*Logger) Printf(format string, v ...interface{}) hasQualifiedName("log", "Logger", "Printf") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).Println(v ...interface{}) + // signature: func (*Logger) Println(v ...interface{}) hasQualifiedName("log", "Logger", "Println") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Logger).SetOutput(w io.Writer) + // signature: func (*Logger) SetOutput(w io.Writer) hasQualifiedName("log", "Logger", "SetOutput") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Logger).SetPrefix(prefix string) + // signature: func (*Logger) SetPrefix(prefix string) hasQualifiedName("log", "Logger", "SetPrefix") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Logger).Writer() io.Writer + // signature: func (*Logger) Writer() io.Writer hasQualifiedName("log", "Logger", "Writer") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Mime.qll b/ql/src/semmle/go/frameworks/stdlib/Mime.qll index 34117d0f1ec..b04acdf4e6f 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Mime.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Mime.qll @@ -30,15 +30,15 @@ module Mime { FunctionOutput outp; MethodModels() { - // signature: func (*WordDecoder).Decode(word string) (string, error) + // signature: func (*WordDecoder) Decode(word string) (string, error) hasQualifiedName("mime", "WordDecoder", "Decode") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (*WordDecoder).DecodeHeader(header string) (string, error) + // signature: func (*WordDecoder) DecodeHeader(header string) (string, error) hasQualifiedName("mime", "WordDecoder", "DecodeHeader") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (WordEncoder).Encode(charset string, s string) string + // signature: func (WordEncoder) Encode(charset string, s string) string hasQualifiedName("mime", "WordEncoder", "Encode") and (inp.isParameter(1) and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/MimeMultipart.qll b/ql/src/semmle/go/frameworks/stdlib/MimeMultipart.qll index 9de15b824be..3f384b29454 100644 --- a/ql/src/semmle/go/frameworks/stdlib/MimeMultipart.qll +++ b/ql/src/semmle/go/frameworks/stdlib/MimeMultipart.qll @@ -30,43 +30,43 @@ module MimeMultipart { FunctionOutput outp; MethodModels() { - // signature: func (*FileHeader).Open() (File, error) + // signature: func (*FileHeader) Open() (File, error) hasQualifiedName("mime/multipart", "FileHeader", "Open") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Part).FileName() string + // signature: func (*Part) FileName() string hasQualifiedName("mime/multipart", "Part", "FileName") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Part).FormName() string + // signature: func (*Part) FormName() string hasQualifiedName("mime/multipart", "Part", "FormName") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).NextPart() (*Part, error) + // signature: func (*Reader) NextPart() (*Part, error) hasQualifiedName("mime/multipart", "Reader", "NextPart") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).NextRawPart() (*Part, error) + // signature: func (*Reader) NextRawPart() (*Part, error) hasQualifiedName("mime/multipart", "Reader", "NextRawPart") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadForm(maxMemory int64) (*Form, error) + // signature: func (*Reader) ReadForm(maxMemory int64) (*Form, error) hasQualifiedName("mime/multipart", "Reader", "ReadForm") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Writer).CreateFormField(fieldname string) (io.Writer, error) + // signature: func (*Writer) CreateFormField(fieldname string) (io.Writer, error) hasQualifiedName("mime/multipart", "Writer", "CreateFormField") and (inp.isResult(0) and outp.isReceiver()) or - // signature: func (*Writer).CreateFormFile(fieldname string, filename string) (io.Writer, error) + // signature: func (*Writer) CreateFormFile(fieldname string, filename string) (io.Writer, error) hasQualifiedName("mime/multipart", "Writer", "CreateFormFile") and (inp.isResult(0) and outp.isReceiver()) or - // signature: func (*Writer).CreatePart(header net/textproto.MIMEHeader) (io.Writer, error) + // signature: func (*Writer) CreatePart(header net/textproto.MIMEHeader) (io.Writer, error) hasQualifiedName("mime/multipart", "Writer", "CreatePart") and (inp.isResult(0) and outp.isReceiver()) or - // signature: func (*Writer).WriteField(fieldname string, value string) error + // signature: func (*Writer) WriteField(fieldname string, value string) error hasQualifiedName("mime/multipart", "Writer", "WriteField") and (inp.isParameter(_) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Net.qll b/ql/src/semmle/go/frameworks/stdlib/Net.qll index 0efc51218e2..96cf161ade6 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Net.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Net.qll @@ -54,15 +54,15 @@ module Net { FunctionOutput outp; MethodModels() { - // signature: func (*IPConn).ReadFromIP(b []byte) (int, *IPAddr, error) + // signature: func (*IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) hasQualifiedName("net", "IPConn", "ReadFromIP") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*IPConn).ReadMsgIP(b []byte, oob []byte) (n int, oobn int, flags int, addr *IPAddr, err error) + // signature: func (*IPConn) ReadMsgIP(b []byte, oob []byte) (n int, oobn int, flags int, addr *IPAddr, err error) hasQualifiedName("net", "IPConn", "ReadMsgIP") and (inp.isReceiver() and outp.isParameter(_)) or - // signature: func (*IPConn).SyscallConn() (syscall.RawConn, error) + // signature: func (*IPConn) SyscallConn() (syscall.RawConn, error) hasQualifiedName("net", "IPConn", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -70,15 +70,15 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*IPConn).WriteMsgIP(b []byte, oob []byte, addr *IPAddr) (n int, oobn int, err error) + // signature: func (*IPConn) WriteMsgIP(b []byte, oob []byte, addr *IPAddr) (n int, oobn int, err error) hasQualifiedName("net", "IPConn", "WriteMsgIP") and (inp.isParameter([0, 1]) and outp.isReceiver()) or - // signature: func (*IPConn).WriteToIP(b []byte, addr *IPAddr) (int, error) + // signature: func (*IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) hasQualifiedName("net", "IPConn", "WriteToIP") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*TCPConn).SyscallConn() (syscall.RawConn, error) + // signature: func (*TCPConn) SyscallConn() (syscall.RawConn, error) hasQualifiedName("net", "TCPConn", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -86,7 +86,7 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*TCPListener).File() (f *os.File, err error) + // signature: func (*TCPListener) File() (f *os.File, err error) hasQualifiedName("net", "TCPListener", "File") and ( inp.isReceiver() and outp.isResult(0) @@ -94,7 +94,7 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*TCPListener).SyscallConn() (syscall.RawConn, error) + // signature: func (*TCPListener) SyscallConn() (syscall.RawConn, error) hasQualifiedName("net", "TCPListener", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -102,15 +102,15 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*UDPConn).ReadFromUDP(b []byte) (int, *UDPAddr, error) + // signature: func (*UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) hasQualifiedName("net", "UDPConn", "ReadFromUDP") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*UDPConn).ReadMsgUDP(b []byte, oob []byte) (n int, oobn int, flags int, addr *UDPAddr, err error) + // signature: func (*UDPConn) ReadMsgUDP(b []byte, oob []byte) (n int, oobn int, flags int, addr *UDPAddr, err error) hasQualifiedName("net", "UDPConn", "ReadMsgUDP") and (inp.isReceiver() and outp.isParameter(_)) or - // signature: func (*UDPConn).SyscallConn() (syscall.RawConn, error) + // signature: func (*UDPConn) SyscallConn() (syscall.RawConn, error) hasQualifiedName("net", "UDPConn", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -118,23 +118,23 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*UDPConn).WriteMsgUDP(b []byte, oob []byte, addr *UDPAddr) (n int, oobn int, err error) + // signature: func (*UDPConn) WriteMsgUDP(b []byte, oob []byte, addr *UDPAddr) (n int, oobn int, err error) hasQualifiedName("net", "UDPConn", "WriteMsgUDP") and (inp.isParameter([0, 1]) and outp.isReceiver()) or - // signature: func (*UDPConn).WriteToUDP(b []byte, addr *UDPAddr) (int, error) + // signature: func (*UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) hasQualifiedName("net", "UDPConn", "WriteToUDP") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*UnixConn).ReadFromUnix(b []byte) (int, *UnixAddr, error) + // signature: func (*UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) hasQualifiedName("net", "UnixConn", "ReadFromUnix") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*UnixConn).ReadMsgUnix(b []byte, oob []byte) (n int, oobn int, flags int, addr *UnixAddr, err error) + // signature: func (*UnixConn) ReadMsgUnix(b []byte, oob []byte) (n int, oobn int, flags int, addr *UnixAddr, err error) hasQualifiedName("net", "UnixConn", "ReadMsgUnix") and (inp.isReceiver() and outp.isParameter(_)) or - // signature: func (*UnixConn).SyscallConn() (syscall.RawConn, error) + // signature: func (*UnixConn) SyscallConn() (syscall.RawConn, error) hasQualifiedName("net", "UnixConn", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -142,15 +142,15 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*UnixConn).WriteMsgUnix(b []byte, oob []byte, addr *UnixAddr) (n int, oobn int, err error) + // signature: func (*UnixConn) WriteMsgUnix(b []byte, oob []byte, addr *UnixAddr) (n int, oobn int, err error) hasQualifiedName("net", "UnixConn", "WriteMsgUnix") and (inp.isParameter([0, 1]) and outp.isReceiver()) or - // signature: func (*UnixConn).WriteToUnix(b []byte, addr *UnixAddr) (int, error) + // signature: func (*UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) hasQualifiedName("net", "UnixConn", "WriteToUnix") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*UnixListener).File() (f *os.File, err error) + // signature: func (*UnixListener) File() (f *os.File, err error) hasQualifiedName("net", "UnixListener", "File") and ( inp.isReceiver() and outp.isResult(0) @@ -158,7 +158,7 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*UnixListener).SyscallConn() (syscall.RawConn, error) + // signature: func (*UnixListener) SyscallConn() (syscall.RawConn, error) hasQualifiedName("net", "UnixListener", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -166,23 +166,23 @@ module Net { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (Conn).Read(b []byte) (n int, err error) + // signature: func (Conn) Read(b []byte) (n int, err error) implements("net", "Conn", "Read") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (PacketConn).ReadFrom(p []byte) (n int, addr Addr, err error) + // signature: func (PacketConn) ReadFrom(p []byte) (n int, addr Addr, err error) implements("net", "PacketConn", "ReadFrom") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (Addr).String() string + // signature: func (Addr) String() string implements("net", "Addr", "String") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Conn).Write(b []byte) (n int, err error) + // signature: func (Conn) Write(b []byte) (n int, err error) implements("net", "Conn", "Write") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (PacketConn).WriteTo(p []byte, addr Addr) (n int, err error) + // signature: func (PacketConn) WriteTo(p []byte, addr Addr) (n int, err error) implements("net", "PacketConn", "WriteTo") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/NetHttp.qll b/ql/src/semmle/go/frameworks/stdlib/NetHttp.qll index cb38284d116..23549f2fd4e 100644 --- a/ql/src/semmle/go/frameworks/stdlib/NetHttp.qll +++ b/ql/src/semmle/go/frameworks/stdlib/NetHttp.qll @@ -326,63 +326,63 @@ module NetHttp { FunctionOutput outp; MethodModels() { - // signature: func (Header).Add(key string, value string) + // signature: func (Header) Add(key string, value string) hasQualifiedName("net/http", "Header", "Add") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (Header).Clone() Header + // signature: func (Header) Clone() Header hasQualifiedName("net/http", "Header", "Clone") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Header).Get(key string) string + // signature: func (Header) Get(key string) string hasQualifiedName("net/http", "Header", "Get") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Header).Set(key string, value string) + // signature: func (Header) Set(key string, value string) hasQualifiedName("net/http", "Header", "Set") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (Header).Values(key string) []string + // signature: func (Header) Values(key string) []string hasQualifiedName("net/http", "Header", "Values") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Header).Write(w io.Writer) error + // signature: func (Header) Write(w io.Writer) error hasQualifiedName("net/http", "Header", "Write") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (Header).WriteSubset(w io.Writer, exclude map[string]bool) error + // signature: func (Header) WriteSubset(w io.Writer, exclude map[string]bool) error hasQualifiedName("net/http", "Header", "WriteSubset") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Request).AddCookie(c *Cookie) + // signature: func (*Request) AddCookie(c *Cookie) hasQualifiedName("net/http", "Request", "AddCookie") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Request).Clone(ctx context.Context) *Request + // signature: func (*Request) Clone(ctx context.Context) *Request hasQualifiedName("net/http", "Request", "Clone") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Request).Write(w io.Writer) error + // signature: func (*Request) Write(w io.Writer) error hasQualifiedName("net/http", "Request", "Write") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Request).WriteProxy(w io.Writer) error + // signature: func (*Request) WriteProxy(w io.Writer) error hasQualifiedName("net/http", "Request", "WriteProxy") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Response).Write(w io.Writer) error + // signature: func (*Response) Write(w io.Writer) error hasQualifiedName("net/http", "Response", "Write") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (*Transport).Clone() *Transport + // signature: func (*Transport) Clone() *Transport hasQualifiedName("net/http", "Transport", "Clone") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Hijacker).Hijack() (net.Conn, *bufio.ReadWriter, error) + // signature: func (Hijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) implements("net/http", "Hijacker", "Hijack") and (inp.isReceiver() and outp.isResult([0, 1])) or - // signature: func (ResponseWriter).Write([]byte) (int, error) + // signature: func (ResponseWriter) Write([]byte) (int, error) implements("net/http", "ResponseWriter", "Write") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/NetHttpHttputil.qll b/ql/src/semmle/go/frameworks/stdlib/NetHttpHttputil.qll index 116f9bdc9c5..aa7668d46b8 100644 --- a/ql/src/semmle/go/frameworks/stdlib/NetHttpHttputil.qll +++ b/ql/src/semmle/go/frameworks/stdlib/NetHttpHttputil.qll @@ -58,7 +58,7 @@ module NetHttpHttputil { FunctionOutput outp; MethodModels() { - // signature: func (*ClientConn).Hijack() (c net.Conn, r *bufio.Reader) + // signature: func (*ClientConn) Hijack() (c net.Conn, r *bufio.Reader) hasQualifiedName("net/http/httputil", "ClientConn", "Hijack") and ( inp.isReceiver() and outp.isResult(_) @@ -66,7 +66,7 @@ module NetHttpHttputil { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (*ServerConn).Hijack() (net.Conn, *bufio.Reader) + // signature: func (*ServerConn) Hijack() (net.Conn, *bufio.Reader) hasQualifiedName("net/http/httputil", "ServerConn", "Hijack") and ( inp.isReceiver() and outp.isResult(_) @@ -74,11 +74,11 @@ module NetHttpHttputil { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (BufferPool).Get() []byte + // signature: func (BufferPool) Get() []byte implements("net/http/httputil", "BufferPool", "Get") and (inp.isReceiver() and outp.isResult()) or - // signature: func (BufferPool).Put([]byte) + // signature: func (BufferPool) Put([]byte) implements("net/http/httputil", "BufferPool", "Put") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/NetMail.qll b/ql/src/semmle/go/frameworks/stdlib/NetMail.qll index 3f9ce44e80a..20e94219752 100644 --- a/ql/src/semmle/go/frameworks/stdlib/NetMail.qll +++ b/ql/src/semmle/go/frameworks/stdlib/NetMail.qll @@ -34,15 +34,15 @@ module NetMail { FunctionOutput outp; MethodModels() { - // signature: func (*AddressParser).Parse(address string) (*Address, error) + // signature: func (*AddressParser) Parse(address string) (*Address, error) hasQualifiedName("net/mail", "AddressParser", "Parse") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (*AddressParser).ParseList(list string) ([]*Address, error) + // signature: func (*AddressParser) ParseList(list string) ([]*Address, error) hasQualifiedName("net/mail", "AddressParser", "ParseList") and (inp.isParameter(0) and outp.isResult(0)) or - // signature: func (Header).Get(key string) string + // signature: func (Header) Get(key string) string hasQualifiedName("net/mail", "Header", "Get") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/NetTextproto.qll b/ql/src/semmle/go/frameworks/stdlib/NetTextproto.qll index b31a57fb248..7704b5486f9 100644 --- a/ql/src/semmle/go/frameworks/stdlib/NetTextproto.qll +++ b/ql/src/semmle/go/frameworks/stdlib/NetTextproto.qll @@ -50,67 +50,67 @@ module NetTextproto { FunctionOutput outp; MethodModels() { - // signature: func (MIMEHeader).Add(key string, value string) + // signature: func (MIMEHeader) Add(key string, value string) hasQualifiedName("net/textproto", "MIMEHeader", "Add") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (MIMEHeader).Get(key string) string + // signature: func (MIMEHeader) Get(key string) string hasQualifiedName("net/textproto", "MIMEHeader", "Get") and (inp.isReceiver() and outp.isResult()) or - // signature: func (MIMEHeader).Set(key string, value string) + // signature: func (MIMEHeader) Set(key string, value string) hasQualifiedName("net/textproto", "MIMEHeader", "Set") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (MIMEHeader).Values(key string) []string + // signature: func (MIMEHeader) Values(key string) []string hasQualifiedName("net/textproto", "MIMEHeader", "Values") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Reader).DotReader() io.Reader + // signature: func (*Reader) DotReader() io.Reader hasQualifiedName("net/textproto", "Reader", "DotReader") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Reader).ReadCodeLine(expectCode int) (code int, message string, err error) + // signature: func (*Reader) ReadCodeLine(expectCode int) (code int, message string, err error) hasQualifiedName("net/textproto", "Reader", "ReadCodeLine") and (inp.isReceiver() and outp.isResult(1)) or - // signature: func (*Reader).ReadContinuedLine() (string, error) + // signature: func (*Reader) ReadContinuedLine() (string, error) hasQualifiedName("net/textproto", "Reader", "ReadContinuedLine") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadContinuedLineBytes() ([]byte, error) + // signature: func (*Reader) ReadContinuedLineBytes() ([]byte, error) hasQualifiedName("net/textproto", "Reader", "ReadContinuedLineBytes") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadDotBytes() ([]byte, error) + // signature: func (*Reader) ReadDotBytes() ([]byte, error) hasQualifiedName("net/textproto", "Reader", "ReadDotBytes") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadDotLines() ([]string, error) + // signature: func (*Reader) ReadDotLines() ([]string, error) hasQualifiedName("net/textproto", "Reader", "ReadDotLines") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadLine() (string, error) + // signature: func (*Reader) ReadLine() (string, error) hasQualifiedName("net/textproto", "Reader", "ReadLine") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadLineBytes() ([]byte, error) + // signature: func (*Reader) ReadLineBytes() ([]byte, error) hasQualifiedName("net/textproto", "Reader", "ReadLineBytes") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadMIMEHeader() (MIMEHeader, error) + // signature: func (*Reader) ReadMIMEHeader() (MIMEHeader, error) hasQualifiedName("net/textproto", "Reader", "ReadMIMEHeader") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Reader).ReadResponse(expectCode int) (code int, message string, err error) + // signature: func (*Reader) ReadResponse(expectCode int) (code int, message string, err error) hasQualifiedName("net/textproto", "Reader", "ReadResponse") and (inp.isReceiver() and outp.isResult(1)) or - // signature: func (*Writer).DotWriter() io.WriteCloser + // signature: func (*Writer) DotWriter() io.WriteCloser hasQualifiedName("net/textproto", "Writer", "DotWriter") and (inp.isResult() and outp.isReceiver()) or - // signature: func (*Writer).PrintfLine(format string, args ...interface{}) error + // signature: func (*Writer) PrintfLine(format string, args ...interface{}) error hasQualifiedName("net/textproto", "Writer", "PrintfLine") and (inp.isParameter(_) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Os.qll b/ql/src/semmle/go/frameworks/stdlib/Os.qll index a5b94f3a471..a022b416d9e 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Os.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Os.qll @@ -110,11 +110,11 @@ module Os { FunctionOutput outp; MethodModels() { - // signature: func (*File).Fd() uintptr + // signature: func (*File) Fd() uintptr hasQualifiedName("os", "File", "Fd") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*File).SyscallConn() (syscall.RawConn, error) + // signature: func (*File) SyscallConn() (syscall.RawConn, error) hasQualifiedName("os", "File", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) diff --git a/ql/src/semmle/go/frameworks/stdlib/Reflect.qll b/ql/src/semmle/go/frameworks/stdlib/Reflect.qll index 46948a57148..150c3ae798e 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Reflect.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Reflect.qll @@ -42,139 +42,139 @@ module Reflect { FunctionOutput outp; MethodModels() { - // signature: func (*MapIter).Key() Value + // signature: func (*MapIter) Key() Value hasQualifiedName("reflect", "MapIter", "Key") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*MapIter).Value() Value + // signature: func (*MapIter) Value() Value hasQualifiedName("reflect", "MapIter", "Value") and (inp.isReceiver() and outp.isResult()) or - // signature: func (StructTag).Get(key string) string + // signature: func (StructTag) Get(key string) string hasQualifiedName("reflect", "StructTag", "Get") and (inp.isReceiver() and outp.isResult()) or - // signature: func (StructTag).Lookup(key string) (value string, ok bool) + // signature: func (StructTag) Lookup(key string) (value string, ok bool) hasQualifiedName("reflect", "StructTag", "Lookup") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (Value).Addr() Value + // signature: func (Value) Addr() Value hasQualifiedName("reflect", "Value", "Addr") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Bytes() []byte + // signature: func (Value) Bytes() []byte hasQualifiedName("reflect", "Value", "Bytes") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Convert(t Type) Value + // signature: func (Value) Convert(t Type) Value hasQualifiedName("reflect", "Value", "Convert") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Elem() Value + // signature: func (Value) Elem() Value hasQualifiedName("reflect", "Value", "Elem") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Field(i int) Value + // signature: func (Value) Field(i int) Value hasQualifiedName("reflect", "Value", "Field") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).FieldByIndex(index []int) Value + // signature: func (Value) FieldByIndex(index []int) Value hasQualifiedName("reflect", "Value", "FieldByIndex") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).FieldByName(name string) Value + // signature: func (Value) FieldByName(name string) Value hasQualifiedName("reflect", "Value", "FieldByName") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).FieldByNameFunc(match func(string) bool) Value + // signature: func (Value) FieldByNameFunc(match func(string) bool) Value hasQualifiedName("reflect", "Value", "FieldByNameFunc") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Index(i int) Value + // signature: func (Value) Index(i int) Value hasQualifiedName("reflect", "Value", "Index") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Interface() (i interface{}) + // signature: func (Value) Interface() (i interface{}) hasQualifiedName("reflect", "Value", "Interface") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).InterfaceData() [2]uintptr + // signature: func (Value) InterfaceData() [2]uintptr hasQualifiedName("reflect", "Value", "InterfaceData") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).MapIndex(key Value) Value + // signature: func (Value) MapIndex(key Value) Value hasQualifiedName("reflect", "Value", "MapIndex") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).MapKeys() []Value + // signature: func (Value) MapKeys() []Value hasQualifiedName("reflect", "Value", "MapKeys") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).MapRange() *MapIter + // signature: func (Value) MapRange() *MapIter hasQualifiedName("reflect", "Value", "MapRange") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Method(i int) Value + // signature: func (Value) Method(i int) Value hasQualifiedName("reflect", "Value", "Method") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).MethodByName(name string) Value + // signature: func (Value) MethodByName(name string) Value hasQualifiedName("reflect", "Value", "MethodByName") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Pointer() uintptr + // signature: func (Value) Pointer() uintptr hasQualifiedName("reflect", "Value", "Pointer") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Recv() (x Value, ok bool) + // signature: func (Value) Recv() (x Value, ok bool) hasQualifiedName("reflect", "Value", "Recv") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (Value).Send(x Value) + // signature: func (Value) Send(x Value) hasQualifiedName("reflect", "Value", "Send") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Value).Set(x Value) + // signature: func (Value) Set(x Value) hasQualifiedName("reflect", "Value", "Set") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Value).SetBytes(x []byte) + // signature: func (Value) SetBytes(x []byte) hasQualifiedName("reflect", "Value", "SetBytes") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Value).SetMapIndex(key Value, elem Value) + // signature: func (Value) SetMapIndex(key Value, elem Value) hasQualifiedName("reflect", "Value", "SetMapIndex") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (Value).SetPointer(x unsafe.Pointer) + // signature: func (Value) SetPointer(x unsafe.Pointer) hasQualifiedName("reflect", "Value", "SetPointer") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Value).SetString(x string) + // signature: func (Value) SetString(x string) hasQualifiedName("reflect", "Value", "SetString") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Value).Slice(i int, j int) Value + // signature: func (Value) Slice(i int, j int) Value hasQualifiedName("reflect", "Value", "Slice") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).Slice3(i int, j int, k int) Value + // signature: func (Value) Slice3(i int, j int, k int) Value hasQualifiedName("reflect", "Value", "Slice3") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).String() string + // signature: func (Value) String() string hasQualifiedName("reflect", "Value", "String") and (inp.isReceiver() and outp.isResult()) or - // signature: func (Value).TryRecv() (x Value, ok bool) + // signature: func (Value) TryRecv() (x Value, ok bool) hasQualifiedName("reflect", "Value", "TryRecv") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (Value).TrySend(x Value) bool + // signature: func (Value) TrySend(x Value) bool hasQualifiedName("reflect", "Value", "TrySend") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (Value).UnsafeAddr() uintptr + // signature: func (Value) UnsafeAddr() uintptr hasQualifiedName("reflect", "Value", "UnsafeAddr") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Regexp.qll b/ql/src/semmle/go/frameworks/stdlib/Regexp.qll index c83d950df39..bd12c50fd20 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Regexp.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Regexp.qll @@ -85,77 +85,77 @@ module Regexp { FunctionOutput outp; MethodModels() { - // signature: func (*Regexp).Expand(dst []byte, template []byte, src []byte, match []int) []byte + // signature: func (*Regexp) Expand(dst []byte, template []byte, src []byte, match []int) []byte hasQualifiedName("regexp", "Regexp", "Expand") and ( inp.isParameter([1, 2]) and (outp.isParameter(0) or outp.isResult()) ) or - // signature: func (*Regexp).ExpandString(dst []byte, template string, src string, match []int) []byte + // signature: func (*Regexp) ExpandString(dst []byte, template string, src string, match []int) []byte hasQualifiedName("regexp", "Regexp", "ExpandString") and ( inp.isParameter([1, 2]) and (outp.isParameter(0) or outp.isResult()) ) or - // signature: func (*Regexp).Find(b []byte) []byte + // signature: func (*Regexp) Find(b []byte) []byte hasQualifiedName("regexp", "Regexp", "Find") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindAll(b []byte, n int) [][]byte + // signature: func (*Regexp) FindAll(b []byte, n int) [][]byte hasQualifiedName("regexp", "Regexp", "FindAll") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindAllString(s string, n int) []string + // signature: func (*Regexp) FindAllString(s string, n int) []string hasQualifiedName("regexp", "Regexp", "FindAllString") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindAllStringSubmatch(s string, n int) [][]string + // signature: func (*Regexp) FindAllStringSubmatch(s string, n int) [][]string hasQualifiedName("regexp", "Regexp", "FindAllStringSubmatch") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindAllSubmatch(b []byte, n int) [][][]byte + // signature: func (*Regexp) FindAllSubmatch(b []byte, n int) [][][]byte hasQualifiedName("regexp", "Regexp", "FindAllSubmatch") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindString(s string) string + // signature: func (*Regexp) FindString(s string) string hasQualifiedName("regexp", "Regexp", "FindString") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindStringSubmatch(s string) []string + // signature: func (*Regexp) FindStringSubmatch(s string) []string hasQualifiedName("regexp", "Regexp", "FindStringSubmatch") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).FindSubmatch(b []byte) [][]byte + // signature: func (*Regexp) FindSubmatch(b []byte) [][]byte hasQualifiedName("regexp", "Regexp", "FindSubmatch") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Regexp).ReplaceAll(src []byte, repl []byte) []byte + // signature: func (*Regexp) ReplaceAll(src []byte, repl []byte) []byte hasQualifiedName("regexp", "Regexp", "ReplaceAll") and (inp.isParameter(_) and outp.isResult()) or - // signature: func (*Regexp).ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte + // signature: func (*Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte hasQualifiedName("regexp", "Regexp", "ReplaceAllFunc") and (inp.isParameter(_) and outp.isResult()) or - // signature: func (*Regexp).ReplaceAllLiteral(src []byte, repl []byte) []byte + // signature: func (*Regexp) ReplaceAllLiteral(src []byte, repl []byte) []byte hasQualifiedName("regexp", "Regexp", "ReplaceAllLiteral") and (inp.isParameter(_) and outp.isResult()) or - // signature: func (*Regexp).ReplaceAllLiteralString(src string, repl string) string + // signature: func (*Regexp) ReplaceAllLiteralString(src string, repl string) string hasQualifiedName("regexp", "Regexp", "ReplaceAllLiteralString") and (inp.isParameter(_) and outp.isResult()) or - // signature: func (*Regexp).ReplaceAllString(src string, repl string) string + // signature: func (*Regexp) ReplaceAllString(src string, repl string) string hasQualifiedName("regexp", "Regexp", "ReplaceAllString") and (inp.isParameter(_) and outp.isResult()) or - // signature: func (*Regexp).ReplaceAllStringFunc(src string, repl func(string) string) string + // signature: func (*Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string hasQualifiedName("regexp", "Regexp", "ReplaceAllStringFunc") and (inp.isParameter(_) and outp.isResult()) or - // signature: func (*Regexp).Split(s string, n int) []string + // signature: func (*Regexp) Split(s string, n int) []string hasQualifiedName("regexp", "Regexp", "Split") and (inp.isParameter(0) and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Strconv.qll b/ql/src/semmle/go/frameworks/stdlib/Strconv.qll index 7ad757e2580..14a5f4f29c4 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Strconv.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Strconv.qll @@ -56,6 +56,10 @@ module Strconv { hasQualifiedName("strconv", "Quote") and (inp.isParameter(0) and outp.isResult()) or + // signature: func QuotedPrefix(s string) (string, error) + hasQualifiedName("strconv", "QuotedPrefix") and + (inp.isParameter(0) and outp.isResult(0)) + or // signature: func QuoteToASCII(s string) string hasQualifiedName("strconv", "QuoteToASCII") and (inp.isParameter(0) and outp.isResult()) diff --git a/ql/src/semmle/go/frameworks/stdlib/Strings.qll b/ql/src/semmle/go/frameworks/stdlib/Strings.qll index f704634ff9b..07a2dcf23df 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Strings.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Strings.qll @@ -142,15 +142,15 @@ module Strings { FunctionOutput outp; MethodModels() { - // signature: func (*Reader).Reset(s string) + // signature: func (*Reader) Reset(s string) hasQualifiedName("strings", "Reader", "Reset") and (inp.isParameter(0) and outp.isReceiver()) or - // signature: func (*Replacer).Replace(s string) string + // signature: func (*Replacer) Replace(s string) string hasQualifiedName("strings", "Replacer", "Replace") and (inp.isParameter(0) and outp.isResult()) or - // signature: func (*Replacer).WriteString(w io.Writer, s string) (n int, err error) + // signature: func (*Replacer) WriteString(w io.Writer, s string) (n int, err error) hasQualifiedName("strings", "Replacer", "WriteString") and (inp.isParameter(1) and outp.isParameter(0)) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Sync.qll b/ql/src/semmle/go/frameworks/stdlib/Sync.qll index 3e7a5b8f0f6..b82e1e59804 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Sync.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Sync.qll @@ -11,11 +11,11 @@ module Sync { FunctionOutput outp; MethodModels() { - // signature: func (*Map).Load(key interface{}) (value interface{}, ok bool) + // signature: func (*Map) Load(key interface{}) (value interface{}, ok bool) hasQualifiedName("sync", "Map", "Load") and (inp.isReceiver() and outp.isResult(0)) or - // signature: func (*Map).LoadOrStore(key interface{}, value interface{}) (actual interface{}, loaded bool) + // signature: func (*Map) LoadOrStore(key interface{}, value interface{}) (actual interface{}, loaded bool) hasQualifiedName("sync", "Map", "LoadOrStore") and ( inp.isReceiver() and outp.isResult(0) @@ -24,15 +24,15 @@ module Sync { (outp.isReceiver() or outp.isResult(0)) ) or - // signature: func (*Map).Store(key interface{}, value interface{}) + // signature: func (*Map) Store(key interface{}, value interface{}) hasQualifiedName("sync", "Map", "Store") and (inp.isParameter(_) and outp.isReceiver()) or - // signature: func (*Pool).Get() interface{} + // signature: func (*Pool) Get() interface{} hasQualifiedName("sync", "Pool", "Get") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Pool).Put(x interface{}) + // signature: func (*Pool) Put(x interface{}) hasQualifiedName("sync", "Pool", "Put") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/SyncAtomic.qll b/ql/src/semmle/go/frameworks/stdlib/SyncAtomic.qll index 35f16ba15a6..373ea1d71ca 100644 --- a/ql/src/semmle/go/frameworks/stdlib/SyncAtomic.qll +++ b/ql/src/semmle/go/frameworks/stdlib/SyncAtomic.qll @@ -69,11 +69,11 @@ module SyncAtomic { FunctionOutput outp; MethodModels() { - // signature: func (*Value).Load() (x interface{}) + // signature: func (*Value) Load() (x interface{}) hasQualifiedName("sync/atomic", "Value", "Load") and (inp.isReceiver() and outp.isResult()) or - // signature: func (*Value).Store(x interface{}) + // signature: func (*Value) Store(x interface{}) hasQualifiedName("sync/atomic", "Value", "Store") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/Syscall.qll b/ql/src/semmle/go/frameworks/stdlib/Syscall.qll index e70591da381..7652a58b6e4 100644 --- a/ql/src/semmle/go/frameworks/stdlib/Syscall.qll +++ b/ql/src/semmle/go/frameworks/stdlib/Syscall.qll @@ -42,11 +42,11 @@ module Syscall { FunctionOutput outp; MethodModels() { - // signature: func (RawConn).Read(f func(fd uintptr) (done bool)) error + // signature: func (RawConn) Read(f func(fd uintptr) (done bool)) error implements("syscall", "RawConn", "Read") and (inp.isReceiver() and outp.isParameter(0)) or - // signature: func (Conn).SyscallConn() (RawConn, error) + // signature: func (Conn) SyscallConn() (RawConn, error) implements("syscall", "Conn", "SyscallConn") and ( inp.isReceiver() and outp.isResult(0) @@ -54,7 +54,7 @@ module Syscall { inp.isResult(0) and outp.isReceiver() ) or - // signature: func (RawConn).Write(f func(fd uintptr) (done bool)) error + // signature: func (RawConn) Write(f func(fd uintptr) (done bool)) error implements("syscall", "RawConn", "Write") and (inp.isParameter(0) and outp.isReceiver()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/TextScanner.qll b/ql/src/semmle/go/frameworks/stdlib/TextScanner.qll index c97104d6ac4..54864078e49 100644 --- a/ql/src/semmle/go/frameworks/stdlib/TextScanner.qll +++ b/ql/src/semmle/go/frameworks/stdlib/TextScanner.qll @@ -11,14 +11,14 @@ module TextScanner { FunctionOutput outp; MethodModels() { - // signature: func (*Scanner).Init(src io.Reader) *Scanner + // signature: func (*Scanner) Init(src io.Reader) *Scanner hasQualifiedName("text/scanner", "Scanner", "Init") and ( inp.isParameter(0) and (outp.isReceiver() or outp.isResult()) ) or - // signature: func (*Scanner).TokenText() string + // signature: func (*Scanner) TokenText() string hasQualifiedName("text/scanner", "Scanner", "TokenText") and (inp.isReceiver() and outp.isResult()) } diff --git a/ql/src/semmle/go/frameworks/stdlib/TextTabwriter.qll b/ql/src/semmle/go/frameworks/stdlib/TextTabwriter.qll index b4928eeb028..5d40f38b72e 100644 --- a/ql/src/semmle/go/frameworks/stdlib/TextTabwriter.qll +++ b/ql/src/semmle/go/frameworks/stdlib/TextTabwriter.qll @@ -26,7 +26,7 @@ module TextTabwriter { FunctionOutput outp; MethodModels() { - // signature: func (*Writer).Init(output io.Writer, minwidth int, tabwidth int, padding int, padchar byte, flags uint) *Writer + // signature: func (*Writer) Init(output io.Writer, minwidth int, tabwidth int, padding int, padchar byte, flags uint) *Writer hasQualifiedName("text/tabwriter", "Writer", "Init") and ( (inp.isReceiver() or inp.isResult()) and diff --git a/ql/src/semmle/go/frameworks/stdlib/TextTemplate.qll b/ql/src/semmle/go/frameworks/stdlib/TextTemplate.qll index 7b17a1679b9..d32630b56cc 100644 --- a/ql/src/semmle/go/frameworks/stdlib/TextTemplate.qll +++ b/ql/src/semmle/go/frameworks/stdlib/TextTemplate.qll @@ -87,11 +87,11 @@ module TextTemplate { FunctionOutput outp; MethodModels() { - // signature: func (*Template).Execute(wr io.Writer, data interface{}) error + // signature: func (*Template) Execute(wr io.Writer, data interface{}) error hasQualifiedName("text/template", "Template", "Execute") and (inp.isParameter(1) and outp.isParameter(0)) or - // signature: func (*Template).ExecuteTemplate(wr io.Writer, name string, data interface{}) error + // signature: func (*Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error hasQualifiedName("text/template", "Template", "ExecuteTemplate") and (inp.isParameter(2) and outp.isParameter(0)) } diff --git a/ql/test/experimental/CWE-326/InsufficientKeySize.qlref b/ql/test/experimental/CWE-326/InsufficientKeySize.qlref deleted file mode 100644 index 0eb444e257a..00000000000 --- a/ql/test/experimental/CWE-326/InsufficientKeySize.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/CWE-326/InsufficientKeySize.ql diff --git a/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected b/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected new file mode 100644 index 00000000000..bb197203f22 --- /dev/null +++ b/ql/test/experimental/CWE-400/DatabaseCallInLoop.expected @@ -0,0 +1,13 @@ +edges +| DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | +| test.go:10:1:12:1 | function declaration | test.go:11:2:11:13 | call to Take | +| test.go:14:1:16:1 | function declaration | test.go:15:2:15:13 | call to runQuery | +| test.go:15:2:15:13 | call to runQuery | test.go:10:1:12:1 | function declaration | +| test.go:20:2:22:2 | for statement | test.go:21:3:21:14 | call to runQuery | +| test.go:21:3:21:14 | call to runQuery | test.go:10:1:12:1 | function declaration | +| test.go:24:2:26:2 | for statement | test.go:25:3:25:17 | call to runRunQuery | +| test.go:25:3:25:17 | call to runRunQuery | test.go:14:1:16:1 | function declaration | +#select +| DatabaseCallInLoop.go:9:3:9:41 | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | $@ is called in $@ | DatabaseCallInLoop.go:9:3:9:41 | call to First | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | a loop | +| test.go:11:2:11:13 | call to Take | test.go:20:2:22:2 | for statement | test.go:11:2:11:13 | call to Take | $@ is called in $@ | test.go:11:2:11:13 | call to Take | call to Take | test.go:20:2:22:2 | for statement | a loop | +| test.go:11:2:11:13 | call to Take | test.go:24:2:26:2 | for statement | test.go:11:2:11:13 | call to Take | $@ is called in $@ | test.go:11:2:11:13 | call to Take | call to Take | test.go:24:2:26:2 | for statement | a loop | diff --git a/ql/test/experimental/CWE-400/DatabaseCallInLoop.go b/ql/test/experimental/CWE-400/DatabaseCallInLoop.go new file mode 100644 index 00000000000..138bbbcd9d4 --- /dev/null +++ b/ql/test/experimental/CWE-400/DatabaseCallInLoop.go @@ -0,0 +1,13 @@ +package main + +import "gorm.io/gorm" + +func getUsers(db *gorm.DB, names []string) []User { + res := make([]User, 0, len(names)) + for _, name := range names { + var user User + db.Where("name = ?", name).First(&user) + res = append(res, user) + } + return res +} diff --git a/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref b/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref new file mode 100644 index 00000000000..63f27c9b41f --- /dev/null +++ b/ql/test/experimental/CWE-400/DatabaseCallInLoop.qlref @@ -0,0 +1 @@ +experimental/CWE-400/DatabaseCallInLoop.ql diff --git a/ql/test/experimental/CWE-400/DatabaseCallInLoopGood.go b/ql/test/experimental/CWE-400/DatabaseCallInLoopGood.go new file mode 100644 index 00000000000..22928a6abc2 --- /dev/null +++ b/ql/test/experimental/CWE-400/DatabaseCallInLoopGood.go @@ -0,0 +1,9 @@ +package main + +import "gorm.io/gorm" + +func getUsersGood(db *gorm.DB, names []string) []User { + res := make([]User, 0, len(names)) + db.Where("name IN ?", names).Find(&res) + return res +} diff --git a/ql/test/experimental/CWE-400/go.mod b/ql/test/experimental/CWE-400/go.mod new file mode 100644 index 00000000000..8fa98bf285f --- /dev/null +++ b/ql/test/experimental/CWE-400/go.mod @@ -0,0 +1,5 @@ +module query-tests/databasecallinloop + +go 1.16 + +require gorm.io/gorm v1.21.12 diff --git a/ql/test/experimental/CWE-400/test.go b/ql/test/experimental/CWE-400/test.go new file mode 100644 index 00000000000..725fb541b38 --- /dev/null +++ b/ql/test/experimental/CWE-400/test.go @@ -0,0 +1,27 @@ +package main + +import "gorm.io/gorm" + +type User struct { + Id int64 + Name string +} + +func runQuery(db *gorm.DB) { + db.Take(nil) +} + +func runRunQuery(db *gorm.DB) { + runQuery(db) +} + +func main() { + var db *gorm.DB + for i := 0; i < 10; i++ { + runQuery(db) + } + + for i := 10; i > 0; i-- { + runRunQuery(db) + } +} diff --git a/ql/test/experimental/CWE-400/vendor/gorm.io/gorm/License b/ql/test/experimental/CWE-400/vendor/gorm.io/gorm/License new file mode 100644 index 00000000000..037e1653e69 --- /dev/null +++ b/ql/test/experimental/CWE-400/vendor/gorm.io/gorm/License @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-NOW Jinzhu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ql/test/experimental/CWE-400/vendor/gorm.io/gorm/stub.go b/ql/test/experimental/CWE-400/vendor/gorm.io/gorm/stub.go new file mode 100644 index 00000000000..dd9f079c446 --- /dev/null +++ b/ql/test/experimental/CWE-400/vendor/gorm.io/gorm/stub.go @@ -0,0 +1,803 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for gorm.io/gorm, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: gorm.io/gorm (exports: DB; functions: ) + +// Package gorm is a stub of gorm.io/gorm, generated by depstubber. +package gorm + +import ( + context "context" + sql "database/sql" + reflect "reflect" + strings "strings" + sync "sync" + time "time" +) + +type Association struct { + DB *DB + Relationship interface{} + Error error +} + +func (_ *Association) Append(_ ...interface{}) error { + return nil +} + +func (_ *Association) Clear() error { + return nil +} + +func (_ *Association) Count() int64 { + return 0 +} + +func (_ *Association) Delete(_ ...interface{}) error { + return nil +} + +func (_ *Association) Find(_ interface{}, _ ...interface{}) error { + return nil +} + +func (_ *Association) Replace(_ ...interface{}) error { + return nil +} + +type ColumnType interface { + DatabaseTypeName() string + DecimalSize() (int64, int64, bool) + Length() (int64, bool) + Name() string + Nullable() (bool, bool) +} + +type Config struct { + SkipDefaultTransaction bool + NamingStrategy interface{} + FullSaveAssociations bool + Logger interface{} + NowFunc func() time.Time + DryRun bool + PrepareStmt bool + DisableAutomaticPing bool + DisableForeignKeyConstraintWhenMigrating bool + DisableNestedTransaction bool + AllowGlobalUpdate bool + QueryFields bool + CreateBatchSize int + ClauseBuilders map[string]interface{} + ConnPool ConnPool + Dialector Dialector + Plugins map[string]Plugin +} + +func (_ Config) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {} + +func (_ Config) DataTypeOf(_ interface{}) string { + return "" +} + +func (_ Config) DefaultValueOf(_ interface{}) interface{} { + return nil +} + +func (_ Config) Explain(_ string, _ ...interface{}) string { + return "" +} + +func (_ Config) Initialize(_ *DB) error { + return nil +} + +func (_ Config) Migrator(_ *DB) Migrator { + return nil +} + +func (_ Config) Name() string { + return "" +} + +func (_ Config) QuoteTo(_ interface{}, _ string) {} + +func (_ *Config) AfterInitialize(_ *DB) error { + return nil +} + +func (_ *Config) Apply(_ *Config) error { + return nil +} + +type ConnPool interface { + ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error) + PrepareContext(_ context.Context, _ string) (*sql.Stmt, error) + QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error) + QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row +} + +type DB struct { + Config *Config + Error error + RowsAffected int64 + Statement *Statement +} + +func (_ DB) AfterInitialize(_ *DB) error { + return nil +} + +func (_ DB) Apply(_ *Config) error { + return nil +} + +func (_ DB) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {} + +func (_ DB) DataTypeOf(_ interface{}) string { + return "" +} + +func (_ DB) DefaultValueOf(_ interface{}) interface{} { + return nil +} + +func (_ DB) Explain(_ string, _ ...interface{}) string { + return "" +} + +func (_ DB) Initialize(_ *DB) error { + return nil +} + +func (_ DB) Name() string { + return "" +} + +func (_ DB) QuoteTo(_ interface{}, _ string) {} + +func (_ *DB) AddError(_ error) error { + return nil +} + +func (_ *DB) Assign(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) Association(_ string) *Association { + return nil +} + +func (_ *DB) Attrs(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) AutoMigrate(_ ...interface{}) error { + return nil +} + +func (_ *DB) Begin(_ ...*sql.TxOptions) *DB { + return nil +} + +func (_ *DB) Callback() interface{} { + return nil +} + +func (_ *DB) Clauses(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) Commit() *DB { + return nil +} + +func (_ *DB) Count(_ *int64) *DB { + return nil +} + +func (_ *DB) Create(_ interface{}) *DB { + return nil +} + +func (_ *DB) CreateInBatches(_ interface{}, _ int) *DB { + return nil +} + +func (_ *DB) DB() (*sql.DB, error) { + return nil, nil +} + +func (_ *DB) Debug() *DB { + return nil +} + +func (_ *DB) Delete(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Distinct(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) Exec(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Find(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB { + return nil +} + +func (_ *DB) First(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) FirstOrCreate(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) FirstOrInit(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Get(_ string) (interface{}, bool) { + return nil, false +} + +func (_ *DB) Group(_ string) *DB { + return nil +} + +func (_ *DB) Having(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) InstanceGet(_ string) (interface{}, bool) { + return nil, false +} + +func (_ *DB) InstanceSet(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) Joins(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Last(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Limit(_ int) *DB { + return nil +} + +func (_ *DB) Migrator() Migrator { + return nil +} + +func (_ *DB) Model(_ interface{}) *DB { + return nil +} + +func (_ *DB) Not(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Offset(_ int) *DB { + return nil +} + +func (_ *DB) Omit(_ ...string) *DB { + return nil +} + +func (_ *DB) Or(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Order(_ interface{}) *DB { + return nil +} + +func (_ *DB) Pluck(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) Preload(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Raw(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Rollback() *DB { + return nil +} + +func (_ *DB) RollbackTo(_ string) *DB { + return nil +} + +func (_ *DB) Row() *sql.Row { + return nil +} + +func (_ *DB) Rows() (*sql.Rows, error) { + return nil, nil +} + +func (_ *DB) Save(_ interface{}) *DB { + return nil +} + +func (_ *DB) SavePoint(_ string) *DB { + return nil +} + +func (_ *DB) Scan(_ interface{}) *DB { + return nil +} + +func (_ *DB) ScanRows(_ *sql.Rows, _ interface{}) error { + return nil +} + +func (_ *DB) Scopes(_ ...func(*DB) *DB) *DB { + return nil +} + +func (_ *DB) Select(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Session(_ *Session) *DB { + return nil +} + +func (_ *DB) Set(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) SetupJoinTable(_ interface{}, _ string, _ interface{}) error { + return nil +} + +func (_ *DB) Table(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Take(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error { + return nil +} + +func (_ *DB) Unscoped() *DB { + return nil +} + +func (_ *DB) Update(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) UpdateColumn(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) UpdateColumns(_ interface{}) *DB { + return nil +} + +func (_ *DB) Updates(_ interface{}) *DB { + return nil +} + +func (_ *DB) Use(_ Plugin) error { + return nil +} + +func (_ *DB) Where(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) WithContext(_ context.Context) *DB { + return nil +} + +type Dialector interface { + BindVarTo(_ interface{}, _ *Statement, _ interface{}) + DataTypeOf(_ interface{}) string + DefaultValueOf(_ interface{}) interface{} + Explain(_ string, _ ...interface{}) string + Initialize(_ *DB) error + Migrator(_ *DB) Migrator + Name() string + QuoteTo(_ interface{}, _ string) +} + +type Migrator interface { + AddColumn(_ interface{}, _ string) error + AlterColumn(_ interface{}, _ string) error + AutoMigrate(_ ...interface{}) error + ColumnTypes(_ interface{}) ([]ColumnType, error) + CreateConstraint(_ interface{}, _ string) error + CreateIndex(_ interface{}, _ string) error + CreateTable(_ ...interface{}) error + CreateView(_ string, _ ViewOption) error + CurrentDatabase() string + DropColumn(_ interface{}, _ string) error + DropConstraint(_ interface{}, _ string) error + DropIndex(_ interface{}, _ string) error + DropTable(_ ...interface{}) error + DropView(_ string) error + FullDataTypeOf(_ interface{}) interface{} + HasColumn(_ interface{}, _ string) bool + HasConstraint(_ interface{}, _ string) bool + HasIndex(_ interface{}, _ string) bool + HasTable(_ interface{}) bool + MigrateColumn(_ interface{}, _ interface{}, _ ColumnType) error + RenameColumn(_ interface{}, _ string, _ string) error + RenameIndex(_ interface{}, _ string, _ string) error + RenameTable(_ interface{}, _ interface{}) error +} + +type Plugin interface { + Initialize(_ *DB) error + Name() string +} + +type Session struct { + DryRun bool + PrepareStmt bool + NewDB bool + SkipHooks bool + SkipDefaultTransaction bool + DisableNestedTransaction bool + AllowGlobalUpdate bool + FullSaveAssociations bool + QueryFields bool + Context context.Context + Logger interface{} + NowFunc func() time.Time + CreateBatchSize int +} + +type Statement struct { + DB *DB + TableExpr interface{} + Table string + Model interface{} + Unscoped bool + Dest interface{} + ReflectValue reflect.Value + Clauses map[string]interface{} + BuildClauses []string + Distinct bool + Selects []string + Omits []string + Joins []interface{} + Preloads map[string][]interface{} + Settings sync.Map + ConnPool ConnPool + Schema interface{} + Context context.Context + RaiseErrorOnNotFound bool + SkipHooks bool + SQL strings.Builder + Vars []interface{} + CurDestIndex int +} + +func (_ Statement) AddError(_ error) error { + return nil +} + +func (_ Statement) AfterInitialize(_ *DB) error { + return nil +} + +func (_ Statement) Apply(_ *Config) error { + return nil +} + +func (_ Statement) Assign(_ ...interface{}) *DB { + return nil +} + +func (_ Statement) Association(_ string) *Association { + return nil +} + +func (_ Statement) Attrs(_ ...interface{}) *DB { + return nil +} + +func (_ Statement) AutoMigrate(_ ...interface{}) error { + return nil +} + +func (_ Statement) Begin(_ ...*sql.TxOptions) *DB { + return nil +} + +func (_ Statement) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {} + +func (_ Statement) Callback() interface{} { + return nil +} + +func (_ Statement) Commit() *DB { + return nil +} + +func (_ Statement) Count(_ *int64) *DB { + return nil +} + +func (_ Statement) Create(_ interface{}) *DB { + return nil +} + +func (_ Statement) CreateInBatches(_ interface{}, _ int) *DB { + return nil +} + +func (_ Statement) DataTypeOf(_ interface{}) string { + return "" +} + +func (_ Statement) Debug() *DB { + return nil +} + +func (_ Statement) DefaultValueOf(_ interface{}) interface{} { + return nil +} + +func (_ Statement) Delete(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Exec(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Explain(_ string, _ ...interface{}) string { + return "" +} + +func (_ Statement) Find(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB { + return nil +} + +func (_ Statement) First(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) FirstOrCreate(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) FirstOrInit(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Get(_ string) (interface{}, bool) { + return nil, false +} + +func (_ Statement) Group(_ string) *DB { + return nil +} + +func (_ Statement) Having(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Initialize(_ *DB) error { + return nil +} + +func (_ Statement) InstanceGet(_ string) (interface{}, bool) { + return nil, false +} + +func (_ Statement) InstanceSet(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) Last(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Limit(_ int) *DB { + return nil +} + +func (_ Statement) Migrator() Migrator { + return nil +} + +func (_ Statement) Name() string { + return "" +} + +func (_ Statement) Not(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Offset(_ int) *DB { + return nil +} + +func (_ Statement) Omit(_ ...string) *DB { + return nil +} + +func (_ Statement) Or(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Order(_ interface{}) *DB { + return nil +} + +func (_ Statement) Pluck(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) Preload(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Raw(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Rollback() *DB { + return nil +} + +func (_ Statement) RollbackTo(_ string) *DB { + return nil +} + +func (_ Statement) Row() *sql.Row { + return nil +} + +func (_ Statement) Rows() (*sql.Rows, error) { + return nil, nil +} + +func (_ Statement) Save(_ interface{}) *DB { + return nil +} + +func (_ Statement) SavePoint(_ string) *DB { + return nil +} + +func (_ Statement) Scan(_ interface{}) *DB { + return nil +} + +func (_ Statement) ScanRows(_ *sql.Rows, _ interface{}) error { + return nil +} + +func (_ Statement) Scopes(_ ...func(*DB) *DB) *DB { + return nil +} + +func (_ Statement) Select(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Session(_ *Session) *DB { + return nil +} + +func (_ Statement) Set(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) SetupJoinTable(_ interface{}, _ string, _ interface{}) error { + return nil +} + +func (_ Statement) Take(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error { + return nil +} + +func (_ Statement) Update(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) UpdateColumn(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) UpdateColumns(_ interface{}) *DB { + return nil +} + +func (_ Statement) Updates(_ interface{}) *DB { + return nil +} + +func (_ Statement) Use(_ Plugin) error { + return nil +} + +func (_ Statement) Where(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) WithContext(_ context.Context) *DB { + return nil +} + +func (_ *Statement) AddClause(_ interface{}) {} + +func (_ *Statement) AddClauseIfNotExists(_ interface{}) {} + +func (_ *Statement) AddVar(_ interface{}, _ ...interface{}) {} + +func (_ *Statement) Build(_ ...string) {} + +func (_ *Statement) BuildCondition(_ interface{}, _ ...interface{}) []interface{} { + return nil +} + +func (_ *Statement) Changed(_ ...string) bool { + return false +} + +func (_ *Statement) Parse(_ interface{}) error { + return nil +} + +func (_ *Statement) Quote(_ interface{}) string { + return "" +} + +func (_ *Statement) QuoteTo(_ interface{}, _ interface{}) {} + +func (_ *Statement) SelectAndOmitColumns(_ bool, _ bool) (map[string]bool, bool) { + return nil, false +} + +func (_ *Statement) SetColumn(_ string, _ interface{}, _ ...bool) {} + +func (_ *Statement) WriteByte(_ byte) error { + return nil +} + +func (_ *Statement) WriteQuoted(_ interface{}) {} + +func (_ *Statement) WriteString(_ string) (int, error) { + return 0, nil +} + +type ViewOption struct { + Replace bool + CheckOption string + Query *DB +} diff --git a/ql/test/experimental/CWE-400/vendor/modules.txt b/ql/test/experimental/CWE-400/vendor/modules.txt new file mode 100644 index 00000000000..52a1f62b367 --- /dev/null +++ b/ql/test/experimental/CWE-400/vendor/modules.txt @@ -0,0 +1,3 @@ +# gorm.io/gorm v1.21.12 +## explicit +gorm.io/gorm diff --git a/ql/test/experimental/InconsistentCode/DeferInLoop.expected b/ql/test/experimental/InconsistentCode/DeferInLoop.expected new file mode 100644 index 00000000000..8652787cc06 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/DeferInLoop.expected @@ -0,0 +1,6 @@ +| DeferInLoop.go:8:3:8:20 | defer statement | This defer statement is in a $@. | DeferInLoop.go:6:2:13:2 | range statement | loop | +| test.go:6:3:6:14 | defer statement | This defer statement is in a $@. | test.go:5:2:7:2 | range statement | loop | +| test.go:11:4:11:15 | defer statement | This defer statement is in a $@. | test.go:9:2:13:2 | range statement | loop | +| test.go:16:3:16:14 | defer statement | This defer statement is in a $@. | test.go:15:2:17:2 | for statement | loop | +| test.go:20:3:20:14 | defer statement | This defer statement is in a $@. | test.go:19:2:21:2 | for statement | loop | +| test.go:24:3:24:14 | defer statement | This defer statement is in a $@. | test.go:23:2:25:2 | for statement | loop | diff --git a/ql/test/experimental/InconsistentCode/DeferInLoop.go b/ql/test/experimental/InconsistentCode/DeferInLoop.go new file mode 100644 index 00000000000..1b57d1855b4 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/DeferInLoop.go @@ -0,0 +1,14 @@ +package main + +import "os" + +func openFiles(filenames []string) { + for _, filename := range filenames { + file, err := os.Open(filename) + defer file.Close() + if err != nil { + // handle error + } + // work on file + } +} diff --git a/ql/test/experimental/InconsistentCode/DeferInLoop.qlref b/ql/test/experimental/InconsistentCode/DeferInLoop.qlref new file mode 100644 index 00000000000..e50bcf4fdf6 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/DeferInLoop.qlref @@ -0,0 +1 @@ +experimental/InconsistentCode/DeferInLoop.ql diff --git a/ql/test/experimental/InconsistentCode/DeferInLoopGood.go b/ql/test/experimental/InconsistentCode/DeferInLoopGood.go new file mode 100644 index 00000000000..d28bc8e4cb9 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/DeferInLoopGood.go @@ -0,0 +1,18 @@ +package main + +import "os" + +func openFile(filename string) { + file, err := os.Open(filename) + defer file.Close() + if err != nil { + // handle error + } + // work on file +} + +func openFilesGood(filenames []string) { + for _, filename := range filenames { + openFile(filename) + } +} diff --git a/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.expected b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.expected new file mode 100644 index 00000000000..4d75b035fec --- /dev/null +++ b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.expected @@ -0,0 +1 @@ +| GORMErrorNotChecked.go:7:2:7:40 | call to First | This call appears to interact with the database without checking whether an error was encountered. | diff --git a/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go new file mode 100644 index 00000000000..422e49b5f10 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.go @@ -0,0 +1,9 @@ +package main + +import "gorm.io/gorm" + +func getUserId(db *gorm.DB, name string) int64 { + var user User + db.Where("name = ?", name).First(&user) + return user.Id +} diff --git a/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qhelp b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qhelp new file mode 100644 index 00000000000..1f64e06dc19 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qhelp @@ -0,0 +1,35 @@ + + + + +

    GORM errors are returned as a field of the return value instead of a separate return value.

    + +

    It is therefore very easy to miss that an error may occur and omit error handling routines.

    +
    + + +

    Ensure that GORM errors are checked.

    + +
    + + +

    In the example below,

    + + + +

    The corrected version of user checks err before using ptr.

    + + + +
    + + +
  • + The Go Blog: + Error handling and Go. +
  • + +
    +
    diff --git a/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref new file mode 100644 index 00000000000..b52256ad539 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/GORMErrorNotChecked.qlref @@ -0,0 +1 @@ +experimental/InconsistentCode/GORMErrorNotChecked.ql diff --git a/ql/test/experimental/InconsistentCode/GORMErrorNotCheckedGood.go b/ql/test/experimental/InconsistentCode/GORMErrorNotCheckedGood.go new file mode 100644 index 00000000000..551e06fb66a --- /dev/null +++ b/ql/test/experimental/InconsistentCode/GORMErrorNotCheckedGood.go @@ -0,0 +1,11 @@ +package main + +import "gorm.io/gorm" + +func getUserIdGood(db *gorm.DB, name string) int64 { + var user User + if err := db.Where("name = ?", name).First(&user).Error; err != nil { + // handle errors + } + return user.Id +} diff --git a/ql/test/experimental/InconsistentCode/go.mod b/ql/test/experimental/InconsistentCode/go.mod new file mode 100644 index 00000000000..e3b89d1ab9f --- /dev/null +++ b/ql/test/experimental/InconsistentCode/go.mod @@ -0,0 +1,5 @@ +module query-tests/gormerrornotchecked + +go 1.16 + +require gorm.io/gorm v1.21.12 diff --git a/ql/test/experimental/InconsistentCode/test.go b/ql/test/experimental/InconsistentCode/test.go new file mode 100644 index 00000000000..1dc64350bd4 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/test.go @@ -0,0 +1,26 @@ +package main + +func test() { + var xs []int + for _ = range xs { + defer test() // not ok + } + + for _ = range xs { + if true { + defer test() // not ok + } + } + + for i := 0; i < 10; i++ { + defer test() + } + + for true { + defer test() // not ok + } + + for false { + defer test() // fine but caught + } +} diff --git a/ql/test/experimental/InconsistentCode/util.go b/ql/test/experimental/InconsistentCode/util.go new file mode 100644 index 00000000000..0074e1f23f1 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/util.go @@ -0,0 +1,9 @@ +package main + +type User struct { + Id int64 + Name string +} + +func main() { +} diff --git a/ql/test/experimental/InconsistentCode/vendor/gorm.io/gorm/License b/ql/test/experimental/InconsistentCode/vendor/gorm.io/gorm/License new file mode 100644 index 00000000000..037e1653e69 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/vendor/gorm.io/gorm/License @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-NOW Jinzhu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/ql/test/experimental/InconsistentCode/vendor/gorm.io/gorm/stub.go b/ql/test/experimental/InconsistentCode/vendor/gorm.io/gorm/stub.go new file mode 100644 index 00000000000..dd9f079c446 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/vendor/gorm.io/gorm/stub.go @@ -0,0 +1,803 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for gorm.io/gorm, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: gorm.io/gorm (exports: DB; functions: ) + +// Package gorm is a stub of gorm.io/gorm, generated by depstubber. +package gorm + +import ( + context "context" + sql "database/sql" + reflect "reflect" + strings "strings" + sync "sync" + time "time" +) + +type Association struct { + DB *DB + Relationship interface{} + Error error +} + +func (_ *Association) Append(_ ...interface{}) error { + return nil +} + +func (_ *Association) Clear() error { + return nil +} + +func (_ *Association) Count() int64 { + return 0 +} + +func (_ *Association) Delete(_ ...interface{}) error { + return nil +} + +func (_ *Association) Find(_ interface{}, _ ...interface{}) error { + return nil +} + +func (_ *Association) Replace(_ ...interface{}) error { + return nil +} + +type ColumnType interface { + DatabaseTypeName() string + DecimalSize() (int64, int64, bool) + Length() (int64, bool) + Name() string + Nullable() (bool, bool) +} + +type Config struct { + SkipDefaultTransaction bool + NamingStrategy interface{} + FullSaveAssociations bool + Logger interface{} + NowFunc func() time.Time + DryRun bool + PrepareStmt bool + DisableAutomaticPing bool + DisableForeignKeyConstraintWhenMigrating bool + DisableNestedTransaction bool + AllowGlobalUpdate bool + QueryFields bool + CreateBatchSize int + ClauseBuilders map[string]interface{} + ConnPool ConnPool + Dialector Dialector + Plugins map[string]Plugin +} + +func (_ Config) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {} + +func (_ Config) DataTypeOf(_ interface{}) string { + return "" +} + +func (_ Config) DefaultValueOf(_ interface{}) interface{} { + return nil +} + +func (_ Config) Explain(_ string, _ ...interface{}) string { + return "" +} + +func (_ Config) Initialize(_ *DB) error { + return nil +} + +func (_ Config) Migrator(_ *DB) Migrator { + return nil +} + +func (_ Config) Name() string { + return "" +} + +func (_ Config) QuoteTo(_ interface{}, _ string) {} + +func (_ *Config) AfterInitialize(_ *DB) error { + return nil +} + +func (_ *Config) Apply(_ *Config) error { + return nil +} + +type ConnPool interface { + ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error) + PrepareContext(_ context.Context, _ string) (*sql.Stmt, error) + QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error) + QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row +} + +type DB struct { + Config *Config + Error error + RowsAffected int64 + Statement *Statement +} + +func (_ DB) AfterInitialize(_ *DB) error { + return nil +} + +func (_ DB) Apply(_ *Config) error { + return nil +} + +func (_ DB) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {} + +func (_ DB) DataTypeOf(_ interface{}) string { + return "" +} + +func (_ DB) DefaultValueOf(_ interface{}) interface{} { + return nil +} + +func (_ DB) Explain(_ string, _ ...interface{}) string { + return "" +} + +func (_ DB) Initialize(_ *DB) error { + return nil +} + +func (_ DB) Name() string { + return "" +} + +func (_ DB) QuoteTo(_ interface{}, _ string) {} + +func (_ *DB) AddError(_ error) error { + return nil +} + +func (_ *DB) Assign(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) Association(_ string) *Association { + return nil +} + +func (_ *DB) Attrs(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) AutoMigrate(_ ...interface{}) error { + return nil +} + +func (_ *DB) Begin(_ ...*sql.TxOptions) *DB { + return nil +} + +func (_ *DB) Callback() interface{} { + return nil +} + +func (_ *DB) Clauses(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) Commit() *DB { + return nil +} + +func (_ *DB) Count(_ *int64) *DB { + return nil +} + +func (_ *DB) Create(_ interface{}) *DB { + return nil +} + +func (_ *DB) CreateInBatches(_ interface{}, _ int) *DB { + return nil +} + +func (_ *DB) DB() (*sql.DB, error) { + return nil, nil +} + +func (_ *DB) Debug() *DB { + return nil +} + +func (_ *DB) Delete(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Distinct(_ ...interface{}) *DB { + return nil +} + +func (_ *DB) Exec(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Find(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB { + return nil +} + +func (_ *DB) First(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) FirstOrCreate(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) FirstOrInit(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Get(_ string) (interface{}, bool) { + return nil, false +} + +func (_ *DB) Group(_ string) *DB { + return nil +} + +func (_ *DB) Having(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) InstanceGet(_ string) (interface{}, bool) { + return nil, false +} + +func (_ *DB) InstanceSet(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) Joins(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Last(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Limit(_ int) *DB { + return nil +} + +func (_ *DB) Migrator() Migrator { + return nil +} + +func (_ *DB) Model(_ interface{}) *DB { + return nil +} + +func (_ *DB) Not(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Offset(_ int) *DB { + return nil +} + +func (_ *DB) Omit(_ ...string) *DB { + return nil +} + +func (_ *DB) Or(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Order(_ interface{}) *DB { + return nil +} + +func (_ *DB) Pluck(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) Preload(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Raw(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Rollback() *DB { + return nil +} + +func (_ *DB) RollbackTo(_ string) *DB { + return nil +} + +func (_ *DB) Row() *sql.Row { + return nil +} + +func (_ *DB) Rows() (*sql.Rows, error) { + return nil, nil +} + +func (_ *DB) Save(_ interface{}) *DB { + return nil +} + +func (_ *DB) SavePoint(_ string) *DB { + return nil +} + +func (_ *DB) Scan(_ interface{}) *DB { + return nil +} + +func (_ *DB) ScanRows(_ *sql.Rows, _ interface{}) error { + return nil +} + +func (_ *DB) Scopes(_ ...func(*DB) *DB) *DB { + return nil +} + +func (_ *DB) Select(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Session(_ *Session) *DB { + return nil +} + +func (_ *DB) Set(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) SetupJoinTable(_ interface{}, _ string, _ interface{}) error { + return nil +} + +func (_ *DB) Table(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Take(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error { + return nil +} + +func (_ *DB) Unscoped() *DB { + return nil +} + +func (_ *DB) Update(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) UpdateColumn(_ string, _ interface{}) *DB { + return nil +} + +func (_ *DB) UpdateColumns(_ interface{}) *DB { + return nil +} + +func (_ *DB) Updates(_ interface{}) *DB { + return nil +} + +func (_ *DB) Use(_ Plugin) error { + return nil +} + +func (_ *DB) Where(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ *DB) WithContext(_ context.Context) *DB { + return nil +} + +type Dialector interface { + BindVarTo(_ interface{}, _ *Statement, _ interface{}) + DataTypeOf(_ interface{}) string + DefaultValueOf(_ interface{}) interface{} + Explain(_ string, _ ...interface{}) string + Initialize(_ *DB) error + Migrator(_ *DB) Migrator + Name() string + QuoteTo(_ interface{}, _ string) +} + +type Migrator interface { + AddColumn(_ interface{}, _ string) error + AlterColumn(_ interface{}, _ string) error + AutoMigrate(_ ...interface{}) error + ColumnTypes(_ interface{}) ([]ColumnType, error) + CreateConstraint(_ interface{}, _ string) error + CreateIndex(_ interface{}, _ string) error + CreateTable(_ ...interface{}) error + CreateView(_ string, _ ViewOption) error + CurrentDatabase() string + DropColumn(_ interface{}, _ string) error + DropConstraint(_ interface{}, _ string) error + DropIndex(_ interface{}, _ string) error + DropTable(_ ...interface{}) error + DropView(_ string) error + FullDataTypeOf(_ interface{}) interface{} + HasColumn(_ interface{}, _ string) bool + HasConstraint(_ interface{}, _ string) bool + HasIndex(_ interface{}, _ string) bool + HasTable(_ interface{}) bool + MigrateColumn(_ interface{}, _ interface{}, _ ColumnType) error + RenameColumn(_ interface{}, _ string, _ string) error + RenameIndex(_ interface{}, _ string, _ string) error + RenameTable(_ interface{}, _ interface{}) error +} + +type Plugin interface { + Initialize(_ *DB) error + Name() string +} + +type Session struct { + DryRun bool + PrepareStmt bool + NewDB bool + SkipHooks bool + SkipDefaultTransaction bool + DisableNestedTransaction bool + AllowGlobalUpdate bool + FullSaveAssociations bool + QueryFields bool + Context context.Context + Logger interface{} + NowFunc func() time.Time + CreateBatchSize int +} + +type Statement struct { + DB *DB + TableExpr interface{} + Table string + Model interface{} + Unscoped bool + Dest interface{} + ReflectValue reflect.Value + Clauses map[string]interface{} + BuildClauses []string + Distinct bool + Selects []string + Omits []string + Joins []interface{} + Preloads map[string][]interface{} + Settings sync.Map + ConnPool ConnPool + Schema interface{} + Context context.Context + RaiseErrorOnNotFound bool + SkipHooks bool + SQL strings.Builder + Vars []interface{} + CurDestIndex int +} + +func (_ Statement) AddError(_ error) error { + return nil +} + +func (_ Statement) AfterInitialize(_ *DB) error { + return nil +} + +func (_ Statement) Apply(_ *Config) error { + return nil +} + +func (_ Statement) Assign(_ ...interface{}) *DB { + return nil +} + +func (_ Statement) Association(_ string) *Association { + return nil +} + +func (_ Statement) Attrs(_ ...interface{}) *DB { + return nil +} + +func (_ Statement) AutoMigrate(_ ...interface{}) error { + return nil +} + +func (_ Statement) Begin(_ ...*sql.TxOptions) *DB { + return nil +} + +func (_ Statement) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {} + +func (_ Statement) Callback() interface{} { + return nil +} + +func (_ Statement) Commit() *DB { + return nil +} + +func (_ Statement) Count(_ *int64) *DB { + return nil +} + +func (_ Statement) Create(_ interface{}) *DB { + return nil +} + +func (_ Statement) CreateInBatches(_ interface{}, _ int) *DB { + return nil +} + +func (_ Statement) DataTypeOf(_ interface{}) string { + return "" +} + +func (_ Statement) Debug() *DB { + return nil +} + +func (_ Statement) DefaultValueOf(_ interface{}) interface{} { + return nil +} + +func (_ Statement) Delete(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Exec(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Explain(_ string, _ ...interface{}) string { + return "" +} + +func (_ Statement) Find(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB { + return nil +} + +func (_ Statement) First(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) FirstOrCreate(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) FirstOrInit(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Get(_ string) (interface{}, bool) { + return nil, false +} + +func (_ Statement) Group(_ string) *DB { + return nil +} + +func (_ Statement) Having(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Initialize(_ *DB) error { + return nil +} + +func (_ Statement) InstanceGet(_ string) (interface{}, bool) { + return nil, false +} + +func (_ Statement) InstanceSet(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) Last(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Limit(_ int) *DB { + return nil +} + +func (_ Statement) Migrator() Migrator { + return nil +} + +func (_ Statement) Name() string { + return "" +} + +func (_ Statement) Not(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Offset(_ int) *DB { + return nil +} + +func (_ Statement) Omit(_ ...string) *DB { + return nil +} + +func (_ Statement) Or(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Order(_ interface{}) *DB { + return nil +} + +func (_ Statement) Pluck(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) Preload(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Raw(_ string, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Rollback() *DB { + return nil +} + +func (_ Statement) RollbackTo(_ string) *DB { + return nil +} + +func (_ Statement) Row() *sql.Row { + return nil +} + +func (_ Statement) Rows() (*sql.Rows, error) { + return nil, nil +} + +func (_ Statement) Save(_ interface{}) *DB { + return nil +} + +func (_ Statement) SavePoint(_ string) *DB { + return nil +} + +func (_ Statement) Scan(_ interface{}) *DB { + return nil +} + +func (_ Statement) ScanRows(_ *sql.Rows, _ interface{}) error { + return nil +} + +func (_ Statement) Scopes(_ ...func(*DB) *DB) *DB { + return nil +} + +func (_ Statement) Select(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Session(_ *Session) *DB { + return nil +} + +func (_ Statement) Set(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) SetupJoinTable(_ interface{}, _ string, _ interface{}) error { + return nil +} + +func (_ Statement) Take(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error { + return nil +} + +func (_ Statement) Update(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) UpdateColumn(_ string, _ interface{}) *DB { + return nil +} + +func (_ Statement) UpdateColumns(_ interface{}) *DB { + return nil +} + +func (_ Statement) Updates(_ interface{}) *DB { + return nil +} + +func (_ Statement) Use(_ Plugin) error { + return nil +} + +func (_ Statement) Where(_ interface{}, _ ...interface{}) *DB { + return nil +} + +func (_ Statement) WithContext(_ context.Context) *DB { + return nil +} + +func (_ *Statement) AddClause(_ interface{}) {} + +func (_ *Statement) AddClauseIfNotExists(_ interface{}) {} + +func (_ *Statement) AddVar(_ interface{}, _ ...interface{}) {} + +func (_ *Statement) Build(_ ...string) {} + +func (_ *Statement) BuildCondition(_ interface{}, _ ...interface{}) []interface{} { + return nil +} + +func (_ *Statement) Changed(_ ...string) bool { + return false +} + +func (_ *Statement) Parse(_ interface{}) error { + return nil +} + +func (_ *Statement) Quote(_ interface{}) string { + return "" +} + +func (_ *Statement) QuoteTo(_ interface{}, _ interface{}) {} + +func (_ *Statement) SelectAndOmitColumns(_ bool, _ bool) (map[string]bool, bool) { + return nil, false +} + +func (_ *Statement) SetColumn(_ string, _ interface{}, _ ...bool) {} + +func (_ *Statement) WriteByte(_ byte) error { + return nil +} + +func (_ *Statement) WriteQuoted(_ interface{}) {} + +func (_ *Statement) WriteString(_ string) (int, error) { + return 0, nil +} + +type ViewOption struct { + Replace bool + CheckOption string + Query *DB +} diff --git a/ql/test/experimental/InconsistentCode/vendor/modules.txt b/ql/test/experimental/InconsistentCode/vendor/modules.txt new file mode 100644 index 00000000000..52a1f62b367 --- /dev/null +++ b/ql/test/experimental/InconsistentCode/vendor/modules.txt @@ -0,0 +1,3 @@ +# gorm.io/gorm v1.21.12 +## explicit +gorm.io/gorm diff --git a/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected b/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected index b78781de117..fc69f87cc3f 100644 --- a/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/ql/test/extractor-tests/diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1,5 +1,9 @@ +| -:0:0:0:0 | package ; expected main | | broken2/test1.go:4:2:4:2 | undeclared name: fmt | | broken2/test1.go:5:2:5:2 | undeclared name: fmt | | broken2/test1.go:5:14:5:14 | undeclared name: a | | broken2/test.go:3:1:3:1 | expected 'package', found pac | +| broken2/test.go:3:1:3:1 | expected 'package', found pac | +| broken2/test.go:3:4:3:4 | expected 'IDENT', found newline | +| broken2/test.go:3:5:3:5 | expected ';', found 'EOF' | | broken/test.go:7:1:7:1 | expected declaration, found This | diff --git a/ql/test/extractor-tests/go1.17/CFG.expected b/ql/test/extractor-tests/go1.17/CFG.expected new file mode 100644 index 00000000000..a918d87337c --- /dev/null +++ b/ql/test/extractor-tests/go1.17/CFG.expected @@ -0,0 +1,64 @@ +nodes +edges +| conversions.go:0:0:0:0 | entry | conversions.go:3:1:3:15 | skip | +| conversions.go:3:1:3:15 | skip | conversions.go:5:6:5:8 | skip | +| conversions.go:5:1:5:1 | entry | conversions.go:5:10:5:10 | argument corresponding to _ | +| conversions.go:5:1:5:29 | function declaration | conversions.go:7:6:7:9 | skip | +| conversions.go:5:6:5:8 | skip | conversions.go:5:1:5:29 | function declaration | +| conversions.go:5:10:5:10 | argument corresponding to _ | conversions.go:5:10:5:10 | initialization of _ | +| conversions.go:5:10:5:10 | initialization of _ | conversions.go:5:28:5:29 | skip | +| conversions.go:5:28:5:29 | skip | conversions.go:5:29:5:29 | exit | +| conversions.go:7:1:7:1 | entry | conversions.go:8:6:8:6 | skip | +| conversions.go:7:1:26:1 | function declaration | conversions.go:0:0:0:0 | exit | +| conversions.go:7:6:7:9 | skip | conversions.go:7:1:26:1 | function declaration | +| conversions.go:8:6:8:6 | assignment to a | conversions.go:10:2:10:2 | skip | +| conversions.go:8:6:8:6 | skip | conversions.go:8:6:8:6 | zero value for a | +| conversions.go:8:6:8:6 | zero value for a | conversions.go:8:6:8:6 | assignment to a | +| conversions.go:10:2:10:2 | assignment to b | conversions.go:11:2:11:4 | use | +| conversions.go:10:2:10:2 | skip | conversions.go:10:7:10:16 | selection of Add | +| conversions.go:10:7:10:16 | selection of Add | conversions.go:10:18:10:18 | a | +| conversions.go:10:7:10:23 | call to Add | conversions.go:10:2:10:2 | assignment to b | +| conversions.go:10:18:10:18 | a | conversions.go:10:21:10:22 | 10 | +| conversions.go:10:21:10:22 | 10 | conversions.go:10:7:10:23 | call to Add | +| conversions.go:11:2:11:4 | use | conversions.go:11:6:11:6 | b | +| conversions.go:11:2:11:7 | call to use | conversions.go:13:6:13:8 | skip | +| conversions.go:11:2:11:7 | call to use | conversions.go:26:1:26:1 | exit | +| conversions.go:11:6:11:6 | b | conversions.go:11:2:11:7 | call to use | +| conversions.go:13:6:13:8 | assignment to arr | conversions.go:14:2:14:6 | skip | +| conversions.go:13:6:13:8 | skip | conversions.go:13:6:13:8 | zero value for arr | +| conversions.go:13:6:13:8 | zero value for arr | conversions.go:13:6:13:8 | assignment to arr | +| conversions.go:14:2:14:6 | assignment to slice | conversions.go:17:2:17:4 | skip | +| conversions.go:14:2:14:6 | skip | conversions.go:14:11:14:22 | selection of Slice | +| conversions.go:14:11:14:22 | selection of Slice | conversions.go:14:24:14:26 | arr | +| conversions.go:14:11:14:31 | call to Slice | conversions.go:14:2:14:6 | assignment to slice | +| conversions.go:14:24:14:26 | arr | conversions.go:14:29:14:30 | 20 | +| conversions.go:14:29:14:30 | 20 | conversions.go:14:11:14:31 | call to Slice | +| conversions.go:17:2:17:4 | assignment to ptr | conversions.go:18:2:18:4 | use | +| conversions.go:17:2:17:4 | skip | conversions.go:17:20:17:24 | slice | +| conversions.go:17:9:17:25 | type conversion | conversions.go:17:2:17:4 | assignment to ptr | +| conversions.go:17:9:17:25 | type conversion | conversions.go:26:1:26:1 | exit | +| conversions.go:17:20:17:24 | slice | conversions.go:17:9:17:25 | type conversion | +| conversions.go:18:2:18:4 | use | conversions.go:18:6:18:8 | ptr | +| conversions.go:18:2:18:9 | call to use | conversions.go:21:2:21:4 | skip | +| conversions.go:18:2:18:9 | call to use | conversions.go:26:1:26:1 | exit | +| conversions.go:18:6:18:8 | ptr | conversions.go:18:2:18:9 | call to use | +| conversions.go:21:2:21:4 | assignment to str | conversions.go:22:2:22:6 | skip | +| conversions.go:21:2:21:4 | skip | conversions.go:21:9:21:18 | "a string" | +| conversions.go:21:9:21:18 | "a string" | conversions.go:21:2:21:4 | assignment to str | +| conversions.go:22:2:22:6 | assignment to bytes | conversions.go:23:2:23:4 | use | +| conversions.go:22:2:22:6 | skip | conversions.go:22:18:22:20 | str | +| conversions.go:22:11:22:21 | type conversion | conversions.go:22:2:22:6 | assignment to bytes | +| conversions.go:22:18:22:20 | str | conversions.go:22:11:22:21 | type conversion | +| conversions.go:23:2:23:4 | use | conversions.go:23:6:23:10 | bytes | +| conversions.go:23:2:23:11 | call to use | conversions.go:24:2:24:6 | skip | +| conversions.go:23:2:23:11 | call to use | conversions.go:26:1:26:1 | exit | +| conversions.go:23:6:23:10 | bytes | conversions.go:23:2:23:11 | call to use | +| conversions.go:24:2:24:6 | assignment to runes | conversions.go:25:2:25:4 | use | +| conversions.go:24:2:24:6 | skip | conversions.go:24:18:24:20 | str | +| conversions.go:24:11:24:21 | type conversion | conversions.go:24:2:24:6 | assignment to runes | +| conversions.go:24:18:24:20 | str | conversions.go:24:11:24:21 | type conversion | +| conversions.go:25:2:25:4 | use | conversions.go:25:6:25:10 | runes | +| conversions.go:25:2:25:11 | call to use | conversions.go:26:1:26:1 | exit | +| conversions.go:25:6:25:10 | runes | conversions.go:25:2:25:11 | call to use | +#select +| | diff --git a/ql/test/extractor-tests/go1.17/CFG.ql b/ql/test/extractor-tests/go1.17/CFG.ql new file mode 100644 index 00000000000..5db94a8ad39 --- /dev/null +++ b/ql/test/extractor-tests/go1.17/CFG.ql @@ -0,0 +1,9 @@ +import go + +query predicate nodes(ControlFlow::Node nd) { none() } + +query predicate edges(ControlFlow::Node pred, ControlFlow::Node succ) { + succ = pred.getASuccessor() +} + +select "" diff --git a/ql/test/extractor-tests/go1.17/conversions.go b/ql/test/extractor-tests/go1.17/conversions.go new file mode 100644 index 00000000000..2439a2e567c --- /dev/null +++ b/ql/test/extractor-tests/go1.17/conversions.go @@ -0,0 +1,26 @@ +package main + +import "unsafe" + +func use(_ ...interface{}) {} + +func main() { + var a unsafe.Pointer + + b := unsafe.Add(a, 10) + use(b) + + var arr *int + slice := unsafe.Slice(arr, 20) + + // may panic + ptr := (*[10]int)(slice) + use(ptr) + + // cannot panic + str := "a string" + bytes := []byte(str) + use(bytes) + runes := []rune(str) + use(runes) +} diff --git a/ql/test/extractor-tests/go1.17/go.mod b/ql/test/extractor-tests/go1.17/go.mod new file mode 100644 index 00000000000..682337bee86 --- /dev/null +++ b/ql/test/extractor-tests/go1.17/go.mod @@ -0,0 +1,3 @@ +module extractor-tests/go117 + +go 1.17 diff --git a/ql/test/library-tests/semmle/go/Files/CONSISTENCY/UnexpectedFrontendErrors.expected b/ql/test/library-tests/semmle/go/Files/CONSISTENCY/UnexpectedFrontendErrors.expected index 8f5c8cc5d4b..6a47139fb8d 100644 --- a/ql/test/library-tests/semmle/go/Files/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/ql/test/library-tests/semmle/go/Files/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1 +1,5 @@ +| -:0:0:0:0 | package ; expected nonexistent | +| vendor/github.com/github/nonexistent/bad.go:1:57:1:57 | expected ';', found 'EOF' | +| vendor/github.com/github/nonexistent/bad.go:1:57:1:57 | expected 'IDENT', found 'EOF' | +| vendor/github.com/github/nonexistent/bad.go:1:57:1:57 | expected 'package', found 'EOF' | | vendor/github.com/github/nonexistent/bad.go:1:57:1:57 | expected 'package', found 'EOF' | diff --git a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.expected b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.expected index 615418114ba..4e62ba42deb 100644 --- a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.expected +++ b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.expected @@ -1,4 +1,1410 @@ -nodes edges +| DuplicateSwitchCase.go:0:0:0:0 | entry | DuplicateSwitchCase.go:3:6:3:15 | skip | +| DuplicateSwitchCase.go:3:1:3:1 | entry | DuplicateSwitchCase.go:3:17:3:19 | argument corresponding to msg | +| DuplicateSwitchCase.go:3:1:12:1 | function declaration | DuplicateSwitchCase.go:14:6:14:10 | skip | +| DuplicateSwitchCase.go:3:6:3:15 | skip | DuplicateSwitchCase.go:3:1:12:1 | function declaration | +| DuplicateSwitchCase.go:3:17:3:19 | argument corresponding to msg | DuplicateSwitchCase.go:3:17:3:19 | initialization of msg | +| DuplicateSwitchCase.go:3:17:3:19 | initialization of msg | DuplicateSwitchCase.go:4:2:4:2 | true | +| DuplicateSwitchCase.go:4:2:4:2 | true | DuplicateSwitchCase.go:5:7:5:9 | msg | +| DuplicateSwitchCase.go:5:7:5:9 | msg | DuplicateSwitchCase.go:5:14:5:20 | "start" | +| DuplicateSwitchCase.go:5:7:5:20 | ...==... | DuplicateSwitchCase.go:5:7:5:20 | case ...==... | +| DuplicateSwitchCase.go:5:7:5:20 | case ...==... | DuplicateSwitchCase.go:5:20:5:20 | ...==... is false | +| DuplicateSwitchCase.go:5:7:5:20 | case ...==... | DuplicateSwitchCase.go:5:20:5:20 | ...==... is true | +| DuplicateSwitchCase.go:5:14:5:20 | "start" | DuplicateSwitchCase.go:5:7:5:20 | ...==... | +| DuplicateSwitchCase.go:5:20:5:20 | ...==... is false | DuplicateSwitchCase.go:7:7:7:9 | msg | +| DuplicateSwitchCase.go:5:20:5:20 | ...==... is true | DuplicateSwitchCase.go:6:3:6:7 | start | +| DuplicateSwitchCase.go:6:3:6:7 | start | DuplicateSwitchCase.go:6:3:6:9 | call to start | +| DuplicateSwitchCase.go:6:3:6:9 | call to start | DuplicateSwitchCase.go:12:1:12:1 | exit | +| DuplicateSwitchCase.go:7:7:7:9 | msg | DuplicateSwitchCase.go:7:14:7:20 | "start" | +| DuplicateSwitchCase.go:7:7:7:20 | ...==... | DuplicateSwitchCase.go:7:7:7:20 | case ...==... | +| DuplicateSwitchCase.go:7:7:7:20 | case ...==... | DuplicateSwitchCase.go:7:20:7:20 | ...==... is false | +| DuplicateSwitchCase.go:7:7:7:20 | case ...==... | DuplicateSwitchCase.go:7:20:7:20 | ...==... is true | +| DuplicateSwitchCase.go:7:14:7:20 | "start" | DuplicateSwitchCase.go:7:7:7:20 | ...==... | +| DuplicateSwitchCase.go:7:20:7:20 | ...==... is false | DuplicateSwitchCase.go:10:3:10:7 | panic | +| DuplicateSwitchCase.go:7:20:7:20 | ...==... is true | DuplicateSwitchCase.go:8:3:8:6 | stop | +| DuplicateSwitchCase.go:8:3:8:6 | stop | DuplicateSwitchCase.go:8:3:8:8 | call to stop | +| DuplicateSwitchCase.go:8:3:8:8 | call to stop | DuplicateSwitchCase.go:12:1:12:1 | exit | +| DuplicateSwitchCase.go:10:3:10:7 | panic | DuplicateSwitchCase.go:10:9:10:33 | "Message not understood." | +| DuplicateSwitchCase.go:10:3:10:34 | call to panic | DuplicateSwitchCase.go:12:1:12:1 | exit | +| DuplicateSwitchCase.go:10:9:10:33 | "Message not understood." | DuplicateSwitchCase.go:10:3:10:34 | call to panic | +| DuplicateSwitchCase.go:14:1:14:1 | entry | DuplicateSwitchCase.go:14:14:14:15 | skip | +| DuplicateSwitchCase.go:14:1:14:15 | function declaration | DuplicateSwitchCase.go:16:6:16:9 | skip | +| DuplicateSwitchCase.go:14:6:14:10 | skip | DuplicateSwitchCase.go:14:1:14:15 | function declaration | +| DuplicateSwitchCase.go:14:14:14:15 | skip | DuplicateSwitchCase.go:14:15:14:15 | exit | +| DuplicateSwitchCase.go:16:1:16:1 | entry | DuplicateSwitchCase.go:16:13:16:14 | skip | +| DuplicateSwitchCase.go:16:1:16:14 | function declaration | DuplicateSwitchCase.go:0:0:0:0 | exit | +| DuplicateSwitchCase.go:16:6:16:9 | skip | DuplicateSwitchCase.go:16:1:16:14 | function declaration | +| DuplicateSwitchCase.go:16:13:16:14 | skip | DuplicateSwitchCase.go:16:14:16:14 | exit | +| equalitytests.go:0:0:0:0 | entry | equalitytests.go:3:1:5:1 | skip | +| equalitytests.go:3:1:5:1 | skip | equalitytests.go:7:1:9:1 | skip | +| equalitytests.go:7:1:9:1 | skip | equalitytests.go:11:6:11:18 | skip | +| equalitytests.go:11:1:11:1 | entry | equalitytests.go:11:20:11:21 | argument corresponding to i1 | +| equalitytests.go:11:1:13:1 | function declaration | equalitytests.go:0:0:0:0 | exit | +| equalitytests.go:11:6:11:18 | skip | equalitytests.go:11:1:13:1 | function declaration | +| equalitytests.go:11:20:11:21 | argument corresponding to i1 | equalitytests.go:11:20:11:21 | initialization of i1 | +| equalitytests.go:11:20:11:21 | initialization of i1 | equalitytests.go:11:28:11:29 | argument corresponding to i2 | +| equalitytests.go:11:28:11:29 | argument corresponding to i2 | equalitytests.go:11:28:11:29 | initialization of i2 | +| equalitytests.go:11:28:11:29 | initialization of i2 | equalitytests.go:11:36:11:37 | argument corresponding to e1 | +| equalitytests.go:11:36:11:37 | argument corresponding to e1 | equalitytests.go:11:36:11:37 | initialization of e1 | +| equalitytests.go:11:36:11:37 | initialization of e1 | equalitytests.go:11:46:11:47 | argument corresponding to e2 | +| equalitytests.go:11:46:11:47 | argument corresponding to e2 | equalitytests.go:11:46:11:47 | initialization of e2 | +| equalitytests.go:11:46:11:47 | initialization of e2 | equalitytests.go:11:56:11:57 | argument corresponding to s1 | +| equalitytests.go:11:56:11:57 | argument corresponding to s1 | equalitytests.go:11:56:11:57 | initialization of s1 | +| equalitytests.go:11:56:11:57 | initialization of s1 | equalitytests.go:11:83:11:84 | argument corresponding to s2 | +| equalitytests.go:11:83:11:84 | argument corresponding to s2 | equalitytests.go:11:83:11:84 | initialization of s2 | +| equalitytests.go:11:83:11:84 | initialization of s2 | equalitytests.go:11:110:11:111 | argument corresponding to s3 | +| equalitytests.go:11:110:11:111 | argument corresponding to s3 | equalitytests.go:11:110:11:111 | initialization of s3 | +| equalitytests.go:11:110:11:111 | initialization of s3 | equalitytests.go:11:134:11:135 | argument corresponding to s4 | +| equalitytests.go:11:134:11:135 | argument corresponding to s4 | equalitytests.go:11:134:11:135 | initialization of s4 | +| equalitytests.go:11:134:11:135 | initialization of s4 | equalitytests.go:11:158:11:159 | argument corresponding to a1 | +| equalitytests.go:11:158:11:159 | argument corresponding to a1 | equalitytests.go:11:158:11:159 | initialization of a1 | +| equalitytests.go:11:158:11:159 | initialization of a1 | equalitytests.go:11:171:11:172 | argument corresponding to a2 | +| equalitytests.go:11:171:11:172 | argument corresponding to a2 | equalitytests.go:11:171:11:172 | initialization of a2 | +| equalitytests.go:11:171:11:172 | initialization of a2 | equalitytests.go:11:184:11:185 | argument corresponding to a3 | +| equalitytests.go:11:184:11:185 | argument corresponding to a3 | equalitytests.go:11:184:11:185 | initialization of a3 | +| equalitytests.go:11:184:11:185 | initialization of a3 | equalitytests.go:11:195:11:196 | argument corresponding to a4 | +| equalitytests.go:11:195:11:196 | argument corresponding to a4 | equalitytests.go:11:195:11:196 | initialization of a4 | +| equalitytests.go:11:195:11:196 | initialization of a4 | equalitytests.go:12:9:12:10 | i1 | +| equalitytests.go:12:2:12:76 | return statement | equalitytests.go:13:1:13:1 | exit | +| equalitytests.go:12:9:12:10 | i1 | equalitytests.go:12:15:12:16 | i2 | +| equalitytests.go:12:9:12:16 | ...==... | equalitytests.go:12:16:12:16 | ...==... is false | +| equalitytests.go:12:9:12:16 | ...==... | equalitytests.go:12:16:12:16 | ...==... is true | +| equalitytests.go:12:9:12:76 | ...&&... | equalitytests.go:12:2:12:76 | return statement | +| equalitytests.go:12:15:12:16 | i2 | equalitytests.go:12:9:12:16 | ...==... | +| equalitytests.go:12:16:12:16 | ...==... is false | equalitytests.go:12:28:12:28 | ...&&... is false | +| equalitytests.go:12:16:12:16 | ...==... is true | equalitytests.go:12:21:12:22 | e1 | +| equalitytests.go:12:21:12:22 | e1 | equalitytests.go:12:27:12:28 | e2 | +| equalitytests.go:12:21:12:28 | ...==... | equalitytests.go:12:28:12:28 | ...&&... is false | +| equalitytests.go:12:21:12:28 | ...==... | equalitytests.go:12:28:12:28 | ...&&... is true | +| equalitytests.go:12:21:12:28 | ...==... | equalitytests.go:13:1:13:1 | exit | +| equalitytests.go:12:27:12:28 | e2 | equalitytests.go:12:21:12:28 | ...==... | +| equalitytests.go:12:28:12:28 | ...&&... is false | equalitytests.go:12:40:12:40 | ...&&... is false | +| equalitytests.go:12:28:12:28 | ...&&... is true | equalitytests.go:12:33:12:34 | s1 | +| equalitytests.go:12:33:12:34 | s1 | equalitytests.go:12:39:12:40 | s2 | +| equalitytests.go:12:33:12:40 | ...==... | equalitytests.go:12:40:12:40 | ...&&... is false | +| equalitytests.go:12:33:12:40 | ...==... | equalitytests.go:12:40:12:40 | ...&&... is true | +| equalitytests.go:12:33:12:40 | ...==... | equalitytests.go:13:1:13:1 | exit | +| equalitytests.go:12:39:12:40 | s2 | equalitytests.go:12:33:12:40 | ...==... | +| equalitytests.go:12:40:12:40 | ...&&... is false | equalitytests.go:12:52:12:52 | ...&&... is false | +| equalitytests.go:12:40:12:40 | ...&&... is true | equalitytests.go:12:45:12:46 | s3 | +| equalitytests.go:12:45:12:46 | s3 | equalitytests.go:12:51:12:52 | s4 | +| equalitytests.go:12:45:12:52 | ...==... | equalitytests.go:12:52:12:52 | ...&&... is false | +| equalitytests.go:12:45:12:52 | ...==... | equalitytests.go:12:52:12:52 | ...&&... is true | +| equalitytests.go:12:45:12:52 | ...==... | equalitytests.go:13:1:13:1 | exit | +| equalitytests.go:12:51:12:52 | s4 | equalitytests.go:12:45:12:52 | ...==... | +| equalitytests.go:12:52:12:52 | ...&&... is false | equalitytests.go:12:64:12:64 | ...&&... is false | +| equalitytests.go:12:52:12:52 | ...&&... is true | equalitytests.go:12:57:12:58 | a1 | +| equalitytests.go:12:57:12:58 | a1 | equalitytests.go:12:63:12:64 | a2 | +| equalitytests.go:12:57:12:64 | ...==... | equalitytests.go:12:64:12:64 | ...&&... is false | +| equalitytests.go:12:57:12:64 | ...==... | equalitytests.go:12:64:12:64 | ...&&... is true | +| equalitytests.go:12:57:12:64 | ...==... | equalitytests.go:13:1:13:1 | exit | +| equalitytests.go:12:63:12:64 | a2 | equalitytests.go:12:57:12:64 | ...==... | +| equalitytests.go:12:64:12:64 | ...&&... is false | equalitytests.go:12:9:12:76 | ...&&... | +| equalitytests.go:12:64:12:64 | ...&&... is true | equalitytests.go:12:69:12:70 | a3 | +| equalitytests.go:12:69:12:70 | a3 | equalitytests.go:12:75:12:76 | a4 | +| equalitytests.go:12:69:12:76 | ...==... | equalitytests.go:12:9:12:76 | ...&&... | +| equalitytests.go:12:69:12:76 | ...==... | equalitytests.go:13:1:13:1 | exit | +| equalitytests.go:12:75:12:76 | a4 | equalitytests.go:12:69:12:76 | ...==... | +| exprs.go:0:0:0:0 | entry | exprs.go:3:1:3:29 | skip | +| exprs.go:3:1:3:29 | skip | exprs.go:5:6:5:9 | skip | +| exprs.go:5:1:5:1 | entry | exprs.go:6:6:6:6 | skip | +| exprs.go:5:1:26:1 | function declaration | exprs.go:28:6:28:10 | skip | +| exprs.go:5:6:5:9 | skip | exprs.go:5:1:26:1 | function declaration | +| exprs.go:6:6:6:6 | assignment to i | exprs.go:6:9:6:9 | assignment to j | +| exprs.go:6:6:6:6 | skip | exprs.go:6:9:6:9 | skip | +| exprs.go:6:9:6:9 | assignment to j | exprs.go:7:6:7:6 | skip | +| exprs.go:6:9:6:9 | skip | exprs.go:6:13:6:13 | 0 | +| exprs.go:6:13:6:13 | 0 | exprs.go:6:16:6:26 | ...+... | +| exprs.go:6:16:6:26 | ...+... | exprs.go:6:6:6:6 | assignment to i | +| exprs.go:7:6:7:6 | assignment to k | exprs.go:8:2:8:2 | skip | +| exprs.go:7:6:7:6 | skip | exprs.go:7:10:7:10 | i | +| exprs.go:7:10:7:10 | i | exprs.go:7:14:7:14 | 2 | +| exprs.go:7:10:7:16 | ...+... | exprs.go:7:6:7:6 | assignment to k | +| exprs.go:7:14:7:14 | 2 | exprs.go:7:16:7:16 | j | +| exprs.go:7:14:7:16 | ...*... | exprs.go:7:10:7:16 | ...+... | +| exprs.go:7:16:7:16 | j | exprs.go:7:14:7:16 | ...*... | +| exprs.go:8:2:8:2 | assignment to s | exprs.go:9:2:9:3 | skip | +| exprs.go:8:2:8:2 | skip | exprs.go:8:7:8:12 | "k = " | +| exprs.go:8:7:8:12 | "k = " | exprs.go:8:23:8:23 | k | +| exprs.go:8:7:8:24 | ...+... | exprs.go:8:2:8:2 | assignment to s | +| exprs.go:8:16:8:24 | type conversion | exprs.go:8:7:8:24 | ...+... | +| exprs.go:8:23:8:23 | k | exprs.go:8:16:8:24 | type conversion | +| exprs.go:9:2:9:3 | assignment to fn | exprs.go:10:2:10:8 | skip | +| exprs.go:9:2:9:3 | skip | exprs.go:9:8:9:61 | function literal | +| exprs.go:9:8:9:8 | entry | exprs.go:9:13:9:13 | argument corresponding to a | +| exprs.go:9:8:9:61 | function literal | exprs.go:9:2:9:3 | assignment to fn | +| exprs.go:9:13:9:13 | argument corresponding to a | exprs.go:9:13:9:13 | initialization of a | +| exprs.go:9:13:9:13 | initialization of a | exprs.go:9:16:9:16 | argument corresponding to b | +| exprs.go:9:16:9:16 | argument corresponding to b | exprs.go:9:16:9:16 | initialization of b | +| exprs.go:9:16:9:16 | initialization of b | exprs.go:9:23:9:23 | argument corresponding to z | +| exprs.go:9:23:9:23 | argument corresponding to z | exprs.go:9:23:9:23 | initialization of z | +| exprs.go:9:23:9:23 | initialization of z | exprs.go:9:48:9:48 | a | +| exprs.go:9:41:9:59 | return statement | exprs.go:9:61:9:61 | exit | +| exprs.go:9:48:9:48 | a | exprs.go:9:50:9:50 | b | +| exprs.go:9:48:9:50 | ...*... | exprs.go:9:58:9:58 | z | +| exprs.go:9:48:9:59 | ...<... | exprs.go:9:41:9:59 | return statement | +| exprs.go:9:50:9:50 | b | exprs.go:9:48:9:50 | ...*... | +| exprs.go:9:54:9:59 | type conversion | exprs.go:9:48:9:59 | ...<... | +| exprs.go:9:58:9:58 | z | exprs.go:9:54:9:59 | type conversion | +| exprs.go:10:2:10:8 | assignment to struct1 | exprs.go:11:2:11:8 | skip | +| exprs.go:10:2:10:8 | skip | exprs.go:10:13:10:32 | struct literal | +| exprs.go:10:13:10:32 | struct literal | exprs.go:10:2:10:8 | assignment to struct1 | +| exprs.go:11:2:11:8 | assignment to struct2 | exprs.go:15:2:15:8 | skip | +| exprs.go:11:2:11:8 | skip | exprs.go:11:13:14:21 | struct literal | +| exprs.go:11:13:14:21 | struct literal | exprs.go:14:4:14:4 | k | +| exprs.go:14:4:14:4 | init of k | exprs.go:14:7:14:8 | fn | +| exprs.go:14:4:14:4 | k | exprs.go:14:4:14:4 | init of k | +| exprs.go:14:7:14:8 | fn | exprs.go:14:10:14:10 | i | +| exprs.go:14:7:14:20 | call to fn | exprs.go:14:7:14:20 | init of call to fn | +| exprs.go:14:7:14:20 | call to fn | exprs.go:26:1:26:1 | exit | +| exprs.go:14:7:14:20 | init of call to fn | exprs.go:11:2:11:8 | assignment to struct2 | +| exprs.go:14:10:14:10 | i | exprs.go:14:13:14:13 | j | +| exprs.go:14:13:14:13 | j | exprs.go:14:16:14:19 | .../... | +| exprs.go:14:16:14:19 | .../... | exprs.go:14:7:14:20 | call to fn | +| exprs.go:15:2:15:8 | assignment to struct3 | exprs.go:16:2:16:5 | skip | +| exprs.go:15:2:15:8 | skip | exprs.go:15:13:15:58 | struct literal | +| exprs.go:15:13:15:58 | struct literal | exprs.go:15:35:15:41 | struct1 | +| exprs.go:15:32:15:43 | init of key-value pair | exprs.go:15:49:15:55 | struct2 | +| exprs.go:15:35:15:41 | struct1 | exprs.go:15:35:15:43 | selection of x | +| exprs.go:15:35:15:43 | selection of x | exprs.go:15:32:15:43 | init of key-value pair | +| exprs.go:15:46:15:57 | init of key-value pair | exprs.go:15:2:15:8 | assignment to struct3 | +| exprs.go:15:49:15:55 | struct2 | exprs.go:15:49:15:57 | selection of x | +| exprs.go:15:49:15:57 | selection of x | exprs.go:15:46:15:57 | init of key-value pair | +| exprs.go:16:2:16:5 | assignment to arr1 | exprs.go:17:2:17:5 | skip | +| exprs.go:16:2:16:5 | skip | exprs.go:16:10:16:26 | array literal | +| exprs.go:16:10:16:26 | array literal | exprs.go:16:17:16:17 | element index | +| exprs.go:16:17:16:17 | element index | exprs.go:16:17:16:23 | struct3 | +| exprs.go:16:17:16:23 | struct3 | exprs.go:16:17:16:25 | selection of x | +| exprs.go:16:17:16:25 | init of selection of x | exprs.go:16:2:16:5 | assignment to arr1 | +| exprs.go:16:17:16:25 | selection of x | exprs.go:16:17:16:25 | init of selection of x | +| exprs.go:17:2:17:5 | assignment to arr2 | exprs.go:18:2:18:4 | skip | +| exprs.go:17:2:17:5 | skip | exprs.go:17:10:17:40 | array literal | +| exprs.go:17:10:17:40 | array literal | exprs.go:17:19:17:19 | element index | +| exprs.go:17:19:17:19 | element index | exprs.go:17:19:17:25 | struct3 | +| exprs.go:17:19:17:25 | struct3 | exprs.go:17:19:17:27 | selection of x | +| exprs.go:17:19:17:27 | init of selection of x | exprs.go:17:30:17:30 | 2 | +| exprs.go:17:19:17:27 | selection of x | exprs.go:17:19:17:27 | init of selection of x | +| exprs.go:17:30:17:30 | 2 | exprs.go:17:33:17:36 | arr1 | +| exprs.go:17:30:17:39 | init of key-value pair | exprs.go:17:2:17:5 | assignment to arr2 | +| exprs.go:17:33:17:36 | arr1 | exprs.go:17:38:17:38 | 0 | +| exprs.go:17:33:17:39 | index expression | exprs.go:17:30:17:39 | init of key-value pair | +| exprs.go:17:33:17:39 | index expression | exprs.go:26:1:26:1 | exit | +| exprs.go:17:38:17:38 | 0 | exprs.go:17:33:17:39 | index expression | +| exprs.go:18:2:18:4 | assignment to slc | exprs.go:19:2:19:3 | skip | +| exprs.go:18:2:18:4 | skip | exprs.go:18:9:18:22 | slice literal | +| exprs.go:18:9:18:22 | slice literal | exprs.go:18:18:18:18 | element index | +| exprs.go:18:18:18:18 | element index | exprs.go:18:18:18:18 | s | +| exprs.go:18:18:18:18 | init of s | exprs.go:18:21:18:21 | element index | +| exprs.go:18:18:18:18 | s | exprs.go:18:18:18:18 | init of s | +| exprs.go:18:21:18:21 | element index | exprs.go:18:21:18:21 | s | +| exprs.go:18:21:18:21 | init of s | exprs.go:18:2:18:4 | assignment to slc | +| exprs.go:18:21:18:21 | s | exprs.go:18:21:18:21 | init of s | +| exprs.go:19:2:19:3 | assignment to mp | exprs.go:20:2:20:5 | skip | +| exprs.go:19:2:19:3 | skip | exprs.go:19:8:19:38 | map literal | +| exprs.go:19:8:19:38 | map literal | exprs.go:19:23:19:25 | slc | +| exprs.go:19:23:19:25 | slc | exprs.go:19:27:19:27 | 0 | +| exprs.go:19:23:19:28 | index expression | exprs.go:19:31:19:34 | arr2 | +| exprs.go:19:23:19:28 | index expression | exprs.go:26:1:26:1 | exit | +| exprs.go:19:23:19:37 | init of key-value pair | exprs.go:19:2:19:3 | assignment to mp | +| exprs.go:19:27:19:27 | 0 | exprs.go:19:23:19:28 | index expression | +| exprs.go:19:31:19:34 | arr2 | exprs.go:19:36:19:36 | 1 | +| exprs.go:19:31:19:37 | index expression | exprs.go:19:23:19:37 | init of key-value pair | +| exprs.go:19:31:19:37 | index expression | exprs.go:26:1:26:1 | exit | +| exprs.go:19:36:19:36 | 1 | exprs.go:19:31:19:37 | index expression | +| exprs.go:20:2:20:5 | assignment to slc2 | exprs.go:21:2:21:5 | skip | +| exprs.go:20:2:20:5 | skip | exprs.go:20:10:20:12 | slc | +| exprs.go:20:10:20:12 | slc | exprs.go:20:14:20:14 | 1 | +| exprs.go:20:10:20:19 | slice expression | exprs.go:20:2:20:5 | assignment to slc2 | +| exprs.go:20:10:20:19 | slice expression | exprs.go:26:1:26:1 | exit | +| exprs.go:20:14:20:14 | 1 | exprs.go:20:16:20:16 | 2 | +| exprs.go:20:16:20:16 | 2 | exprs.go:20:18:20:18 | 3 | +| exprs.go:20:18:20:18 | 3 | exprs.go:20:10:20:19 | slice expression | +| exprs.go:21:2:21:5 | assignment to slc3 | exprs.go:22:2:22:5 | skip | +| exprs.go:21:2:21:5 | skip | exprs.go:21:10:21:13 | slc2 | +| exprs.go:21:10:21:13 | slc2 | exprs.go:21:10:21:19 | 0 | +| exprs.go:21:10:21:19 | 0 | exprs.go:21:16:21:16 | 2 | +| exprs.go:21:10:21:19 | slice expression | exprs.go:21:2:21:5 | assignment to slc3 | +| exprs.go:21:10:21:19 | slice expression | exprs.go:26:1:26:1 | exit | +| exprs.go:21:16:21:16 | 2 | exprs.go:21:18:21:18 | 3 | +| exprs.go:21:18:21:18 | 3 | exprs.go:21:10:21:19 | slice expression | +| exprs.go:22:2:22:5 | assignment to slc4 | exprs.go:23:2:23:5 | skip | +| exprs.go:22:2:22:5 | skip | exprs.go:22:10:22:13 | slc3 | +| exprs.go:22:10:22:13 | slc3 | exprs.go:22:15:22:15 | 0 | +| exprs.go:22:10:22:18 | cap | exprs.go:22:10:22:18 | slice expression | +| exprs.go:22:10:22:18 | slice expression | exprs.go:22:2:22:5 | assignment to slc4 | +| exprs.go:22:10:22:18 | slice expression | exprs.go:26:1:26:1 | exit | +| exprs.go:22:15:22:15 | 0 | exprs.go:22:17:22:17 | 2 | +| exprs.go:22:17:22:17 | 2 | exprs.go:22:10:22:18 | cap | +| exprs.go:23:2:23:5 | assignment to slc5 | exprs.go:24:2:24:5 | skip | +| exprs.go:23:2:23:5 | skip | exprs.go:23:10:23:13 | slc4 | +| exprs.go:23:10:23:13 | slc4 | exprs.go:23:15:23:15 | 0 | +| exprs.go:23:10:23:17 | cap | exprs.go:23:10:23:17 | slice expression | +| exprs.go:23:10:23:17 | len | exprs.go:23:10:23:17 | cap | +| exprs.go:23:10:23:17 | slice expression | exprs.go:23:2:23:5 | assignment to slc5 | +| exprs.go:23:10:23:17 | slice expression | exprs.go:26:1:26:1 | exit | +| exprs.go:23:15:23:15 | 0 | exprs.go:23:10:23:17 | len | +| exprs.go:24:2:24:5 | assignment to slc6 | exprs.go:25:9:25:34 | struct literal | +| exprs.go:24:2:24:5 | skip | exprs.go:24:10:24:13 | slc5 | +| exprs.go:24:10:24:13 | slc5 | exprs.go:24:10:24:17 | 0 | +| exprs.go:24:10:24:17 | 0 | exprs.go:24:16:24:16 | 2 | +| exprs.go:24:10:24:17 | cap | exprs.go:24:10:24:17 | slice expression | +| exprs.go:24:10:24:17 | slice expression | exprs.go:24:2:24:5 | assignment to slc6 | +| exprs.go:24:10:24:17 | slice expression | exprs.go:26:1:26:1 | exit | +| exprs.go:24:16:24:16 | 2 | exprs.go:24:10:24:17 | cap | +| exprs.go:25:2:25:34 | return statement | exprs.go:26:1:26:1 | exit | +| exprs.go:25:9:25:34 | struct literal | exprs.go:25:15:25:16 | mp | +| exprs.go:25:15:25:16 | mp | exprs.go:25:18:25:18 | s | +| exprs.go:25:15:25:19 | index expression | exprs.go:25:15:25:19 | init of index expression | +| exprs.go:25:15:25:19 | index expression | exprs.go:26:1:26:1 | exit | +| exprs.go:25:15:25:19 | init of index expression | exprs.go:25:22:25:24 | len | +| exprs.go:25:18:25:18 | s | exprs.go:25:15:25:19 | index expression | +| exprs.go:25:22:25:24 | len | exprs.go:25:26:25:29 | slc6 | +| exprs.go:25:22:25:33 | call to len | exprs.go:25:22:25:33 | init of call to len | +| exprs.go:25:22:25:33 | init of call to len | exprs.go:25:2:25:34 | return statement | +| exprs.go:25:26:25:29 | slc6 | exprs.go:25:31:25:31 | 0 | +| exprs.go:25:26:25:32 | index expression | exprs.go:25:22:25:33 | call to len | +| exprs.go:25:26:25:32 | index expression | exprs.go:26:1:26:1 | exit | +| exprs.go:25:31:25:31 | 0 | exprs.go:25:26:25:32 | index expression | +| exprs.go:28:1:28:1 | entry | exprs.go:28:12:28:14 | argument corresponding to arg | +| exprs.go:28:1:30:1 | function declaration | exprs.go:32:6:32:10 | skip | +| exprs.go:28:6:28:10 | skip | exprs.go:28:1:30:1 | function declaration | +| exprs.go:28:12:28:14 | argument corresponding to arg | exprs.go:28:12:28:14 | initialization of arg | +| exprs.go:28:12:28:14 | initialization of arg | exprs.go:29:9:29:11 | arg | +| exprs.go:29:2:29:21 | return statement | exprs.go:30:1:30:1 | exit | +| exprs.go:29:9:29:11 | arg | exprs.go:29:9:29:19 | type assertion | +| exprs.go:29:9:29:19 | type assertion | exprs.go:29:9:29:21 | selection of x | +| exprs.go:29:9:29:19 | type assertion | exprs.go:30:1:30:1 | exit | +| exprs.go:29:9:29:21 | selection of x | exprs.go:29:2:29:21 | return statement | +| exprs.go:32:1:32:1 | entry | exprs.go:32:12:32:14 | argument corresponding to arg | +| exprs.go:32:1:37:1 | function declaration | exprs.go:39:6:39:10 | skip | +| exprs.go:32:6:32:10 | skip | exprs.go:32:1:37:1 | function declaration | +| exprs.go:32:12:32:14 | argument corresponding to arg | exprs.go:32:12:32:14 | initialization of arg | +| exprs.go:32:12:32:14 | initialization of arg | exprs.go:33:5:33:5 | skip | +| exprs.go:33:5:33:5 | assignment to p | exprs.go:33:5:33:24 | ... := ...[1] | +| exprs.go:33:5:33:5 | skip | exprs.go:33:8:33:9 | skip | +| exprs.go:33:5:33:24 | ... := ...[0] | exprs.go:33:5:33:5 | assignment to p | +| exprs.go:33:5:33:24 | ... := ...[1] | exprs.go:33:8:33:9 | assignment to ok | +| exprs.go:33:8:33:9 | assignment to ok | exprs.go:33:27:33:28 | ok | +| exprs.go:33:8:33:9 | skip | exprs.go:33:14:33:16 | arg | +| exprs.go:33:14:33:16 | arg | exprs.go:33:14:33:24 | type assertion | +| exprs.go:33:14:33:24 | type assertion | exprs.go:33:5:33:24 | ... := ...[0] | +| exprs.go:33:27:33:28 | ok | exprs.go:33:28:33:28 | ok is false | +| exprs.go:33:27:33:28 | ok | exprs.go:33:28:33:28 | ok is true | +| exprs.go:33:28:33:28 | ok is false | exprs.go:36:9:36:10 | -... | +| exprs.go:33:28:33:28 | ok is true | exprs.go:34:10:34:10 | p | +| exprs.go:34:3:34:12 | return statement | exprs.go:37:1:37:1 | exit | +| exprs.go:34:10:34:10 | p | exprs.go:34:10:34:12 | selection of x | +| exprs.go:34:10:34:12 | selection of x | exprs.go:34:3:34:12 | return statement | +| exprs.go:36:2:36:10 | return statement | exprs.go:37:1:37:1 | exit | +| exprs.go:36:9:36:10 | -... | exprs.go:36:2:36:10 | return statement | +| exprs.go:39:1:39:1 | entry | exprs.go:39:12:39:14 | argument corresponding to arg | +| exprs.go:39:1:47:1 | function declaration | exprs.go:49:6:49:8 | skip | +| exprs.go:39:6:39:10 | skip | exprs.go:39:1:47:1 | function declaration | +| exprs.go:39:12:39:14 | argument corresponding to arg | exprs.go:39:12:39:14 | initialization of arg | +| exprs.go:39:12:39:14 | initialization of arg | exprs.go:40:6:40:6 | skip | +| exprs.go:40:6:40:6 | assignment to p | exprs.go:41:6:41:7 | skip | +| exprs.go:40:6:40:6 | skip | exprs.go:40:6:40:6 | zero value for p | +| exprs.go:40:6:40:6 | zero value for p | exprs.go:40:6:40:6 | assignment to p | +| exprs.go:41:6:41:7 | assignment to ok | exprs.go:42:2:42:2 | skip | +| exprs.go:41:6:41:7 | skip | exprs.go:41:6:41:7 | zero value for ok | +| exprs.go:41:6:41:7 | zero value for ok | exprs.go:41:6:41:7 | assignment to ok | +| exprs.go:42:2:42:2 | assignment to p | exprs.go:42:2:42:20 | ... = ...[1] | +| exprs.go:42:2:42:2 | skip | exprs.go:42:5:42:6 | skip | +| exprs.go:42:2:42:20 | ... = ...[0] | exprs.go:42:2:42:2 | assignment to p | +| exprs.go:42:2:42:20 | ... = ...[1] | exprs.go:42:5:42:6 | assignment to ok | +| exprs.go:42:5:42:6 | assignment to ok | exprs.go:43:5:43:6 | ok | +| exprs.go:42:5:42:6 | skip | exprs.go:42:10:42:12 | arg | +| exprs.go:42:10:42:12 | arg | exprs.go:42:10:42:20 | type assertion | +| exprs.go:42:10:42:20 | type assertion | exprs.go:42:2:42:20 | ... = ...[0] | +| exprs.go:43:5:43:6 | ok | exprs.go:43:6:43:6 | ok is false | +| exprs.go:43:5:43:6 | ok | exprs.go:43:6:43:6 | ok is true | +| exprs.go:43:6:43:6 | ok is false | exprs.go:46:9:46:10 | -... | +| exprs.go:43:6:43:6 | ok is true | exprs.go:44:10:44:10 | p | +| exprs.go:44:3:44:12 | return statement | exprs.go:47:1:47:1 | exit | +| exprs.go:44:10:44:10 | p | exprs.go:44:10:44:12 | selection of x | +| exprs.go:44:10:44:12 | selection of x | exprs.go:44:3:44:12 | return statement | +| exprs.go:46:2:46:10 | return statement | exprs.go:47:1:47:1 | exit | +| exprs.go:46:9:46:10 | -... | exprs.go:46:2:46:10 | return statement | +| exprs.go:49:1:49:1 | entry | exprs.go:49:10:49:11 | argument corresponding to xs | +| exprs.go:49:1:54:1 | function declaration | exprs.go:56:6:56:9 | skip | +| exprs.go:49:6:49:8 | skip | exprs.go:49:1:54:1 | function declaration | +| exprs.go:49:10:49:11 | argument corresponding to xs | exprs.go:49:10:49:11 | initialization of xs | +| exprs.go:49:10:49:11 | initialization of xs | exprs.go:49:21:49:23 | zero value for res | +| exprs.go:49:21:49:23 | implicit read of res | exprs.go:54:1:54:1 | exit | +| exprs.go:49:21:49:23 | initialization of res | exprs.go:50:6:50:6 | skip | +| exprs.go:49:21:49:23 | zero value for res | exprs.go:49:21:49:23 | initialization of res | +| exprs.go:50:6:50:6 | assignment to i | exprs.go:50:14:50:14 | i | +| exprs.go:50:6:50:6 | skip | exprs.go:50:11:50:11 | 0 | +| exprs.go:50:11:50:11 | 0 | exprs.go:50:6:50:6 | assignment to i | +| exprs.go:50:14:50:14 | i | exprs.go:50:18:50:20 | len | +| exprs.go:50:14:50:24 | ...<... | exprs.go:50:24:50:24 | ...<... is false | +| exprs.go:50:14:50:24 | ...<... | exprs.go:50:24:50:24 | ...<... is true | +| exprs.go:50:18:50:20 | len | exprs.go:50:22:50:23 | xs | +| exprs.go:50:18:50:24 | call to len | exprs.go:50:14:50:24 | ...<... | +| exprs.go:50:22:50:23 | xs | exprs.go:50:18:50:24 | call to len | +| exprs.go:50:24:50:24 | ...<... is false | exprs.go:53:2:53:7 | return statement | +| exprs.go:50:24:50:24 | ...<... is true | exprs.go:51:3:51:5 | res | +| exprs.go:50:27:50:27 | i | exprs.go:50:27:50:29 | 1 | +| exprs.go:50:27:50:29 | 1 | exprs.go:50:27:50:29 | rhs of increment statement | +| exprs.go:50:27:50:29 | increment statement | exprs.go:50:14:50:14 | i | +| exprs.go:50:27:50:29 | rhs of increment statement | exprs.go:50:27:50:29 | increment statement | +| exprs.go:51:3:51:5 | assignment to res | exprs.go:50:27:50:27 | i | +| exprs.go:51:3:51:5 | res | exprs.go:51:10:51:11 | xs | +| exprs.go:51:3:51:14 | ... += ... | exprs.go:51:3:51:5 | assignment to res | +| exprs.go:51:10:51:11 | xs | exprs.go:51:13:51:13 | i | +| exprs.go:51:10:51:14 | index expression | exprs.go:51:3:51:14 | ... += ... | +| exprs.go:51:10:51:14 | index expression | exprs.go:54:1:54:1 | exit | +| exprs.go:51:13:51:13 | i | exprs.go:51:10:51:14 | index expression | +| exprs.go:53:2:53:7 | return statement | exprs.go:49:21:49:23 | implicit read of res | +| exprs.go:56:1:56:1 | entry | exprs.go:56:11:56:12 | argument corresponding to xs | +| exprs.go:56:1:58:1 | function declaration | exprs.go:60:6:60:9 | skip | +| exprs.go:56:6:56:9 | skip | exprs.go:56:1:58:1 | function declaration | +| exprs.go:56:11:56:12 | argument corresponding to xs | exprs.go:56:11:56:12 | initialization of xs | +| exprs.go:56:11:56:12 | initialization of xs | exprs.go:57:9:57:11 | sum | +| exprs.go:57:2:57:15 | return statement | exprs.go:58:1:58:1 | exit | +| exprs.go:57:9:57:11 | sum | exprs.go:57:13:57:14 | xs | +| exprs.go:57:9:57:15 | call to sum | exprs.go:57:2:57:15 | return statement | +| exprs.go:57:9:57:15 | call to sum | exprs.go:58:1:58:1 | exit | +| exprs.go:57:13:57:14 | xs | exprs.go:57:9:57:15 | call to sum | +| exprs.go:60:1:60:1 | entry | exprs.go:61:9:61:22 | slice literal | +| exprs.go:60:1:62:1 | function declaration | exprs.go:64:5:64:5 | skip | +| exprs.go:60:6:60:9 | skip | exprs.go:60:1:62:1 | function declaration | +| exprs.go:61:2:61:22 | return statement | exprs.go:62:1:62:1 | exit | +| exprs.go:61:9:61:22 | slice literal | exprs.go:61:15:61:15 | element index | +| exprs.go:61:15:61:15 | 1 | exprs.go:61:15:61:15 | init of 1 | +| exprs.go:61:15:61:15 | element index | exprs.go:61:15:61:15 | 1 | +| exprs.go:61:15:61:15 | init of 1 | exprs.go:61:18:61:18 | element index | +| exprs.go:61:18:61:18 | 2 | exprs.go:61:18:61:18 | init of 2 | +| exprs.go:61:18:61:18 | element index | exprs.go:61:18:61:18 | 2 | +| exprs.go:61:18:61:18 | init of 2 | exprs.go:61:21:61:21 | element index | +| exprs.go:61:21:61:21 | 3 | exprs.go:61:21:61:21 | init of 3 | +| exprs.go:61:21:61:21 | element index | exprs.go:61:21:61:21 | 3 | +| exprs.go:61:21:61:21 | init of 3 | exprs.go:61:2:61:22 | return statement | +| exprs.go:64:5:64:5 | assignment to s | exprs.go:65:5:65:6 | skip | +| exprs.go:64:5:64:5 | skip | exprs.go:64:9:64:11 | sum | +| exprs.go:64:9:64:11 | sum | exprs.go:64:13:64:16 | ints | +| exprs.go:64:9:64:19 | call to sum | exprs.go:0:0:0:0 | exit | +| exprs.go:64:9:64:19 | call to sum | exprs.go:64:5:64:5 | assignment to s | +| exprs.go:64:13:64:16 | ints | exprs.go:64:13:64:18 | call to ints | +| exprs.go:64:13:64:18 | call to ints | exprs.go:0:0:0:0 | exit | +| exprs.go:64:13:64:18 | call to ints | exprs.go:64:9:64:19 | call to sum | +| exprs.go:65:5:65:6 | assignment to s2 | exprs.go:67:6:67:8 | skip | +| exprs.go:65:5:65:6 | skip | exprs.go:65:10:65:13 | sum2 | +| exprs.go:65:10:65:13 | sum2 | exprs.go:65:15:65:18 | ints | +| exprs.go:65:10:65:24 | call to sum2 | exprs.go:0:0:0:0 | exit | +| exprs.go:65:10:65:24 | call to sum2 | exprs.go:65:5:65:6 | assignment to s2 | +| exprs.go:65:15:65:18 | ints | exprs.go:65:15:65:20 | call to ints | +| exprs.go:65:15:65:20 | call to ints | exprs.go:0:0:0:0 | exit | +| exprs.go:65:15:65:20 | call to ints | exprs.go:65:10:65:24 | call to sum2 | +| exprs.go:67:1:67:1 | entry | exprs.go:67:10:67:10 | argument corresponding to x | +| exprs.go:67:1:69:1 | function declaration | exprs.go:71:6:71:8 | skip | +| exprs.go:67:6:67:8 | skip | exprs.go:67:1:69:1 | function declaration | +| exprs.go:67:10:67:10 | argument corresponding to x | exprs.go:67:10:67:10 | initialization of x | +| exprs.go:67:10:67:10 | initialization of x | exprs.go:67:13:67:13 | argument corresponding to y | +| exprs.go:67:13:67:13 | argument corresponding to y | exprs.go:67:13:67:13 | initialization of y | +| exprs.go:67:13:67:13 | initialization of y | exprs.go:68:9:68:9 | x | +| exprs.go:68:2:68:13 | return statement | exprs.go:69:1:69:1 | exit | +| exprs.go:68:9:68:9 | x | exprs.go:68:13:68:13 | y | +| exprs.go:68:9:68:13 | ...+... | exprs.go:68:2:68:13 | return statement | +| exprs.go:68:13:68:13 | y | exprs.go:68:9:68:13 | ...+... | +| exprs.go:71:1:71:1 | entry | exprs.go:72:9:72:9 | 1 | +| exprs.go:71:1:73:1 | function declaration | exprs.go:75:5:75:6 | skip | +| exprs.go:71:6:71:8 | skip | exprs.go:71:1:73:1 | function declaration | +| exprs.go:72:2:72:12 | return statement | exprs.go:73:1:73:1 | exit | +| exprs.go:72:9:72:9 | 1 | exprs.go:72:12:72:12 | 2 | +| exprs.go:72:12:72:12 | 2 | exprs.go:72:2:72:12 | return statement | +| exprs.go:75:5:75:6 | assignment to s3 | exprs.go:77:6:77:10 | skip | +| exprs.go:75:5:75:6 | skip | exprs.go:75:10:75:12 | add | +| exprs.go:75:10:75:12 | add | exprs.go:75:14:75:16 | gen | +| exprs.go:75:10:75:19 | call to add | exprs.go:0:0:0:0 | exit | +| exprs.go:75:10:75:19 | call to add | exprs.go:75:5:75:6 | assignment to s3 | +| exprs.go:75:10:75:19 | call to add[0] | exprs.go:75:10:75:19 | call to add[1] | +| exprs.go:75:10:75:19 | call to add[1] | exprs.go:75:10:75:19 | call to add | +| exprs.go:75:14:75:16 | gen | exprs.go:75:14:75:18 | call to gen | +| exprs.go:75:14:75:18 | call to gen | exprs.go:0:0:0:0 | exit | +| exprs.go:75:14:75:18 | call to gen | exprs.go:75:10:75:19 | call to add[0] | +| exprs.go:77:1:77:1 | entry | exprs.go:77:12:77:12 | argument corresponding to x | +| exprs.go:77:1:79:1 | function declaration | exprs.go:81:6:81:16 | skip | +| exprs.go:77:6:77:10 | skip | exprs.go:77:1:79:1 | function declaration | +| exprs.go:77:12:77:12 | argument corresponding to x | exprs.go:77:12:77:12 | initialization of x | +| exprs.go:77:12:77:12 | initialization of x | exprs.go:77:15:77:15 | argument corresponding to y | +| exprs.go:77:15:77:15 | argument corresponding to y | exprs.go:77:15:77:15 | initialization of y | +| exprs.go:77:15:77:15 | initialization of y | exprs.go:77:18:77:18 | argument corresponding to z | +| exprs.go:77:18:77:18 | argument corresponding to z | exprs.go:77:18:77:18 | initialization of z | +| exprs.go:77:18:77:18 | initialization of z | exprs.go:78:11:78:11 | x | +| exprs.go:78:2:78:22 | return statement | exprs.go:79:1:79:1 | exit | +| exprs.go:78:9:78:17 | !... | exprs.go:78:17:78:17 | !... is false | +| exprs.go:78:9:78:17 | !... | exprs.go:78:17:78:17 | !... is true | +| exprs.go:78:9:78:22 | ...\|\|... | exprs.go:78:2:78:22 | return statement | +| exprs.go:78:11:78:11 | x | exprs.go:78:11:78:11 | x is false | +| exprs.go:78:11:78:11 | x | exprs.go:78:11:78:11 | x is true | +| exprs.go:78:11:78:11 | x is false | exprs.go:78:11:78:16 | ...&&... | +| exprs.go:78:11:78:11 | x is true | exprs.go:78:16:78:16 | y | +| exprs.go:78:11:78:16 | ...&&... | exprs.go:78:9:78:17 | !... | +| exprs.go:78:16:78:16 | y | exprs.go:78:11:78:16 | ...&&... | +| exprs.go:78:17:78:17 | !... is false | exprs.go:78:22:78:22 | z | +| exprs.go:78:17:78:17 | !... is true | exprs.go:78:9:78:22 | ...\|\|... | +| exprs.go:78:22:78:22 | z | exprs.go:78:9:78:22 | ...\|\|... | +| exprs.go:81:1:81:1 | entry | exprs.go:81:18:81:19 | argument corresponding to ch | +| exprs.go:81:1:87:1 | function declaration | exprs.go:89:7:89:9 | skip | +| exprs.go:81:6:81:16 | skip | exprs.go:81:1:87:1 | function declaration | +| exprs.go:81:18:81:19 | argument corresponding to ch | exprs.go:81:18:81:19 | initialization of ch | +| exprs.go:81:18:81:19 | initialization of ch | exprs.go:82:2:82:4 | skip | +| exprs.go:82:2:82:4 | assignment to val | exprs.go:82:2:82:16 | ... := ...[1] | +| exprs.go:82:2:82:4 | skip | exprs.go:82:7:82:8 | skip | +| exprs.go:82:2:82:16 | ... := ...[0] | exprs.go:82:2:82:4 | assignment to val | +| exprs.go:82:2:82:16 | ... := ...[1] | exprs.go:82:7:82:8 | assignment to ok | +| exprs.go:82:7:82:8 | assignment to ok | exprs.go:83:5:83:6 | ok | +| exprs.go:82:7:82:8 | skip | exprs.go:82:15:82:16 | ch | +| exprs.go:82:13:82:16 | <-... | exprs.go:82:2:82:16 | ... := ...[0] | +| exprs.go:82:15:82:16 | ch | exprs.go:82:13:82:16 | <-... | +| exprs.go:83:5:83:6 | ok | exprs.go:83:6:83:6 | ok is false | +| exprs.go:83:5:83:6 | ok | exprs.go:83:6:83:6 | ok is true | +| exprs.go:83:6:83:6 | ok is false | exprs.go:86:2:86:6 | panic | +| exprs.go:83:6:83:6 | ok is true | exprs.go:84:10:84:12 | val | +| exprs.go:84:3:84:12 | return statement | exprs.go:87:1:87:1 | exit | +| exprs.go:84:10:84:12 | val | exprs.go:84:3:84:12 | return statement | +| exprs.go:86:2:86:6 | panic | exprs.go:86:8:86:17 | "No value" | +| exprs.go:86:2:86:18 | call to panic | exprs.go:87:1:87:1 | exit | +| exprs.go:86:8:86:17 | "No value" | exprs.go:86:2:86:18 | call to panic | +| exprs.go:89:7:89:9 | assignment to one | exprs.go:91:5:91:5 | skip | +| exprs.go:89:7:89:9 | skip | exprs.go:89:13:89:13 | 1 | +| exprs.go:89:13:89:13 | 1 | exprs.go:89:7:89:9 | assignment to one | +| exprs.go:91:5:91:5 | assignment to a | exprs.go:93:6:93:11 | skip | +| exprs.go:91:5:91:5 | skip | exprs.go:91:9:91:25 | slice literal | +| exprs.go:91:9:91:25 | slice literal | exprs.go:91:15:91:21 | ...+... | +| exprs.go:91:15:91:21 | ...+... | exprs.go:91:24:91:24 | 2 | +| exprs.go:91:15:91:24 | init of key-value pair | exprs.go:91:5:91:5 | assignment to a | +| exprs.go:91:24:91:24 | 2 | exprs.go:91:15:91:24 | init of key-value pair | +| exprs.go:93:1:93:1 | entry | exprs.go:93:13:93:13 | argument corresponding to x | +| exprs.go:93:1:95:1 | function declaration | exprs.go:0:0:0:0 | exit | +| exprs.go:93:6:93:11 | skip | exprs.go:93:1:95:1 | function declaration | +| exprs.go:93:13:93:13 | argument corresponding to x | exprs.go:93:13:93:13 | initialization of x | +| exprs.go:93:13:93:13 | initialization of x | exprs.go:93:16:93:16 | argument corresponding to y | +| exprs.go:93:16:93:16 | argument corresponding to y | exprs.go:93:16:93:16 | initialization of y | +| exprs.go:93:16:93:16 | initialization of y | exprs.go:93:19:93:19 | argument corresponding to z | +| exprs.go:93:19:93:19 | argument corresponding to z | exprs.go:93:19:93:19 | initialization of z | +| exprs.go:93:19:93:19 | initialization of z | exprs.go:94:10:94:10 | x | +| exprs.go:94:2:94:21 | return statement | exprs.go:95:1:95:1 | exit | +| exprs.go:94:9:94:21 | ...\|\|... | exprs.go:94:2:94:21 | return statement | +| exprs.go:94:10:94:10 | x | exprs.go:94:10:94:10 | x is false | +| exprs.go:94:10:94:10 | x | exprs.go:94:10:94:10 | x is true | +| exprs.go:94:10:94:10 | x is false | exprs.go:94:16:94:16 | (...) is false | +| exprs.go:94:10:94:10 | x is true | exprs.go:94:15:94:15 | y | +| exprs.go:94:15:94:15 | y | exprs.go:94:16:94:16 | (...) is false | +| exprs.go:94:15:94:15 | y | exprs.go:94:16:94:16 | (...) is true | +| exprs.go:94:16:94:16 | (...) is false | exprs.go:94:21:94:21 | z | +| exprs.go:94:16:94:16 | (...) is true | exprs.go:94:9:94:21 | ...\|\|... | +| exprs.go:94:21:94:21 | z | exprs.go:94:9:94:21 | ...\|\|... | +| hello.go:0:0:0:0 | entry | hello.go:3:1:3:12 | skip | +| hello.go:3:1:3:12 | skip | hello.go:5:7:5:13 | skip | +| hello.go:5:7:5:13 | assignment to message | hello.go:7:6:7:13 | skip | +| hello.go:5:7:5:13 | skip | hello.go:5:17:5:31 | "Hello, world!" | +| hello.go:5:17:5:31 | "Hello, world!" | hello.go:5:7:5:13 | assignment to message | +| hello.go:7:1:7:1 | entry | hello.go:8:2:8:12 | selection of Println | +| hello.go:7:1:9:1 | function declaration | hello.go:0:0:0:0 | exit | +| hello.go:7:6:7:13 | skip | hello.go:7:1:9:1 | function declaration | +| hello.go:8:2:8:12 | selection of Println | hello.go:8:14:8:20 | message | +| hello.go:8:2:8:21 | call to Println | hello.go:9:1:9:1 | exit | +| hello.go:8:14:8:20 | message | hello.go:8:2:8:21 | call to Println | +| main.go:0:0:0:0 | entry | main.go:3:1:6:1 | skip | +| main.go:3:1:6:1 | skip | main.go:8:6:8:9 | skip | +| main.go:8:1:8:1 | entry | main.go:9:9:9:20 | selection of Float64 | +| main.go:8:1:10:1 | function declaration | main.go:12:6:12:9 | skip | +| main.go:8:6:8:9 | skip | main.go:8:1:10:1 | function declaration | +| main.go:9:2:9:29 | return statement | main.go:10:1:10:1 | exit | +| main.go:9:9:9:20 | selection of Float64 | main.go:9:9:9:22 | call to Float64 | +| main.go:9:9:9:22 | call to Float64 | main.go:9:27:9:29 | 0.5 | +| main.go:9:9:9:22 | call to Float64 | main.go:10:1:10:1 | exit | +| main.go:9:9:9:29 | ...>=... | main.go:9:2:9:29 | return statement | +| main.go:9:27:9:29 | 0.5 | main.go:9:9:9:29 | ...>=... | +| main.go:12:1:12:1 | entry | main.go:13:6:13:6 | skip | +| main.go:12:1:24:1 | function declaration | main.go:26:6:26:8 | skip | +| main.go:12:6:12:9 | skip | main.go:12:1:24:1 | function declaration | +| main.go:13:6:13:6 | assignment to x | main.go:14:2:14:2 | skip | +| main.go:13:6:13:6 | skip | main.go:13:6:13:6 | zero value for x | +| main.go:13:6:13:6 | zero value for x | main.go:13:6:13:6 | assignment to x | +| main.go:14:2:14:2 | assignment to y | main.go:15:2:15:10 | selection of Print | +| main.go:14:2:14:2 | skip | main.go:14:7:14:8 | 23 | +| main.go:14:7:14:8 | 23 | main.go:14:2:14:2 | assignment to y | +| main.go:15:2:15:10 | selection of Print | main.go:15:12:15:12 | x | +| main.go:15:2:15:16 | call to Print | main.go:16:5:16:8 | cond | +| main.go:15:2:15:16 | call to Print | main.go:24:1:24:1 | exit | +| main.go:15:12:15:12 | x | main.go:15:15:15:15 | y | +| main.go:15:15:15:15 | y | main.go:15:2:15:16 | call to Print | +| main.go:16:5:16:8 | cond | main.go:16:5:16:10 | call to cond | +| main.go:16:5:16:10 | call to cond | main.go:16:10:16:10 | call to cond is false | +| main.go:16:5:16:10 | call to cond | main.go:16:10:16:10 | call to cond is true | +| main.go:16:5:16:10 | call to cond | main.go:24:1:24:1 | exit | +| main.go:16:10:16:10 | call to cond is false | main.go:19:2:19:10 | selection of Print | +| main.go:16:10:16:10 | call to cond is true | main.go:17:3:17:3 | y | +| main.go:17:3:17:3 | assignment to y | main.go:19:2:19:10 | selection of Print | +| main.go:17:3:17:3 | y | main.go:17:8:17:9 | 19 | +| main.go:17:3:17:9 | ... += ... | main.go:17:3:17:3 | assignment to y | +| main.go:17:8:17:9 | 19 | main.go:17:3:17:9 | ... += ... | +| main.go:19:2:19:10 | selection of Print | main.go:19:12:19:12 | x | +| main.go:19:2:19:16 | call to Print | main.go:20:5:20:8 | cond | +| main.go:19:2:19:16 | call to Print | main.go:24:1:24:1 | exit | +| main.go:19:12:19:12 | x | main.go:19:15:19:15 | y | +| main.go:19:15:19:15 | y | main.go:19:2:19:16 | call to Print | +| main.go:20:5:20:8 | cond | main.go:20:5:20:10 | call to cond | +| main.go:20:5:20:10 | call to cond | main.go:20:10:20:10 | call to cond is false | +| main.go:20:5:20:10 | call to cond | main.go:20:10:20:10 | call to cond is true | +| main.go:20:5:20:10 | call to cond | main.go:24:1:24:1 | exit | +| main.go:20:10:20:10 | call to cond is false | main.go:23:2:23:10 | selection of Print | +| main.go:20:10:20:10 | call to cond is true | main.go:21:3:21:3 | skip | +| main.go:21:3:21:3 | assignment to x | main.go:23:2:23:10 | selection of Print | +| main.go:21:3:21:3 | skip | main.go:21:7:21:7 | y | +| main.go:21:7:21:7 | y | main.go:21:3:21:3 | assignment to x | +| main.go:23:2:23:10 | selection of Print | main.go:23:12:23:12 | x | +| main.go:23:2:23:16 | call to Print | main.go:24:1:24:1 | exit | +| main.go:23:12:23:12 | x | main.go:23:15:23:15 | y | +| main.go:23:15:23:15 | y | main.go:23:2:23:16 | call to Print | +| main.go:26:1:26:1 | entry | main.go:26:10:26:10 | argument corresponding to x | +| main.go:26:1:32:1 | function declaration | main.go:34:6:34:9 | skip | +| main.go:26:6:26:8 | skip | main.go:26:1:32:1 | function declaration | +| main.go:26:10:26:10 | argument corresponding to x | main.go:26:10:26:10 | initialization of x | +| main.go:26:10:26:10 | initialization of x | main.go:27:2:27:2 | skip | +| main.go:27:2:27:2 | assignment to a | main.go:27:5:27:5 | assignment to b | +| main.go:27:2:27:2 | skip | main.go:27:5:27:5 | skip | +| main.go:27:5:27:5 | assignment to b | main.go:28:5:28:8 | cond | +| main.go:27:5:27:5 | skip | main.go:27:10:27:10 | x | +| main.go:27:10:27:10 | x | main.go:27:13:27:13 | 0 | +| main.go:27:13:27:13 | 0 | main.go:27:2:27:2 | assignment to a | +| main.go:28:5:28:8 | cond | main.go:28:5:28:10 | call to cond | +| main.go:28:5:28:10 | call to cond | main.go:28:10:28:10 | call to cond is false | +| main.go:28:5:28:10 | call to cond | main.go:28:10:28:10 | call to cond is true | +| main.go:28:5:28:10 | call to cond | main.go:32:1:32:1 | exit | +| main.go:28:10:28:10 | call to cond is false | main.go:31:9:31:9 | a | +| main.go:28:10:28:10 | call to cond is true | main.go:29:3:29:3 | skip | +| main.go:29:3:29:3 | assignment to a | main.go:29:6:29:6 | assignment to b | +| main.go:29:3:29:3 | skip | main.go:29:6:29:6 | skip | +| main.go:29:6:29:6 | assignment to b | main.go:31:9:31:9 | a | +| main.go:29:6:29:6 | skip | main.go:29:10:29:10 | b | +| main.go:29:10:29:10 | b | main.go:29:13:29:13 | a | +| main.go:29:13:29:13 | a | main.go:29:3:29:3 | assignment to a | +| main.go:31:2:31:12 | return statement | main.go:32:1:32:1 | exit | +| main.go:31:9:31:9 | a | main.go:31:12:31:12 | b | +| main.go:31:12:31:12 | b | main.go:31:2:31:12 | return statement | +| main.go:34:1:34:1 | entry | main.go:34:11:34:11 | argument corresponding to x | +| main.go:34:1:36:1 | function declaration | main.go:38:6:38:8 | skip | +| main.go:34:6:34:9 | skip | main.go:34:1:36:1 | function declaration | +| main.go:34:11:34:11 | argument corresponding to x | main.go:34:11:34:11 | initialization of x | +| main.go:34:11:34:11 | initialization of x | main.go:35:3:35:3 | x | +| main.go:35:2:35:3 | assignment to star expression | main.go:36:1:36:1 | exit | +| main.go:35:2:35:3 | star expression | main.go:35:8:35:9 | 19 | +| main.go:35:2:35:3 | star expression | main.go:36:1:36:1 | exit | +| main.go:35:2:35:9 | ... += ... | main.go:35:2:35:3 | assignment to star expression | +| main.go:35:3:35:3 | x | main.go:35:2:35:3 | star expression | +| main.go:35:8:35:9 | 19 | main.go:35:2:35:9 | ... += ... | +| main.go:38:1:38:1 | entry | main.go:39:2:39:2 | skip | +| main.go:38:1:45:1 | function declaration | main.go:47:6:47:8 | skip | +| main.go:38:6:38:8 | skip | main.go:38:1:45:1 | function declaration | +| main.go:39:2:39:2 | assignment to x | main.go:40:2:40:4 | skip | +| main.go:39:2:39:2 | skip | main.go:39:7:39:8 | 23 | +| main.go:39:7:39:8 | 23 | main.go:39:2:39:2 | assignment to x | +| main.go:40:2:40:4 | assignment to ptr | main.go:41:5:41:8 | cond | +| main.go:40:2:40:4 | skip | main.go:40:10:40:10 | x | +| main.go:40:9:40:10 | &... | main.go:40:2:40:4 | assignment to ptr | +| main.go:40:10:40:10 | x | main.go:40:9:40:10 | &... | +| main.go:41:5:41:8 | cond | main.go:41:5:41:10 | call to cond | +| main.go:41:5:41:10 | call to cond | main.go:41:10:41:10 | call to cond is false | +| main.go:41:5:41:10 | call to cond | main.go:41:10:41:10 | call to cond is true | +| main.go:41:5:41:10 | call to cond | main.go:45:1:45:1 | exit | +| main.go:41:10:41:10 | call to cond is false | main.go:44:2:44:10 | selection of Print | +| main.go:41:10:41:10 | call to cond is true | main.go:42:3:42:6 | bump | +| main.go:42:3:42:6 | bump | main.go:42:8:42:10 | ptr | +| main.go:42:3:42:11 | call to bump | main.go:44:2:44:10 | selection of Print | +| main.go:42:3:42:11 | call to bump | main.go:45:1:45:1 | exit | +| main.go:42:8:42:10 | ptr | main.go:42:3:42:11 | call to bump | +| main.go:44:2:44:10 | selection of Print | main.go:44:12:44:12 | x | +| main.go:44:2:44:13 | call to Print | main.go:45:1:45:1 | exit | +| main.go:44:12:44:12 | x | main.go:44:2:44:13 | call to Print | +| main.go:47:1:47:1 | entry | main.go:47:13:47:18 | zero value for result | +| main.go:47:1:50:1 | function declaration | main.go:52:6:52:9 | skip | +| main.go:47:6:47:8 | skip | main.go:47:1:50:1 | function declaration | +| main.go:47:13:47:18 | implicit read of result | main.go:50:1:50:1 | exit | +| main.go:47:13:47:18 | initialization of result | main.go:48:2:48:7 | skip | +| main.go:47:13:47:18 | zero value for result | main.go:47:13:47:18 | initialization of result | +| main.go:48:2:48:7 | assignment to result | main.go:49:2:49:7 | return statement | +| main.go:48:2:48:7 | skip | main.go:48:11:48:12 | 42 | +| main.go:48:11:48:12 | 42 | main.go:48:2:48:7 | assignment to result | +| main.go:49:2:49:7 | return statement | main.go:47:13:47:18 | implicit read of result | +| main.go:52:1:52:1 | entry | main.go:52:14:52:19 | zero value for result | +| main.go:52:1:54:1 | function declaration | main.go:56:6:56:10 | skip | +| main.go:52:6:52:9 | skip | main.go:52:1:54:1 | function declaration | +| main.go:52:14:52:19 | implicit read of result | main.go:54:1:54:1 | exit | +| main.go:52:14:52:19 | initialization of result | main.go:53:2:53:7 | return statement | +| main.go:52:14:52:19 | zero value for result | main.go:52:14:52:19 | initialization of result | +| main.go:53:2:53:7 | return statement | main.go:52:14:52:19 | implicit read of result | +| main.go:56:1:56:1 | entry | main.go:57:6:57:6 | skip | +| main.go:56:1:80:1 | function declaration | main.go:82:6:82:13 | skip | +| main.go:56:6:56:10 | skip | main.go:56:1:80:1 | function declaration | +| main.go:57:6:57:6 | assignment to x | main.go:58:6:58:9 | cond | +| main.go:57:6:57:6 | skip | main.go:57:6:57:6 | zero value for x | +| main.go:57:6:57:6 | zero value for x | main.go:57:6:57:6 | assignment to x | +| main.go:58:6:58:9 | cond | main.go:58:6:58:11 | call to cond | +| main.go:58:6:58:11 | call to cond | main.go:58:11:58:11 | call to cond is false | +| main.go:58:6:58:11 | call to cond | main.go:58:11:58:11 | call to cond is true | +| main.go:58:6:58:11 | call to cond | main.go:80:1:80:1 | exit | +| main.go:58:11:58:11 | call to cond is false | main.go:61:2:61:10 | selection of Print | +| main.go:58:11:58:11 | call to cond is true | main.go:59:3:59:3 | skip | +| main.go:59:3:59:3 | assignment to x | main.go:58:6:58:9 | cond | +| main.go:59:3:59:3 | skip | main.go:59:7:59:7 | 2 | +| main.go:59:7:59:7 | 2 | main.go:59:3:59:3 | assignment to x | +| main.go:61:2:61:10 | selection of Print | main.go:61:12:61:12 | x | +| main.go:61:2:61:13 | call to Print | main.go:63:2:63:2 | skip | +| main.go:61:2:61:13 | call to Print | main.go:80:1:80:1 | exit | +| main.go:61:12:61:12 | x | main.go:61:2:61:13 | call to Print | +| main.go:63:2:63:2 | assignment to y | main.go:64:6:64:6 | skip | +| main.go:63:2:63:2 | skip | main.go:63:7:63:7 | 1 | +| main.go:63:7:63:7 | 1 | main.go:63:2:63:2 | assignment to y | +| main.go:64:6:64:6 | assignment to i | main.go:65:6:65:9 | cond | +| main.go:64:6:64:6 | skip | main.go:64:11:64:11 | 0 | +| main.go:64:11:64:11 | 0 | main.go:64:6:64:6 | assignment to i | +| main.go:64:16:64:16 | i | main.go:64:16:64:18 | 1 | +| main.go:64:16:64:18 | 1 | main.go:64:16:64:18 | rhs of increment statement | +| main.go:64:16:64:18 | increment statement | main.go:65:6:65:9 | cond | +| main.go:64:16:64:18 | rhs of increment statement | main.go:64:16:64:18 | increment statement | +| main.go:65:6:65:9 | cond | main.go:65:6:65:11 | call to cond | +| main.go:65:6:65:11 | call to cond | main.go:65:11:65:11 | call to cond is false | +| main.go:65:6:65:11 | call to cond | main.go:65:11:65:11 | call to cond is true | +| main.go:65:6:65:11 | call to cond | main.go:80:1:80:1 | exit | +| main.go:65:11:65:11 | call to cond is false | main.go:68:3:68:3 | skip | +| main.go:65:11:65:11 | call to cond is true | main.go:66:4:66:8 | skip | +| main.go:66:4:66:8 | skip | main.go:70:2:70:10 | selection of Print | +| main.go:68:3:68:3 | assignment to y | main.go:64:16:64:16 | i | +| main.go:68:3:68:3 | skip | main.go:68:7:68:7 | 2 | +| main.go:68:7:68:7 | 2 | main.go:68:3:68:3 | assignment to y | +| main.go:70:2:70:10 | selection of Print | main.go:70:12:70:12 | y | +| main.go:70:2:70:13 | call to Print | main.go:72:2:72:2 | skip | +| main.go:70:2:70:13 | call to Print | main.go:80:1:80:1 | exit | +| main.go:70:12:70:12 | y | main.go:70:2:70:13 | call to Print | +| main.go:72:2:72:2 | assignment to z | main.go:73:6:73:6 | skip | +| main.go:72:2:72:2 | skip | main.go:72:7:72:7 | 1 | +| main.go:72:7:72:7 | 1 | main.go:72:2:72:2 | assignment to z | +| main.go:73:6:73:6 | assignment to i | main.go:74:3:74:3 | skip | +| main.go:73:6:73:6 | skip | main.go:73:11:73:11 | 0 | +| main.go:73:11:73:11 | 0 | main.go:73:6:73:6 | assignment to i | +| main.go:73:16:73:16 | i | main.go:73:16:73:18 | 1 | +| main.go:73:16:73:18 | 1 | main.go:73:16:73:18 | rhs of increment statement | +| main.go:73:16:73:18 | increment statement | main.go:74:3:74:3 | skip | +| main.go:73:16:73:18 | rhs of increment statement | main.go:73:16:73:18 | increment statement | +| main.go:74:3:74:3 | assignment to z | main.go:75:6:75:9 | cond | +| main.go:74:3:74:3 | skip | main.go:74:7:74:7 | 2 | +| main.go:74:7:74:7 | 2 | main.go:74:3:74:3 | assignment to z | +| main.go:75:6:75:9 | cond | main.go:75:6:75:11 | call to cond | +| main.go:75:6:75:11 | call to cond | main.go:75:11:75:11 | call to cond is false | +| main.go:75:6:75:11 | call to cond | main.go:75:11:75:11 | call to cond is true | +| main.go:75:6:75:11 | call to cond | main.go:80:1:80:1 | exit | +| main.go:75:11:75:11 | call to cond is false | main.go:73:16:73:16 | i | +| main.go:75:11:75:11 | call to cond is true | main.go:76:4:76:8 | skip | +| main.go:76:4:76:8 | skip | main.go:79:2:79:10 | selection of Print | +| main.go:79:2:79:10 | selection of Print | main.go:79:12:79:12 | z | +| main.go:79:2:79:13 | call to Print | main.go:80:1:80:1 | exit | +| main.go:79:12:79:12 | z | main.go:79:2:79:13 | call to Print | +| main.go:82:1:82:1 | entry | main.go:82:18:82:18 | zero value for a | +| main.go:82:1:86:1 | function declaration | main.go:88:6:88:23 | skip | +| main.go:82:6:82:13 | skip | main.go:82:1:86:1 | function declaration | +| main.go:82:18:82:18 | implicit read of a | main.go:82:25:82:25 | implicit read of b | +| main.go:82:18:82:18 | initialization of a | main.go:82:25:82:25 | zero value for b | +| main.go:82:18:82:18 | zero value for a | main.go:82:18:82:18 | initialization of a | +| main.go:82:25:82:25 | implicit read of b | main.go:86:1:86:1 | exit | +| main.go:82:25:82:25 | initialization of b | main.go:83:2:83:2 | skip | +| main.go:82:25:82:25 | zero value for b | main.go:82:25:82:25 | initialization of b | +| main.go:83:2:83:2 | assignment to x | main.go:84:2:84:2 | skip | +| main.go:83:2:83:2 | skip | main.go:83:7:83:8 | 23 | +| main.go:83:7:83:8 | 23 | main.go:83:2:83:2 | assignment to x | +| main.go:84:2:84:2 | assignment to x | main.go:84:5:84:5 | assignment to a | +| main.go:84:2:84:2 | skip | main.go:84:5:84:5 | skip | +| main.go:84:5:84:5 | assignment to a | main.go:85:2:85:7 | return statement | +| main.go:84:5:84:5 | skip | main.go:84:9:84:9 | x | +| main.go:84:9:84:9 | x | main.go:84:11:84:12 | 19 | +| main.go:84:9:84:12 | ...+... | main.go:84:15:84:15 | x | +| main.go:84:11:84:12 | 19 | main.go:84:9:84:12 | ...+... | +| main.go:84:15:84:15 | x | main.go:84:2:84:2 | assignment to x | +| main.go:85:2:85:7 | return statement | main.go:82:18:82:18 | implicit read of a | +| main.go:88:1:88:1 | entry | main.go:88:25:88:25 | argument corresponding to x | +| main.go:88:1:96:1 | function declaration | main.go:0:0:0:0 | exit | +| main.go:88:6:88:23 | skip | main.go:88:1:96:1 | function declaration | +| main.go:88:25:88:25 | argument corresponding to x | main.go:88:25:88:25 | initialization of x | +| main.go:88:25:88:25 | initialization of x | main.go:89:2:89:2 | skip | +| main.go:89:2:89:2 | assignment to a | main.go:89:5:89:5 | assignment to b | +| main.go:89:2:89:2 | skip | main.go:89:5:89:5 | skip | +| main.go:89:5:89:5 | assignment to b | main.go:90:5:90:8 | cond | +| main.go:89:5:89:5 | skip | main.go:89:10:89:10 | x | +| main.go:89:10:89:10 | x | main.go:89:13:89:13 | 0 | +| main.go:89:13:89:13 | 0 | main.go:89:2:89:2 | assignment to a | +| main.go:90:5:90:8 | cond | main.go:90:5:90:10 | call to cond | +| main.go:90:5:90:10 | call to cond | main.go:90:10:90:10 | call to cond is false | +| main.go:90:5:90:10 | call to cond | main.go:90:10:90:10 | call to cond is true | +| main.go:90:5:90:10 | call to cond | main.go:96:1:96:1 | exit | +| main.go:90:10:90:10 | call to cond is false | main.go:93:3:93:3 | skip | +| main.go:90:10:90:10 | call to cond is true | main.go:91:3:91:3 | skip | +| main.go:91:3:91:3 | assignment to a | main.go:95:9:95:9 | a | +| main.go:91:3:91:3 | skip | main.go:91:6:91:6 | skip | +| main.go:91:6:91:6 | skip | main.go:91:10:91:10 | b | +| main.go:91:10:91:10 | b | main.go:91:13:91:13 | a | +| main.go:91:13:91:13 | a | main.go:91:3:91:3 | assignment to a | +| main.go:93:3:93:3 | skip | main.go:93:6:93:6 | skip | +| main.go:93:6:93:6 | assignment to b | main.go:95:9:95:9 | a | +| main.go:93:6:93:6 | skip | main.go:93:10:93:10 | b | +| main.go:93:10:93:10 | b | main.go:93:13:93:13 | a | +| main.go:93:13:93:13 | a | main.go:93:6:93:6 | assignment to b | +| main.go:95:2:95:12 | return statement | main.go:96:1:96:1 | exit | +| main.go:95:9:95:9 | a | main.go:95:12:95:12 | b | +| main.go:95:12:95:12 | b | main.go:95:2:95:12 | return statement | +| noretfunctions.go:0:0:0:0 | entry | noretfunctions.go:3:1:6:1 | skip | +| noretfunctions.go:3:1:6:1 | skip | noretfunctions.go:8:6:8:12 | skip | +| noretfunctions.go:8:1:8:1 | entry | noretfunctions.go:9:2:9:8 | selection of Exit | +| noretfunctions.go:8:1:10:1 | function declaration | noretfunctions.go:12:6:12:11 | skip | +| noretfunctions.go:8:6:8:12 | skip | noretfunctions.go:8:1:10:1 | function declaration | +| noretfunctions.go:9:2:9:8 | selection of Exit | noretfunctions.go:9:10:9:10 | 1 | +| noretfunctions.go:9:2:9:11 | call to Exit | noretfunctions.go:10:1:10:1 | exit | +| noretfunctions.go:9:10:9:10 | 1 | noretfunctions.go:9:2:9:11 | call to Exit | +| noretfunctions.go:12:1:12:1 | entry | noretfunctions.go:12:13:12:13 | argument corresponding to x | +| noretfunctions.go:12:1:16:1 | function declaration | noretfunctions.go:18:6:18:12 | skip | +| noretfunctions.go:12:6:12:11 | skip | noretfunctions.go:12:1:16:1 | function declaration | +| noretfunctions.go:12:13:12:13 | argument corresponding to x | noretfunctions.go:12:13:12:13 | initialization of x | +| noretfunctions.go:12:13:12:13 | initialization of x | noretfunctions.go:13:5:13:5 | x | +| noretfunctions.go:13:5:13:5 | x | noretfunctions.go:13:10:13:10 | 0 | +| noretfunctions.go:13:5:13:10 | ...!=... | noretfunctions.go:13:10:13:10 | ...!=... is false | +| noretfunctions.go:13:5:13:10 | ...!=... | noretfunctions.go:13:10:13:10 | ...!=... is true | +| noretfunctions.go:13:10:13:10 | 0 | noretfunctions.go:13:5:13:10 | ...!=... | +| noretfunctions.go:13:10:13:10 | ...!=... is false | noretfunctions.go:16:1:16:1 | exit | +| noretfunctions.go:13:10:13:10 | ...!=... is true | noretfunctions.go:14:3:14:9 | selection of Exit | +| noretfunctions.go:14:3:14:9 | selection of Exit | noretfunctions.go:14:11:14:11 | x | +| noretfunctions.go:14:3:14:12 | call to Exit | noretfunctions.go:16:1:16:1 | exit | +| noretfunctions.go:14:11:14:11 | x | noretfunctions.go:14:3:14:12 | call to Exit | +| noretfunctions.go:18:1:18:1 | entry | noretfunctions.go:18:16:18:17 | skip | +| noretfunctions.go:18:1:18:17 | function declaration | noretfunctions.go:20:6:20:22 | skip | +| noretfunctions.go:18:6:18:12 | skip | noretfunctions.go:18:1:18:17 | function declaration | +| noretfunctions.go:18:16:18:17 | skip | noretfunctions.go:18:17:18:17 | exit | +| noretfunctions.go:20:1:20:1 | entry | noretfunctions.go:21:2:21:10 | selection of Fatal | +| noretfunctions.go:20:1:22:1 | function declaration | noretfunctions.go:24:6:24:23 | skip | +| noretfunctions.go:20:6:20:22 | skip | noretfunctions.go:20:1:22:1 | function declaration | +| noretfunctions.go:21:2:21:10 | selection of Fatal | noretfunctions.go:21:12:21:18 | "Oh no" | +| noretfunctions.go:21:2:21:19 | call to Fatal | noretfunctions.go:22:1:22:1 | exit | +| noretfunctions.go:21:12:21:18 | "Oh no" | noretfunctions.go:21:2:21:19 | call to Fatal | +| noretfunctions.go:24:1:24:1 | entry | noretfunctions.go:25:2:25:11 | selection of Fatalf | +| noretfunctions.go:24:1:26:1 | function declaration | noretfunctions.go:0:0:0:0 | exit | +| noretfunctions.go:24:6:24:23 | skip | noretfunctions.go:24:1:26:1 | function declaration | +| noretfunctions.go:25:2:25:11 | selection of Fatalf | noretfunctions.go:25:13:25:30 | "It's as I feared" | +| noretfunctions.go:25:2:25:31 | call to Fatalf | noretfunctions.go:26:1:26:1 | exit | +| noretfunctions.go:25:13:25:30 | "It's as I feared" | noretfunctions.go:25:2:25:31 | call to Fatalf | +| stmts2.go:0:0:0:0 | entry | stmts2.go:3:6:3:11 | skip | +| stmts2.go:3:1:3:1 | entry | stmts2.go:4:2:4:2 | skip | +| stmts2.go:3:1:7:1 | function declaration | stmts2.go:9:6:9:11 | skip | +| stmts2.go:3:6:3:11 | skip | stmts2.go:3:1:7:1 | function declaration | +| stmts2.go:4:2:4:2 | skip | stmts2.go:4:6:4:10 | test7 | +| stmts2.go:4:6:4:10 | test7 | stmts2.go:4:12:4:12 | 0 | +| stmts2.go:4:6:4:13 | call to test7 | stmts2.go:5:6:5:6 | skip | +| stmts2.go:4:6:4:13 | call to test7 | stmts2.go:7:1:7:1 | exit | +| stmts2.go:4:12:4:12 | 0 | stmts2.go:4:6:4:13 | call to test7 | +| stmts2.go:5:6:5:6 | skip | stmts2.go:5:10:5:14 | test7 | +| stmts2.go:5:10:5:14 | test7 | stmts2.go:5:16:5:16 | 1 | +| stmts2.go:5:10:5:17 | call to test7 | stmts2.go:6:9:6:9 | 2 | +| stmts2.go:5:10:5:17 | call to test7 | stmts2.go:7:1:7:1 | exit | +| stmts2.go:5:16:5:16 | 1 | stmts2.go:5:10:5:17 | call to test7 | +| stmts2.go:6:2:6:9 | return statement | stmts2.go:7:1:7:1 | exit | +| stmts2.go:6:9:6:9 | 2 | stmts2.go:6:2:6:9 | return statement | +| stmts2.go:9:1:9:1 | entry | stmts2.go:10:2:10:2 | skip | +| stmts2.go:9:1:13:1 | function declaration | stmts2.go:15:6:15:11 | skip | +| stmts2.go:9:6:9:11 | skip | stmts2.go:9:1:13:1 | function declaration | +| stmts2.go:10:2:10:2 | skip | stmts2.go:10:5:10:5 | skip | +| stmts2.go:10:2:10:14 | ... := ...[0] | stmts2.go:10:2:10:14 | ... := ...[1] | +| stmts2.go:10:2:10:14 | ... := ...[1] | stmts2.go:10:5:10:5 | assignment to x | +| stmts2.go:10:5:10:5 | assignment to x | stmts2.go:11:6:11:6 | skip | +| stmts2.go:10:5:10:5 | skip | stmts2.go:10:10:10:12 | gen | +| stmts2.go:10:10:10:12 | gen | stmts2.go:10:10:10:14 | call to gen | +| stmts2.go:10:10:10:14 | call to gen | stmts2.go:10:2:10:14 | ... := ...[0] | +| stmts2.go:10:10:10:14 | call to gen | stmts2.go:13:1:13:1 | exit | +| stmts2.go:11:6:11:6 | skip | stmts2.go:11:9:11:9 | skip | +| stmts2.go:11:6:11:17 | value declaration specifier[0] | stmts2.go:11:6:11:17 | value declaration specifier[1] | +| stmts2.go:11:6:11:17 | value declaration specifier[1] | stmts2.go:11:9:11:9 | assignment to y | +| stmts2.go:11:9:11:9 | assignment to y | stmts2.go:12:9:12:9 | x | +| stmts2.go:11:9:11:9 | skip | stmts2.go:11:13:11:15 | gen | +| stmts2.go:11:13:11:15 | gen | stmts2.go:11:13:11:17 | call to gen | +| stmts2.go:11:13:11:17 | call to gen | stmts2.go:11:6:11:17 | value declaration specifier[0] | +| stmts2.go:11:13:11:17 | call to gen | stmts2.go:13:1:13:1 | exit | +| stmts2.go:12:2:12:13 | return statement | stmts2.go:13:1:13:1 | exit | +| stmts2.go:12:9:12:9 | x | stmts2.go:12:13:12:13 | y | +| stmts2.go:12:9:12:13 | ...+... | stmts2.go:12:2:12:13 | return statement | +| stmts2.go:12:13:12:13 | y | stmts2.go:12:9:12:13 | ...+... | +| stmts2.go:15:1:15:1 | entry | stmts2.go:15:13:15:14 | argument corresponding to ch | +| stmts2.go:15:1:28:1 | function declaration | stmts2.go:30:6:30:12 | skip | +| stmts2.go:15:6:15:11 | skip | stmts2.go:15:1:28:1 | function declaration | +| stmts2.go:15:13:15:14 | argument corresponding to ch | stmts2.go:15:13:15:14 | initialization of ch | +| stmts2.go:15:13:15:14 | initialization of ch | stmts2.go:17:13:17:14 | ch | +| stmts2.go:16:2:26:2 | select statement | stmts2.go:17:11:17:14 | <-... | +| stmts2.go:16:2:26:2 | select statement | stmts2.go:18:15:18:18 | <-... | +| stmts2.go:16:2:26:2 | select statement | stmts2.go:20:15:20:18 | <-... | +| stmts2.go:16:2:26:2 | select statement | stmts2.go:25:14:25:17 | <-... | +| stmts2.go:17:2:17:15 | skip | stmts2.go:27:9:27:9 | 1 | +| stmts2.go:17:7:17:7 | skip | stmts2.go:17:2:17:15 | skip | +| stmts2.go:17:11:17:14 | <-... | stmts2.go:17:7:17:7 | skip | +| stmts2.go:17:13:17:14 | ch | stmts2.go:18:17:18:18 | ch | +| stmts2.go:18:7:18:7 | assignment to x | stmts2.go:18:7:18:18 | ... := ...[1] | +| stmts2.go:18:7:18:7 | skip | stmts2.go:18:10:18:10 | skip | +| stmts2.go:18:7:18:18 | ... := ...[0] | stmts2.go:18:7:18:7 | assignment to x | +| stmts2.go:18:7:18:18 | ... := ...[1] | stmts2.go:19:10:19:10 | x | +| stmts2.go:18:10:18:10 | skip | stmts2.go:18:7:18:18 | ... := ...[0] | +| stmts2.go:18:15:18:18 | <-... | stmts2.go:18:7:18:7 | skip | +| stmts2.go:18:17:18:18 | ch | stmts2.go:20:17:20:18 | ch | +| stmts2.go:19:3:19:10 | return statement | stmts2.go:28:1:28:1 | exit | +| stmts2.go:19:10:19:10 | x | stmts2.go:19:3:19:10 | return statement | +| stmts2.go:20:7:20:7 | skip | stmts2.go:20:10:20:10 | skip | +| stmts2.go:20:7:20:18 | ... := ...[0] | stmts2.go:20:7:20:18 | ... := ...[1] | +| stmts2.go:20:7:20:18 | ... := ...[1] | stmts2.go:20:10:20:10 | assignment to y | +| stmts2.go:20:10:20:10 | assignment to y | stmts2.go:21:6:21:6 | y | +| stmts2.go:20:10:20:10 | skip | stmts2.go:20:7:20:18 | ... := ...[0] | +| stmts2.go:20:15:20:18 | <-... | stmts2.go:20:7:20:7 | skip | +| stmts2.go:20:17:20:18 | ch | stmts2.go:25:16:25:17 | ch | +| stmts2.go:21:6:21:6 | y | stmts2.go:21:6:21:6 | y is false | +| stmts2.go:21:6:21:6 | y | stmts2.go:21:6:21:6 | y is true | +| stmts2.go:21:6:21:6 | y is false | stmts2.go:24:10:24:10 | 0 | +| stmts2.go:21:6:21:6 | y is true | stmts2.go:22:4:22:8 | skip | +| stmts2.go:22:4:22:8 | skip | stmts2.go:27:9:27:9 | 1 | +| stmts2.go:24:3:24:10 | return statement | stmts2.go:28:1:28:1 | exit | +| stmts2.go:24:10:24:10 | 0 | stmts2.go:24:3:24:10 | return statement | +| stmts2.go:25:2:25:18 | skip | stmts2.go:27:9:27:9 | 1 | +| stmts2.go:25:7:25:7 | skip | stmts2.go:25:10:25:10 | skip | +| stmts2.go:25:7:25:17 | ... = ...[0] | stmts2.go:25:7:25:17 | ... = ...[1] | +| stmts2.go:25:7:25:17 | ... = ...[1] | stmts2.go:25:2:25:18 | skip | +| stmts2.go:25:10:25:10 | skip | stmts2.go:25:7:25:17 | ... = ...[0] | +| stmts2.go:25:14:25:17 | <-... | stmts2.go:25:7:25:7 | skip | +| stmts2.go:25:16:25:17 | ch | stmts2.go:16:2:26:2 | select statement | +| stmts2.go:27:2:27:9 | return statement | stmts2.go:28:1:28:1 | exit | +| stmts2.go:27:9:27:9 | 1 | stmts2.go:27:2:27:9 | return statement | +| stmts2.go:30:1:30:1 | entry | stmts2.go:31:2:31:2 | skip | +| stmts2.go:30:1:34:1 | function declaration | stmts2.go:0:0:0:0 | exit | +| stmts2.go:30:6:30:12 | skip | stmts2.go:30:1:34:1 | function declaration | +| stmts2.go:31:2:31:2 | assignment to x | stmts2.go:31:2:31:14 | ... := ...[1] | +| stmts2.go:31:2:31:2 | skip | stmts2.go:31:5:31:5 | skip | +| stmts2.go:31:2:31:14 | ... := ...[0] | stmts2.go:31:2:31:2 | assignment to x | +| stmts2.go:31:2:31:14 | ... := ...[1] | stmts2.go:32:6:32:6 | skip | +| stmts2.go:31:5:31:5 | skip | stmts2.go:31:10:31:12 | gen | +| stmts2.go:31:10:31:12 | gen | stmts2.go:31:10:31:14 | call to gen | +| stmts2.go:31:10:31:14 | call to gen | stmts2.go:31:2:31:14 | ... := ...[0] | +| stmts2.go:31:10:31:14 | call to gen | stmts2.go:34:1:34:1 | exit | +| stmts2.go:32:6:32:6 | assignment to y | stmts2.go:32:6:32:17 | value declaration specifier[1] | +| stmts2.go:32:6:32:6 | skip | stmts2.go:32:9:32:9 | skip | +| stmts2.go:32:6:32:17 | value declaration specifier[0] | stmts2.go:32:6:32:6 | assignment to y | +| stmts2.go:32:6:32:17 | value declaration specifier[1] | stmts2.go:33:9:33:9 | x | +| stmts2.go:32:9:32:9 | skip | stmts2.go:32:13:32:15 | gen | +| stmts2.go:32:13:32:15 | gen | stmts2.go:32:13:32:17 | call to gen | +| stmts2.go:32:13:32:17 | call to gen | stmts2.go:32:6:32:17 | value declaration specifier[0] | +| stmts2.go:32:13:32:17 | call to gen | stmts2.go:34:1:34:1 | exit | +| stmts2.go:33:2:33:13 | return statement | stmts2.go:34:1:34:1 | exit | +| stmts2.go:33:9:33:9 | x | stmts2.go:33:13:33:13 | y | +| stmts2.go:33:9:33:13 | ...+... | stmts2.go:33:2:33:13 | return statement | +| stmts2.go:33:13:33:13 | y | stmts2.go:33:9:33:13 | ...+... | +| stmts3.go:0:0:0:0 | entry | stmts3.go:3:1:3:13 | skip | +| stmts3.go:3:1:3:13 | skip | stmts3.go:5:6:5:11 | skip | +| stmts3.go:5:1:5:1 | entry | stmts3.go:7:3:7:5 | skip | +| stmts3.go:5:1:12:1 | function declaration | stmts3.go:14:6:14:11 | skip | +| stmts3.go:5:6:5:11 | skip | stmts3.go:5:1:12:1 | function declaration | +| stmts3.go:7:3:7:5 | assignment to red | stmts3.go:8:3:8:7 | skip | +| stmts3.go:7:3:7:5 | skip | stmts3.go:7:9:7:12 | iota | +| stmts3.go:7:9:7:12 | iota | stmts3.go:7:3:7:5 | assignment to red | +| stmts3.go:8:3:8:7 | assignment to green | stmts3.go:9:3:9:6 | skip | +| stmts3.go:8:3:8:7 | skip | stmts3.go:8:3:8:7 | zero value for green | +| stmts3.go:8:3:8:7 | zero value for green | stmts3.go:8:3:8:7 | assignment to green | +| stmts3.go:9:3:9:6 | assignment to blue | stmts3.go:11:9:11:26 | ...-... | +| stmts3.go:9:3:9:6 | skip | stmts3.go:9:3:9:6 | zero value for blue | +| stmts3.go:9:3:9:6 | zero value for blue | stmts3.go:9:3:9:6 | assignment to blue | +| stmts3.go:11:2:11:26 | return statement | stmts3.go:12:1:12:1 | exit | +| stmts3.go:11:9:11:26 | ...-... | stmts3.go:11:2:11:26 | return statement | +| stmts3.go:14:1:14:1 | entry | stmts3.go:14:13:14:13 | argument corresponding to x | +| stmts3.go:14:1:16:1 | function declaration | stmts3.go:18:6:18:11 | skip | +| stmts3.go:14:6:14:11 | skip | stmts3.go:14:1:16:1 | function declaration | +| stmts3.go:14:13:14:13 | argument corresponding to x | stmts3.go:14:13:14:13 | initialization of x | +| stmts3.go:14:13:14:13 | initialization of x | stmts3.go:15:3:15:3 | x | +| stmts3.go:15:2:15:3 | assignment to star expression | stmts3.go:16:1:16:1 | exit | +| stmts3.go:15:2:15:3 | skip | stmts3.go:15:7:15:8 | 42 | +| stmts3.go:15:2:15:3 | skip | stmts3.go:16:1:16:1 | exit | +| stmts3.go:15:3:15:3 | x | stmts3.go:15:2:15:3 | skip | +| stmts3.go:15:7:15:8 | 42 | stmts3.go:15:2:15:3 | assignment to star expression | +| stmts3.go:18:1:18:1 | entry | stmts3.go:19:2:19:11 | skip | +| stmts3.go:18:1:20:1 | function declaration | stmts3.go:0:0:0:0 | exit | +| stmts3.go:18:6:18:11 | skip | stmts3.go:18:1:20:1 | function declaration | +| stmts3.go:19:2:19:11 | assignment to Usage | stmts3.go:20:1:20:1 | exit | +| stmts3.go:19:2:19:11 | skip | stmts3.go:19:15:19:23 | function literal | +| stmts3.go:19:15:19:15 | entry | stmts3.go:19:22:19:23 | skip | +| stmts3.go:19:15:19:23 | function literal | stmts3.go:19:2:19:11 | assignment to Usage | +| stmts3.go:19:22:19:23 | skip | stmts3.go:19:23:19:23 | exit | +| stmts4.go:0:0:0:0 | entry | stmts4.go:3:5:3:5 | skip | +| stmts4.go:3:5:3:5 | skip | stmts4.go:3:5:3:5 | zero value for _ | +| stmts4.go:3:5:3:5 | zero value for _ | stmts4.go:5:6:5:11 | skip | +| stmts4.go:5:1:5:26 | function declaration | stmts4.go:0:0:0:0 | exit | +| stmts4.go:5:6:5:11 | skip | stmts4.go:5:1:5:26 | function declaration | +| stmts5.go:0:0:0:0 | entry | stmts5.go:3:1:5:1 | skip | +| stmts5.go:3:1:5:1 | skip | stmts5.go:7:17:7:20 | skip | +| stmts5.go:7:1:7:1 | entry | stmts5.go:7:7:7:8 | argument corresponding to me | +| stmts5.go:7:1:9:1 | function declaration | stmts5.go:11:14:11:16 | skip | +| stmts5.go:7:7:7:8 | argument corresponding to me | stmts5.go:7:7:7:8 | initialization of me | +| stmts5.go:7:7:7:8 | initialization of me | stmts5.go:7:22:7:26 | argument corresponding to other | +| stmts5.go:7:17:7:20 | skip | stmts5.go:7:1:9:1 | function declaration | +| stmts5.go:7:22:7:26 | argument corresponding to other | stmts5.go:7:22:7:26 | initialization of other | +| stmts5.go:7:22:7:26 | initialization of other | stmts5.go:8:2:8:3 | me | +| stmts5.go:8:2:8:3 | me | stmts5.go:8:2:8:7 | selection of val | +| stmts5.go:8:2:8:7 | assignment to field val | stmts5.go:9:1:9:1 | exit | +| stmts5.go:8:2:8:7 | selection of val | stmts5.go:8:12:8:16 | other | +| stmts5.go:8:2:8:16 | ... += ... | stmts5.go:8:2:8:7 | assignment to field val | +| stmts5.go:8:12:8:16 | other | stmts5.go:8:2:8:16 | ... += ... | +| stmts5.go:11:1:11:1 | entry | stmts5.go:11:20:12:1 | skip | +| stmts5.go:11:1:12:1 | function declaration | stmts5.go:0:0:0:0 | exit | +| stmts5.go:11:14:11:16 | skip | stmts5.go:11:1:12:1 | function declaration | +| stmts5.go:11:20:12:1 | skip | stmts5.go:12:1:12:1 | exit | +| stmts6.go:0:0:0:0 | entry | stmts6.go:3:6:3:11 | skip | +| stmts6.go:3:1:3:1 | entry | stmts6.go:4:5:4:8 | true | +| stmts6.go:3:1:8:1 | function declaration | stmts6.go:0:0:0:0 | exit | +| stmts6.go:3:6:3:11 | skip | stmts6.go:3:1:8:1 | function declaration | +| stmts6.go:4:5:4:8 | true | stmts6.go:4:8:4:8 | true is true | +| stmts6.go:4:8:4:8 | true is false | stmts6.go:7:9:7:10 | 23 | +| stmts6.go:4:8:4:8 | true is true | stmts6.go:5:10:5:11 | 42 | +| stmts6.go:5:3:5:11 | return statement | stmts6.go:8:1:8:1 | exit | +| stmts6.go:5:10:5:11 | 42 | stmts6.go:5:3:5:11 | return statement | +| stmts6.go:7:9:7:10 | 23 | stmts6.go:7:2:7:10 | return statement | +| stmts7.go:0:0:0:0 | entry | stmts7.go:3:1:3:12 | skip | +| stmts7.go:3:1:3:12 | skip | stmts7.go:5:6:5:17 | skip | +| stmts7.go:5:1:5:1 | entry | stmts7.go:6:2:6:5 | skip | +| stmts7.go:5:1:8:1 | function declaration | stmts7.go:10:6:10:15 | skip | +| stmts7.go:5:6:5:17 | skip | stmts7.go:5:1:8:1 | function declaration | +| stmts7.go:6:2:6:5 | assignment to blah | stmts7.go:7:2:7:12 | selection of Println | +| stmts7.go:6:2:6:5 | skip | stmts7.go:6:10:6:16 | recover | +| stmts7.go:6:10:6:16 | recover | stmts7.go:6:10:6:18 | call to recover | +| stmts7.go:6:10:6:18 | call to recover | stmts7.go:6:2:6:5 | assignment to blah | +| stmts7.go:7:2:7:12 | selection of Println | stmts7.go:7:14:7:26 | "recovered: " | +| stmts7.go:7:2:7:33 | call to Println | stmts7.go:8:1:8:1 | exit | +| stmts7.go:7:14:7:26 | "recovered: " | stmts7.go:7:29:7:32 | blah | +| stmts7.go:7:29:7:32 | blah | stmts7.go:7:2:7:33 | call to Println | +| stmts7.go:10:1:10:1 | entry | stmts7.go:11:8:11:19 | recoverPanic | +| stmts7.go:10:1:13:1 | function declaration | stmts7.go:15:1:17:1 | skip | +| stmts7.go:10:6:10:15 | skip | stmts7.go:10:1:13:1 | function declaration | +| stmts7.go:11:2:11:21 | defer statement | stmts7.go:12:2:12:6 | panic | +| stmts7.go:11:8:11:19 | recoverPanic | stmts7.go:11:2:11:21 | defer statement | +| stmts7.go:11:8:11:21 | call to recoverPanic | stmts7.go:13:1:13:1 | exit | +| stmts7.go:12:2:12:6 | panic | stmts7.go:12:8:12:9 | "" | +| stmts7.go:12:2:12:10 | call to panic | stmts7.go:11:8:11:21 | call to recoverPanic | +| stmts7.go:12:8:12:9 | "" | stmts7.go:12:2:12:10 | call to panic | +| stmts7.go:15:1:17:1 | skip | stmts7.go:19:26:19:28 | skip | +| stmts7.go:19:1:19:1 | entry | stmts7.go:19:7:19:13 | argument corresponding to methods | +| stmts7.go:19:1:21:1 | function declaration | stmts7.go:23:6:23:14 | skip | +| stmts7.go:19:7:19:13 | argument corresponding to methods | stmts7.go:19:7:19:13 | initialization of methods | +| stmts7.go:19:7:19:13 | initialization of methods | stmts7.go:20:2:20:8 | methods | +| stmts7.go:19:26:19:28 | skip | stmts7.go:19:1:21:1 | function declaration | +| stmts7.go:20:2:20:8 | implicit dereference | stmts7.go:20:2:20:11 | selection of fn | +| stmts7.go:20:2:20:8 | implicit dereference | stmts7.go:21:1:21:1 | exit | +| stmts7.go:20:2:20:8 | methods | stmts7.go:20:2:20:8 | implicit dereference | +| stmts7.go:20:2:20:11 | selection of fn | stmts7.go:20:2:20:13 | call to fn | +| stmts7.go:20:2:20:13 | call to fn | stmts7.go:21:1:21:1 | exit | +| stmts7.go:23:1:23:1 | entry | stmts7.go:23:16:23:23 | argument corresponding to callback | +| stmts7.go:23:1:28:1 | function declaration | stmts7.go:0:0:0:0 | exit | +| stmts7.go:23:6:23:14 | skip | stmts7.go:23:1:28:1 | function declaration | +| stmts7.go:23:16:23:23 | argument corresponding to callback | stmts7.go:23:16:23:23 | initialization of callback | +| stmts7.go:23:16:23:23 | initialization of callback | stmts7.go:24:8:24:15 | callback | +| stmts7.go:24:2:24:20 | defer statement | stmts7.go:25:10:25:17 | callback | +| stmts7.go:24:8:24:15 | callback | stmts7.go:24:8:24:18 | selection of fn | +| stmts7.go:24:8:24:18 | selection of fn | stmts7.go:24:2:24:20 | defer statement | +| stmts7.go:24:8:24:20 | call to fn | stmts7.go:28:1:28:1 | exit | +| stmts7.go:25:2:25:23 | defer statement | stmts7.go:26:2:26:12 | selection of Println | +| stmts7.go:25:8:25:18 | implicit dereference | stmts7.go:24:8:24:20 | call to fn | +| stmts7.go:25:8:25:18 | implicit dereference | stmts7.go:25:8:25:21 | selection of fn | +| stmts7.go:25:8:25:21 | selection of fn | stmts7.go:25:2:25:23 | defer statement | +| stmts7.go:25:8:25:23 | call to fn | stmts7.go:24:8:24:20 | call to fn | +| stmts7.go:25:9:25:17 | &... | stmts7.go:25:8:25:18 | implicit dereference | +| stmts7.go:25:10:25:17 | callback | stmts7.go:25:9:25:17 | &... | +| stmts7.go:26:2:26:12 | selection of Println | stmts7.go:26:14:26:30 | "print something" | +| stmts7.go:26:2:26:31 | call to Println | stmts7.go:25:8:25:23 | call to fn | +| stmts7.go:26:2:26:31 | call to Println | stmts7.go:27:9:27:13 | false | +| stmts7.go:26:14:26:30 | "print something" | stmts7.go:26:2:26:31 | call to Println | +| stmts7.go:27:2:27:13 | return statement | stmts7.go:25:8:25:23 | call to fn | +| stmts7.go:27:9:27:13 | false | stmts7.go:27:2:27:13 | return statement | +| stmts8.go:0:0:0:0 | entry | stmts8.go:3:6:3:11 | skip | +| stmts8.go:3:1:3:1 | entry | stmts8.go:3:13:3:13 | argument corresponding to x | +| stmts8.go:3:1:7:1 | function declaration | stmts8.go:9:6:9:12 | skip | +| stmts8.go:3:6:3:11 | skip | stmts8.go:3:1:7:1 | function declaration | +| stmts8.go:3:13:3:13 | argument corresponding to x | stmts8.go:3:13:3:13 | initialization of x | +| stmts8.go:3:13:3:13 | initialization of x | stmts8.go:4:2:4:2 | skip | +| stmts8.go:4:2:4:2 | assignment to y | stmts8.go:5:2:5:2 | skip | +| stmts8.go:4:2:4:2 | skip | stmts8.go:4:7:4:7 | x | +| stmts8.go:4:7:4:7 | x | stmts8.go:4:12:4:12 | 5 | +| stmts8.go:4:7:4:12 | ...>>... | stmts8.go:4:2:4:2 | assignment to y | +| stmts8.go:4:12:4:12 | 5 | stmts8.go:4:7:4:12 | ...>>... | +| stmts8.go:5:2:5:2 | assignment to z | stmts8.go:6:9:6:9 | z | +| stmts8.go:5:2:5:2 | skip | stmts8.go:5:7:5:7 | x | +| stmts8.go:5:7:5:7 | x | stmts8.go:5:12:5:12 | 1 | +| stmts8.go:5:7:5:13 | ...%... | stmts8.go:5:2:5:2 | assignment to z | +| stmts8.go:5:12:5:12 | 1 | stmts8.go:5:7:5:13 | ...%... | +| stmts8.go:6:2:6:17 | return statement | stmts8.go:7:1:7:1 | exit | +| stmts8.go:6:9:6:9 | z | stmts8.go:6:12:6:12 | y | +| stmts8.go:6:12:6:12 | y | stmts8.go:6:16:6:17 | 13 | +| stmts8.go:6:12:6:17 | ...%... | stmts8.go:6:2:6:17 | return statement | +| stmts8.go:6:16:6:17 | 13 | stmts8.go:6:12:6:17 | ...%... | +| stmts8.go:9:1:9:1 | entry | stmts8.go:10:5:10:9 | linux | +| stmts8.go:9:1:14:1 | function declaration | stmts8.go:0:0:0:0 | exit | +| stmts8.go:9:6:9:12 | skip | stmts8.go:9:1:14:1 | function declaration | +| stmts8.go:10:5:10:9 | linux | stmts8.go:10:9:10:9 | linux is false | +| stmts8.go:10:5:10:9 | linux | stmts8.go:10:9:10:9 | linux is true | +| stmts8.go:10:9:10:9 | linux is false | stmts8.go:13:9:13:13 | false | +| stmts8.go:10:9:10:9 | linux is true | stmts8.go:11:10:11:13 | true | +| stmts8.go:11:3:11:13 | return statement | stmts8.go:14:1:14:1 | exit | +| stmts8.go:11:10:11:13 | true | stmts8.go:11:3:11:13 | return statement | +| stmts8.go:13:2:13:13 | return statement | stmts8.go:14:1:14:1 | exit | +| stmts8.go:13:9:13:13 | false | stmts8.go:13:2:13:13 | return statement | +| stmts.go:0:0:0:0 | entry | stmts.go:3:1:3:12 | skip | +| stmts.go:3:1:3:12 | skip | stmts.go:10:6:10:10 | skip | +| stmts.go:10:1:10:1 | entry | stmts.go:10:12:10:12 | argument corresponding to b | +| stmts.go:10:1:43:1 | function declaration | stmts.go:46:6:46:10 | skip | +| stmts.go:10:6:10:10 | skip | stmts.go:10:1:43:1 | function declaration | +| stmts.go:10:12:10:12 | argument corresponding to b | stmts.go:10:12:10:12 | initialization of b | +| stmts.go:10:12:10:12 | initialization of b | stmts.go:12:7:12:7 | b | +| stmts.go:12:6:12:7 | !... | stmts.go:12:7:12:7 | !... is false | +| stmts.go:12:6:12:7 | !... | stmts.go:12:7:12:7 | !... is true | +| stmts.go:12:7:12:7 | !... is false | stmts.go:15:3:16:3 | skip | +| stmts.go:12:7:12:7 | !... is true | stmts.go:13:4:13:13 | skip | +| stmts.go:12:7:12:7 | b | stmts.go:12:6:12:7 | !... | +| stmts.go:13:4:13:13 | skip | stmts.go:23:6:23:9 | true | +| stmts.go:15:3:16:3 | skip | stmts.go:17:3:17:3 | skip | +| stmts.go:17:3:17:3 | skip | stmts.go:20:2:20:12 | selection of Println | +| stmts.go:20:2:20:12 | selection of Println | stmts.go:20:14:20:17 | "Hi" | +| stmts.go:20:2:20:18 | call to Println | stmts.go:23:6:23:9 | true | +| stmts.go:20:2:20:18 | call to Println | stmts.go:43:1:43:1 | exit | +| stmts.go:20:14:20:17 | "Hi" | stmts.go:20:2:20:18 | call to Println | +| stmts.go:23:6:23:9 | true | stmts.go:23:9:23:9 | true is true | +| stmts.go:23:9:23:9 | true is false | stmts.go:39:2:39:2 | skip | +| stmts.go:23:9:23:9 | true is true | stmts.go:24:7:24:7 | skip | +| stmts.go:24:7:24:7 | assignment to i | stmts.go:24:15:24:15 | i | +| stmts.go:24:7:24:7 | skip | stmts.go:24:12:24:12 | 0 | +| stmts.go:24:12:24:12 | 0 | stmts.go:24:7:24:7 | assignment to i | +| stmts.go:24:15:24:15 | i | stmts.go:24:19:24:20 | 10 | +| stmts.go:24:15:24:20 | ...<... | stmts.go:24:20:24:20 | ...<... is false | +| stmts.go:24:15:24:20 | ...<... | stmts.go:24:20:24:20 | ...<... is true | +| stmts.go:24:19:24:20 | 10 | stmts.go:24:15:24:20 | ...<... | +| stmts.go:24:20:24:20 | ...<... is false | stmts.go:23:6:23:9 | true | +| stmts.go:24:20:24:20 | ...<... is true | stmts.go:25:7:25:7 | skip | +| stmts.go:24:23:24:23 | i | stmts.go:24:23:24:25 | 1 | +| stmts.go:24:23:24:25 | 1 | stmts.go:24:23:24:25 | rhs of increment statement | +| stmts.go:24:23:24:25 | increment statement | stmts.go:24:15:24:15 | i | +| stmts.go:24:23:24:25 | rhs of increment statement | stmts.go:24:23:24:25 | increment statement | +| stmts.go:25:7:25:7 | assignment to j | stmts.go:25:19:25:19 | j | +| stmts.go:25:7:25:7 | skip | stmts.go:25:12:25:12 | i | +| stmts.go:25:12:25:12 | i | stmts.go:25:16:25:16 | 1 | +| stmts.go:25:12:25:16 | ...-... | stmts.go:25:7:25:7 | assignment to j | +| stmts.go:25:16:25:16 | 1 | stmts.go:25:12:25:16 | ...-... | +| stmts.go:25:19:25:19 | j | stmts.go:25:23:25:23 | 5 | +| stmts.go:25:19:25:23 | ...>... | stmts.go:25:23:25:23 | ...>... is false | +| stmts.go:25:19:25:23 | ...>... | stmts.go:25:23:25:23 | ...>... is true | +| stmts.go:25:23:25:23 | 5 | stmts.go:25:19:25:23 | ...>... | +| stmts.go:25:23:25:23 | ...>... is false | stmts.go:27:14:27:14 | i | +| stmts.go:25:23:25:23 | ...>... is true | stmts.go:26:5:26:15 | skip | +| stmts.go:26:5:26:15 | skip | stmts.go:39:2:39:2 | skip | +| stmts.go:27:14:27:14 | i | stmts.go:27:18:27:18 | 3 | +| stmts.go:27:14:27:18 | ...<... | stmts.go:27:18:27:18 | ...<... is false | +| stmts.go:27:14:27:18 | ...<... | stmts.go:27:18:27:18 | ...<... is true | +| stmts.go:27:18:27:18 | 3 | stmts.go:27:14:27:18 | ...<... | +| stmts.go:27:18:27:18 | ...<... is false | stmts.go:29:14:29:14 | i | +| stmts.go:27:18:27:18 | ...<... is true | stmts.go:28:5:28:9 | skip | +| stmts.go:28:5:28:9 | skip | stmts.go:23:6:23:9 | true | +| stmts.go:29:14:29:14 | i | stmts.go:29:19:29:19 | 9 | +| stmts.go:29:14:29:19 | ...!=... | stmts.go:29:19:29:19 | ...!=... is false | +| stmts.go:29:14:29:19 | ...!=... | stmts.go:29:19:29:19 | ...!=... is true | +| stmts.go:29:19:29:19 | 9 | stmts.go:29:14:29:19 | ...!=... | +| stmts.go:29:19:29:19 | ...!=... is false | stmts.go:31:14:31:14 | i | +| stmts.go:29:19:29:19 | ...!=... is true | stmts.go:30:5:30:18 | skip | +| stmts.go:30:5:30:18 | skip | stmts.go:23:6:23:9 | true | +| stmts.go:31:14:31:14 | i | stmts.go:31:19:31:19 | 4 | +| stmts.go:31:14:31:19 | ...>=... | stmts.go:31:19:31:19 | ...>=... is false | +| stmts.go:31:14:31:19 | ...>=... | stmts.go:31:19:31:19 | ...>=... is true | +| stmts.go:31:19:31:19 | 4 | stmts.go:31:14:31:19 | ...>=... | +| stmts.go:31:19:31:19 | ...>=... is false | stmts.go:34:5:34:12 | skip | +| stmts.go:31:19:31:19 | ...>=... is true | stmts.go:32:5:32:14 | skip | +| stmts.go:32:5:32:14 | skip | stmts.go:23:6:23:9 | true | +| stmts.go:34:5:34:12 | skip | stmts.go:24:23:24:23 | i | +| stmts.go:39:2:39:2 | assignment to k | stmts.go:41:3:41:12 | skip | +| stmts.go:39:2:39:2 | skip | stmts.go:39:7:39:7 | 9 | +| stmts.go:39:7:39:7 | 9 | stmts.go:39:2:39:2 | assignment to k | +| stmts.go:40:10:40:10 | k | stmts.go:40:10:40:12 | 1 | +| stmts.go:40:10:40:12 | 1 | stmts.go:40:10:40:12 | rhs of increment statement | +| stmts.go:40:10:40:12 | increment statement | stmts.go:41:3:41:12 | skip | +| stmts.go:40:10:40:12 | rhs of increment statement | stmts.go:40:10:40:12 | increment statement | +| stmts.go:41:3:41:12 | skip | stmts.go:23:6:23:9 | true | +| stmts.go:46:1:46:1 | entry | stmts.go:46:12:46:14 | argument corresponding to ch1 | +| stmts.go:46:1:62:1 | function declaration | stmts.go:65:6:65:10 | skip | +| stmts.go:46:6:46:10 | skip | stmts.go:46:1:62:1 | function declaration | +| stmts.go:46:12:46:14 | argument corresponding to ch1 | stmts.go:46:12:46:14 | initialization of ch1 | +| stmts.go:46:12:46:14 | initialization of ch1 | stmts.go:46:26:46:28 | argument corresponding to ch2 | +| stmts.go:46:26:46:28 | argument corresponding to ch2 | stmts.go:46:26:46:28 | initialization of ch2 | +| stmts.go:46:26:46:28 | initialization of ch2 | stmts.go:47:6:47:6 | skip | +| stmts.go:47:6:47:6 | assignment to a | stmts.go:48:6:48:6 | skip | +| stmts.go:47:6:47:6 | skip | stmts.go:47:6:47:6 | zero value for a | +| stmts.go:47:6:47:6 | zero value for a | stmts.go:47:6:47:6 | assignment to a | +| stmts.go:48:6:48:6 | assignment to w | stmts.go:51:9:51:11 | ch1 | +| stmts.go:48:6:48:6 | skip | stmts.go:48:6:48:6 | zero value for w | +| stmts.go:48:6:48:6 | zero value for w | stmts.go:48:6:48:6 | assignment to w | +| stmts.go:50:2:59:2 | select statement | stmts.go:51:7:51:11 | <-... | +| stmts.go:50:2:59:2 | select statement | stmts.go:53:17:53:21 | <-... | +| stmts.go:50:2:59:2 | select statement | stmts.go:57:3:57:13 | selection of Println | +| stmts.go:50:2:59:2 | select statement | stmts.go:58:7:58:15 | send statement | +| stmts.go:51:7:51:11 | <-... | stmts.go:52:3:52:13 | selection of Println | +| stmts.go:51:9:51:11 | ch1 | stmts.go:53:19:53:21 | ch2 | +| stmts.go:52:3:52:13 | selection of Println | stmts.go:52:15:52:30 | "Heard from ch1" | +| stmts.go:52:3:52:31 | call to Println | stmts.go:61:2:61:10 | select statement | +| stmts.go:52:3:52:31 | call to Println | stmts.go:62:1:62:1 | exit | +| stmts.go:52:15:52:30 | "Heard from ch1" | stmts.go:52:3:52:31 | call to Println | +| stmts.go:53:7:53:7 | a | stmts.go:53:9:53:9 | 0 | +| stmts.go:53:7:53:10 | assignment to element | stmts.go:53:7:53:21 | ... = ...[1] | +| stmts.go:53:7:53:10 | skip | stmts.go:53:13:53:13 | skip | +| stmts.go:53:7:53:10 | skip | stmts.go:62:1:62:1 | exit | +| stmts.go:53:7:53:21 | ... = ...[0] | stmts.go:53:7:53:10 | assignment to element | +| stmts.go:53:7:53:21 | ... = ...[1] | stmts.go:53:13:53:13 | assignment to w | +| stmts.go:53:9:53:9 | 0 | stmts.go:53:7:53:10 | skip | +| stmts.go:53:13:53:13 | assignment to w | stmts.go:54:3:54:13 | selection of Println | +| stmts.go:53:13:53:13 | skip | stmts.go:53:7:53:21 | ... = ...[0] | +| stmts.go:53:17:53:21 | <-... | stmts.go:53:7:53:7 | a | +| stmts.go:53:19:53:21 | ch2 | stmts.go:58:7:58:9 | ch1 | +| stmts.go:54:3:54:13 | selection of Println | stmts.go:54:15:54:15 | a | +| stmts.go:54:3:54:16 | call to Println | stmts.go:55:3:55:13 | selection of Println | +| stmts.go:54:3:54:16 | call to Println | stmts.go:62:1:62:1 | exit | +| stmts.go:54:15:54:15 | a | stmts.go:54:3:54:16 | call to Println | +| stmts.go:55:3:55:13 | selection of Println | stmts.go:55:15:55:15 | w | +| stmts.go:55:3:55:16 | call to Println | stmts.go:61:2:61:10 | select statement | +| stmts.go:55:3:55:16 | call to Println | stmts.go:62:1:62:1 | exit | +| stmts.go:55:15:55:15 | w | stmts.go:55:3:55:16 | call to Println | +| stmts.go:57:3:57:13 | selection of Println | stmts.go:57:3:57:15 | call to Println | +| stmts.go:57:3:57:15 | call to Println | stmts.go:61:2:61:10 | select statement | +| stmts.go:57:3:57:15 | call to Println | stmts.go:62:1:62:1 | exit | +| stmts.go:58:2:58:16 | skip | stmts.go:61:2:61:10 | select statement | +| stmts.go:58:7:58:9 | ch1 | stmts.go:58:14:58:15 | 42 | +| stmts.go:58:7:58:15 | send statement | stmts.go:58:2:58:16 | skip | +| stmts.go:58:7:58:15 | send statement | stmts.go:62:1:62:1 | exit | +| stmts.go:58:14:58:15 | 42 | stmts.go:50:2:59:2 | select statement | +| stmts.go:65:1:65:1 | entry | stmts.go:65:12:65:12 | argument corresponding to x | +| stmts.go:65:1:72:1 | function declaration | stmts.go:75:6:75:10 | skip | +| stmts.go:65:6:65:10 | skip | stmts.go:65:1:72:1 | function declaration | +| stmts.go:65:12:65:12 | argument corresponding to x | stmts.go:65:12:65:12 | initialization of x | +| stmts.go:65:12:65:12 | initialization of x | stmts.go:66:5:66:5 | x | +| stmts.go:66:5:66:5 | x | stmts.go:66:9:66:9 | 0 | +| stmts.go:66:5:66:9 | ...>... | stmts.go:66:9:66:9 | ...>... is false | +| stmts.go:66:5:66:9 | ...>... | stmts.go:66:9:66:9 | ...>... is true | +| stmts.go:66:9:66:9 | 0 | stmts.go:66:5:66:9 | ...>... | +| stmts.go:66:9:66:9 | ...>... is false | stmts.go:69:9:69:34 | function literal | +| stmts.go:66:9:66:9 | ...>... is true | stmts.go:67:9:67:33 | function literal | +| stmts.go:67:3:67:35 | defer statement | stmts.go:71:9:71:10 | 42 | +| stmts.go:67:9:67:9 | entry | stmts.go:67:18:67:28 | selection of Println | +| stmts.go:67:9:67:33 | function literal | stmts.go:67:3:67:35 | defer statement | +| stmts.go:67:9:67:35 | function call | stmts.go:72:1:72:1 | exit | +| stmts.go:67:18:67:28 | selection of Println | stmts.go:67:30:67:30 | x | +| stmts.go:67:18:67:31 | call to Println | stmts.go:67:33:67:33 | exit | +| stmts.go:67:30:67:30 | x | stmts.go:67:18:67:31 | call to Println | +| stmts.go:69:3:69:36 | defer statement | stmts.go:71:9:71:10 | 42 | +| stmts.go:69:9:69:9 | entry | stmts.go:69:18:69:28 | selection of Println | +| stmts.go:69:9:69:34 | function literal | stmts.go:69:3:69:36 | defer statement | +| stmts.go:69:9:69:36 | function call | stmts.go:72:1:72:1 | exit | +| stmts.go:69:18:69:28 | selection of Println | stmts.go:69:31:69:31 | x | +| stmts.go:69:18:69:32 | call to Println | stmts.go:69:34:69:34 | exit | +| stmts.go:69:30:69:31 | -... | stmts.go:69:18:69:32 | call to Println | +| stmts.go:69:31:69:31 | x | stmts.go:69:30:69:31 | -... | +| stmts.go:71:2:71:10 | return statement | stmts.go:67:9:67:35 | function call | +| stmts.go:71:2:71:10 | return statement | stmts.go:69:9:69:36 | function call | +| stmts.go:71:9:71:10 | 42 | stmts.go:71:2:71:10 | return statement | +| stmts.go:75:1:75:1 | entry | stmts.go:75:12:75:12 | argument corresponding to x | +| stmts.go:75:1:109:1 | function declaration | stmts.go:112:6:112:10 | skip | +| stmts.go:75:6:75:10 | skip | stmts.go:75:1:109:1 | function declaration | +| stmts.go:75:12:75:12 | argument corresponding to x | stmts.go:75:12:75:12 | initialization of x | +| stmts.go:75:12:75:12 | initialization of x | stmts.go:76:9:76:9 | x | +| stmts.go:76:9:76:9 | x | stmts.go:79:9:79:9 | skip | +| stmts.go:79:9:79:9 | assignment to y | stmts.go:79:17:79:17 | y | +| stmts.go:79:9:79:9 | skip | stmts.go:79:14:79:14 | x | +| stmts.go:79:14:79:14 | x | stmts.go:79:9:79:9 | assignment to y | +| stmts.go:79:17:79:17 | y | stmts.go:79:21:79:22 | 19 | +| stmts.go:79:17:79:22 | ...-... | stmts.go:81:3:81:7 | test5 | +| stmts.go:79:21:79:22 | 19 | stmts.go:79:17:79:22 | ...-... | +| stmts.go:81:3:81:7 | test5 | stmts.go:81:9:81:13 | false | +| stmts.go:81:3:81:14 | call to test5 | stmts.go:109:1:109:1 | exit | +| stmts.go:81:9:81:13 | false | stmts.go:81:3:81:14 | call to test5 | +| stmts.go:84:9:84:9 | x | stmts.go:85:7:85:7 | 1 | +| stmts.go:84:9:84:9 | x | stmts.go:90:9:90:9 | x | +| stmts.go:85:2:85:8 | skip | stmts.go:90:9:90:9 | x | +| stmts.go:85:7:85:7 | 1 | stmts.go:85:7:85:7 | case 1 | +| stmts.go:85:7:85:7 | case 1 | stmts.go:85:2:85:8 | skip | +| stmts.go:85:7:85:7 | case 1 | stmts.go:86:7:86:7 | 2 | +| stmts.go:86:7:86:7 | 2 | stmts.go:86:7:86:7 | case 2 | +| stmts.go:86:7:86:7 | case 2 | stmts.go:86:10:86:10 | 3 | +| stmts.go:86:7:86:7 | case 2 | stmts.go:87:3:87:7 | test5 | +| stmts.go:86:10:86:10 | 3 | stmts.go:86:10:86:10 | case 3 | +| stmts.go:86:10:86:10 | case 3 | stmts.go:87:3:87:7 | test5 | +| stmts.go:86:10:86:10 | case 3 | stmts.go:90:9:90:9 | x | +| stmts.go:87:3:87:7 | test5 | stmts.go:87:9:87:12 | true | +| stmts.go:87:9:87:12 | true | stmts.go:87:3:87:13 | call to test5 | +| stmts.go:90:9:90:9 | x | stmts.go:91:7:91:7 | 1 | +| stmts.go:90:9:90:9 | x | stmts.go:98:9:98:9 | x | +| stmts.go:91:7:91:7 | 1 | stmts.go:91:7:91:7 | case 1 | +| stmts.go:91:7:91:7 | case 1 | stmts.go:92:3:92:7 | test5 | +| stmts.go:91:7:91:7 | case 1 | stmts.go:94:7:94:11 | ...-... | +| stmts.go:92:3:92:7 | test5 | stmts.go:92:9:92:13 | false | +| stmts.go:92:9:92:13 | false | stmts.go:92:3:92:14 | call to test5 | +| stmts.go:93:3:93:13 | skip | stmts.go:95:3:95:7 | test5 | +| stmts.go:94:7:94:11 | ...-... | stmts.go:94:7:94:11 | case ...-... | +| stmts.go:94:7:94:11 | case ...-... | stmts.go:95:3:95:7 | test5 | +| stmts.go:94:7:94:11 | case ...-... | stmts.go:98:9:98:9 | x | +| stmts.go:95:3:95:7 | test5 | stmts.go:95:9:95:12 | true | +| stmts.go:95:9:95:12 | true | stmts.go:95:3:95:13 | call to test5 | +| stmts.go:98:9:98:9 | x | stmts.go:100:7:100:7 | 2 | +| stmts.go:99:2:99:9 | skip | stmts.go:104:2:104:2 | true | +| stmts.go:100:7:100:7 | 2 | stmts.go:100:7:100:7 | case 2 | +| stmts.go:100:7:100:7 | case 2 | stmts.go:99:2:99:9 | skip | +| stmts.go:100:7:100:7 | case 2 | stmts.go:101:3:101:7 | test5 | +| stmts.go:101:3:101:7 | test5 | stmts.go:101:9:101:12 | true | +| stmts.go:101:9:101:12 | true | stmts.go:101:3:101:13 | call to test5 | +| stmts.go:104:2:104:2 | true | stmts.go:107:7:107:10 | true | +| stmts.go:107:7:107:10 | case true | stmts.go:107:10:107:10 | true is false | +| stmts.go:107:7:107:10 | case true | stmts.go:107:10:107:10 | true is true | +| stmts.go:107:7:107:10 | true | stmts.go:107:7:107:10 | case true | +| stmts.go:107:10:107:10 | true is false | stmts.go:106:3:106:7 | skip | +| stmts.go:107:10:107:10 | true is true | stmts.go:107:2:107:11 | skip | +| stmts.go:112:1:112:1 | entry | stmts.go:112:12:112:12 | argument corresponding to x | +| stmts.go:112:1:125:1 | function declaration | stmts.go:128:6:128:11 | skip | +| stmts.go:112:6:112:10 | skip | stmts.go:112:1:125:1 | function declaration | +| stmts.go:112:12:112:12 | argument corresponding to x | stmts.go:112:12:112:12 | initialization of x | +| stmts.go:112:12:112:12 | initialization of x | stmts.go:113:9:113:9 | skip | +| stmts.go:113:9:113:9 | assignment to y | stmts.go:114:7:114:11 | case error | +| stmts.go:113:9:113:9 | assignment to y | stmts.go:121:9:121:9 | skip | +| stmts.go:113:9:113:9 | skip | stmts.go:113:14:113:14 | x | +| stmts.go:113:14:113:14 | x | stmts.go:113:14:113:21 | type assertion | +| stmts.go:113:14:113:21 | type assertion | stmts.go:113:9:113:9 | assignment to y | +| stmts.go:114:7:114:11 | case error | stmts.go:114:14:114:19 | case string | +| stmts.go:114:7:114:11 | case error | stmts.go:115:3:115:13 | selection of Println | +| stmts.go:114:14:114:19 | case string | stmts.go:115:3:115:13 | selection of Println | +| stmts.go:114:14:114:19 | case string | stmts.go:116:7:116:13 | case float32 | +| stmts.go:115:3:115:13 | selection of Println | stmts.go:115:15:115:15 | y | +| stmts.go:115:3:115:16 | call to Println | stmts.go:121:9:121:9 | skip | +| stmts.go:115:3:115:16 | call to Println | stmts.go:125:1:125:1 | exit | +| stmts.go:115:15:115:15 | y | stmts.go:115:3:115:16 | call to Println | +| stmts.go:116:7:116:13 | case float32 | stmts.go:117:3:117:7 | test5 | +| stmts.go:116:7:116:13 | case float32 | stmts.go:121:9:121:9 | skip | +| stmts.go:117:3:117:7 | test5 | stmts.go:117:9:117:12 | true | +| stmts.go:117:3:117:13 | call to test5 | stmts.go:125:1:125:1 | exit | +| stmts.go:117:9:117:12 | true | stmts.go:117:3:117:13 | call to test5 | +| stmts.go:118:3:118:7 | test5 | stmts.go:118:9:118:13 | false | +| stmts.go:118:9:118:13 | false | stmts.go:118:3:118:14 | call to test5 | +| stmts.go:121:9:121:9 | assignment to y | stmts.go:121:17:121:17 | y | +| stmts.go:121:9:121:9 | skip | stmts.go:121:14:121:14 | x | +| stmts.go:121:14:121:14 | x | stmts.go:121:9:121:9 | assignment to y | +| stmts.go:121:17:121:17 | y | stmts.go:121:17:121:24 | type assertion | +| stmts.go:121:17:121:24 | type assertion | stmts.go:123:3:123:7 | test5 | +| stmts.go:123:3:123:7 | test5 | stmts.go:123:9:123:13 | false | +| stmts.go:123:3:123:14 | call to test5 | stmts.go:125:1:125:1 | exit | +| stmts.go:123:9:123:13 | false | stmts.go:123:3:123:14 | call to test5 | +| stmts.go:128:1:128:1 | entry | stmts.go:128:13:128:13 | argument corresponding to f | +| stmts.go:128:1:130:1 | function declaration | stmts.go:133:6:133:11 | skip | +| stmts.go:128:6:128:11 | skip | stmts.go:128:1:130:1 | function declaration | +| stmts.go:128:13:128:13 | argument corresponding to f | stmts.go:128:13:128:13 | initialization of f | +| stmts.go:128:13:128:13 | initialization of f | stmts.go:129:5:129:5 | f | +| stmts.go:129:2:129:7 | go statement | stmts.go:130:1:130:1 | exit | +| stmts.go:129:5:129:5 | f | stmts.go:129:2:129:7 | go statement | +| stmts.go:133:1:133:1 | entry | stmts.go:133:13:133:14 | argument corresponding to xs | +| stmts.go:133:1:147:1 | function declaration | stmts.go:0:0:0:0 | exit | +| stmts.go:133:6:133:11 | skip | stmts.go:133:1:147:1 | function declaration | +| stmts.go:133:13:133:14 | argument corresponding to xs | stmts.go:133:13:133:14 | initialization of xs | +| stmts.go:133:13:133:14 | initialization of xs | stmts.go:134:17:134:18 | xs | +| stmts.go:134:2:139:2 | range statement[0] | stmts.go:134:6:134:6 | assignment to x | +| stmts.go:134:6:134:6 | assignment to x | stmts.go:135:6:135:6 | x | +| stmts.go:134:6:134:6 | skip | stmts.go:134:2:139:2 | range statement[0] | +| stmts.go:134:17:134:18 | next key-value pair in range | stmts.go:134:6:134:6 | skip | +| stmts.go:134:17:134:18 | next key-value pair in range | stmts.go:141:20:141:21 | xs | +| stmts.go:134:17:134:18 | xs | stmts.go:134:17:134:18 | next key-value pair in range | +| stmts.go:135:6:135:6 | x | stmts.go:135:10:135:10 | 5 | +| stmts.go:135:6:135:10 | ...>... | stmts.go:135:10:135:10 | ...>... is false | +| stmts.go:135:6:135:10 | ...>... | stmts.go:135:10:135:10 | ...>... is true | +| stmts.go:135:10:135:10 | 5 | stmts.go:135:6:135:10 | ...>... | +| stmts.go:135:10:135:10 | ...>... is false | stmts.go:138:3:138:11 | selection of Print | +| stmts.go:135:10:135:10 | ...>... is true | stmts.go:136:4:136:11 | skip | +| stmts.go:136:4:136:11 | skip | stmts.go:134:17:134:18 | next key-value pair in range | +| stmts.go:138:3:138:11 | selection of Print | stmts.go:138:13:138:13 | x | +| stmts.go:138:3:138:14 | call to Print | stmts.go:134:17:134:18 | next key-value pair in range | +| stmts.go:138:3:138:14 | call to Print | stmts.go:147:1:147:1 | exit | +| stmts.go:138:13:138:13 | x | stmts.go:138:3:138:14 | call to Print | +| stmts.go:141:2:143:2 | range statement[0] | stmts.go:141:2:143:2 | range statement[1] | +| stmts.go:141:2:143:2 | range statement[1] | stmts.go:141:6:141:6 | assignment to i | +| stmts.go:141:6:141:6 | assignment to i | stmts.go:141:9:141:9 | assignment to v | +| stmts.go:141:6:141:6 | skip | stmts.go:141:9:141:9 | skip | +| stmts.go:141:9:141:9 | assignment to v | stmts.go:142:3:142:11 | selection of Print | +| stmts.go:141:9:141:9 | skip | stmts.go:141:2:143:2 | range statement[0] | +| stmts.go:141:20:141:21 | next key-value pair in range | stmts.go:141:6:141:6 | skip | +| stmts.go:141:20:141:21 | next key-value pair in range | stmts.go:145:12:145:13 | xs | +| stmts.go:141:20:141:21 | xs | stmts.go:141:20:141:21 | next key-value pair in range | +| stmts.go:142:3:142:11 | selection of Print | stmts.go:142:13:142:13 | i | +| stmts.go:142:3:142:17 | call to Print | stmts.go:141:20:141:21 | next key-value pair in range | +| stmts.go:142:3:142:17 | call to Print | stmts.go:147:1:147:1 | exit | +| stmts.go:142:13:142:13 | i | stmts.go:142:16:142:16 | v | +| stmts.go:142:16:142:16 | v | stmts.go:142:3:142:17 | call to Print | +| stmts.go:145:12:145:13 | next key-value pair in range | stmts.go:145:15:146:2 | skip | +| stmts.go:145:12:145:13 | next key-value pair in range | stmts.go:147:1:147:1 | exit | +| stmts.go:145:12:145:13 | xs | stmts.go:145:12:145:13 | next key-value pair in range | +| stmts.go:145:15:146:2 | skip | stmts.go:145:12:145:13 | next key-value pair in range | +| tst.go:0:0:0:0 | entry | tst.go:3:6:3:10 | skip | +| tst.go:3:1:3:1 | entry | tst.go:3:12:3:12 | argument corresponding to x | +| tst.go:3:1:12:1 | function declaration | tst.go:14:6:14:11 | skip | +| tst.go:3:6:3:10 | skip | tst.go:3:1:12:1 | function declaration | +| tst.go:3:12:3:12 | argument corresponding to x | tst.go:3:12:3:12 | initialization of x | +| tst.go:3:12:3:12 | initialization of x | tst.go:4:2:4:2 | true | +| tst.go:4:2:4:2 | true | tst.go:5:7:5:7 | x | +| tst.go:5:2:5:13 | skip | tst.go:12:1:12:1 | exit | +| tst.go:5:7:5:7 | x | tst.go:5:11:5:12 | 23 | +| tst.go:5:7:5:12 | ...<... | tst.go:5:7:5:12 | case ...<... | +| tst.go:5:7:5:12 | case ...<... | tst.go:5:12:5:12 | ...<... is false | +| tst.go:5:7:5:12 | case ...<... | tst.go:5:12:5:12 | ...<... is true | +| tst.go:5:11:5:12 | 23 | tst.go:5:7:5:12 | ...<... | +| tst.go:5:12:5:12 | ...<... is false | tst.go:7:7:7:7 | x | +| tst.go:5:12:5:12 | ...<... is true | tst.go:5:2:5:13 | skip | +| tst.go:7:2:7:13 | skip | tst.go:12:1:12:1 | exit | +| tst.go:7:7:7:7 | x | tst.go:7:11:7:12 | 42 | +| tst.go:7:7:7:12 | ...<... | tst.go:7:7:7:12 | case ...<... | +| tst.go:7:7:7:12 | case ...<... | tst.go:7:12:7:12 | ...<... is false | +| tst.go:7:7:7:12 | case ...<... | tst.go:7:12:7:12 | ...<... is true | +| tst.go:7:11:7:12 | 42 | tst.go:7:7:7:12 | ...<... | +| tst.go:7:12:7:12 | ...<... is false | tst.go:9:7:9:7 | x | +| tst.go:7:12:7:12 | ...<... is true | tst.go:7:2:7:13 | skip | +| tst.go:9:2:9:13 | skip | tst.go:12:1:12:1 | exit | +| tst.go:9:7:9:7 | x | tst.go:9:11:9:12 | 23 | +| tst.go:9:7:9:12 | ...<... | tst.go:9:7:9:12 | case ...<... | +| tst.go:9:7:9:12 | case ...<... | tst.go:9:12:9:12 | ...<... is false | +| tst.go:9:7:9:12 | case ...<... | tst.go:9:12:9:12 | ...<... is true | +| tst.go:9:11:9:12 | 23 | tst.go:9:7:9:12 | ...<... | +| tst.go:9:12:9:12 | ...<... is false | tst.go:12:1:12:1 | exit | +| tst.go:9:12:9:12 | ...<... is true | tst.go:9:2:9:13 | skip | +| tst.go:14:1:14:1 | entry | tst.go:14:13:14:17 | argument corresponding to value | +| tst.go:14:1:21:1 | function declaration | tst.go:23:6:23:11 | skip | +| tst.go:14:6:14:11 | skip | tst.go:14:1:21:1 | function declaration | +| tst.go:14:13:14:17 | argument corresponding to value | tst.go:14:13:14:17 | initialization of value | +| tst.go:14:13:14:17 | initialization of value | tst.go:15:2:15:2 | true | +| tst.go:15:2:15:2 | true | tst.go:16:7:16:11 | value | +| tst.go:16:2:16:34 | skip | tst.go:21:1:21:1 | exit | +| tst.go:16:7:16:11 | value | tst.go:16:15:16:33 | ...*... | +| tst.go:16:7:16:33 | ...<... | tst.go:16:7:16:33 | case ...<... | +| tst.go:16:7:16:33 | case ...<... | tst.go:16:33:16:33 | ...<... is false | +| tst.go:16:7:16:33 | case ...<... | tst.go:16:33:16:33 | ...<... is true | +| tst.go:16:15:16:33 | ...*... | tst.go:16:7:16:33 | ...<... | +| tst.go:16:33:16:33 | ...<... is false | tst.go:18:7:18:11 | value | +| tst.go:16:33:16:33 | ...<... is true | tst.go:16:2:16:34 | skip | +| tst.go:18:2:18:39 | skip | tst.go:21:1:21:1 | exit | +| tst.go:18:7:18:11 | value | tst.go:18:15:18:38 | ...*... | +| tst.go:18:7:18:38 | ...<... | tst.go:18:7:18:38 | case ...<... | +| tst.go:18:7:18:38 | case ...<... | tst.go:18:38:18:38 | ...<... is false | +| tst.go:18:7:18:38 | case ...<... | tst.go:18:38:18:38 | ...<... is true | +| tst.go:18:15:18:38 | ...*... | tst.go:18:7:18:38 | ...<... | +| tst.go:18:38:18:38 | ...<... is false | tst.go:21:1:21:1 | exit | +| tst.go:18:38:18:38 | ...<... is true | tst.go:18:2:18:39 | skip | +| tst.go:23:1:23:1 | entry | tst.go:24:2:24:2 | true | +| tst.go:23:1:26:1 | function declaration | tst.go:28:6:28:11 | skip | +| tst.go:23:6:23:11 | skip | tst.go:23:1:26:1 | function declaration | +| tst.go:24:2:24:2 | true | tst.go:26:1:26:1 | exit | +| tst.go:28:1:28:1 | entry | tst.go:29:2:29:2 | true | +| tst.go:28:1:32:1 | function declaration | tst.go:0:0:0:0 | exit | +| tst.go:28:6:28:11 | skip | tst.go:28:1:32:1 | function declaration | +| tst.go:29:2:29:2 | true | tst.go:30:2:30:9 | skip | +| tst.go:30:2:30:9 | skip | tst.go:32:1:32:1 | exit | #select | | diff --git a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.ql b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.ql index 144a01f2aa5..3f0afd67cae 100644 --- a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.ql +++ b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/CFG.ql @@ -1,10 +1,9 @@ import go -query predicate nodes(ControlFlow::Node nd) { none() } - query predicate edges(ControlFlow::Node pred, ControlFlow::Node succ) { - none() - // succ = pred.getASuccessor() + not succ.getFile().hasBuildConstraints() and + not pred.getFile().hasBuildConstraints() and + succ = pred.getASuccessor() } select "" diff --git a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/linux.go b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/linux.go index 66c40b54084..4f8f6b615fe 100644 --- a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/linux.go +++ b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package main diff --git a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/nonlinux.go b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/nonlinux.go index 3347a26fa7a..e0ec489338f 100644 --- a/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/nonlinux.go +++ b/ql/test/library-tests/semmle/go/controlflow/ControlFlowGraph/nonlinux.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package main diff --git a/ql/test/library-tests/semmle/go/frameworks/SQL/go.mod b/ql/test/library-tests/semmle/go/frameworks/SQL/go.mod index 23bb420b262..69db5c96c41 100644 --- a/ql/test/library-tests/semmle/go/frameworks/SQL/go.mod +++ b/ql/test/library-tests/semmle/go/frameworks/SQL/go.mod @@ -6,4 +6,9 @@ require ( github.com/Masterminds/squirrel v1.1.0 github.com/go-pg/pg v8.0.6+incompatible github.com/go-pg/pg/v9 v9.1.3 + github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/go-xorm/xorm v0.7.9 + github.com/lib/pq v1.10.2 // indirect + github.com/mattn/go-sqlite3 v1.14.7 // indirect + xorm.io/xorm v1.1.0 ) diff --git a/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/go-xorm/xorm/stub.go b/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/go-xorm/xorm/stub.go new file mode 100644 index 00000000000..9853e015547 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/github.com/go-xorm/xorm/stub.go @@ -0,0 +1,917 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/go-xorm/xorm, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/go-xorm/xorm (exports: Engine,Session; functions: ) + +// Package xorm is a stub of github.com/go-xorm/xorm, generated by depstubber. +package xorm + +import ( + context "context" + sql "database/sql" + io "io" + reflect "reflect" + strings "strings" + time "time" +) + +type ContextCache interface { + Get(_ string) interface{} + Put(_ string, _ interface{}) +} + +type Engine struct { + ColumnMapper interface{} + TableMapper interface{} + TagIdentifier string + Tables map[reflect.Type]interface{} + Cacher interface{} + TZLocation *time.Location + DatabaseTZ *time.Location +} + +func (_ *Engine) After(_ func(interface{})) *Session { + return nil +} + +func (_ *Engine) Alias(_ string) *Session { + return nil +} + +func (_ *Engine) AllCols() *Session { + return nil +} + +func (_ *Engine) Asc(_ ...string) *Session { + return nil +} + +func (_ *Engine) AutoIncrStr() string { + return "" +} + +func (_ *Engine) Before(_ func(interface{})) *Session { + return nil +} + +func (_ *Engine) BufferSize(_ int) *Session { + return nil +} + +func (_ *Engine) Cascade(_ ...bool) *Session { + return nil +} + +func (_ *Engine) Charset(_ string) *Session { + return nil +} + +func (_ *Engine) ClearCache(_ ...interface{}) error { + return nil +} + +func (_ *Engine) ClearCacheBean(_ interface{}, _ string) error { + return nil +} + +func (_ *Engine) Clone() (*Engine, error) { + return nil, nil +} + +func (_ *Engine) Close() error { + return nil +} + +func (_ *Engine) Cols(_ ...string) *Session { + return nil +} + +func (_ *Engine) CondDeleted(_ string) interface{} { + return nil +} + +func (_ *Engine) Context(_ context.Context) *Session { + return nil +} + +func (_ *Engine) Count(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) CreateIndexes(_ interface{}) error { + return nil +} + +func (_ *Engine) CreateTables(_ ...interface{}) error { + return nil +} + +func (_ *Engine) CreateUniques(_ interface{}) error { + return nil +} + +func (_ *Engine) DB() interface{} { + return nil +} + +func (_ *Engine) DBMetas() ([]interface{}, error) { + return nil, nil +} + +func (_ *Engine) DataSourceName() string { + return "" +} + +func (_ *Engine) Decr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Delete(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) Desc(_ ...string) *Session { + return nil +} + +func (_ *Engine) Dialect() interface{} { + return nil +} + +func (_ *Engine) Distinct(_ ...string) *Session { + return nil +} + +func (_ *Engine) DriverName() string { + return "" +} + +func (_ *Engine) DropIndexes(_ interface{}) error { + return nil +} + +func (_ *Engine) DropTables(_ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpAll(_ io.Writer, _ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpAllToFile(_ string, _ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpTables(_ []interface{}, _ io.Writer, _ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpTablesToFile(_ []interface{}, _ string, _ ...interface{}) error { + return nil +} + +func (_ *Engine) Exec(_ ...interface{}) (sql.Result, error) { + return nil, nil +} + +func (_ *Engine) Exist(_ ...interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) Find(_ interface{}, _ ...interface{}) error { + return nil +} + +func (_ *Engine) FindAndCount(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) Get(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) GetCacher(_ string) interface{} { + return nil +} + +func (_ *Engine) GetColumnMapper() interface{} { + return nil +} + +func (_ *Engine) GetDefaultCacher() interface{} { + return nil +} + +func (_ *Engine) GetTZDatabase() *time.Location { + return nil +} + +func (_ *Engine) GetTZLocation() *time.Location { + return nil +} + +func (_ *Engine) GetTableMapper() interface{} { + return nil +} + +func (_ *Engine) GobRegister(_ interface{}) *Engine { + return nil +} + +func (_ *Engine) GroupBy(_ string) *Session { + return nil +} + +func (_ *Engine) Having(_ string) *Session { + return nil +} + +func (_ *Engine) ID(_ interface{}) *Session { + return nil +} + +func (_ *Engine) IDOf(_ interface{}) interface{} { + return nil +} + +func (_ *Engine) IDOfV(_ reflect.Value) interface{} { + return nil +} + +func (_ *Engine) Id(_ interface{}) *Session { + return nil +} + +func (_ *Engine) IdOf(_ interface{}) interface{} { + return nil +} + +func (_ *Engine) IdOfV(_ reflect.Value) interface{} { + return nil +} + +func (_ *Engine) Import(_ io.Reader) ([]sql.Result, error) { + return nil, nil +} + +func (_ *Engine) ImportFile(_ string) ([]sql.Result, error) { + return nil, nil +} + +func (_ *Engine) In(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Incr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Insert(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) InsertOne(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) IsTableEmpty(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) IsTableExist(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) Iterate(_ interface{}, _ IterFunc) error { + return nil +} + +func (_ *Engine) Join(_ string, _ interface{}, _ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Limit(_ int, _ ...int) *Session { + return nil +} + +func (_ *Engine) Logger() interface{} { + return nil +} + +func (_ *Engine) MapCacher(_ interface{}, _ interface{}) error { + return nil +} + +func (_ *Engine) MustCols(_ ...string) *Session { + return nil +} + +func (_ *Engine) NewDB() (interface{}, error) { + return nil, nil +} + +func (_ *Engine) NewSession() *Session { + return nil +} + +func (_ *Engine) NoAutoCondition(_ ...bool) *Session { + return nil +} + +func (_ *Engine) NoAutoTime() *Session { + return nil +} + +func (_ *Engine) NoCache() *Session { + return nil +} + +func (_ *Engine) NoCascade() *Session { + return nil +} + +func (_ *Engine) NotIn(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Nullable(_ ...string) *Session { + return nil +} + +func (_ *Engine) Omit(_ ...string) *Session { + return nil +} + +func (_ *Engine) OrderBy(_ string) *Session { + return nil +} + +func (_ *Engine) Ping() error { + return nil +} + +func (_ *Engine) PingContext(_ context.Context) error { + return nil +} + +func (_ *Engine) Prepare() *Session { + return nil +} + +func (_ *Engine) Query(_ ...interface{}) ([]map[string][]byte, error) { + return nil, nil +} + +func (_ *Engine) QueryInterface(_ ...interface{}) ([]map[string]interface{}, error) { + return nil, nil +} + +func (_ *Engine) QueryString(_ ...interface{}) ([]map[string]string, error) { + return nil, nil +} + +func (_ *Engine) Quote(_ string) string { + return "" +} + +func (_ *Engine) QuoteTo(_ *strings.Builder, _ string) {} + +func (_ *Engine) Rows(_ interface{}) (*Rows, error) { + return nil, nil +} + +func (_ *Engine) SQL(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) SQLType(_ interface{}) string { + return "" +} + +func (_ *Engine) Select(_ string) *Session { + return nil +} + +func (_ *Engine) SetCacher(_ string, _ interface{}) {} + +func (_ *Engine) SetColumnMapper(_ interface{}) {} + +func (_ *Engine) SetConnMaxLifetime(_ time.Duration) {} + +func (_ *Engine) SetDefaultCacher(_ interface{}) {} + +func (_ *Engine) SetDefaultContext(_ context.Context) {} + +func (_ *Engine) SetDisableGlobalCache(_ bool) {} + +func (_ *Engine) SetExpr(_ string, _ interface{}) *Session { + return nil +} + +func (_ *Engine) SetLogLevel(_ interface{}) {} + +func (_ *Engine) SetLogger(_ interface{}) {} + +func (_ *Engine) SetMapper(_ interface{}) {} + +func (_ *Engine) SetMaxIdleConns(_ int) {} + +func (_ *Engine) SetMaxOpenConns(_ int) {} + +func (_ *Engine) SetSchema(_ string) {} + +func (_ *Engine) SetTZDatabase(_ *time.Location) {} + +func (_ *Engine) SetTZLocation(_ *time.Location) {} + +func (_ *Engine) SetTableMapper(_ interface{}) {} + +func (_ *Engine) ShowExecTime(_ ...bool) {} + +func (_ *Engine) ShowSQL(_ ...bool) {} + +func (_ *Engine) Sql(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) SqlType(_ interface{}) string { + return "" +} + +func (_ *Engine) StoreEngine(_ string) *Session { + return nil +} + +func (_ *Engine) Sum(_ interface{}, _ string) (float64, error) { + return 0, nil +} + +func (_ *Engine) SumInt(_ interface{}, _ string) (int64, error) { + return 0, nil +} + +func (_ *Engine) Sums(_ interface{}, _ ...string) ([]float64, error) { + return nil, nil +} + +func (_ *Engine) SumsInt(_ interface{}, _ ...string) ([]int64, error) { + return nil, nil +} + +func (_ *Engine) SupportInsertMany() bool { + return false +} + +func (_ *Engine) Sync(_ ...interface{}) error { + return nil +} + +func (_ *Engine) Sync2(_ ...interface{}) error { + return nil +} + +func (_ *Engine) Table(_ interface{}) *Session { + return nil +} + +func (_ *Engine) TableInfo(_ interface{}) *Table { + return nil +} + +func (_ *Engine) TableName(_ interface{}, _ ...bool) string { + return "" +} + +func (_ *Engine) Transaction(_ func(*Session) (interface{}, error)) (interface{}, error) { + return nil, nil +} + +func (_ *Engine) UnMapType(_ reflect.Type) {} + +func (_ *Engine) Unscoped() *Session { + return nil +} + +func (_ *Engine) Update(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) UseBool(_ ...string) *Session { + return nil +} + +func (_ *Engine) Where(_ interface{}, _ ...interface{}) *Session { + return nil +} + +type IterFunc func(int, interface{}) error + +type Rows struct{} + +func (_ *Rows) Close() error { + return nil +} + +func (_ *Rows) Err() error { + return nil +} + +func (_ *Rows) Next() bool { + return false +} + +func (_ *Rows) Scan(_ interface{}) error { + return nil +} + +type Session struct{} + +func (_ *Session) After(_ func(interface{})) *Session { + return nil +} + +func (_ *Session) Alias(_ string) *Session { + return nil +} + +func (_ *Session) AllCols() *Session { + return nil +} + +func (_ *Session) And(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Asc(_ ...string) *Session { + return nil +} + +func (_ *Session) Before(_ func(interface{})) *Session { + return nil +} + +func (_ *Session) Begin() error { + return nil +} + +func (_ *Session) BufferSize(_ int) *Session { + return nil +} + +func (_ *Session) Cascade(_ ...bool) *Session { + return nil +} + +func (_ *Session) Charset(_ string) *Session { + return nil +} + +func (_ *Session) Clone() *Session { + return nil +} + +func (_ *Session) Close() {} + +func (_ *Session) Cols(_ ...string) *Session { + return nil +} + +func (_ *Session) Commit() error { + return nil +} + +func (_ *Session) Conds() interface{} { + return nil +} + +func (_ *Session) Context(_ context.Context) *Session { + return nil +} + +func (_ *Session) ContextCache(_ ContextCache) *Session { + return nil +} + +func (_ *Session) Count(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) CreateIndexes(_ interface{}) error { + return nil +} + +func (_ *Session) CreateTable(_ interface{}) error { + return nil +} + +func (_ *Session) CreateUniques(_ interface{}) error { + return nil +} + +func (_ *Session) DB() interface{} { + return nil +} + +func (_ *Session) Decr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Delete(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) Desc(_ ...string) *Session { + return nil +} + +func (_ *Session) Distinct(_ ...string) *Session { + return nil +} + +func (_ *Session) DropIndexes(_ interface{}) error { + return nil +} + +func (_ *Session) DropTable(_ interface{}) error { + return nil +} + +func (_ *Session) Exec(_ ...interface{}) (sql.Result, error) { + return nil, nil +} + +func (_ *Session) Exist(_ ...interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) Find(_ interface{}, _ ...interface{}) error { + return nil +} + +func (_ *Session) FindAndCount(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) ForUpdate() *Session { + return nil +} + +func (_ *Session) Get(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) GroupBy(_ string) *Session { + return nil +} + +func (_ *Session) Having(_ string) *Session { + return nil +} + +func (_ *Session) ID(_ interface{}) *Session { + return nil +} + +func (_ *Session) Id(_ interface{}) *Session { + return nil +} + +func (_ *Session) In(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Incr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Init() {} + +func (_ *Session) Insert(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) InsertMulti(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) InsertOne(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) IsClosed() bool { + return false +} + +func (_ *Session) IsTableEmpty(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) IsTableExist(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) Iterate(_ interface{}, _ IterFunc) error { + return nil +} + +func (_ *Session) Join(_ string, _ interface{}, _ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) LastSQL() (string, []interface{}) { + return "", nil +} + +func (_ *Session) Limit(_ int, _ ...int) *Session { + return nil +} + +func (_ *Session) MustCols(_ ...string) *Session { + return nil +} + +func (_ *Session) NoAutoCondition(_ ...bool) *Session { + return nil +} + +func (_ *Session) NoAutoTime() *Session { + return nil +} + +func (_ *Session) NoCache() *Session { + return nil +} + +func (_ *Session) NoCascade() *Session { + return nil +} + +func (_ *Session) NotIn(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Nullable(_ ...string) *Session { + return nil +} + +func (_ *Session) Omit(_ ...string) *Session { + return nil +} + +func (_ *Session) Or(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) OrderBy(_ string) *Session { + return nil +} + +func (_ *Session) Ping() error { + return nil +} + +func (_ *Session) PingContext(_ context.Context) error { + return nil +} + +func (_ *Session) Prepare() *Session { + return nil +} + +func (_ *Session) Query(_ ...interface{}) ([]map[string][]byte, error) { + return nil, nil +} + +func (_ *Session) QueryInterface(_ ...interface{}) ([]map[string]interface{}, error) { + return nil, nil +} + +func (_ *Session) QuerySliceString(_ ...interface{}) ([][]string, error) { + return nil, nil +} + +func (_ *Session) QueryString(_ ...interface{}) ([]map[string]string, error) { + return nil, nil +} + +func (_ *Session) Rollback() error { + return nil +} + +func (_ *Session) Rows(_ interface{}) (*Rows, error) { + return nil, nil +} + +func (_ *Session) SQL(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Select(_ string) *Session { + return nil +} + +func (_ *Session) SetExpr(_ string, _ interface{}) *Session { + return nil +} + +func (_ *Session) Sql(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) StoreEngine(_ string) *Session { + return nil +} + +func (_ *Session) Sum(_ interface{}, _ string) (float64, error) { + return 0, nil +} + +func (_ *Session) SumInt(_ interface{}, _ string) (int64, error) { + return 0, nil +} + +func (_ *Session) Sums(_ interface{}, _ ...string) ([]float64, error) { + return nil, nil +} + +func (_ *Session) SumsInt(_ interface{}, _ ...string) ([]int64, error) { + return nil, nil +} + +func (_ *Session) Sync2(_ ...interface{}) error { + return nil +} + +func (_ *Session) Table(_ interface{}) *Session { + return nil +} + +func (_ *Session) Unscoped() *Session { + return nil +} + +func (_ *Session) Update(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) UseBool(_ ...string) *Session { + return nil +} + +func (_ *Session) Where(_ interface{}, _ ...interface{}) *Session { + return nil +} + +type Table struct { + Table interface{} + Name string +} + +func (_ Table) AddColumn(_ interface{}) {} + +func (_ Table) AddIndex(_ interface{}) {} + +func (_ Table) AutoIncrColumn() interface{} { + return nil +} + +func (_ Table) ColumnType(_ string) reflect.Type { + return nil +} + +func (_ Table) Columns() []interface{} { + return nil +} + +func (_ Table) ColumnsSeq() []string { + return nil +} + +func (_ Table) DeletedColumn() interface{} { + return nil +} + +func (_ Table) GetColumn(_ string) interface{} { + return nil +} + +func (_ Table) GetColumnIdx(_ string, _ int) interface{} { + return nil +} + +func (_ Table) PKColumns() []interface{} { + return nil +} + +func (_ Table) UpdatedColumn() interface{} { + return nil +} + +func (_ Table) VersionColumn() interface{} { + return nil +} + +func (_ *Table) IsValid() bool { + return false +} diff --git a/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/xorm.io/xorm/LICENSE b/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/xorm.io/xorm/LICENSE new file mode 100644 index 00000000000..84d2ae5386d --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/xorm.io/xorm/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013 - 2015 The Xorm Authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/xorm.io/xorm/stub.go b/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/xorm.io/xorm/stub.go new file mode 100644 index 00000000000..ccadc994d34 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/SQL/vendor/xorm.io/xorm/stub.go @@ -0,0 +1,824 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for xorm.io/xorm, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: xorm.io/xorm (exports: Engine,Session; functions: ) + +// Package xorm is a stub of xorm.io/xorm, generated by depstubber. +package xorm + +import ( + context "context" + sql "database/sql" + io "io" + reflect "reflect" + strings "strings" + time "time" +) + +type Engine struct { + TZLocation *time.Location + DatabaseTZ *time.Location +} + +func (_ *Engine) AddHook(_ interface{}) {} + +func (_ *Engine) After(_ func(interface{})) *Session { + return nil +} + +func (_ *Engine) Alias(_ string) *Session { + return nil +} + +func (_ *Engine) AllCols() *Session { + return nil +} + +func (_ *Engine) Asc(_ ...string) *Session { + return nil +} + +func (_ *Engine) AutoIncrStr() string { + return "" +} + +func (_ *Engine) Before(_ func(interface{})) *Session { + return nil +} + +func (_ *Engine) BufferSize(_ int) *Session { + return nil +} + +func (_ *Engine) Cascade(_ ...bool) *Session { + return nil +} + +func (_ *Engine) Charset(_ string) *Session { + return nil +} + +func (_ *Engine) ClearCache(_ ...interface{}) error { + return nil +} + +func (_ *Engine) ClearCacheBean(_ interface{}, _ string) error { + return nil +} + +func (_ *Engine) Close() error { + return nil +} + +func (_ *Engine) Cols(_ ...string) *Session { + return nil +} + +func (_ *Engine) Context(_ context.Context) *Session { + return nil +} + +func (_ *Engine) Count(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) CreateIndexes(_ interface{}) error { + return nil +} + +func (_ *Engine) CreateTables(_ ...interface{}) error { + return nil +} + +func (_ *Engine) CreateUniques(_ interface{}) error { + return nil +} + +func (_ *Engine) DB() interface{} { + return nil +} + +func (_ *Engine) DBMetas() ([]interface{}, error) { + return nil, nil +} + +func (_ *Engine) DataSourceName() string { + return "" +} + +func (_ *Engine) Decr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Delete(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) Desc(_ ...string) *Session { + return nil +} + +func (_ *Engine) Dialect() interface{} { + return nil +} + +func (_ *Engine) Distinct(_ ...string) *Session { + return nil +} + +func (_ *Engine) DriverName() string { + return "" +} + +func (_ *Engine) DropIndexes(_ interface{}) error { + return nil +} + +func (_ *Engine) DropTables(_ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpAll(_ io.Writer, _ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpAllToFile(_ string, _ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpTables(_ []interface{}, _ io.Writer, _ ...interface{}) error { + return nil +} + +func (_ *Engine) DumpTablesToFile(_ []interface{}, _ string, _ ...interface{}) error { + return nil +} + +func (_ *Engine) EnableSessionID(_ bool) {} + +func (_ *Engine) Exec(_ ...interface{}) (sql.Result, error) { + return nil, nil +} + +func (_ *Engine) Exist(_ ...interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) Find(_ interface{}, _ ...interface{}) error { + return nil +} + +func (_ *Engine) FindAndCount(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) Get(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) GetCacher(_ string) interface{} { + return nil +} + +func (_ *Engine) GetColumnMapper() interface{} { + return nil +} + +func (_ *Engine) GetDefaultCacher() interface{} { + return nil +} + +func (_ *Engine) GetTZDatabase() *time.Location { + return nil +} + +func (_ *Engine) GetTZLocation() *time.Location { + return nil +} + +func (_ *Engine) GetTableMapper() interface{} { + return nil +} + +func (_ *Engine) GroupBy(_ string) *Session { + return nil +} + +func (_ *Engine) Having(_ string) *Session { + return nil +} + +func (_ *Engine) ID(_ interface{}) *Session { + return nil +} + +func (_ *Engine) Import(_ io.Reader) ([]sql.Result, error) { + return nil, nil +} + +func (_ *Engine) ImportFile(_ string) ([]sql.Result, error) { + return nil, nil +} + +func (_ *Engine) In(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Incr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Insert(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) InsertOne(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) IsTableEmpty(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) IsTableExist(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Engine) Iterate(_ interface{}, _ IterFunc) error { + return nil +} + +func (_ *Engine) Join(_ string, _ interface{}, _ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Limit(_ int, _ ...int) *Session { + return nil +} + +func (_ *Engine) Logger() interface{} { + return nil +} + +func (_ *Engine) MapCacher(_ interface{}, _ interface{}) error { + return nil +} + +func (_ *Engine) MustCols(_ ...string) *Session { + return nil +} + +func (_ *Engine) NewDB() (interface{}, error) { + return nil, nil +} + +func (_ *Engine) NewSession() *Session { + return nil +} + +func (_ *Engine) NoAutoCondition(_ ...bool) *Session { + return nil +} + +func (_ *Engine) NoAutoTime() *Session { + return nil +} + +func (_ *Engine) NoCache() *Session { + return nil +} + +func (_ *Engine) NoCascade() *Session { + return nil +} + +func (_ *Engine) NotIn(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) Nullable(_ ...string) *Session { + return nil +} + +func (_ *Engine) Omit(_ ...string) *Session { + return nil +} + +func (_ *Engine) OrderBy(_ string) *Session { + return nil +} + +func (_ *Engine) Ping() error { + return nil +} + +func (_ *Engine) PingContext(_ context.Context) error { + return nil +} + +func (_ *Engine) Prepare() *Session { + return nil +} + +func (_ *Engine) Query(_ ...interface{}) ([]map[string][]byte, error) { + return nil, nil +} + +func (_ *Engine) QueryInterface(_ ...interface{}) ([]map[string]interface{}, error) { + return nil, nil +} + +func (_ *Engine) QueryString(_ ...interface{}) ([]map[string]string, error) { + return nil, nil +} + +func (_ *Engine) Quote(_ string) string { + return "" +} + +func (_ *Engine) QuoteTo(_ *strings.Builder, _ string) {} + +func (_ *Engine) Rows(_ interface{}) (*Rows, error) { + return nil, nil +} + +func (_ *Engine) SQL(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Engine) SQLType(_ interface{}) string { + return "" +} + +func (_ *Engine) Select(_ string) *Session { + return nil +} + +func (_ *Engine) SetCacher(_ string, _ interface{}) {} + +func (_ *Engine) SetColumnMapper(_ interface{}) {} + +func (_ *Engine) SetConnMaxLifetime(_ time.Duration) {} + +func (_ *Engine) SetDefaultCacher(_ interface{}) {} + +func (_ *Engine) SetDefaultContext(_ context.Context) {} + +func (_ *Engine) SetDisableGlobalCache(_ bool) {} + +func (_ *Engine) SetExpr(_ string, _ interface{}) *Session { + return nil +} + +func (_ *Engine) SetLogLevel(_ interface{}) {} + +func (_ *Engine) SetLogger(_ interface{}) {} + +func (_ *Engine) SetMapper(_ interface{}) {} + +func (_ *Engine) SetMaxIdleConns(_ int) {} + +func (_ *Engine) SetMaxOpenConns(_ int) {} + +func (_ *Engine) SetQuotePolicy(_ interface{}) {} + +func (_ *Engine) SetSchema(_ string) {} + +func (_ *Engine) SetTZDatabase(_ *time.Location) {} + +func (_ *Engine) SetTZLocation(_ *time.Location) {} + +func (_ *Engine) SetTableMapper(_ interface{}) {} + +func (_ *Engine) SetTagIdentifier(_ string) {} + +func (_ *Engine) ShowSQL(_ ...bool) {} + +func (_ *Engine) StoreEngine(_ string) *Session { + return nil +} + +func (_ *Engine) Sum(_ interface{}, _ string) (float64, error) { + return 0, nil +} + +func (_ *Engine) SumInt(_ interface{}, _ string) (int64, error) { + return 0, nil +} + +func (_ *Engine) Sums(_ interface{}, _ ...string) ([]float64, error) { + return nil, nil +} + +func (_ *Engine) SumsInt(_ interface{}, _ ...string) ([]int64, error) { + return nil, nil +} + +func (_ *Engine) Sync(_ ...interface{}) error { + return nil +} + +func (_ *Engine) Sync2(_ ...interface{}) error { + return nil +} + +func (_ *Engine) Table(_ interface{}) *Session { + return nil +} + +func (_ *Engine) TableInfo(_ interface{}) (interface{}, error) { + return nil, nil +} + +func (_ *Engine) TableName(_ interface{}, _ ...bool) string { + return "" +} + +func (_ *Engine) Transaction(_ func(*Session) (interface{}, error)) (interface{}, error) { + return nil, nil +} + +func (_ *Engine) UnMapType(_ reflect.Type) {} + +func (_ *Engine) Unscoped() *Session { + return nil +} + +func (_ *Engine) Update(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Engine) UseBool(_ ...string) *Session { + return nil +} + +func (_ *Engine) Where(_ interface{}, _ ...interface{}) *Session { + return nil +} + +type IterFunc func(int, interface{}) error + +type Rows struct{} + +func (_ *Rows) Close() error { + return nil +} + +func (_ *Rows) Err() error { + return nil +} + +func (_ *Rows) Next() bool { + return false +} + +func (_ *Rows) Scan(_ interface{}) error { + return nil +} + +type Session struct{} + +func (_ *Session) After(_ func(interface{})) *Session { + return nil +} + +func (_ *Session) Alias(_ string) *Session { + return nil +} + +func (_ *Session) AllCols() *Session { + return nil +} + +func (_ *Session) And(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Asc(_ ...string) *Session { + return nil +} + +func (_ *Session) Before(_ func(interface{})) *Session { + return nil +} + +func (_ *Session) Begin() error { + return nil +} + +func (_ *Session) BufferSize(_ int) *Session { + return nil +} + +func (_ *Session) Cascade(_ ...bool) *Session { + return nil +} + +func (_ *Session) Charset(_ string) *Session { + return nil +} + +func (_ *Session) Close() error { + return nil +} + +func (_ *Session) Cols(_ ...string) *Session { + return nil +} + +func (_ *Session) Commit() error { + return nil +} + +func (_ *Session) Conds() interface{} { + return nil +} + +func (_ *Session) Context(_ context.Context) *Session { + return nil +} + +func (_ *Session) ContextCache(_ interface{}) *Session { + return nil +} + +func (_ *Session) Count(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) CreateIndexes(_ interface{}) error { + return nil +} + +func (_ *Session) CreateTable(_ interface{}) error { + return nil +} + +func (_ *Session) CreateUniques(_ interface{}) error { + return nil +} + +func (_ *Session) DB() interface{} { + return nil +} + +func (_ *Session) Decr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Delete(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) Desc(_ ...string) *Session { + return nil +} + +func (_ *Session) Distinct(_ ...string) *Session { + return nil +} + +func (_ *Session) DropIndexes(_ interface{}) error { + return nil +} + +func (_ *Session) DropTable(_ interface{}) error { + return nil +} + +func (_ *Session) Engine() *Engine { + return nil +} + +func (_ *Session) Exec(_ ...interface{}) (sql.Result, error) { + return nil, nil +} + +func (_ *Session) Exist(_ ...interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) Find(_ interface{}, _ ...interface{}) error { + return nil +} + +func (_ *Session) FindAndCount(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) ForUpdate() *Session { + return nil +} + +func (_ *Session) Get(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) GroupBy(_ string) *Session { + return nil +} + +func (_ *Session) Having(_ string) *Session { + return nil +} + +func (_ *Session) ID(_ interface{}) *Session { + return nil +} + +func (_ *Session) Import(_ io.Reader) ([]sql.Result, error) { + return nil, nil +} + +func (_ *Session) ImportFile(_ string) ([]sql.Result, error) { + return nil, nil +} + +func (_ *Session) In(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Incr(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Insert(_ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) InsertMulti(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) InsertOne(_ interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) IsClosed() bool { + return false +} + +func (_ *Session) IsInTx() bool { + return false +} + +func (_ *Session) IsTableEmpty(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) IsTableExist(_ interface{}) (bool, error) { + return false, nil +} + +func (_ *Session) Iterate(_ interface{}, _ IterFunc) error { + return nil +} + +func (_ *Session) Join(_ string, _ interface{}, _ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) LastSQL() (string, []interface{}) { + return "", nil +} + +func (_ *Session) Limit(_ int, _ ...int) *Session { + return nil +} + +func (_ *Session) MustCols(_ ...string) *Session { + return nil +} + +func (_ *Session) MustLogSQL(_ ...bool) *Session { + return nil +} + +func (_ *Session) NoAutoCondition(_ ...bool) *Session { + return nil +} + +func (_ *Session) NoAutoTime() *Session { + return nil +} + +func (_ *Session) NoCache() *Session { + return nil +} + +func (_ *Session) NoCascade() *Session { + return nil +} + +func (_ *Session) NotIn(_ string, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Nullable(_ ...string) *Session { + return nil +} + +func (_ *Session) Omit(_ ...string) *Session { + return nil +} + +func (_ *Session) Or(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) OrderBy(_ string) *Session { + return nil +} + +func (_ *Session) Ping() error { + return nil +} + +func (_ *Session) PingContext(_ context.Context) error { + return nil +} + +func (_ *Session) Prepare() *Session { + return nil +} + +func (_ *Session) Query(_ ...interface{}) ([]map[string][]byte, error) { + return nil, nil +} + +func (_ *Session) QueryInterface(_ ...interface{}) ([]map[string]interface{}, error) { + return nil, nil +} + +func (_ *Session) QuerySliceString(_ ...interface{}) ([][]string, error) { + return nil, nil +} + +func (_ *Session) QueryString(_ ...interface{}) ([]map[string]string, error) { + return nil, nil +} + +func (_ *Session) Rollback() error { + return nil +} + +func (_ *Session) Rows(_ interface{}) (*Rows, error) { + return nil, nil +} + +func (_ *Session) SQL(_ interface{}, _ ...interface{}) *Session { + return nil +} + +func (_ *Session) Select(_ string) *Session { + return nil +} + +func (_ *Session) SetExpr(_ string, _ interface{}) *Session { + return nil +} + +func (_ *Session) StoreEngine(_ string) *Session { + return nil +} + +func (_ *Session) Sum(_ interface{}, _ string) (float64, error) { + return 0, nil +} + +func (_ *Session) SumInt(_ interface{}, _ string) (int64, error) { + return 0, nil +} + +func (_ *Session) Sums(_ interface{}, _ ...string) ([]float64, error) { + return nil, nil +} + +func (_ *Session) SumsInt(_ interface{}, _ ...string) ([]int64, error) { + return nil, nil +} + +func (_ *Session) Sync2(_ ...interface{}) error { + return nil +} + +func (_ *Session) Table(_ interface{}) *Session { + return nil +} + +func (_ *Session) Unscoped() *Session { + return nil +} + +func (_ *Session) Update(_ interface{}, _ ...interface{}) (int64, error) { + return 0, nil +} + +func (_ *Session) UseBool(_ ...string) *Session { + return nil +} + +func (_ *Session) Where(_ interface{}, _ ...interface{}) *Session { + return nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go b/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go new file mode 100644 index 00000000000..3aa8857a61b --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/SQL/xorm.go @@ -0,0 +1,77 @@ +package main + +//go:generate depstubber -vendor xorm.io/xorm Engine,Session +//go:generate depstubber -vendor github.com/go-xorm/xorm Engine,Session + +import ( + xorm1 "github.com/go-xorm/xorm" + xorm2 "xorm.io/xorm" +) + +func xormtest() { + query := "UntrustedString" + + engine1 := xorm1.Engine{} + engine1.Query(query) // $querystring=query + engine1.QueryString(query) // $querystring=query + engine1.QueryInterface(query) // $querystring=query + engine1.SQL(query) // $querystring=query + engine1.Where(query) // $querystring=query + engine1.Alias(query) // $querystring=query + engine1.NotIn(query) // $querystring=query + engine1.In(query) // $querystring=query + engine1.Select(query) // $querystring=query + engine1.SetExpr(query, nil) // $querystring=query + engine1.OrderBy(query) // $querystring=query + engine1.Having(query) // $querystring=query + engine1.GroupBy(query) // $querystring=query + + engine2 := xorm2.Engine{} + engine2.Query(query) // $querystring=query + engine2.QueryString(query) // $querystring=query + engine2.QueryInterface(query) // $querystring=query + engine2.SQL(query) // $querystring=query + engine2.Where(query) // $querystring=query + engine2.Alias(query) // $querystring=query + engine2.NotIn(query) // $querystring=query + engine2.In(query) // $querystring=query + engine2.Select(query) // $querystring=query + engine2.SetExpr(query, nil) // $querystring=query + engine2.OrderBy(query) // $querystring=query + engine2.Having(query) // $querystring=query + engine2.GroupBy(query) // $querystring=query + + session1 := xorm1.Session{} + session1.Query(query) // $querystring=query + session1.QueryString(query) // $querystring=query + session1.QueryInterface(query) // $querystring=query + session1.SQL(query) // $querystring=query + session1.Where(query) // $querystring=query + session1.Alias(query) // $querystring=query + session1.NotIn(query) // $querystring=query + session1.In(query) // $querystring=query + session1.Select(query) // $querystring=query + session1.SetExpr(query, nil) // $querystring=query + session1.OrderBy(query) // $querystring=query + session1.Having(query) // $querystring=query + session1.GroupBy(query) // $querystring=query + session1.And(query) // $querystring=query + session1.Or(query) // $querystring=query + + session2 := xorm2.Session{} + session2.Query(query) // $querystring=query + session2.QueryString(query) // $querystring=query + session2.QueryInterface(query) // $querystring=query + session2.SQL(query) // $querystring=query + session2.Where(query) // $querystring=query + session2.Alias(query) // $querystring=query + session2.NotIn(query) // $querystring=query + session2.In(query) // $querystring=query + session2.Select(query) // $querystring=query + session2.SetExpr(query, nil) // $querystring=query + session2.OrderBy(query) // $querystring=query + session2.Having(query) // $querystring=query + session2.GroupBy(query) // $querystring=query + session2.And(query) // $querystring=query + session2.Or(query) // $querystring=query +} diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/ArchiveZip.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/ArchiveZip.go index 6cbbfcb77e2..f968c5c11e0 100644 --- a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/ArchiveZip.go +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/ArchiveZip.go @@ -40,6 +40,19 @@ func TaintStepTest_ArchiveZipFileOpen_B0I0O0(sourceCQL interface{}) interface{} return intoReadCloser483 } +func TaintStepTest_ArchiveZipFileOpenRaw_B0I0O0(sourceCQL interface{}) interface{} { + fromFile127 := sourceCQL.(zip.File) + intoReadCloser483, _ := fromFile127.OpenRaw() + return intoReadCloser483 +} + +func TaintStepTest_ArchiveZipWriterCopy_B0I0O0(sourceCQL interface{}) interface{} { + fromFile127 := sourceCQL.(*zip.File) + var intoWriter982 zip.Writer + intoWriter982.Copy(fromFile127) + return intoWriter982 +} + func TaintStepTest_ArchiveZipWriterCreate_B0I0O0(sourceCQL interface{}) interface{} { fromWriter989 := sourceCQL.(io.Writer) var intoWriter982 zip.Writer @@ -48,6 +61,14 @@ func TaintStepTest_ArchiveZipWriterCreate_B0I0O0(sourceCQL interface{}) interfac return intoWriter982 } +func TaintStepTest_ArchiveZipWriterCreateRaw_B0I0O0(sourceCQL interface{}) interface{} { + fromWriter989 := sourceCQL.(io.Writer) + var intoWriter982 zip.Writer + intermediateCQL, _ := intoWriter982.CreateRaw(nil) + link(fromWriter989, intermediateCQL) + return intoWriter982 +} + func TaintStepTest_ArchiveZipWriterCreateHeader_B0I0O0(sourceCQL interface{}) interface{} { fromWriter417 := sourceCQL.(io.Writer) var intoWriter584 zip.Writer diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/IoFs.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/IoFs.go index 9eea2dc516f..4b910200841 100644 --- a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/IoFs.go +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/IoFs.go @@ -11,6 +11,11 @@ func walkDirCallback(path string, d fs.DirEntry, _ error) error { } func steps() { + { + source := newSource(16).(fs.FileInfo) + out := fs.FileInfoToDirEntry(source) + sink(16, out) + } { source := newSource(0).(fs.FS) out, _ := fs.Glob(source, "*") diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Strconv.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Strconv.go index da01b976862..d7f84f6c031 100644 --- a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Strconv.go +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Strconv.go @@ -46,6 +46,12 @@ func TaintStepTest_StrconvQuote_B0I0O0(sourceCQL interface{}) interface{} { return intoString584 } +func TaintStepTest_StrconvQuotedPrefix_B0I0O0(sourceCQL interface{}) interface{} { + fromString417 := sourceCQL.(string) + intoString584, _ := strconv.QuotedPrefix(fromString417) + return intoString584 +} + func TaintStepTest_StrconvQuoteToASCII_B0I0O0(sourceCQL interface{}) interface{} { fromString991 := sourceCQL.(string) intoString881 := strconv.QuoteToASCII(fromString991) diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Syscall_non_win.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Syscall_non_win.go index c2d7f55e259..06db4fa3c0b 100644 --- a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Syscall_non_win.go +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/Syscall_non_win.go @@ -1,5 +1,6 @@ // Code generated by https://github.com/gagliardetto/codebox. DO NOT EDIT. +//go:build !windows // +build !windows package main diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/m b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/m new file mode 100755 index 00000000000..b0d3e8c228e Binary files /dev/null and b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/m differ diff --git a/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected b/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected index dfd4a4ff15d..7c7600b70da 100644 --- a/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/ql/test/query-tests/Diagnostics/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1,3 +1,9 @@ | -:0:0:0:0 | malformed import path "github.com/github/codeql-go/ql/test/query-tests/Diagnostics/invalid{": invalid char '{' | +| -:0:0:0:0 | package ; expected main | | bad.go:3:1:3:1 | expected 'package', found avvu | +| bad.go:3:1:3:1 | expected 'package', found avvu | +| bad.go:3:5:3:5 | expected 'IDENT', found newline | +| bad.go:5:1:5:1 | expected ';', found wnvwun | +| badimport.go:6:2:6:2 | invalid import path (invalid character U+007B '{') | +| badimport.go:6:2:6:2 | invalid import path: "github.com/pkg{}" | | type.go:11:9:11:9 | cannot use v (variable of type V) as T value in argument to takesT | diff --git a/ql/test/query-tests/Diagnostics/ExtractionErrors.expected b/ql/test/query-tests/Diagnostics/ExtractionErrors.expected index 4154baaaccd..50b08606056 100644 --- a/ql/test/query-tests/Diagnostics/ExtractionErrors.expected +++ b/ql/test/query-tests/Diagnostics/ExtractionErrors.expected @@ -1,3 +1,8 @@ +| Extraction failed in query-tests/Diagnostics/badimport.go with error invalid import path (invalid character U+007B '{') | 2 | +| Extraction failed in query-tests/Diagnostics/badimport.go with error invalid import path: "github.com/pkg{}" | 2 | | Extraction failed in query-tests/Diagnostics/type.go with error cannot use v (variable of type V) as T value in argument to takesT | 2 | +| Extraction failed with error expected ';', found wnvwun | 2 | +| Extraction failed with error expected 'IDENT', found newline | 2 | | Extraction failed with error expected 'package', found avvu | 2 | | Extraction failed with error malformed import path "github.com/github/codeql-go/ql/test/query-tests/Diagnostics/invalid{": invalid char '{' | 2 | +| Extraction failed with error package ; expected main | 2 | diff --git a/ql/test/query-tests/RedundantCode/CompareIdenticalValues/constants.go b/ql/test/query-tests/RedundantCode/CompareIdenticalValues/constants.go index d999a815ecf..50ec41c081c 100644 --- a/ql/test/query-tests/RedundantCode/CompareIdenticalValues/constants.go +++ b/ql/test/query-tests/RedundantCode/CompareIdenticalValues/constants.go @@ -1,4 +1,5 @@ -// +build linux, amd64 +//go:build (linux && ignore) || amd64 +// +build linux,ignore amd64 package main diff --git a/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst.go b/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst.go index a81e4c931b0..485ee15fe8c 100644 --- a/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst.go +++ b/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package main diff --git a/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst_nonlinux.go b/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst_nonlinux.go index 43bd1a07ad6..2326c147a9a 100644 --- a/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst_nonlinux.go +++ b/ql/test/query-tests/RedundantCode/ExprHasNoEffect/tst_nonlinux.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package main diff --git a/ql/test/experimental/CWE-326/InsufficientKeySize.expected b/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.expected similarity index 100% rename from ql/test/experimental/CWE-326/InsufficientKeySize.expected rename to ql/test/query-tests/Security/CWE-326/InsufficientKeySize.expected diff --git a/ql/test/experimental/CWE-326/InsufficientKeySize.go b/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.go similarity index 100% rename from ql/test/experimental/CWE-326/InsufficientKeySize.go rename to ql/test/query-tests/Security/CWE-326/InsufficientKeySize.go diff --git a/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref b/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref new file mode 100644 index 00000000000..fbb59dd4be6 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-326/InsufficientKeySize.qlref @@ -0,0 +1 @@ +Security/CWE-326/InsufficientKeySize.ql diff --git a/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go index 11e317d46cd..2914e2178e9 100644 --- a/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go +++ b/ql/test/query-tests/Security/CWE-681/Test32BitArchitectureBuildConstraints.go @@ -1,3 +1,4 @@ +//go:build (386 || amd64p32 || arm || armbe || mips || mipsle || mips64p32 || mips64p32le || ppc || s390 || sparc) && gc && go1.4 // +build 386 amd64p32 arm armbe mips mipsle mips64p32 mips64p32le ppc s390 sparc // +build gc // +build go1.4 diff --git a/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go index 82bd2965cee..8c1e23fe721 100644 --- a/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go +++ b/ql/test/query-tests/Security/CWE-681/Test64BitArchitectureBuildConstraints.go @@ -1,3 +1,4 @@ +//go:build (amd64 || arm64 || arm64be || ppc64 || ppc64le || mips64 || mips64le || s390x || sparc64) && gc && go1.4 // +build amd64 arm64 arm64be ppc64 ppc64le mips64 mips64le s390x sparc64 // +build gc // +build go1.4 diff --git a/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go index 98cb6abdd61..905ee836b9b 100644 --- a/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go +++ b/ql/test/query-tests/Security/CWE-681/TestNoArchitectureBuildConstraints.go @@ -1,5 +1,5 @@ -// +build gc -// +build go1.4 +//go:build gc && go1.4 +// +build gc,go1.4 package main diff --git a/ql/test/query-tests/Security/CWE-681/TestOldBuildConstraints.go b/ql/test/query-tests/Security/CWE-681/TestOldBuildConstraints.go new file mode 100644 index 00000000000..e7f6b058ed7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-681/TestOldBuildConstraints.go @@ -0,0 +1,29 @@ +// autoformat-ignore (gofmt adds new style build constraints) +// +build amd64 arm64 arm64be ppc64 ppc64le mips64 mips64le s390x sparc64 +// +build gc +// +build go1.4 + +package main + +import ( + "strconv" +) + +func oldTestIntSink64() { + { + parsed, err := strconv.ParseInt("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } + { + parsed, err := strconv.ParseUint("3456", 10, 64) + if err != nil { + panic(err) + } + _ = int(parsed) // OK + _ = uint(parsed) // OK + } +} diff --git a/ql/test/query-tests/Summary/CONSISTENCY/UnexpectedFrontendErrors.expected b/ql/test/query-tests/Summary/CONSISTENCY/UnexpectedFrontendErrors.expected index a17dae68734..d4dff7b992f 100644 --- a/ql/test/query-tests/Summary/CONSISTENCY/UnexpectedFrontendErrors.expected +++ b/ql/test/query-tests/Summary/CONSISTENCY/UnexpectedFrontendErrors.expected @@ -1 +1,5 @@ +| -:0:0:0:0 | package ; expected main | +| empty-file.go:1:1:1:1 | expected ';', found 'EOF' | +| empty-file.go:1:1:1:1 | expected 'IDENT', found 'EOF' | +| empty-file.go:1:1:1:1 | expected 'package', found 'EOF' | | empty-file.go:1:1:1:1 | expected 'package', found 'EOF' | diff --git a/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/go.dbscheme b/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/go.dbscheme new file mode 100644 index 00000000000..2842941c6f9 --- /dev/null +++ b/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/go.dbscheme @@ -0,0 +1,528 @@ +/** Auto-generated dbscheme; do not edit. */ + + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +compilations(unique int id: @compilation, string cwd: string ref); + +#keyset[id, num] +compilation_args(int id: @compilation ref, int num: int ref, string arg: string ref); + +#keyset[id, num, kind] +compilation_time(int id: @compilation ref, int num: int ref, int kind: int ref, float secs: float ref); + +diagnostic_for(unique int diagnostic: @diagnostic ref, int compilation: @compilation ref, int file_number: int ref, int file_number_diagnostic_number: int ref); + +compilation_finished(unique int id: @compilation ref, float cpu_seconds: float ref, float elapsed_seconds: float ref); + +#keyset[id, num] +compilation_compiling_files(int id: @compilation ref, int num: int ref, int file: @file ref); + +diagnostics(unique int id: @diagnostic, int severity: int ref, string error_tag: string ref, string error_message: string ref, + string full_error_message: string ref, int location: @location ref); + +locations_default(unique int id: @location_default, int file: @file ref, int beginLine: int ref, int beginColumn: int ref, + int endLine: int ref, int endColumn: int ref); + +numlines(int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, int num_comment: int ref); + +files(unique int id: @file, string name: string ref); + +folders(unique int id: @folder, string name: string ref); + +containerparent(int parent: @container ref, unique int child: @container ref); + +has_location(unique int locatable: @locatable ref, int location: @location ref); + +#keyset[parent, idx] +comment_groups(unique int id: @comment_group, int parent: @file ref, int idx: int ref); + +comments(unique int id: @comment, int kind: int ref, int parent: @comment_group ref, int idx: int ref, string text: string ref); + +doc_comments(unique int node: @documentable ref, int comment: @comment_group ref); + +#keyset[parent, idx] +exprs(unique int id: @expr, int kind: int ref, int parent: @exprparent ref, int idx: int ref); + +literals(unique int expr: @expr ref, string value: string ref, string raw: string ref); + +constvalues(unique int expr: @expr ref, string value: string ref, string exact: string ref); + +fields(unique int id: @field, int parent: @fieldparent ref, int idx: int ref); + +#keyset[parent, idx] +stmts(unique int id: @stmt, int kind: int ref, int parent: @stmtparent ref, int idx: int ref); + +#keyset[parent, idx] +decls(unique int id: @decl, int kind: int ref, int parent: @declparent ref, int idx: int ref); + +#keyset[parent, idx] +specs(unique int id: @spec, int kind: int ref, int parent: @gendecl ref, int idx: int ref); + +scopes(unique int id: @scope, int kind: int ref); + +scopenesting(unique int inner: @scope ref, int outer: @scope ref); + +scopenodes(unique int node: @scopenode ref, int scope: @localscope ref); + +objects(unique int id: @object, int kind: int ref, string name: string ref); + +objectscopes(unique int object: @object ref, int scope: @scope ref); + +objecttypes(unique int object: @object ref, int tp: @type ref); + +methodreceivers(unique int method: @object ref, int receiver: @object ref); + +fieldstructs(unique int field: @object ref, int struct: @structtype ref); + +methodhosts(int method: @object ref, int host: @namedtype ref); + +defs(int ident: @ident ref, int object: @object ref); + +uses(int ident: @ident ref, int object: @object ref); + +types(unique int id: @type, int kind: int ref); + +type_of(unique int expr: @expr ref, int tp: @type ref); + +typename(unique int tp: @type ref, string name: string ref); + +key_type(unique int map: @maptype ref, int tp: @type ref); + +element_type(unique int container: @containertype ref, int tp: @type ref); + +base_type(unique int ptr: @pointertype ref, int tp: @type ref); + +underlying_type(unique int named: @namedtype ref, int tp: @type ref); + +#keyset[parent, index] +component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref); + +array_length(unique int tp: @arraytype ref, string len: string ref); + +type_objects(unique int tp: @type ref, int object: @object ref); + +packages(unique int id: @package, string name: string ref, string path: string ref, int scope: @packagescope ref); + +#keyset[parent, idx] +modexprs(unique int id: @modexpr, int kind: int ref, int parent: @modexprparent ref, int idx: int ref); + +#keyset[parent, idx] +modtokens(string token: string ref, int parent: @modexpr ref, int idx: int ref); + +#keyset[package, idx] +errors(unique int id: @error, int kind: int ref, string msg: string ref, string rawpos: string ref, + string file: string ref, int line: int ref, int col: int ref, int package: @package ref, int idx: int ref); + +has_ellipsis(int id: @callorconversionexpr ref); + +@container = @file | @folder; + +@locatable = @xmllocatable | @node | @localscope; + +@node = @documentable | @exprparent | @modexprparent | @fieldparent | @stmtparent | @declparent | @scopenode + | @comment_group | @comment; + +@documentable = @file | @field | @spec | @gendecl | @funcdecl | @modexpr; + +@exprparent = @funcdef | @file | @expr | @field | @stmt | @decl | @spec; + +@modexprparent = @file | @modexpr; + +@fieldparent = @decl | @structtypeexpr | @functypeexpr | @interfacetypeexpr; + +@stmtparent = @funcdef | @stmt | @decl; + +@declparent = @file | @declstmt; + +@funcdef = @funclit | @funcdecl; + +@scopenode = @file | @functypeexpr | @blockstmt | @ifstmt | @caseclause | @switchstmt | @commclause | @loopstmt; + +@location = @location_default; + +@sourceline = @locatable; + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment; + +case @expr.kind of + 0 = @badexpr +| 1 = @ident +| 2 = @ellipsis +| 3 = @intlit +| 4 = @floatlit +| 5 = @imaglit +| 6 = @charlit +| 7 = @stringlit +| 8 = @funclit +| 9 = @compositelit +| 10 = @parenexpr +| 11 = @selectorexpr +| 12 = @indexexpr +| 13 = @sliceexpr +| 14 = @typeassertexpr +| 15 = @callorconversionexpr +| 16 = @starexpr +| 17 = @keyvalueexpr +| 18 = @arraytypeexpr +| 19 = @structtypeexpr +| 20 = @functypeexpr +| 21 = @interfacetypeexpr +| 22 = @maptypeexpr +| 23 = @plusexpr +| 24 = @minusexpr +| 25 = @notexpr +| 26 = @complementexpr +| 27 = @derefexpr +| 28 = @addressexpr +| 29 = @arrowexpr +| 30 = @lorexpr +| 31 = @landexpr +| 32 = @eqlexpr +| 33 = @neqexpr +| 34 = @lssexpr +| 35 = @leqexpr +| 36 = @gtrexpr +| 37 = @geqexpr +| 38 = @addexpr +| 39 = @subexpr +| 40 = @orexpr +| 41 = @xorexpr +| 42 = @mulexpr +| 43 = @quoexpr +| 44 = @remexpr +| 45 = @shlexpr +| 46 = @shrexpr +| 47 = @andexpr +| 48 = @andnotexpr +| 49 = @sendchantypeexpr +| 50 = @recvchantypeexpr +| 51 = @sendrcvchantypeexpr; + +@basiclit = @intlit | @floatlit | @imaglit | @charlit | @stringlit; + +@operatorexpr = @logicalexpr | @arithmeticexpr | @bitwiseexpr | @unaryexpr | @binaryexpr; + +@logicalexpr = @logicalunaryexpr | @logicalbinaryexpr; + +@arithmeticexpr = @arithmeticunaryexpr | @arithmeticbinaryexpr; + +@bitwiseexpr = @bitwiseunaryexpr | @bitwisebinaryexpr; + +@unaryexpr = @logicalunaryexpr | @bitwiseunaryexpr | @arithmeticunaryexpr | @derefexpr | @addressexpr | @arrowexpr; + +@logicalunaryexpr = @notexpr; + +@bitwiseunaryexpr = @complementexpr; + +@arithmeticunaryexpr = @plusexpr | @minusexpr; + +@binaryexpr = @logicalbinaryexpr | @bitwisebinaryexpr | @arithmeticbinaryexpr | @comparison; + +@logicalbinaryexpr = @lorexpr | @landexpr; + +@bitwisebinaryexpr = @shiftexpr | @orexpr | @xorexpr | @andexpr | @andnotexpr; + +@arithmeticbinaryexpr = @addexpr | @subexpr | @mulexpr | @quoexpr | @remexpr; + +@shiftexpr = @shlexpr | @shrexpr; + +@comparison = @equalitytest | @relationalcomparison; + +@equalitytest = @eqlexpr | @neqexpr; + +@relationalcomparison = @lssexpr | @leqexpr | @gtrexpr | @geqexpr; + +@chantypeexpr = @sendchantypeexpr | @recvchantypeexpr | @sendrcvchantypeexpr; + +case @stmt.kind of + 0 = @badstmt +| 1 = @declstmt +| 2 = @emptystmt +| 3 = @labeledstmt +| 4 = @exprstmt +| 5 = @sendstmt +| 6 = @incstmt +| 7 = @decstmt +| 8 = @gostmt +| 9 = @deferstmt +| 10 = @returnstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @gotostmt +| 14 = @fallthroughstmt +| 15 = @blockstmt +| 16 = @ifstmt +| 17 = @caseclause +| 18 = @exprswitchstmt +| 19 = @typeswitchstmt +| 20 = @commclause +| 21 = @selectstmt +| 22 = @forstmt +| 23 = @rangestmt +| 24 = @assignstmt +| 25 = @definestmt +| 26 = @addassignstmt +| 27 = @subassignstmt +| 28 = @mulassignstmt +| 29 = @quoassignstmt +| 30 = @remassignstmt +| 31 = @andassignstmt +| 32 = @orassignstmt +| 33 = @xorassignstmt +| 34 = @shlassignstmt +| 35 = @shrassignstmt +| 36 = @andnotassignstmt; + +@incdecstmt = @incstmt | @decstmt; + +@assignment = @simpleassignstmt | @compoundassignstmt; + +@simpleassignstmt = @assignstmt | @definestmt; + +@compoundassignstmt = @addassignstmt | @subassignstmt | @mulassignstmt | @quoassignstmt | @remassignstmt + | @andassignstmt | @orassignstmt | @xorassignstmt | @shlassignstmt | @shrassignstmt | @andnotassignstmt; + +@branchstmt = @breakstmt | @continuestmt | @gotostmt | @fallthroughstmt; + +@switchstmt = @exprswitchstmt | @typeswitchstmt; + +@loopstmt = @forstmt | @rangestmt; + +case @decl.kind of + 0 = @baddecl +| 1 = @importdecl +| 2 = @constdecl +| 3 = @typedecl +| 4 = @vardecl +| 5 = @funcdecl; + +@gendecl = @importdecl | @constdecl | @typedecl | @vardecl; + +case @spec.kind of + 0 = @importspec +| 1 = @valuespec +| 2 = @typedefspec +| 3 = @aliasspec; + +@typespec = @typedefspec | @aliasspec; + +case @object.kind of + 0 = @pkgobject +| 1 = @decltypeobject +| 2 = @builtintypeobject +| 3 = @declconstobject +| 4 = @builtinconstobject +| 5 = @declvarobject +| 6 = @declfunctionobject +| 7 = @builtinfunctionobject +| 8 = @labelobject; + +@declobject = @decltypeobject | @declconstobject | @declvarobject | @declfunctionobject; + +@builtinobject = @builtintypeobject | @builtinconstobject | @builtinfunctionobject; + +@typeobject = @decltypeobject | @builtintypeobject; + +@valueobject = @constobject | @varobject | @functionobject; + +@constobject = @declconstobject | @builtinconstobject; + +@varobject = @declvarobject; + +@functionobject = @declfunctionobject | @builtinfunctionobject; + +case @scope.kind of + 0 = @universescope +| 1 = @packagescope +| 2 = @localscope; + +case @type.kind of + 0 = @invalidtype +| 1 = @boolexprtype +| 2 = @inttype +| 3 = @int8type +| 4 = @int16type +| 5 = @int32type +| 6 = @int64type +| 7 = @uinttype +| 8 = @uint8type +| 9 = @uint16type +| 10 = @uint32type +| 11 = @uint64type +| 12 = @uintptrtype +| 13 = @float32type +| 14 = @float64type +| 15 = @complex64type +| 16 = @complex128type +| 17 = @stringexprtype +| 18 = @unsafepointertype +| 19 = @boolliteraltype +| 20 = @intliteraltype +| 21 = @runeliteraltype +| 22 = @floatliteraltype +| 23 = @complexliteraltype +| 24 = @stringliteraltype +| 25 = @nilliteraltype +| 26 = @arraytype +| 27 = @slicetype +| 28 = @structtype +| 29 = @pointertype +| 30 = @interfacetype +| 31 = @tupletype +| 32 = @signaturetype +| 33 = @maptype +| 34 = @sendchantype +| 35 = @recvchantype +| 36 = @sendrcvchantype +| 37 = @namedtype; + +@basictype = @booltype | @numerictype | @stringtype | @literaltype | @invalidtype | @unsafepointertype; + +@booltype = @boolexprtype | @boolliteraltype; + +@numerictype = @integertype | @floattype | @complextype; + +@integertype = @signedintegertype | @unsignedintegertype; + +@signedintegertype = @inttype | @int8type | @int16type | @int32type | @int64type | @intliteraltype | @runeliteraltype; + +@unsignedintegertype = @uinttype | @uint8type | @uint16type | @uint32type | @uint64type | @uintptrtype; + +@floattype = @float32type | @float64type | @floatliteraltype; + +@complextype = @complex64type | @complex128type | @complexliteraltype; + +@stringtype = @stringexprtype | @stringliteraltype; + +@literaltype = @boolliteraltype | @intliteraltype | @runeliteraltype | @floatliteraltype | @complexliteraltype + | @stringliteraltype | @nilliteraltype; + +@compositetype = @containertype | @structtype | @pointertype | @interfacetype | @tupletype | @signaturetype | @namedtype; + +@containertype = @arraytype | @slicetype | @maptype | @chantype; + +@chantype = @sendchantype | @recvchantype | @sendrcvchantype; + +case @modexpr.kind of + 0 = @modcommentblock +| 1 = @modline +| 2 = @modlineblock +| 3 = @modlparen +| 4 = @modrparen; + +case @error.kind of + 0 = @unknownerror +| 1 = @listerror +| 2 = @parseerror +| 3 = @typeerror; + diff --git a/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/old.dbscheme b/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/old.dbscheme new file mode 100644 index 00000000000..b37faf5d62c --- /dev/null +++ b/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/old.dbscheme @@ -0,0 +1,528 @@ +/** Auto-generated dbscheme; do not edit. */ + + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + + +/* + * XML Files + */ + +xmlEncoding( + unique int id: @file ref, + string encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + string root: string ref, + string publicId: string ref, + string systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + string name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + string name: string ref, + string value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + string prefixName: string ref, + string URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + string text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + string text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +compilations(unique int id: @compilation, string cwd: string ref); + +#keyset[id, num] +compilation_args(int id: @compilation ref, int num: int ref, string arg: string ref); + +#keyset[id, num, kind] +compilation_time(int id: @compilation ref, int num: int ref, int kind: int ref, float secs: float ref); + +diagnostic_for(unique int diagnostic: @diagnostic ref, int compilation: @compilation ref, int file_number: int ref, int file_number_diagnostic_number: int ref); + +compilation_finished(unique int id: @compilation ref, float cpu_seconds: float ref, float elapsed_seconds: float ref); + +#keyset[id, num] +compilation_compiling_files(int id: @compilation ref, int num: int ref, int file: @file ref); + +diagnostics(unique int id: @diagnostic, int severity: int ref, string error_tag: string ref, string error_message: string ref, + string full_error_message: string ref, int location: @location ref); + +locations_default(unique int id: @location_default, int file: @file ref, int beginLine: int ref, int beginColumn: int ref, + int endLine: int ref, int endColumn: int ref); + +numlines(int element_id: @sourceline ref, int num_lines: int ref, int num_code: int ref, int num_comment: int ref); + +files(unique int id: @file, string name: string ref, string simple: string ref, string ext: string ref, int fromSource: int ref); + +folders(unique int id: @folder, string name: string ref, string simple: string ref); + +containerparent(int parent: @container ref, unique int child: @container ref); + +has_location(unique int locatable: @locatable ref, int location: @location ref); + +#keyset[parent, idx] +comment_groups(unique int id: @comment_group, int parent: @file ref, int idx: int ref); + +comments(unique int id: @comment, int kind: int ref, int parent: @comment_group ref, int idx: int ref, string text: string ref); + +doc_comments(unique int node: @documentable ref, int comment: @comment_group ref); + +#keyset[parent, idx] +exprs(unique int id: @expr, int kind: int ref, int parent: @exprparent ref, int idx: int ref); + +literals(unique int expr: @expr ref, string value: string ref, string raw: string ref); + +constvalues(unique int expr: @expr ref, string value: string ref, string exact: string ref); + +fields(unique int id: @field, int parent: @fieldparent ref, int idx: int ref); + +#keyset[parent, idx] +stmts(unique int id: @stmt, int kind: int ref, int parent: @stmtparent ref, int idx: int ref); + +#keyset[parent, idx] +decls(unique int id: @decl, int kind: int ref, int parent: @declparent ref, int idx: int ref); + +#keyset[parent, idx] +specs(unique int id: @spec, int kind: int ref, int parent: @gendecl ref, int idx: int ref); + +scopes(unique int id: @scope, int kind: int ref); + +scopenesting(unique int inner: @scope ref, int outer: @scope ref); + +scopenodes(unique int node: @scopenode ref, int scope: @localscope ref); + +objects(unique int id: @object, int kind: int ref, string name: string ref); + +objectscopes(unique int object: @object ref, int scope: @scope ref); + +objecttypes(unique int object: @object ref, int tp: @type ref); + +methodreceivers(unique int method: @object ref, int receiver: @object ref); + +fieldstructs(unique int field: @object ref, int struct: @structtype ref); + +methodhosts(int method: @object ref, int host: @namedtype ref); + +defs(int ident: @ident ref, int object: @object ref); + +uses(int ident: @ident ref, int object: @object ref); + +types(unique int id: @type, int kind: int ref); + +type_of(unique int expr: @expr ref, int tp: @type ref); + +typename(unique int tp: @type ref, string name: string ref); + +key_type(unique int map: @maptype ref, int tp: @type ref); + +element_type(unique int container: @containertype ref, int tp: @type ref); + +base_type(unique int ptr: @pointertype ref, int tp: @type ref); + +underlying_type(unique int named: @namedtype ref, int tp: @type ref); + +#keyset[parent, index] +component_types(int parent: @compositetype ref, int index: int ref, string name: string ref, int tp: @type ref); + +array_length(unique int tp: @arraytype ref, string len: string ref); + +type_objects(unique int tp: @type ref, int object: @object ref); + +packages(unique int id: @package, string name: string ref, string path: string ref, int scope: @packagescope ref); + +#keyset[parent, idx] +modexprs(unique int id: @modexpr, int kind: int ref, int parent: @modexprparent ref, int idx: int ref); + +#keyset[parent, idx] +modtokens(string token: string ref, int parent: @modexpr ref, int idx: int ref); + +#keyset[package, idx] +errors(unique int id: @error, int kind: int ref, string msg: string ref, string rawpos: string ref, + string file: string ref, int line: int ref, int col: int ref, int package: @package ref, int idx: int ref); + +has_ellipsis(int id: @callorconversionexpr ref); + +@container = @file | @folder; + +@locatable = @xmllocatable | @node | @localscope; + +@node = @documentable | @exprparent | @modexprparent | @fieldparent | @stmtparent | @declparent | @scopenode + | @comment_group | @comment; + +@documentable = @file | @field | @spec | @gendecl | @funcdecl | @modexpr; + +@exprparent = @funcdef | @file | @expr | @field | @stmt | @decl | @spec; + +@modexprparent = @file | @modexpr; + +@fieldparent = @decl | @structtypeexpr | @functypeexpr | @interfacetypeexpr; + +@stmtparent = @funcdef | @stmt | @decl; + +@declparent = @file | @declstmt; + +@funcdef = @funclit | @funcdecl; + +@scopenode = @file | @functypeexpr | @blockstmt | @ifstmt | @caseclause | @switchstmt | @commclause | @loopstmt; + +@location = @location_default; + +@sourceline = @locatable; + +case @comment.kind of + 0 = @slashslashcomment +| 1 = @slashstarcomment; + +case @expr.kind of + 0 = @badexpr +| 1 = @ident +| 2 = @ellipsis +| 3 = @intlit +| 4 = @floatlit +| 5 = @imaglit +| 6 = @charlit +| 7 = @stringlit +| 8 = @funclit +| 9 = @compositelit +| 10 = @parenexpr +| 11 = @selectorexpr +| 12 = @indexexpr +| 13 = @sliceexpr +| 14 = @typeassertexpr +| 15 = @callorconversionexpr +| 16 = @starexpr +| 17 = @keyvalueexpr +| 18 = @arraytypeexpr +| 19 = @structtypeexpr +| 20 = @functypeexpr +| 21 = @interfacetypeexpr +| 22 = @maptypeexpr +| 23 = @plusexpr +| 24 = @minusexpr +| 25 = @notexpr +| 26 = @complementexpr +| 27 = @derefexpr +| 28 = @addressexpr +| 29 = @arrowexpr +| 30 = @lorexpr +| 31 = @landexpr +| 32 = @eqlexpr +| 33 = @neqexpr +| 34 = @lssexpr +| 35 = @leqexpr +| 36 = @gtrexpr +| 37 = @geqexpr +| 38 = @addexpr +| 39 = @subexpr +| 40 = @orexpr +| 41 = @xorexpr +| 42 = @mulexpr +| 43 = @quoexpr +| 44 = @remexpr +| 45 = @shlexpr +| 46 = @shrexpr +| 47 = @andexpr +| 48 = @andnotexpr +| 49 = @sendchantypeexpr +| 50 = @recvchantypeexpr +| 51 = @sendrcvchantypeexpr; + +@basiclit = @intlit | @floatlit | @imaglit | @charlit | @stringlit; + +@operatorexpr = @logicalexpr | @arithmeticexpr | @bitwiseexpr | @unaryexpr | @binaryexpr; + +@logicalexpr = @logicalunaryexpr | @logicalbinaryexpr; + +@arithmeticexpr = @arithmeticunaryexpr | @arithmeticbinaryexpr; + +@bitwiseexpr = @bitwiseunaryexpr | @bitwisebinaryexpr; + +@unaryexpr = @logicalunaryexpr | @bitwiseunaryexpr | @arithmeticunaryexpr | @derefexpr | @addressexpr | @arrowexpr; + +@logicalunaryexpr = @notexpr; + +@bitwiseunaryexpr = @complementexpr; + +@arithmeticunaryexpr = @plusexpr | @minusexpr; + +@binaryexpr = @logicalbinaryexpr | @bitwisebinaryexpr | @arithmeticbinaryexpr | @comparison; + +@logicalbinaryexpr = @lorexpr | @landexpr; + +@bitwisebinaryexpr = @shiftexpr | @orexpr | @xorexpr | @andexpr | @andnotexpr; + +@arithmeticbinaryexpr = @addexpr | @subexpr | @mulexpr | @quoexpr | @remexpr; + +@shiftexpr = @shlexpr | @shrexpr; + +@comparison = @equalitytest | @relationalcomparison; + +@equalitytest = @eqlexpr | @neqexpr; + +@relationalcomparison = @lssexpr | @leqexpr | @gtrexpr | @geqexpr; + +@chantypeexpr = @sendchantypeexpr | @recvchantypeexpr | @sendrcvchantypeexpr; + +case @stmt.kind of + 0 = @badstmt +| 1 = @declstmt +| 2 = @emptystmt +| 3 = @labeledstmt +| 4 = @exprstmt +| 5 = @sendstmt +| 6 = @incstmt +| 7 = @decstmt +| 8 = @gostmt +| 9 = @deferstmt +| 10 = @returnstmt +| 11 = @breakstmt +| 12 = @continuestmt +| 13 = @gotostmt +| 14 = @fallthroughstmt +| 15 = @blockstmt +| 16 = @ifstmt +| 17 = @caseclause +| 18 = @exprswitchstmt +| 19 = @typeswitchstmt +| 20 = @commclause +| 21 = @selectstmt +| 22 = @forstmt +| 23 = @rangestmt +| 24 = @assignstmt +| 25 = @definestmt +| 26 = @addassignstmt +| 27 = @subassignstmt +| 28 = @mulassignstmt +| 29 = @quoassignstmt +| 30 = @remassignstmt +| 31 = @andassignstmt +| 32 = @orassignstmt +| 33 = @xorassignstmt +| 34 = @shlassignstmt +| 35 = @shrassignstmt +| 36 = @andnotassignstmt; + +@incdecstmt = @incstmt | @decstmt; + +@assignment = @simpleassignstmt | @compoundassignstmt; + +@simpleassignstmt = @assignstmt | @definestmt; + +@compoundassignstmt = @addassignstmt | @subassignstmt | @mulassignstmt | @quoassignstmt | @remassignstmt + | @andassignstmt | @orassignstmt | @xorassignstmt | @shlassignstmt | @shrassignstmt | @andnotassignstmt; + +@branchstmt = @breakstmt | @continuestmt | @gotostmt | @fallthroughstmt; + +@switchstmt = @exprswitchstmt | @typeswitchstmt; + +@loopstmt = @forstmt | @rangestmt; + +case @decl.kind of + 0 = @baddecl +| 1 = @importdecl +| 2 = @constdecl +| 3 = @typedecl +| 4 = @vardecl +| 5 = @funcdecl; + +@gendecl = @importdecl | @constdecl | @typedecl | @vardecl; + +case @spec.kind of + 0 = @importspec +| 1 = @valuespec +| 2 = @typedefspec +| 3 = @aliasspec; + +@typespec = @typedefspec | @aliasspec; + +case @object.kind of + 0 = @pkgobject +| 1 = @decltypeobject +| 2 = @builtintypeobject +| 3 = @declconstobject +| 4 = @builtinconstobject +| 5 = @declvarobject +| 6 = @declfunctionobject +| 7 = @builtinfunctionobject +| 8 = @labelobject; + +@declobject = @decltypeobject | @declconstobject | @declvarobject | @declfunctionobject; + +@builtinobject = @builtintypeobject | @builtinconstobject | @builtinfunctionobject; + +@typeobject = @decltypeobject | @builtintypeobject; + +@valueobject = @constobject | @varobject | @functionobject; + +@constobject = @declconstobject | @builtinconstobject; + +@varobject = @declvarobject; + +@functionobject = @declfunctionobject | @builtinfunctionobject; + +case @scope.kind of + 0 = @universescope +| 1 = @packagescope +| 2 = @localscope; + +case @type.kind of + 0 = @invalidtype +| 1 = @boolexprtype +| 2 = @inttype +| 3 = @int8type +| 4 = @int16type +| 5 = @int32type +| 6 = @int64type +| 7 = @uinttype +| 8 = @uint8type +| 9 = @uint16type +| 10 = @uint32type +| 11 = @uint64type +| 12 = @uintptrtype +| 13 = @float32type +| 14 = @float64type +| 15 = @complex64type +| 16 = @complex128type +| 17 = @stringexprtype +| 18 = @unsafepointertype +| 19 = @boolliteraltype +| 20 = @intliteraltype +| 21 = @runeliteraltype +| 22 = @floatliteraltype +| 23 = @complexliteraltype +| 24 = @stringliteraltype +| 25 = @nilliteraltype +| 26 = @arraytype +| 27 = @slicetype +| 28 = @structtype +| 29 = @pointertype +| 30 = @interfacetype +| 31 = @tupletype +| 32 = @signaturetype +| 33 = @maptype +| 34 = @sendchantype +| 35 = @recvchantype +| 36 = @sendrcvchantype +| 37 = @namedtype; + +@basictype = @booltype | @numerictype | @stringtype | @literaltype | @invalidtype | @unsafepointertype; + +@booltype = @boolexprtype | @boolliteraltype; + +@numerictype = @integertype | @floattype | @complextype; + +@integertype = @signedintegertype | @unsignedintegertype; + +@signedintegertype = @inttype | @int8type | @int16type | @int32type | @int64type | @intliteraltype | @runeliteraltype; + +@unsignedintegertype = @uinttype | @uint8type | @uint16type | @uint32type | @uint64type | @uintptrtype; + +@floattype = @float32type | @float64type | @floatliteraltype; + +@complextype = @complex64type | @complex128type | @complexliteraltype; + +@stringtype = @stringexprtype | @stringliteraltype; + +@literaltype = @boolliteraltype | @intliteraltype | @runeliteraltype | @floatliteraltype | @complexliteraltype + | @stringliteraltype | @nilliteraltype; + +@compositetype = @containertype | @structtype | @pointertype | @interfacetype | @tupletype | @signaturetype | @namedtype; + +@containertype = @arraytype | @slicetype | @maptype | @chantype; + +@chantype = @sendchantype | @recvchantype | @sendrcvchantype; + +case @modexpr.kind of + 0 = @modcommentblock +| 1 = @modline +| 2 = @modlineblock +| 3 = @modlparen +| 4 = @modrparen; + +case @error.kind of + 0 = @unknownerror +| 1 = @listerror +| 2 = @parseerror +| 3 = @typeerror; + diff --git a/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/upgrade.properties b/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/upgrade.properties new file mode 100644 index 00000000000..71f3ee178e5 --- /dev/null +++ b/upgrades/b37faf5d62cccefad9fcfd8f5c026620097b2355/upgrade.properties @@ -0,0 +1,4 @@ +description: Removed unused column from the `folders` and `files` relations +compatibility: full +files.rel: reorder files.rel (int id, string name, string simple, string ext, int fromSource) id name +folders.rel: reorder folders.rel (int id, string name, string simple) id name diff --git a/vendor/golang.org/x/mod/modfile/read.go b/vendor/golang.org/x/mod/modfile/read.go index c1f2008ee4c..956f30cbb39 100644 --- a/vendor/golang.org/x/mod/modfile/read.go +++ b/vendor/golang.org/x/mod/modfile/read.go @@ -194,12 +194,15 @@ func (x *FileSyntax) updateLine(line *Line, tokens ...string) { line.Token = tokens } -func (x *FileSyntax) removeLine(line *Line) { +// markRemoved modifies line so that it (and its end-of-line comment, if any) +// will be dropped by (*FileSyntax).Cleanup. +func (line *Line) markRemoved() { line.Token = nil + line.Comments.Suffix = nil } // Cleanup cleans up the file syntax x after any edit operations. -// To avoid quadratic behavior, removeLine marks the line as dead +// To avoid quadratic behavior, (*Line).markRemoved marks the line as dead // by setting line.Token = nil but does not remove it from the slice // in which it appears. After edits have all been indicated, // calling Cleanup cleans out the dead lines. @@ -477,9 +480,17 @@ func (in *input) startToken() { // endToken marks the end of an input token. // It records the actual token string in tok.text. +// A single trailing newline (LF or CRLF) will be removed from comment tokens. func (in *input) endToken(kind tokenKind) { in.token.kind = kind text := string(in.tokenStart[:len(in.tokenStart)-len(in.remaining)]) + if kind.isComment() { + if strings.HasSuffix(text, "\r\n") { + text = text[:len(text)-2] + } else { + text = strings.TrimSuffix(text, "\n") + } + } in.token.text = text in.token.endPos = in.pos } diff --git a/vendor/golang.org/x/mod/modfile/rule.go b/vendor/golang.org/x/mod/modfile/rule.go index 91ca6828df0..78f83fa7144 100644 --- a/vendor/golang.org/x/mod/modfile/rule.go +++ b/vendor/golang.org/x/mod/modfile/rule.go @@ -30,6 +30,7 @@ import ( "golang.org/x/mod/internal/lazyregexp" "golang.org/x/mod/module" + "golang.org/x/mod/semver" ) // A File is the parsed, interpreted form of a go.mod file. @@ -39,14 +40,16 @@ type File struct { Require []*Require Exclude []*Exclude Replace []*Replace + Retract []*Retract Syntax *FileSyntax } // A Module is the module statement. type Module struct { - Mod module.Version - Syntax *Line + Mod module.Version + Deprecated string + Syntax *Line } // A Go is the go statement. @@ -55,13 +58,6 @@ type Go struct { Syntax *Line } -// A Require is a single require statement. -type Require struct { - Mod module.Version - Indirect bool // has "// indirect" comment - Syntax *Line -} - // An Exclude is a single exclude statement. type Exclude struct { Mod module.Version @@ -75,6 +71,108 @@ type Replace struct { Syntax *Line } +// A Retract is a single retract statement. +type Retract struct { + VersionInterval + Rationale string + Syntax *Line +} + +// A VersionInterval represents a range of versions with upper and lower bounds. +// Intervals are closed: both bounds are included. When Low is equal to High, +// the interval may refer to a single version ('v1.2.3') or an interval +// ('[v1.2.3, v1.2.3]'); both have the same representation. +type VersionInterval struct { + Low, High string +} + +// A Require is a single require statement. +type Require struct { + Mod module.Version + Indirect bool // has "// indirect" comment + Syntax *Line +} + +func (r *Require) markRemoved() { + r.Syntax.markRemoved() + *r = Require{} +} + +func (r *Require) setVersion(v string) { + r.Mod.Version = v + + if line := r.Syntax; len(line.Token) > 0 { + if line.InBlock { + // If the line is preceded by an empty line, remove it; see + // https://golang.org/issue/33779. + if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 { + line.Comments.Before = line.Comments.Before[:0] + } + if len(line.Token) >= 2 { // example.com v1.2.3 + line.Token[1] = v + } + } else { + if len(line.Token) >= 3 { // require example.com v1.2.3 + line.Token[2] = v + } + } + } +} + +// setIndirect sets line to have (or not have) a "// indirect" comment. +func (r *Require) setIndirect(indirect bool) { + r.Indirect = indirect + line := r.Syntax + if isIndirect(line) == indirect { + return + } + if indirect { + // Adding comment. + if len(line.Suffix) == 0 { + // New comment. + line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} + return + } + + com := &line.Suffix[0] + text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash))) + if text == "" { + // Empty comment. + com.Token = "// indirect" + return + } + + // Insert at beginning of existing comment. + com.Token = "// indirect; " + text + return + } + + // Removing comment. + f := strings.TrimSpace(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) + if f == "indirect" { + // Remove whole comment. + line.Suffix = nil + return + } + + // Remove comment prefix. + com := &line.Suffix[0] + i := strings.Index(com.Token, "indirect;") + com.Token = "//" + com.Token[i+len("indirect;"):] +} + +// isIndirect reports whether line has a "// indirect" comment, +// meaning it is in go.mod only for its effect on indirect dependencies, +// so that it can be dropped entirely once the effective version of the +// indirect dependency reaches the given minimum version. +func isIndirect(line *Line) bool { + if len(line.Suffix) == 0 { + return false + } + f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) + return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;") +} + func (f *File) AddModuleStmt(path string) error { if f.Syntax == nil { f.Syntax = new(FileSyntax) @@ -108,8 +206,21 @@ func (f *File) AddComment(text string) { type VersionFixer func(path, version string) (string, error) -// Parse parses the data, reported in errors as being from file, -// into a File struct. It applies fix, if non-nil, to canonicalize all module versions found. +// errDontFix is returned by a VersionFixer to indicate the version should be +// left alone, even if it's not canonical. +var dontFixRetract VersionFixer = func(_, vers string) (string, error) { + return vers, nil +} + +// Parse parses and returns a go.mod file. +// +// file is the name of the file, used in positions and errors. +// +// data is the content of the file. +// +// fix is an optional function that canonicalizes module versions. +// If fix is nil, all module versions must be canonical (module.CanonicalVersion +// must return the same string). func Parse(file string, data []byte, fix VersionFixer) (*File, error) { return parseToFile(file, data, fix, true) } @@ -125,7 +236,7 @@ func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) { return parseToFile(file, data, fix, false) } -func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) { +func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (parsed *File, err error) { fs, err := parse(file, data) if err != nil { return nil, err @@ -133,12 +244,22 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File f := &File{ Syntax: fs, } - var errs ErrorList + + // fix versions in retract directives after the file is parsed. + // We need the module path to fix versions, and it might be at the end. + defer func() { + oldLen := len(errs) + f.fixRetract(fix, &errs) + if len(errs) > oldLen { + parsed, err = nil, errs + } + }() + for _, x := range fs.Stmt { switch x := x.(type) { case *Line: - f.add(&errs, x, x.Token[0], x.Token[1:], fix, strict) + f.add(&errs, nil, x, x.Token[0], x.Token[1:], fix, strict) case *LineBlock: if len(x.Token) > 1 { @@ -161,9 +282,9 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File }) } continue - case "module", "require", "exclude", "replace": + case "module", "require", "exclude", "replace", "retract": for _, l := range x.Line { - f.add(&errs, l, x.Token[0], l.Token, fix, strict) + f.add(&errs, x, l, x.Token[0], l.Token, fix, strict) } } } @@ -176,8 +297,9 @@ func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File } var GoVersionRE = lazyregexp.New(`^([1-9][0-9]*)\.(0|[1-9][0-9]*)$`) +var laxGoVersionRE = lazyregexp.New(`^v?(([1-9][0-9]*)\.(0|[1-9][0-9]*))([^0-9].*)$`) -func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix VersionFixer, strict bool) { +func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, args []string, fix VersionFixer, strict bool) { // If strict is false, this module is a dependency. // We ignore all unknown directives as well as main-module-only // directives like replace and exclude. It will work better for @@ -186,7 +308,7 @@ func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix // and simply ignore those statements. if !strict { switch verb { - case "module", "require", "go": + case "go", "module", "retract", "require": // want these even for dependency go.mods default: return @@ -226,18 +348,32 @@ func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix errorf("go directive expects exactly one argument") return } else if !GoVersionRE.MatchString(args[0]) { - errorf("invalid go version '%s': must match format 1.23", args[0]) - return + fixed := false + if !strict { + if m := laxGoVersionRE.FindStringSubmatch(args[0]); m != nil { + args[0] = m[1] + fixed = true + } + } + if !fixed { + errorf("invalid go version '%s': must match format 1.23", args[0]) + return + } } f.Go = &Go{Syntax: line} f.Go.Version = args[0] + case "module": if f.Module != nil { errorf("repeated module statement") return } - f.Module = &Module{Syntax: line} + deprecated := parseDeprecation(block, line) + f.Module = &Module{ + Syntax: line, + Deprecated: deprecated, + } if len(args) != 1 { errorf("usage: module module/path") return @@ -248,6 +384,7 @@ func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix return } f.Module.Mod = module.Version{Path: s} + case "require", "exclude": if len(args) != 2 { errorf("usage: %s module/path v1.2.3", verb) @@ -284,6 +421,7 @@ func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix Syntax: line, }) } + case "replace": arrow := 2 if len(args) >= 2 && args[1] == "=>" { @@ -347,59 +485,75 @@ func (f *File) add(errs *ErrorList, line *Line, verb string, args []string, fix New: module.Version{Path: ns, Version: nv}, Syntax: line, }) + + case "retract": + rationale := parseDirectiveComment(block, line) + vi, err := parseVersionInterval(verb, "", &args, dontFixRetract) + if err != nil { + if strict { + wrapError(err) + return + } else { + // Only report errors parsing intervals in the main module. We may + // support additional syntax in the future, such as open and half-open + // intervals. Those can't be supported now, because they break the + // go.mod parser, even in lax mode. + return + } + } + if len(args) > 0 && strict { + // In the future, there may be additional information after the version. + errorf("unexpected token after version: %q", args[0]) + return + } + retract := &Retract{ + VersionInterval: vi, + Rationale: rationale, + Syntax: line, + } + f.Retract = append(f.Retract, retract) } } -// isIndirect reports whether line has a "// indirect" comment, -// meaning it is in go.mod only for its effect on indirect dependencies, -// so that it can be dropped entirely once the effective version of the -// indirect dependency reaches the given minimum version. -func isIndirect(line *Line) bool { - if len(line.Suffix) == 0 { - return false - } - f := strings.Fields(strings.TrimPrefix(line.Suffix[0].Token, string(slashSlash))) - return (len(f) == 1 && f[0] == "indirect" || len(f) > 1 && f[0] == "indirect;") -} - -// setIndirect sets line to have (or not have) a "// indirect" comment. -func setIndirect(line *Line, indirect bool) { - if isIndirect(line) == indirect { +// fixRetract applies fix to each retract directive in f, appending any errors +// to errs. +// +// Most versions are fixed as we parse the file, but for retract directives, +// the relevant module path is the one specified with the module directive, +// and that might appear at the end of the file (or not at all). +func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) { + if fix == nil { return } - if indirect { - // Adding comment. - if len(line.Suffix) == 0 { - // New comment. - line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} - return + path := "" + if f.Module != nil { + path = f.Module.Mod.Path + } + var r *Retract + wrapError := func(err error) { + *errs = append(*errs, Error{ + Filename: f.Syntax.Name, + Pos: r.Syntax.Start, + Err: err, + }) + } + + for _, r = range f.Retract { + if path == "" { + wrapError(errors.New("no module directive found, so retract cannot be used")) + return // only print the first one of these } - com := &line.Suffix[0] - text := strings.TrimSpace(strings.TrimPrefix(com.Token, string(slashSlash))) - if text == "" { - // Empty comment. - com.Token = "// indirect" - return + args := r.Syntax.Token + if args[0] == "retract" { + args = args[1:] } - - // Insert at beginning of existing comment. - com.Token = "// indirect; " + text - return + vi, err := parseVersionInterval("retract", path, &args, fix) + if err != nil { + wrapError(err) + } + r.VersionInterval = vi } - - // Removing comment. - f := strings.Fields(line.Suffix[0].Token) - if len(f) == 2 { - // Remove whole comment. - line.Suffix = nil - return - } - - // Remove comment prefix. - com := &line.Suffix[0] - i := strings.Index(com.Token, "indirect;") - com.Token = "//" + com.Token[i+len("indirect;"):] } // IsDirectoryPath reports whether the given path should be interpreted @@ -444,6 +598,53 @@ func AutoQuote(s string) string { return s } +func parseVersionInterval(verb string, path string, args *[]string, fix VersionFixer) (VersionInterval, error) { + toks := *args + if len(toks) == 0 || toks[0] == "(" { + return VersionInterval{}, fmt.Errorf("expected '[' or version") + } + if toks[0] != "[" { + v, err := parseVersion(verb, path, &toks[0], fix) + if err != nil { + return VersionInterval{}, err + } + *args = toks[1:] + return VersionInterval{Low: v, High: v}, nil + } + toks = toks[1:] + + if len(toks) == 0 { + return VersionInterval{}, fmt.Errorf("expected version after '['") + } + low, err := parseVersion(verb, path, &toks[0], fix) + if err != nil { + return VersionInterval{}, err + } + toks = toks[1:] + + if len(toks) == 0 || toks[0] != "," { + return VersionInterval{}, fmt.Errorf("expected ',' after version") + } + toks = toks[1:] + + if len(toks) == 0 { + return VersionInterval{}, fmt.Errorf("expected version after ','") + } + high, err := parseVersion(verb, path, &toks[0], fix) + if err != nil { + return VersionInterval{}, err + } + toks = toks[1:] + + if len(toks) == 0 || toks[0] != "]" { + return VersionInterval{}, fmt.Errorf("expected ']' after version") + } + toks = toks[1:] + + *args = toks + return VersionInterval{Low: low, High: high}, nil +} + func parseString(s *string) (string, error) { t := *s if strings.HasPrefix(t, `"`) { @@ -461,6 +662,46 @@ func parseString(s *string) (string, error) { return t, nil } +var deprecatedRE = lazyregexp.New(`(?s)(?:^|\n\n)Deprecated: *(.*?)(?:$|\n\n)`) + +// parseDeprecation extracts the text of comments on a "module" directive and +// extracts a deprecation message from that. +// +// A deprecation message is contained in a paragraph within a block of comments +// that starts with "Deprecated:" (case sensitive). The message runs until the +// end of the paragraph and does not include the "Deprecated:" prefix. If the +// comment block has multiple paragraphs that start with "Deprecated:", +// parseDeprecation returns the message from the first. +func parseDeprecation(block *LineBlock, line *Line) string { + text := parseDirectiveComment(block, line) + m := deprecatedRE.FindStringSubmatch(text) + if m == nil { + return "" + } + return m[1] +} + +// parseDirectiveComment extracts the text of comments on a directive. +// If the directive's line does not have comments and is part of a block that +// does have comments, the block's comments are used. +func parseDirectiveComment(block *LineBlock, line *Line) string { + comments := line.Comment() + if block != nil && len(comments.Before) == 0 && len(comments.Suffix) == 0 { + comments = block.Comment() + } + groups := [][]Comment{comments.Before, comments.Suffix} + var lines []string + for _, g := range groups { + for _, c := range g { + if !strings.HasPrefix(c.Token, "//") { + continue // blank line + } + lines = append(lines, strings.TrimSpace(strings.TrimPrefix(c.Token, "//"))) + } + } + return strings.Join(lines, "\n") +} + type ErrorList []Error func (e ErrorList) Error() string { @@ -494,6 +735,8 @@ func (e *Error) Error() string { var directive string if e.ModPath != "" { directive = fmt.Sprintf("%s %s: ", e.Verb, e.ModPath) + } else if e.Verb != "" { + directive = fmt.Sprintf("%s: ", e.Verb) } return pos + directive + e.Err.Error() @@ -514,8 +757,7 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string } } if fix != nil { - var err error - t, err = fix(path, t) + fixed, err := fix(path, t) if err != nil { if err, ok := err.(*module.ModuleError); ok { return "", &Error{ @@ -526,19 +768,23 @@ func parseVersion(verb string, path string, s *string, fix VersionFixer) (string } return "", err } + t = fixed + } else { + cv := module.CanonicalVersion(t) + if cv == "" { + return "", &Error{ + Verb: verb, + ModPath: path, + Err: &module.InvalidVersionError{ + Version: t, + Err: errors.New("must be of the form v1.2.3"), + }, + } + } + t = cv } - if v := module.CanonicalVersion(t); v != "" { - *s = v - return *s, nil - } - return "", &Error{ - Verb: verb, - ModPath: path, - Err: &module.InvalidVersionError{ - Version: t, - Err: errors.New("must be of the form v1.2.3"), - }, - } + *s = t + return *s, nil } func modulePathMajor(path string) (string, error) { @@ -585,6 +831,15 @@ func (f *File) Cleanup() { } f.Replace = f.Replace[:w] + w = 0 + for _, r := range f.Retract { + if r.Low != "" || r.High != "" { + f.Retract[w] = r + w++ + } + } + f.Retract = f.Retract[:w] + f.Syntax.Cleanup() } @@ -608,6 +863,12 @@ func (f *File) AddGoStmt(version string) error { return nil } +// AddRequire sets the first require line for path to version vers, +// preserving any existing comments for that line and removing all +// other lines for path. +// +// If no line currently exists for path, AddRequire adds a new line +// at the end of the last require block. func (f *File) AddRequire(path, vers string) error { need := true for _, r := range f.Require { @@ -617,7 +878,7 @@ func (f *File) AddRequire(path, vers string) error { f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers) need = false } else { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Require{} } } @@ -629,69 +890,235 @@ func (f *File) AddRequire(path, vers string) error { return nil } +// AddNewRequire adds a new require line for path at version vers at the end of +// the last require block, regardless of any existing require lines for path. func (f *File) AddNewRequire(path, vers string, indirect bool) { line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers) - setIndirect(line, indirect) - f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line}) + r := &Require{ + Mod: module.Version{Path: path, Version: vers}, + Syntax: line, + } + r.setIndirect(indirect) + f.Require = append(f.Require, r) } +// SetRequire updates the requirements of f to contain exactly req, preserving +// the existing block structure and line comment contents (except for 'indirect' +// markings) for the first requirement on each named module path. +// +// The Syntax field is ignored for the requirements in req. +// +// Any requirements not already present in the file are added to the block +// containing the last require line. +// +// The requirements in req must specify at most one distinct version for each +// module path. +// +// If any existing requirements may be removed, the caller should call Cleanup +// after all edits are complete. func (f *File) SetRequire(req []*Require) { - need := make(map[string]string) - indirect := make(map[string]bool) + type elem struct { + version string + indirect bool + } + need := make(map[string]elem) for _, r := range req { - need[r.Mod.Path] = r.Mod.Version - indirect[r.Mod.Path] = r.Indirect - } - - for _, r := range f.Require { - if v, ok := need[r.Mod.Path]; ok { - r.Mod.Version = v - r.Indirect = indirect[r.Mod.Path] - } else { - *r = Require{} + if prev, dup := need[r.Mod.Path]; dup && prev.version != r.Mod.Version { + panic(fmt.Errorf("SetRequire called with conflicting versions for path %s (%s and %s)", r.Mod.Path, prev.version, r.Mod.Version)) } + need[r.Mod.Path] = elem{r.Mod.Version, r.Indirect} } - var newStmts []Expr + // Update or delete the existing Require entries to preserve + // only the first for each module path in req. + for _, r := range f.Require { + e, ok := need[r.Mod.Path] + if ok { + r.setVersion(e.version) + r.setIndirect(e.indirect) + } else { + r.markRemoved() + } + delete(need, r.Mod.Path) + } + + // Add new entries in the last block of the file for any paths that weren't + // already present. + // + // This step is nondeterministic, but the final result will be deterministic + // because we will sort the block. + for path, e := range need { + f.AddNewRequire(path, e.version, e.indirect) + } + + f.SortBlocks() +} + +// SetRequireSeparateIndirect updates the requirements of f to contain the given +// requirements. Comment contents (except for 'indirect' markings) are retained +// from the first existing requirement for each module path, and block structure +// is maintained as long as the indirect markings match. +// +// Any requirements on paths not already present in the file are added. Direct +// requirements are added to the last block containing *any* other direct +// requirement. Indirect requirements are added to the last block containing +// *only* other indirect requirements. If no suitable block exists, a new one is +// added, with the last block containing a direct dependency (if any) +// immediately before the first block containing only indirect dependencies. +// +// The Syntax field is ignored for requirements in the given blocks. +func (f *File) SetRequireSeparateIndirect(req []*Require) { + type modKey struct { + path string + indirect bool + } + need := make(map[modKey]string) + for _, r := range req { + need[modKey{r.Mod.Path, r.Indirect}] = r.Mod.Version + } + + comments := make(map[string]Comments) + for _, r := range f.Require { + v, ok := need[modKey{r.Mod.Path, r.Indirect}] + if !ok { + if _, ok := need[modKey{r.Mod.Path, !r.Indirect}]; ok { + if _, dup := comments[r.Mod.Path]; !dup { + comments[r.Mod.Path] = r.Syntax.Comments + } + } + r.markRemoved() + continue + } + r.setVersion(v) + delete(need, modKey{r.Mod.Path, r.Indirect}) + } + + var ( + lastDirectOrMixedBlock Expr + firstIndirectOnlyBlock Expr + lastIndirectOnlyBlock Expr + ) for _, stmt := range f.Syntax.Stmt { switch stmt := stmt.(type) { - case *LineBlock: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - var newLines []*Line - for _, line := range stmt.Line { - if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" { - if len(line.Comments.Before) == 1 && len(line.Comments.Before[0].Token) == 0 { - line.Comments.Before = line.Comments.Before[:0] - } - line.Token[1] = need[p] - delete(need, p) - setIndirect(line, indirect[p]) - newLines = append(newLines, line) - } - } - if len(newLines) == 0 { - continue // drop stmt - } - stmt.Line = newLines - } - case *Line: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" { - stmt.Token[2] = need[p] - delete(need, p) - setIndirect(stmt, indirect[p]) - } else { - continue // drop stmt + if len(stmt.Token) == 0 || stmt.Token[0] != "require" { + continue + } + if isIndirect(stmt) { + lastIndirectOnlyBlock = stmt + } else { + lastDirectOrMixedBlock = stmt + } + case *LineBlock: + if len(stmt.Token) == 0 || stmt.Token[0] != "require" { + continue + } + indirectOnly := true + for _, line := range stmt.Line { + if len(line.Token) == 0 { + continue + } + if !isIndirect(line) { + indirectOnly = false + break + } + } + if indirectOnly { + lastIndirectOnlyBlock = stmt + if firstIndirectOnlyBlock == nil { + firstIndirectOnlyBlock = stmt + } + } else { + lastDirectOrMixedBlock = stmt + } + } + } + + isOrContainsStmt := func(stmt Expr, target Expr) bool { + if stmt == target { + return true + } + if stmt, ok := stmt.(*LineBlock); ok { + if target, ok := target.(*Line); ok { + for _, line := range stmt.Line { + if line == target { + return true + } } } } - newStmts = append(newStmts, stmt) + return false } - f.Syntax.Stmt = newStmts - for path, vers := range need { - f.AddNewRequire(path, vers, indirect[path]) + addRequire := func(path, vers string, indirect bool, comments Comments) { + var line *Line + if indirect { + if lastIndirectOnlyBlock != nil { + line = f.Syntax.addLine(lastIndirectOnlyBlock, "require", path, vers) + } else { + // Add a new require block after the last direct-only or mixed "require" + // block (if any). + // + // (f.Syntax.addLine would add the line to an existing "require" block if + // present, but here the existing "require" blocks are all direct-only, so + // we know we need to add a new block instead.) + line = &Line{Token: []string{"require", path, vers}} + lastIndirectOnlyBlock = line + firstIndirectOnlyBlock = line // only block implies first block + if lastDirectOrMixedBlock == nil { + f.Syntax.Stmt = append(f.Syntax.Stmt, line) + } else { + for i, stmt := range f.Syntax.Stmt { + if isOrContainsStmt(stmt, lastDirectOrMixedBlock) { + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size + copy(f.Syntax.Stmt[i+2:], f.Syntax.Stmt[i+1:]) // shuffle elements up + f.Syntax.Stmt[i+1] = line + break + } + } + } + } + } else { + if lastDirectOrMixedBlock != nil { + line = f.Syntax.addLine(lastDirectOrMixedBlock, "require", path, vers) + } else { + // Add a new require block before the first indirect block (if any). + // + // That way if the file initially contains only indirect lines, + // the direct lines still appear before it: we preserve existing + // structure, but only to the extent that that structure already + // reflects the direct/indirect split. + line = &Line{Token: []string{"require", path, vers}} + lastDirectOrMixedBlock = line + if firstIndirectOnlyBlock == nil { + f.Syntax.Stmt = append(f.Syntax.Stmt, line) + } else { + for i, stmt := range f.Syntax.Stmt { + if isOrContainsStmt(stmt, firstIndirectOnlyBlock) { + f.Syntax.Stmt = append(f.Syntax.Stmt, nil) // increase size + copy(f.Syntax.Stmt[i+1:], f.Syntax.Stmt[i:]) // shuffle elements up + f.Syntax.Stmt[i] = line + break + } + } + } + } + } + + line.Comments.Before = commentsAdd(line.Comments.Before, comments.Before) + line.Comments.Suffix = commentsAdd(line.Comments.Suffix, comments.Suffix) + + r := &Require{ + Mod: module.Version{Path: path, Version: vers}, + Indirect: indirect, + Syntax: line, + } + r.setIndirect(indirect) + f.Require = append(f.Require, r) + } + + for k, vers := range need { + addRequire(k.path, vers, k.indirect, comments[k.path]) } f.SortBlocks() } @@ -699,14 +1126,20 @@ func (f *File) SetRequire(req []*Require) { func (f *File) DropRequire(path string) error { for _, r := range f.Require { if r.Mod.Path == path { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Require{} } } return nil } +// AddExclude adds a exclude statement to the mod file. Errors if the provided +// version is not a canonical version string func (f *File) AddExclude(path, vers string) error { + if err := checkCanonicalVersion(path, vers); err != nil { + return err + } + var hint *Line for _, x := range f.Exclude { if x.Mod.Path == path && x.Mod.Version == vers { @@ -724,7 +1157,7 @@ func (f *File) AddExclude(path, vers string) error { func (f *File) DropExclude(path, vers string) error { for _, x := range f.Exclude { if x.Mod.Path == path && x.Mod.Version == vers { - f.Syntax.removeLine(x.Syntax) + x.Syntax.markRemoved() *x = Exclude{} } } @@ -755,7 +1188,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { continue } // Already added; delete other replacements for same. - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Replace{} } if r.Old.Path == oldPath { @@ -771,13 +1204,54 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { func (f *File) DropReplace(oldPath, oldVers string) error { for _, r := range f.Replace { if r.Old.Path == oldPath && r.Old.Version == oldVers { - f.Syntax.removeLine(r.Syntax) + r.Syntax.markRemoved() *r = Replace{} } } return nil } +// AddRetract adds a retract statement to the mod file. Errors if the provided +// version interval does not consist of canonical version strings +func (f *File) AddRetract(vi VersionInterval, rationale string) error { + var path string + if f.Module != nil { + path = f.Module.Mod.Path + } + if err := checkCanonicalVersion(path, vi.High); err != nil { + return err + } + if err := checkCanonicalVersion(path, vi.Low); err != nil { + return err + } + + r := &Retract{ + VersionInterval: vi, + } + if vi.Low == vi.High { + r.Syntax = f.Syntax.addLine(nil, "retract", AutoQuote(vi.Low)) + } else { + r.Syntax = f.Syntax.addLine(nil, "retract", "[", AutoQuote(vi.Low), ",", AutoQuote(vi.High), "]") + } + if rationale != "" { + for _, line := range strings.Split(rationale, "\n") { + com := Comment{Token: "// " + line} + r.Syntax.Comment().Before = append(r.Syntax.Comment().Before, com) + } + } + return nil +} + +func (f *File) DropRetract(vi VersionInterval) error { + for _, r := range f.Retract { + if r.VersionInterval == vi { + r.Syntax.markRemoved() + *r = Retract{} + } + } + return nil +} + func (f *File) SortBlocks() { f.removeDups() // otherwise sorting is unsafe @@ -786,28 +1260,38 @@ func (f *File) SortBlocks() { if !ok { continue } - sort.Slice(block.Line, func(i, j int) bool { - li := block.Line[i] - lj := block.Line[j] - for k := 0; k < len(li.Token) && k < len(lj.Token); k++ { - if li.Token[k] != lj.Token[k] { - return li.Token[k] < lj.Token[k] - } - } - return len(li.Token) < len(lj.Token) + less := lineLess + if block.Token[0] == "retract" { + less = lineRetractLess + } + sort.SliceStable(block.Line, func(i, j int) bool { + return less(block.Line[i], block.Line[j]) }) } } +// removeDups removes duplicate exclude and replace directives. +// +// Earlier exclude directives take priority. +// +// Later replace directives take priority. +// +// require directives are not de-duplicated. That's left up to higher-level +// logic (MVS). +// +// retract directives are not de-duplicated since comments are +// meaningful, and versions may be retracted multiple times. func (f *File) removeDups() { - have := make(map[module.Version]bool) kill := make(map[*Line]bool) + + // Remove duplicate excludes. + haveExclude := make(map[module.Version]bool) for _, x := range f.Exclude { - if have[x.Mod] { + if haveExclude[x.Mod] { kill[x.Syntax] = true continue } - have[x.Mod] = true + haveExclude[x.Mod] = true } var excl []*Exclude for _, x := range f.Exclude { @@ -817,15 +1301,16 @@ func (f *File) removeDups() { } f.Exclude = excl - have = make(map[module.Version]bool) + // Remove duplicate replacements. // Later replacements take priority over earlier ones. + haveReplace := make(map[module.Version]bool) for i := len(f.Replace) - 1; i >= 0; i-- { x := f.Replace[i] - if have[x.Old] { + if haveReplace[x.Old] { kill[x.Syntax] = true continue } - have[x.Old] = true + haveReplace[x.Old] = true } var repl []*Replace for _, x := range f.Replace { @@ -835,6 +1320,9 @@ func (f *File) removeDups() { } f.Replace = repl + // Duplicate require and retract directives are not removed. + + // Drop killed statements from the syntax tree. var stmts []Expr for _, stmt := range f.Syntax.Stmt { switch stmt := stmt.(type) { @@ -858,3 +1346,76 @@ func (f *File) removeDups() { } f.Syntax.Stmt = stmts } + +// lineLess returns whether li should be sorted before lj. It sorts +// lexicographically without assigning any special meaning to tokens. +func lineLess(li, lj *Line) bool { + for k := 0; k < len(li.Token) && k < len(lj.Token); k++ { + if li.Token[k] != lj.Token[k] { + return li.Token[k] < lj.Token[k] + } + } + return len(li.Token) < len(lj.Token) +} + +// lineRetractLess returns whether li should be sorted before lj for lines in +// a "retract" block. It treats each line as a version interval. Single versions +// are compared as if they were intervals with the same low and high version. +// Intervals are sorted in descending order, first by low version, then by +// high version, using semver.Compare. +func lineRetractLess(li, lj *Line) bool { + interval := func(l *Line) VersionInterval { + if len(l.Token) == 1 { + return VersionInterval{Low: l.Token[0], High: l.Token[0]} + } else if len(l.Token) == 5 && l.Token[0] == "[" && l.Token[2] == "," && l.Token[4] == "]" { + return VersionInterval{Low: l.Token[1], High: l.Token[3]} + } else { + // Line in unknown format. Treat as an invalid version. + return VersionInterval{} + } + } + vii := interval(li) + vij := interval(lj) + if cmp := semver.Compare(vii.Low, vij.Low); cmp != 0 { + return cmp > 0 + } + return semver.Compare(vii.High, vij.High) > 0 +} + +// checkCanonicalVersion returns a non-nil error if vers is not a canonical +// version string or does not match the major version of path. +// +// If path is non-empty, the error text suggests a format with a major version +// corresponding to the path. +func checkCanonicalVersion(path, vers string) error { + _, pathMajor, pathMajorOk := module.SplitPathVersion(path) + + if vers == "" || vers != module.CanonicalVersion(vers) { + if pathMajor == "" { + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("must be of the form v1.2.3"), + } + } + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("must be of the form %s.2.3", module.PathMajorPrefix(pathMajor)), + } + } + + if pathMajorOk { + if err := module.CheckPathMajor(vers, pathMajor); err != nil { + if pathMajor == "" { + // In this context, the user probably wrote "v2.3.4" when they meant + // "v2.3.4+incompatible". Suggest that instead of "v0 or v1". + return &module.InvalidVersionError{ + Version: vers, + Err: fmt.Errorf("should be %s+incompatible (or module %s/%v)", vers, path, semver.Major(vers)), + } + } + return err + } + } + + return nil +} diff --git a/vendor/golang.org/x/mod/module/module.go b/vendor/golang.org/x/mod/module/module.go index 6cd37280a85..ba97ac356e9 100644 --- a/vendor/golang.org/x/mod/module/module.go +++ b/vendor/golang.org/x/mod/module/module.go @@ -97,6 +97,7 @@ package module import ( "fmt" + "path" "sort" "strings" "unicode" @@ -191,6 +192,21 @@ func (e *InvalidVersionError) Error() string { func (e *InvalidVersionError) Unwrap() error { return e.Err } +// An InvalidPathError indicates a module, import, or file path doesn't +// satisfy all naming constraints. See CheckPath, CheckImportPath, +// and CheckFilePath for specific restrictions. +type InvalidPathError struct { + Kind string // "module", "import", or "file" + Path string + Err error +} + +func (e *InvalidPathError) Error() string { + return fmt.Sprintf("malformed %s path %q: %v", e.Kind, e.Path, e.Err) +} + +func (e *InvalidPathError) Unwrap() error { return e.Err } + // Check checks that a given module path, version pair is valid. // In addition to the path being a valid module path // and the version being a valid semantic version, @@ -223,14 +239,18 @@ func firstPathOK(r rune) bool { 'a' <= r && r <= 'z' } -// pathOK reports whether r can appear in an import path element. -// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. -// This matches what "go get" has historically recognized in import paths. +// modPathOK reports whether r can appear in a module path element. +// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. +// +// This matches what "go get" has historically recognized in import paths, +// and avoids confusing sequences like '%20' or '+' that would change meaning +// if used in a URL. +// // TODO(rsc): We would like to allow Unicode letters, but that requires additional // care in the safe encoding (see "escaped paths" above). -func pathOK(r rune) bool { +func modPathOK(r rune) bool { if r < utf8.RuneSelf { - return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' || + return r == '-' || r == '.' || r == '_' || r == '~' || '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' @@ -238,6 +258,17 @@ func pathOK(r rune) bool { return false } +// modPathOK reports whether r can appear in a package import path element. +// +// Import paths are intermediate between module paths and file paths: we allow +// disallow characters that would be confusing or ambiguous as arguments to +// 'go get' (such as '@' and ' ' ), but allow certain characters that are +// otherwise-unambiguous on the command line and historically used for some +// binary names (such as '++' as a suffix for compiler binaries and wrappers). +func importPathOK(r rune) bool { + return modPathOK(r) || r == '+' +} + // fileNameOK reports whether r can appear in a file name. // For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters. // If we expand the set of allowed characters here, we have to @@ -269,7 +300,7 @@ func fileNameOK(r rune) bool { // CheckPath checks that a module path is valid. // A valid module path is a valid import path, as checked by CheckImportPath, -// with two additional constraints. +// with three additional constraints. // First, the leading path element (up to the first slash, if any), // by convention a domain name, must contain only lower-case ASCII letters, // ASCII digits, dots (U+002E), and dashes (U+002D); @@ -279,30 +310,37 @@ func fileNameOK(r rune) bool { // and must not contain any dots. For paths beginning with "gopkg.in/", // this second requirement is replaced by a requirement that the path // follow the gopkg.in server's conventions. -func CheckPath(path string) error { - if err := checkPath(path, false); err != nil { - return fmt.Errorf("malformed module path %q: %v", path, err) +// Third, no path element may begin with a dot. +func CheckPath(path string) (err error) { + defer func() { + if err != nil { + err = &InvalidPathError{Kind: "module", Path: path, Err: err} + } + }() + + if err := checkPath(path, modulePath); err != nil { + return err } i := strings.Index(path, "/") if i < 0 { i = len(path) } if i == 0 { - return fmt.Errorf("malformed module path %q: leading slash", path) + return fmt.Errorf("leading slash") } if !strings.Contains(path[:i], ".") { - return fmt.Errorf("malformed module path %q: missing dot in first path element", path) + return fmt.Errorf("missing dot in first path element") } if path[0] == '-' { - return fmt.Errorf("malformed module path %q: leading dash in first path element", path) + return fmt.Errorf("leading dash in first path element") } for _, r := range path[:i] { if !firstPathOK(r) { - return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r) + return fmt.Errorf("invalid char %q in first path element", r) } } if _, _, ok := SplitPathVersion(path); !ok { - return fmt.Errorf("malformed module path %q: invalid version", path) + return fmt.Errorf("invalid version") } return nil } @@ -313,36 +351,49 @@ func CheckPath(path string) error { // separated by slashes (U+002F). (It must not begin with nor end in a slash.) // // A valid path element is a non-empty string made up of -// ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. -// It must not begin or end with a dot (U+002E), nor contain two dots in a row. +// ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. +// It must not end with a dot (U+002E), nor contain two dots in a row. // // The element prefix up to the first dot must not be a reserved file name -// on Windows, regardless of case (CON, com1, NuL, and so on). +// on Windows, regardless of case (CON, com1, NuL, and so on). The element +// must not have a suffix of a tilde followed by one or more ASCII digits +// (to exclude paths elements that look like Windows short-names). // // CheckImportPath may be less restrictive in the future, but see the // top-level package documentation for additional information about // subtleties of Unicode. func CheckImportPath(path string) error { - if err := checkPath(path, false); err != nil { - return fmt.Errorf("malformed import path %q: %v", path, err) + if err := checkPath(path, importPath); err != nil { + return &InvalidPathError{Kind: "import", Path: path, Err: err} } return nil } -// checkPath checks that a general path is valid. -// It returns an error describing why but not mentioning path. -// Because these checks apply to both module paths and import paths, -// the caller is expected to add the "malformed ___ path %q: " prefix. -// fileName indicates whether the final element of the path is a file name -// (as opposed to a directory name). -func checkPath(path string, fileName bool) error { +// pathKind indicates what kind of path we're checking. Module paths, +// import paths, and file paths have different restrictions. +type pathKind int + +const ( + modulePath pathKind = iota + importPath + filePath +) + +// checkPath checks that a general path is valid. kind indicates what +// specific constraints should be applied. +// +// checkPath returns an error describing why the path is not valid. +// Because these checks apply to module, import, and file paths, +// and because other checks may be applied, the caller is expected to wrap +// this error with InvalidPathError. +func checkPath(path string, kind pathKind) error { if !utf8.ValidString(path) { return fmt.Errorf("invalid UTF-8") } if path == "" { return fmt.Errorf("empty string") } - if path[0] == '-' { + if path[0] == '-' && kind != filePath { return fmt.Errorf("leading dash") } if strings.Contains(path, "//") { @@ -354,39 +405,45 @@ func checkPath(path string, fileName bool) error { elemStart := 0 for i, r := range path { if r == '/' { - if err := checkElem(path[elemStart:i], fileName); err != nil { + if err := checkElem(path[elemStart:i], kind); err != nil { return err } elemStart = i + 1 } } - if err := checkElem(path[elemStart:], fileName); err != nil { + if err := checkElem(path[elemStart:], kind); err != nil { return err } return nil } // checkElem checks whether an individual path element is valid. -// fileName indicates whether the element is a file name (not a directory name). -func checkElem(elem string, fileName bool) error { +func checkElem(elem string, kind pathKind) error { if elem == "" { return fmt.Errorf("empty path element") } if strings.Count(elem, ".") == len(elem) { return fmt.Errorf("invalid path element %q", elem) } - if elem[0] == '.' && !fileName { + if elem[0] == '.' && kind == modulePath { return fmt.Errorf("leading dot in path element") } if elem[len(elem)-1] == '.' { return fmt.Errorf("trailing dot in path element") } - charOK := pathOK - if fileName { - charOK = fileNameOK - } for _, r := range elem { - if !charOK(r) { + ok := false + switch kind { + case modulePath: + ok = modPathOK(r) + case importPath: + ok = importPathOK(r) + case filePath: + ok = fileNameOK(r) + default: + panic(fmt.Sprintf("internal error: invalid kind %v", kind)) + } + if !ok { return fmt.Errorf("invalid char %q", r) } } @@ -402,6 +459,29 @@ func checkElem(elem string, fileName bool) error { return fmt.Errorf("%q disallowed as path element component on Windows", short) } } + + if kind == filePath { + // don't check for Windows short-names in file names. They're + // only an issue for import paths. + return nil + } + + // Reject path components that look like Windows short-names. + // Those usually end in a tilde followed by one or more ASCII digits. + if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 { + suffix := short[tilde+1:] + suffixIsDigits := true + for _, r := range suffix { + if r < '0' || r > '9' { + suffixIsDigits = false + break + } + } + if suffixIsDigits { + return fmt.Errorf("trailing tilde and digits in path element") + } + } + return nil } @@ -418,8 +498,8 @@ func checkElem(elem string, fileName bool) error { // top-level package documentation for additional information about // subtleties of Unicode. func CheckFilePath(path string) error { - if err := checkPath(path, true); err != nil { - return fmt.Errorf("malformed file path %q: %v", path, err) + if err := checkPath(path, filePath); err != nil { + return &InvalidPathError{Kind: "file", Path: path, Err: err} } return nil } @@ -621,7 +701,7 @@ func EscapePath(path string) (escaped string, err error) { // Versions are allowed to be in non-semver form but must be valid file names // and not contain exclamation marks. func EscapeVersion(v string) (escaped string, err error) { - if err := checkElem(v, true); err != nil || strings.Contains(v, "!") { + if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { return "", &InvalidVersionError{ Version: v, Err: fmt.Errorf("disallowed version string"), @@ -680,7 +760,7 @@ func UnescapeVersion(escaped string) (v string, err error) { if !ok { return "", fmt.Errorf("invalid escaped version %q", escaped) } - if err := checkElem(v, true); err != nil { + if err := checkElem(v, filePath); err != nil { return "", fmt.Errorf("invalid escaped version %q: %v", v, err) } return v, nil @@ -716,3 +796,49 @@ func unescapeString(escaped string) (string, bool) { } return string(buf), true } + +// MatchPrefixPatterns reports whether any path prefix of target matches one of +// the glob patterns (as defined by path.Match) in the comma-separated globs +// list. This implements the algorithm used when matching a module path to the +// GOPRIVATE environment variable, as described by 'go help module-private'. +// +// It ignores any empty or malformed patterns in the list. +func MatchPrefixPatterns(globs, target string) bool { + for globs != "" { + // Extract next non-empty glob in comma-separated list. + var glob string + if i := strings.Index(globs, ","); i >= 0 { + glob, globs = globs[:i], globs[i+1:] + } else { + glob, globs = globs, "" + } + if glob == "" { + continue + } + + // A glob with N+1 path elements (N slashes) needs to be matched + // against the first N+1 path elements of target, + // which end just before the N+1'th slash. + n := strings.Count(glob, "/") + prefix := target + // Walk target, counting slashes, truncating at the N+1'th slash. + for i := 0; i < len(target); i++ { + if target[i] == '/' { + if n == 0 { + prefix = target[:i] + break + } + n-- + } + } + if n > 0 { + // Not enough prefix elements. + continue + } + matched, _ := path.Match(glob, prefix) + if matched { + return true + } + } + return false +} diff --git a/vendor/golang.org/x/mod/module/pseudo.go b/vendor/golang.org/x/mod/module/pseudo.go new file mode 100644 index 00000000000..f04ad378869 --- /dev/null +++ b/vendor/golang.org/x/mod/module/pseudo.go @@ -0,0 +1,250 @@ +// Copyright 2018 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. + +// Pseudo-versions +// +// Code authors are expected to tag the revisions they want users to use, +// including prereleases. However, not all authors tag versions at all, +// and not all commits a user might want to try will have tags. +// A pseudo-version is a version with a special form that allows us to +// address an untagged commit and order that version with respect to +// other versions we might encounter. +// +// A pseudo-version takes one of the general forms: +// +// (1) vX.0.0-yyyymmddhhmmss-abcdef123456 +// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 +// (3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible +// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 +// (5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible +// +// If there is no recently tagged version with the right major version vX, +// then form (1) is used, creating a space of pseudo-versions at the bottom +// of the vX version range, less than any tagged version, including the unlikely v0.0.0. +// +// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible, +// then the pseudo-version uses form (2) or (3), making it a prerelease for the next +// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string +// ensures that the pseudo-version compares less than possible future explicit prereleases +// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1. +// +// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible, +// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease. + +package module + +import ( + "errors" + "fmt" + "strings" + "time" + + "golang.org/x/mod/internal/lazyregexp" + "golang.org/x/mod/semver" +) + +var pseudoVersionRE = lazyregexp.New(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`) + +const PseudoVersionTimestampFormat = "20060102150405" + +// PseudoVersion returns a pseudo-version for the given major version ("v1") +// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time, +// and revision identifier (usually a 12-byte commit hash prefix). +func PseudoVersion(major, older string, t time.Time, rev string) string { + if major == "" { + major = "v0" + } + segment := fmt.Sprintf("%s-%s", t.UTC().Format(PseudoVersionTimestampFormat), rev) + build := semver.Build(older) + older = semver.Canonical(older) + if older == "" { + return major + ".0.0-" + segment // form (1) + } + if semver.Prerelease(older) != "" { + return older + ".0." + segment + build // form (4), (5) + } + + // Form (2), (3). + // Extract patch from vMAJOR.MINOR.PATCH + i := strings.LastIndex(older, ".") + 1 + v, patch := older[:i], older[i:] + + // Reassemble. + return v + incDecimal(patch) + "-0." + segment + build +} + +// ZeroPseudoVersion returns a pseudo-version with a zero timestamp and +// revision, which may be used as a placeholder. +func ZeroPseudoVersion(major string) string { + return PseudoVersion(major, "", time.Time{}, "000000000000") +} + +// incDecimal returns the decimal string incremented by 1. +func incDecimal(decimal string) string { + // Scan right to left turning 9s to 0s until you find a digit to increment. + digits := []byte(decimal) + i := len(digits) - 1 + for ; i >= 0 && digits[i] == '9'; i-- { + digits[i] = '0' + } + if i >= 0 { + digits[i]++ + } else { + // digits is all zeros + digits[0] = '1' + digits = append(digits, '0') + } + return string(digits) +} + +// decDecimal returns the decimal string decremented by 1, or the empty string +// if the decimal is all zeroes. +func decDecimal(decimal string) string { + // Scan right to left turning 0s to 9s until you find a digit to decrement. + digits := []byte(decimal) + i := len(digits) - 1 + for ; i >= 0 && digits[i] == '0'; i-- { + digits[i] = '9' + } + if i < 0 { + // decimal is all zeros + return "" + } + if i == 0 && digits[i] == '1' && len(digits) > 1 { + digits = digits[1:] + } else { + digits[i]-- + } + return string(digits) +} + +// IsPseudoVersion reports whether v is a pseudo-version. +func IsPseudoVersion(v string) bool { + return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v) +} + +// IsZeroPseudoVersion returns whether v is a pseudo-version with a zero base, +// timestamp, and revision, as returned by ZeroPseudoVersion. +func IsZeroPseudoVersion(v string) bool { + return v == ZeroPseudoVersion(semver.Major(v)) +} + +// PseudoVersionTime returns the time stamp of the pseudo-version v. +// It returns an error if v is not a pseudo-version or if the time stamp +// embedded in the pseudo-version is not a valid time. +func PseudoVersionTime(v string) (time.Time, error) { + _, timestamp, _, _, err := parsePseudoVersion(v) + if err != nil { + return time.Time{}, err + } + t, err := time.Parse("20060102150405", timestamp) + if err != nil { + return time.Time{}, &InvalidVersionError{ + Version: v, + Pseudo: true, + Err: fmt.Errorf("malformed time %q", timestamp), + } + } + return t, nil +} + +// PseudoVersionRev returns the revision identifier of the pseudo-version v. +// It returns an error if v is not a pseudo-version. +func PseudoVersionRev(v string) (rev string, err error) { + _, _, rev, _, err = parsePseudoVersion(v) + return +} + +// PseudoVersionBase returns the canonical parent version, if any, upon which +// the pseudo-version v is based. +// +// If v has no parent version (that is, if it is "vX.0.0-[…]"), +// PseudoVersionBase returns the empty string and a nil error. +func PseudoVersionBase(v string) (string, error) { + base, _, _, build, err := parsePseudoVersion(v) + if err != nil { + return "", err + } + + switch pre := semver.Prerelease(base); pre { + case "": + // vX.0.0-yyyymmddhhmmss-abcdef123456 → "" + if build != "" { + // Pseudo-versions of the form vX.0.0-yyyymmddhhmmss-abcdef123456+incompatible + // are nonsensical: the "vX.0.0-" prefix implies that there is no parent tag, + // but the "+incompatible" suffix implies that the major version of + // the parent tag is not compatible with the module's import path. + // + // There are a few such entries in the index generated by proxy.golang.org, + // but we believe those entries were generated by the proxy itself. + return "", &InvalidVersionError{ + Version: v, + Pseudo: true, + Err: fmt.Errorf("lacks base version, but has build metadata %q", build), + } + } + return "", nil + + case "-0": + // vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z + // vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z+incompatible + base = strings.TrimSuffix(base, pre) + i := strings.LastIndexByte(base, '.') + if i < 0 { + panic("base from parsePseudoVersion missing patch number: " + base) + } + patch := decDecimal(base[i+1:]) + if patch == "" { + // vX.0.0-0 is invalid, but has been observed in the wild in the index + // generated by requests to proxy.golang.org. + // + // NOTE(bcmills): I cannot find a historical bug that accounts for + // pseudo-versions of this form, nor have I seen such versions in any + // actual go.mod files. If we find actual examples of this form and a + // reasonable theory of how they came into existence, it seems fine to + // treat them as equivalent to vX.0.0 (especially since the invalid + // pseudo-versions have lower precedence than the real ones). For now, we + // reject them. + return "", &InvalidVersionError{ + Version: v, + Pseudo: true, + Err: fmt.Errorf("version before %s would have negative patch number", base), + } + } + return base[:i+1] + patch + build, nil + + default: + // vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 → vX.Y.Z-pre + // vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible → vX.Y.Z-pre+incompatible + if !strings.HasSuffix(base, ".0") { + panic(`base from parsePseudoVersion missing ".0" before date: ` + base) + } + return strings.TrimSuffix(base, ".0") + build, nil + } +} + +var errPseudoSyntax = errors.New("syntax error") + +func parsePseudoVersion(v string) (base, timestamp, rev, build string, err error) { + if !IsPseudoVersion(v) { + return "", "", "", "", &InvalidVersionError{ + Version: v, + Pseudo: true, + Err: errPseudoSyntax, + } + } + build = semver.Build(v) + v = strings.TrimSuffix(v, build) + j := strings.LastIndex(v, "-") + v, rev = v[:j], v[j+1:] + i := strings.LastIndex(v, "-") + if j := strings.LastIndex(v, "."); j > i { + base = v[:j] // "vX.Y.Z-pre.0" or "vX.Y.(Z+1)-0" + timestamp = v[j+1:] + } else { + base = v[:i] // "vX.0.0" + timestamp = v[i+1:] + } + return base, timestamp, rev, build, nil +} diff --git a/vendor/golang.org/x/mod/semver/semver.go b/vendor/golang.org/x/mod/semver/semver.go index 2988e3cf9c5..7be398f80d3 100644 --- a/vendor/golang.org/x/mod/semver/semver.go +++ b/vendor/golang.org/x/mod/semver/semver.go @@ -22,6 +22,8 @@ // as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0. package semver +import "sort" + // parsed returns the parsed form of a semantic version string. type parsed struct { major string @@ -138,6 +140,9 @@ func Compare(v, w string) int { // Max canonicalizes its arguments and then returns the version string // that compares greater. +// +// Deprecated: use Compare instead. In most cases, returning a canonicalized +// version is not expected or desired. func Max(v, w string) string { v = Canonical(v) w = Canonical(w) @@ -147,6 +152,24 @@ func Max(v, w string) string { return w } +// ByVersion implements sort.Interface for sorting semantic version strings. +type ByVersion []string + +func (vs ByVersion) Len() int { return len(vs) } +func (vs ByVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] } +func (vs ByVersion) Less(i, j int) bool { + cmp := Compare(vs[i], vs[j]) + if cmp != 0 { + return cmp < 0 + } + return vs[i] < vs[j] +} + +// Sort sorts a list of semantic version strings using ByVersion. +func Sort(list []string) { + sort.Sort(ByVersion(list)) +} + func parse(v string) (p parsed, ok bool) { if v == "" || v[0] != 'v' { p.err = "missing v prefix" diff --git a/vendor/golang.org/x/sys/AUTHORS b/vendor/golang.org/x/sys/AUTHORS new file mode 100644 index 00000000000..15167cd746c --- /dev/null +++ b/vendor/golang.org/x/sys/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/vendor/golang.org/x/sys/CONTRIBUTORS b/vendor/golang.org/x/sys/CONTRIBUTORS new file mode 100644 index 00000000000..1c4577e9680 --- /dev/null +++ b/vendor/golang.org/x/sys/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/vendor/golang.org/x/sys/LICENSE b/vendor/golang.org/x/sys/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/vendor/golang.org/x/sys/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/sys/PATENTS b/vendor/golang.org/x/sys/PATENTS new file mode 100644 index 00000000000..733099041f8 --- /dev/null +++ b/vendor/golang.org/x/sys/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/sys/execabs/execabs.go b/vendor/golang.org/x/sys/execabs/execabs.go new file mode 100644 index 00000000000..78192498db0 --- /dev/null +++ b/vendor/golang.org/x/sys/execabs/execabs.go @@ -0,0 +1,102 @@ +// Copyright 2020 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 execabs is a drop-in replacement for os/exec +// that requires PATH lookups to find absolute paths. +// That is, execabs.Command("cmd") runs the same PATH lookup +// as exec.Command("cmd"), but if the result is a path +// which is relative, the Run and Start methods will report +// an error instead of running the executable. +// +// See https://blog.golang.org/path-security for more information +// about when it may be necessary or appropriate to use this package. +package execabs + +import ( + "context" + "fmt" + "os/exec" + "path/filepath" + "reflect" + "unsafe" +) + +// ErrNotFound is the error resulting if a path search failed to find an executable file. +// It is an alias for exec.ErrNotFound. +var ErrNotFound = exec.ErrNotFound + +// Cmd represents an external command being prepared or run. +// It is an alias for exec.Cmd. +type Cmd = exec.Cmd + +// Error is returned by LookPath when it fails to classify a file as an executable. +// It is an alias for exec.Error. +type Error = exec.Error + +// An ExitError reports an unsuccessful exit by a command. +// It is an alias for exec.ExitError. +type ExitError = exec.ExitError + +func relError(file, path string) error { + return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path) +} + +// LookPath searches for an executable named file in the directories +// named by the PATH environment variable. If file contains a slash, +// it is tried directly and the PATH is not consulted. The result will be +// an absolute path. +// +// LookPath differs from exec.LookPath in its handling of PATH lookups, +// which are used for file names without slashes. If exec.LookPath's +// PATH lookup would have returned an executable from the current directory, +// LookPath instead returns an error. +func LookPath(file string) (string, error) { + path, err := exec.LookPath(file) + if err != nil { + return "", err + } + if filepath.Base(file) == file && !filepath.IsAbs(path) { + return "", relError(file, path) + } + return path, nil +} + +func fixCmd(name string, cmd *exec.Cmd) { + if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) { + // exec.Command was called with a bare binary name and + // exec.LookPath returned a path which is not absolute. + // Set cmd.lookPathErr and clear cmd.Path so that it + // cannot be run. + lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) + if *lookPathErr == nil { + *lookPathErr = relError(name, cmd.Path) + } + cmd.Path = "" + } +} + +// CommandContext is like Command but includes a context. +// +// The provided context is used to kill the process (by calling os.Process.Kill) +// if the context becomes done before the command completes on its own. +func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { + cmd := exec.CommandContext(ctx, name, arg...) + fixCmd(name, cmd) + return cmd + +} + +// Command returns the Cmd struct to execute the named program with the given arguments. +// See exec.Command for most details. +// +// Command differs from exec.Command in its handling of PATH lookups, +// which are used when the program name contains no slashes. +// If exec.Command would have returned an exec.Cmd configured to run an +// executable from the current directory, Command instead +// returns an exec.Cmd that will return an error from Start or Run. +func Command(name string, arg ...string) *exec.Cmd { + cmd := exec.Command(name, arg...) + fixCmd(name, cmd) + return cmd +} diff --git a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go index f8363d8faae..fc8beea5d8a 100644 --- a/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go +++ b/vendor/golang.org/x/tools/go/gcexportdata/gcexportdata.go @@ -100,10 +100,34 @@ func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, // Write writes encoded type information for the specified package to out. // The FileSet provides file position information for named objects. func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error { - b, err := gcimporter.IExportData(fset, pkg) - if err != nil { + if _, err := io.WriteString(out, "i"); err != nil { return err } - _, err = out.Write(b) - return err + return gcimporter.IExportData(out, fset, pkg) +} + +// ReadBundle reads an export bundle from in, decodes it, and returns type +// information for the packages. +// File position information is added to fset. +// +// ReadBundle may inspect and add to the imports map to ensure that references +// within the export bundle to other packages are consistent. +// +// On return, the state of the reader is undefined. +// +// Experimental: This API is experimental and may change in the future. +func ReadBundle(in io.Reader, fset *token.FileSet, imports map[string]*types.Package) ([]*types.Package, error) { + data, err := ioutil.ReadAll(in) + if err != nil { + return nil, fmt.Errorf("reading export bundle: %v", err) + } + return gcimporter.IImportBundle(fset, imports, data) +} + +// WriteBundle writes encoded type information for the specified packages to out. +// The FileSet provides file position information for named objects. +// +// Experimental: This API is experimental and may change in the future. +func WriteBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { + return gcimporter.IExportBundle(out, fset, pkgs) } diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go index 4be32a2e55f..d2fc8b6fa3e 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/iexport.go @@ -25,12 +25,25 @@ import ( // 0: Go1.11 encoding const iexportVersion = 0 -// IExportData returns the binary export data for pkg. +// Current bundled export format version. Increase with each format change. +// 0: initial implementation +const bundleVersion = 0 + +// IExportData writes indexed export data for pkg to out. // // If no file set is provided, position info will be missing. // The package path of the top-level package will not be recorded, // so that calls to IImportData can override with a provided package path. -func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) { +func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error { + return iexportCommon(out, fset, false, []*types.Package{pkg}) +} + +// IExportBundle writes an indexed export bundle for pkgs to out. +func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { + return iexportCommon(out, fset, true, pkgs) +} + +func iexportCommon(out io.Writer, fset *token.FileSet, bundle bool, pkgs []*types.Package) (err error) { defer func() { if e := recover(); e != nil { if ierr, ok := e.(internalError); ok { @@ -43,13 +56,14 @@ func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) }() p := iexporter{ - out: bytes.NewBuffer(nil), fset: fset, allPkgs: map[*types.Package]bool{}, stringIndex: map[string]uint64{}, declIndex: map[types.Object]uint64{}, typIndex: map[types.Type]uint64{}, - localpkg: pkg, + } + if !bundle { + p.localpkg = pkgs[0] } for i, pt := range predeclared() { @@ -60,10 +74,20 @@ func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) } // Initialize work queue with exported declarations. - scope := pkg.Scope() - for _, name := range scope.Names() { - if ast.IsExported(name) { - p.pushDecl(scope.Lookup(name)) + for _, pkg := range pkgs { + scope := pkg.Scope() + for _, name := range scope.Names() { + if ast.IsExported(name) { + p.pushDecl(scope.Lookup(name)) + } + } + + if bundle { + // Ensure pkg and its imports are included in the index. + p.allPkgs[pkg] = true + for _, imp := range pkg.Imports() { + p.allPkgs[imp] = true + } } } @@ -76,21 +100,35 @@ func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) dataLen := uint64(p.data0.Len()) w := p.newWriter() w.writeIndex(p.declIndex) + + if bundle { + w.uint64(uint64(len(pkgs))) + for _, pkg := range pkgs { + w.pkg(pkg) + imps := pkg.Imports() + w.uint64(uint64(len(imps))) + for _, imp := range imps { + w.pkg(imp) + } + } + } w.flush() // Assemble header. var hdr intWriter - hdr.WriteByte('i') + if bundle { + hdr.uint64(bundleVersion) + } hdr.uint64(iexportVersion) hdr.uint64(uint64(p.strings.Len())) hdr.uint64(dataLen) // Flush output. - io.Copy(p.out, &hdr) - io.Copy(p.out, &p.strings) - io.Copy(p.out, &p.data0) + io.Copy(out, &hdr) + io.Copy(out, &p.strings) + io.Copy(out, &p.data0) - return p.out.Bytes(), nil + return nil } // writeIndex writes out an object index. mainIndex indicates whether @@ -104,7 +142,9 @@ func (w *exportWriter) writeIndex(index map[types.Object]uint64) { // For the main index, make sure to include every package that // we reference, even if we're not exporting (or reexporting) // any symbols from it. - pkgObjs[w.p.localpkg] = nil + if w.p.localpkg != nil { + pkgObjs[w.p.localpkg] = nil + } for pkg := range w.p.allPkgs { pkgObjs[pkg] = nil } @@ -474,10 +514,10 @@ func (w *exportWriter) param(obj types.Object) { func (w *exportWriter) value(typ types.Type, v constant.Value) { w.typ(typ, nil) - switch v.Kind() { - case constant.Bool: + switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { + case types.IsBoolean: w.bool(constant.BoolVal(v)) - case constant.Int: + case types.IsInteger: var i big.Int if i64, exact := constant.Int64Val(v); exact { i.SetInt64(i64) @@ -487,25 +527,27 @@ func (w *exportWriter) value(typ types.Type, v constant.Value) { i.SetString(v.ExactString(), 10) } w.mpint(&i, typ) - case constant.Float: + case types.IsFloat: f := constantToFloat(v) w.mpfloat(f, typ) - case constant.Complex: + case types.IsComplex: w.mpfloat(constantToFloat(constant.Real(v)), typ) w.mpfloat(constantToFloat(constant.Imag(v)), typ) - case constant.String: + case types.IsString: w.string(constant.StringVal(v)) - case constant.Unknown: - // package contains type errors default: - panic(internalErrorf("unexpected value %v (%T)", v, v)) + if b.Kind() == types.Invalid { + // package contains type errors + break + } + panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying())) } } // constantToFloat converts a constant.Value with kind constant.Float to a // big.Float. func constantToFloat(x constant.Value) *big.Float { - assert(x.Kind() == constant.Float) + x = constant.ToFloat(x) // Use the same floating-point precision (512) as cmd/compile // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). const mpprec = 512 diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go b/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go index a31a880263e..8ed8bc62d68 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/iimport.go @@ -59,10 +59,23 @@ const ( ) // IImportData imports a package from the serialized package data -// and returns the number of bytes consumed and a reference to the package. +// and returns 0 and a reference to the package. // If the export data version is not recognized or the format is otherwise // compromised, an error is returned. -func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { +func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { + pkgs, err := iimportCommon(fset, imports, data, false, path) + if err != nil { + return 0, nil, err + } + return 0, pkgs[0], nil +} + +// IImportBundle imports a set of packages from the serialized package bundle. +func IImportBundle(fset *token.FileSet, imports map[string]*types.Package, data []byte) ([]*types.Package, error) { + return iimportCommon(fset, imports, data, true, "") +} + +func iimportCommon(fset *token.FileSet, imports map[string]*types.Package, data []byte, bundle bool, path string) (pkgs []*types.Package, err error) { const currentVersion = 1 version := int64(-1) defer func() { @@ -77,6 +90,15 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] r := &intReader{bytes.NewReader(data), path} + if bundle { + bundleVersion := r.uint64() + switch bundleVersion { + case bundleVersion: + default: + errorf("unknown bundle format version %d", bundleVersion) + } + } + version = int64(r.uint64()) switch version { case currentVersion, 0: @@ -143,39 +165,58 @@ func IImportData(fset *token.FileSet, imports map[string]*types.Package, data [] p.pkgIndex[pkg] = nameIndex pkgList[i] = pkg } - if len(pkgList) == 0 { - errorf("no packages found for %s", path) - panic("unreachable") + + if bundle { + pkgs = make([]*types.Package, r.uint64()) + for i := range pkgs { + pkg := p.pkgAt(r.uint64()) + imps := make([]*types.Package, r.uint64()) + for j := range imps { + imps[j] = p.pkgAt(r.uint64()) + } + pkg.SetImports(imps) + pkgs[i] = pkg + } + } else { + if len(pkgList) == 0 { + errorf("no packages found for %s", path) + panic("unreachable") + } + pkgs = pkgList[:1] + + // record all referenced packages as imports + list := append(([]*types.Package)(nil), pkgList[1:]...) + sort.Sort(byPath(list)) + pkgs[0].SetImports(list) } - p.ipkg = pkgList[0] - names := make([]string, 0, len(p.pkgIndex[p.ipkg])) - for name := range p.pkgIndex[p.ipkg] { - names = append(names, name) - } - sort.Strings(names) - for _, name := range names { - p.doDecl(p.ipkg, name) + + for _, pkg := range pkgs { + if pkg.Complete() { + continue + } + + names := make([]string, 0, len(p.pkgIndex[pkg])) + for name := range p.pkgIndex[pkg] { + names = append(names, name) + } + sort.Strings(names) + for _, name := range names { + p.doDecl(pkg, name) + } + + // package was imported completely and without errors + pkg.MarkComplete() } for _, typ := range p.interfaceList { typ.Complete() } - // record all referenced packages as imports - list := append(([]*types.Package)(nil), pkgList[1:]...) - sort.Sort(byPath(list)) - p.ipkg.SetImports(list) - - // package was imported completely and without errors - p.ipkg.MarkComplete() - - consumed, _ := r.Seek(0, io.SeekCurrent) - return int(consumed), p.ipkg, nil + return pkgs, nil } type iimporter struct { ipath string - ipkg *types.Package version int stringData []byte @@ -227,9 +268,6 @@ func (p *iimporter) pkgAt(off uint64) *types.Package { return pkg } path := p.stringAt(off) - if path == p.ipath { - return p.ipkg - } errorf("missing package %q in %q", path, p.ipath) return nil } @@ -435,6 +473,14 @@ func (r *importReader) mpfloat(b *types.Basic) constant.Value { switch { case exp > 0: x = constant.Shift(x, token.SHL, uint(exp)) + // Ensure that the imported Kind is Float, else this constant may run into + // bitsize limits on overlarge integers. Eventually we can instead adopt + // the approach of CL 288632, but that CL relies on go/constant APIs that + // were introduced in go1.13. + // + // TODO(rFindley): sync the logic here with tip Go once we no longer + // support go1.12. + x = constant.ToFloat(x) case exp < 0: d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) x = constant.BinaryOp(x, token.QUO, d) diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go index 463f2522714..8b163e3d058 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface10.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !go1.11 // +build !go1.11 package gcimporter diff --git a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go index ab28b95cbb8..49984f40fd8 100644 --- a/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go +++ b/vendor/golang.org/x/tools/go/internal/gcimporter/newInterface11.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build go1.11 // +build go1.11 package gcimporter diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go index 35bc6a4127a..18a002f82a1 100644 --- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go +++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -6,12 +6,9 @@ package packagesdriver import ( - "bytes" "context" - "encoding/json" "fmt" "go/types" - "os/exec" "strings" "golang.org/x/tools/internal/gocommand" @@ -19,74 +16,13 @@ import ( var debug = false -func GetSizes(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) { - // TODO(matloob): Clean this up. This code is mostly a copy of packages.findExternalDriver. - const toolPrefix = "GOPACKAGESDRIVER=" - tool := "" - for _, env := range env { - if val := strings.TrimPrefix(env, toolPrefix); val != env { - tool = val - } - } - - if tool == "" { - var err error - tool, err = exec.LookPath("gopackagesdriver") - if err != nil { - // We did not find the driver, so use "go list". - tool = "off" - } - } - - if tool == "off" { - inv := gocommand.Invocation{ - BuildFlags: buildFlags, - Env: env, - WorkingDir: dir, - } - return GetSizesGolist(ctx, inv, gocmdRunner) - } - - req, err := json.Marshal(struct { - Command string `json:"command"` - Env []string `json:"env"` - BuildFlags []string `json:"build_flags"` - }{ - Command: "sizes", - Env: env, - BuildFlags: buildFlags, - }) - if err != nil { - return nil, fmt.Errorf("failed to encode message to driver tool: %v", err) - } - - buf := new(bytes.Buffer) - cmd := exec.CommandContext(ctx, tool) - cmd.Dir = dir - cmd.Env = env - cmd.Stdin = bytes.NewReader(req) - cmd.Stdout = buf - cmd.Stderr = new(bytes.Buffer) - if err := cmd.Run(); err != nil { - return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr) - } - var response struct { - // Sizes, if not nil, is the types.Sizes to use when type checking. - Sizes *types.StdSizes - } - if err := json.Unmarshal(buf.Bytes(), &response); err != nil { - return nil, err - } - return response.Sizes, nil -} - func GetSizesGolist(ctx context.Context, inv gocommand.Invocation, gocmdRunner *gocommand.Runner) (types.Sizes, error) { inv.Verb = "list" inv.Args = []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"} stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv) var goarch, compiler string if rawErr != nil { - if strings.Contains(rawErr.Error(), "cannot find main module") { + if rawErrMsg := rawErr.Error(); strings.Contains(rawErrMsg, "cannot find main module") || strings.Contains(rawErrMsg, "go.mod file not found") { // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc. // TODO(matloob): Is this a problem in practice? inv.Verb = "env" diff --git a/vendor/golang.org/x/tools/go/packages/external.go b/vendor/golang.org/x/tools/go/packages/external.go index 8c8473fd0bd..7242a0a7d2b 100644 --- a/vendor/golang.org/x/tools/go/packages/external.go +++ b/vendor/golang.org/x/tools/go/packages/external.go @@ -12,8 +12,8 @@ import ( "bytes" "encoding/json" "fmt" + exec "golang.org/x/sys/execabs" "os" - "os/exec" "strings" ) @@ -89,7 +89,7 @@ func findExternalDriver(cfg *Config) driver { return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr) } if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTDRIVERERRORS") != "" { - fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd, words...), stderr) + fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr) } var response driverResponse diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go index 787783cd9f5..0e1e7f11fee 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -10,9 +10,9 @@ import ( "encoding/json" "fmt" "go/types" + "io/ioutil" "log" "os" - "os/exec" "path" "path/filepath" "reflect" @@ -22,8 +22,10 @@ import ( "sync" "unicode" + exec "golang.org/x/sys/execabs" "golang.org/x/tools/go/internal/packagesdriver" "golang.org/x/tools/internal/gocommand" + "golang.org/x/tools/internal/packagesinternal" "golang.org/x/xerrors" ) @@ -208,56 +210,58 @@ extractQueries: } } - modifiedPkgs, needPkgs, err := state.processGolistOverlay(response) - if err != nil { - return nil, err - } + // Only use go/packages' overlay processing if we're using a Go version + // below 1.16. Otherwise, go list handles it. + if goVersion, err := state.getGoVersion(); err == nil && goVersion < 16 { + modifiedPkgs, needPkgs, err := state.processGolistOverlay(response) + if err != nil { + return nil, err + } - var containsCandidates []string - if len(containFiles) > 0 { - containsCandidates = append(containsCandidates, modifiedPkgs...) - containsCandidates = append(containsCandidates, needPkgs...) - } - if err := state.addNeededOverlayPackages(response, needPkgs); err != nil { - return nil, err - } - // Check candidate packages for containFiles. - if len(containFiles) > 0 { - for _, id := range containsCandidates { - pkg, ok := response.seenPackages[id] - if !ok { - response.addPackage(&Package{ - ID: id, - Errors: []Error{ - { + var containsCandidates []string + if len(containFiles) > 0 { + containsCandidates = append(containsCandidates, modifiedPkgs...) + containsCandidates = append(containsCandidates, needPkgs...) + } + if err := state.addNeededOverlayPackages(response, needPkgs); err != nil { + return nil, err + } + // Check candidate packages for containFiles. + if len(containFiles) > 0 { + for _, id := range containsCandidates { + pkg, ok := response.seenPackages[id] + if !ok { + response.addPackage(&Package{ + ID: id, + Errors: []Error{{ Kind: ListError, Msg: fmt.Sprintf("package %s expected but not seen", id), - }, - }, - }) - continue - } - for _, f := range containFiles { - for _, g := range pkg.GoFiles { - if sameFile(f, g) { - response.addRoot(id) + }}, + }) + continue + } + for _, f := range containFiles { + for _, g := range pkg.GoFiles { + if sameFile(f, g) { + response.addRoot(id) + } } } } } - } - // Add root for any package that matches a pattern. This applies only to - // packages that are modified by overlays, since they are not added as - // roots automatically. - for _, pattern := range restPatterns { - match := matchPattern(pattern) - for _, pkgID := range modifiedPkgs { - pkg, ok := response.seenPackages[pkgID] - if !ok { - continue - } - if match(pkg.PkgPath) { - response.addRoot(pkg.ID) + // Add root for any package that matches a pattern. This applies only to + // packages that are modified by overlays, since they are not added as + // roots automatically. + for _, pattern := range restPatterns { + match := matchPattern(pattern) + for _, pkgID := range modifiedPkgs { + pkg, ok := response.seenPackages[pkgID] + if !ok { + continue + } + if match(pkg.PkgPath) { + response.addRoot(pkg.ID) + } } } } @@ -410,7 +414,8 @@ type jsonPackage struct { ForTest string // q in a "p [q.test]" package, else "" DepOnly bool - Error *jsonPackageError + Error *packagesinternal.PackageError + DepsErrors []*packagesinternal.PackageError } type jsonPackageError struct { @@ -562,6 +567,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse OtherFiles: absJoin(p.Dir, otherFiles(p)...), IgnoredFiles: absJoin(p.Dir, p.IgnoredGoFiles, p.IgnoredOtherFiles), forTest: p.ForTest, + depsErrors: p.DepsErrors, Module: p.Module, } @@ -578,7 +584,7 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse // golang/go#38990: go list silently fails to do cgo processing pkg.CompiledGoFiles = nil pkg.Errors = append(pkg.Errors, Error{ - Msg: "go list failed to return CompiledGoFiles; https://golang.org/issue/38990?", + Msg: "go list failed to return CompiledGoFiles. This may indicate failure to perform cgo processing; try building at the command line. See https://golang.org/issue/38990.", Kind: ListError, }) } @@ -824,6 +830,7 @@ func (state *golistState) cfgInvocation() gocommand.Invocation { BuildFlags: cfg.BuildFlags, ModFile: cfg.modFile, ModFlag: cfg.modFlag, + CleanEnv: cfg.Env != nil, Env: cfg.Env, Logf: cfg.Logf, WorkingDir: cfg.Dir, @@ -835,13 +842,33 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, cfg := state.cfg inv := state.cfgInvocation() + + // For Go versions 1.16 and above, `go list` accepts overlays directly via + // the -overlay flag. Set it, if it's available. + // + // The check for "list" is not necessarily required, but we should avoid + // getting the go version if possible. + if verb == "list" { + goVersion, err := state.getGoVersion() + if err != nil { + return nil, err + } + if goVersion >= 16 { + filename, cleanup, err := state.writeOverlays() + if err != nil { + return nil, err + } + defer cleanup() + inv.Overlay = filename + } + } inv.Verb = verb inv.Args = args gocmdRunner := cfg.gocmdRunner if gocmdRunner == nil { gocmdRunner = &gocommand.Runner{} } - stdout, stderr, _, err := gocmdRunner.RunRaw(cfg.Context, inv) + stdout, stderr, friendlyErr, err := gocmdRunner.RunRaw(cfg.Context, inv) if err != nil { // Check for 'go' executable not being found. if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound { @@ -862,7 +889,7 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, // Related to #24854 if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "unexpected directory layout") { - return nil, fmt.Errorf("%s", stderr.String()) + return nil, friendlyErr } // Is there an error running the C compiler in cgo? This will be reported in the "Error" field @@ -878,8 +905,13 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, return unicode.IsOneOf([]*unicode.RangeTable{unicode.L, unicode.M, unicode.N, unicode.P, unicode.S}, r) && !strings.ContainsRune("!\"#$%&'()*,:;<=>?[\\]^`{|}\uFFFD", r) } + // golang/go#36770: Handle case where cmd/go prints module download messages before the error. + msg := stderr.String() + for strings.HasPrefix(msg, "go: downloading") { + msg = msg[strings.IndexRune(msg, '\n')+1:] + } if len(stderr.String()) > 0 && strings.HasPrefix(stderr.String(), "# ") { - msg := stderr.String()[len("# "):] + msg := msg[len("# "):] if strings.HasPrefix(strings.TrimLeftFunc(msg, isPkgPathRune), "\n") { return stdout, nil } @@ -970,12 +1002,73 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, // TODO(matloob): Remove these once we can depend on go list to exit with a zero status with -e even when // packages don't exist or a build fails. if !usesExportData(cfg) && !containsGoFile(args) { - return nil, fmt.Errorf("go %v: %s: %s", args, exitErr, stderr) + return nil, friendlyErr } } return stdout, nil } +// OverlayJSON is the format overlay files are expected to be in. +// The Replace map maps from overlaid paths to replacement paths: +// the Go command will forward all reads trying to open +// each overlaid path to its replacement path, or consider the overlaid +// path not to exist if the replacement path is empty. +// +// From golang/go#39958. +type OverlayJSON struct { + Replace map[string]string `json:"replace,omitempty"` +} + +// writeOverlays writes out files for go list's -overlay flag, as described +// above. +func (state *golistState) writeOverlays() (filename string, cleanup func(), err error) { + // Do nothing if there are no overlays in the config. + if len(state.cfg.Overlay) == 0 { + return "", func() {}, nil + } + dir, err := ioutil.TempDir("", "gopackages-*") + if err != nil { + return "", nil, err + } + // The caller must clean up this directory, unless this function returns an + // error. + cleanup = func() { + os.RemoveAll(dir) + } + defer func() { + if err != nil { + cleanup() + } + }() + overlays := map[string]string{} + for k, v := range state.cfg.Overlay { + // Create a unique filename for the overlaid files, to avoid + // creating nested directories. + noSeparator := strings.Join(strings.Split(filepath.ToSlash(k), "/"), "") + f, err := ioutil.TempFile(dir, fmt.Sprintf("*-%s", noSeparator)) + if err != nil { + return "", func() {}, err + } + if _, err := f.Write(v); err != nil { + return "", func() {}, err + } + if err := f.Close(); err != nil { + return "", func() {}, err + } + overlays[k] = f.Name() + } + b, err := json.Marshal(OverlayJSON{Replace: overlays}) + if err != nil { + return "", func() {}, err + } + // Write out the overlay file that contains the filepath mappings. + filename = filepath.Join(dir, "overlay.json") + if err := ioutil.WriteFile(filename, b, 0665); err != nil { + return "", func() {}, err + } + return filename, cleanup, nil +} + func containsGoFile(s []string) bool { for _, f := range s { if strings.HasSuffix(f, ".go") { @@ -985,17 +1078,22 @@ func containsGoFile(s []string) bool { return false } -func cmdDebugStr(cmd *exec.Cmd, args ...string) string { +func cmdDebugStr(cmd *exec.Cmd) string { env := make(map[string]string) for _, kv := range cmd.Env { - split := strings.Split(kv, "=") + split := strings.SplitN(kv, "=", 2) k, v := split[0], split[1] env[k] = v } - var quotedArgs []string - for _, arg := range args { - quotedArgs = append(quotedArgs, strconv.Quote(arg)) - } - return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %s", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["PWD"], strings.Join(quotedArgs, " ")) + var args []string + for _, arg := range cmd.Args { + quoted := strconv.Quote(arg) + if quoted[1:len(quoted)-1] != arg || strings.Contains(arg, " ") { + args = append(args, quoted) + } else { + args = append(args, arg) + } + } + return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], strings.Join(args, " ")) } diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go index de2c1dc5793..9576b472f9c 100644 --- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go +++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -9,7 +9,6 @@ import ( "fmt" "go/parser" "go/token" - "log" "os" "path/filepath" "regexp" @@ -35,9 +34,12 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif // This is an approximation of import path to id. This can be // wrong for tests, vendored packages, and a number of other cases. havePkgs[pkg.PkgPath] = pkg.ID - x := commonDir(pkg.GoFiles) - if x != "" { - pkgOfDir[x] = append(pkgOfDir[x], pkg) + dir, err := commonDir(pkg.GoFiles) + if err != nil { + return nil, nil, err + } + if dir != "" { + pkgOfDir[dir] = append(pkgOfDir[dir], pkg) } } @@ -441,20 +443,21 @@ func extractPackageName(filename string, contents []byte) (string, bool) { return f.Name.Name, true } -func commonDir(a []string) string { +// commonDir returns the directory that all files are in, "" if files is empty, +// or an error if they aren't in the same directory. +func commonDir(files []string) (string, error) { seen := make(map[string]bool) - x := append([]string{}, a...) - for _, f := range x { + for _, f := range files { seen[filepath.Dir(f)] = true } if len(seen) > 1 { - log.Fatalf("commonDir saw %v for %v", seen, x) + return "", fmt.Errorf("files (%v) are in more than one directory: %v", files, seen) } for k := range seen { - // len(seen) == 1 - return k + // seen has only one element; return it. + return k, nil } - return "" // no files + return "", nil // no files } // It is possible that the files in the disk directory dir have a different package diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go index 38475e8712a..8a1a2d68100 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -339,6 +339,9 @@ type Package struct { // forTest is the package under test, if any. forTest string + // depsErrors is the DepsErrors field from the go list response, if any. + depsErrors []*packagesinternal.PackageError + // module is the module information for the package if it exists. Module *Module } @@ -366,6 +369,9 @@ func init() { packagesinternal.GetForTest = func(p interface{}) string { return p.(*Package).forTest } + packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError { + return p.(*Package).depsErrors + } packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return config.(*Config).gocmdRunner } diff --git a/vendor/golang.org/x/tools/go/packages/visit.go b/vendor/golang.org/x/tools/go/packages/visit.go index b13cb081fcb..a1dcc40b727 100644 --- a/vendor/golang.org/x/tools/go/packages/visit.go +++ b/vendor/golang.org/x/tools/go/packages/visit.go @@ -1,3 +1,7 @@ +// Copyright 2018 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 packages import ( diff --git a/vendor/golang.org/x/tools/internal/event/core/event.go b/vendor/golang.org/x/tools/internal/event/core/event.go index e37b4949150..a6cf0e64a4b 100644 --- a/vendor/golang.org/x/tools/internal/event/core/event.go +++ b/vendor/golang.org/x/tools/internal/event/core/event.go @@ -12,7 +12,7 @@ import ( "golang.org/x/tools/internal/event/label" ) -// Event holds the information about an event of note that ocurred. +// Event holds the information about an event of note that occurred. type Event struct { at time.Time diff --git a/vendor/golang.org/x/tools/internal/event/label/label.go b/vendor/golang.org/x/tools/internal/event/label/label.go index b55c12eb250..0f526e1f9ab 100644 --- a/vendor/golang.org/x/tools/internal/event/label/label.go +++ b/vendor/golang.org/x/tools/internal/event/label/label.go @@ -96,6 +96,8 @@ func Of64(k Key, v uint64) Label { return Label{key: k, packed: v} } // access should be done with the From method of the key. func (t Label) Unpack64() uint64 { return t.packed } +type stringptr unsafe.Pointer + // OfString creates a new label from a key and a string. // This method is for implementing new key types, label creation should // normally be done with the Of method of the key. @@ -104,7 +106,7 @@ func OfString(k Key, v string) Label { return Label{ key: k, packed: uint64(hdr.Len), - untyped: unsafe.Pointer(hdr.Data), + untyped: stringptr(hdr.Data), } } @@ -115,9 +117,9 @@ func OfString(k Key, v string) Label { func (t Label) UnpackString() string { var v string hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) - hdr.Data = uintptr(t.untyped.(unsafe.Pointer)) + hdr.Data = uintptr(t.untyped.(stringptr)) hdr.Len = int(t.packed) - return *(*string)(unsafe.Pointer(hdr)) + return v } // Valid returns true if the Label is a valid one (it has a key). diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go index b5c061b0125..8659a0c5da6 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -9,10 +9,11 @@ import ( "bytes" "context" "fmt" + exec "golang.org/x/sys/execabs" "io" "os" - "os/exec" "regexp" + "strconv" "strings" "sync" "time" @@ -132,6 +133,10 @@ type Invocation struct { BuildFlags []string ModFlag string ModFile string + Overlay string + // If CleanEnv is set, the invocation will run only with the environment + // in Env, not starting with os.Environ. + CleanEnv bool Env []string WorkingDir string Logf func(format string, args ...interface{}) @@ -171,6 +176,11 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { goArgs = append(goArgs, "-mod="+i.ModFlag) } } + appendOverlayFlag := func() { + if i.Overlay != "" { + goArgs = append(goArgs, "-overlay="+i.Overlay) + } + } switch i.Verb { case "env", "version": @@ -189,6 +199,7 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { goArgs = append(goArgs, i.BuildFlags...) appendModFile() appendModFlag() + appendOverlayFlag() goArgs = append(goArgs, i.Args...) } cmd := exec.Command("go", goArgs...) @@ -200,7 +211,10 @@ func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { // The Go stdlib has a special feature where if the cwd and the PWD are the // same node then it trusts the PWD, so by setting it in the env for the child // process we fix up all the paths returned by the go command. - cmd.Env = append(os.Environ(), i.Env...) + if !i.CleanEnv { + cmd.Env = os.Environ() + } + cmd.Env = append(cmd.Env, i.Env...) if i.WorkingDir != "" { cmd.Env = append(cmd.Env, "PWD="+i.WorkingDir) cmd.Dir = i.WorkingDir @@ -241,10 +255,19 @@ func runCmdContext(ctx context.Context, cmd *exec.Cmd) error { func cmdDebugStr(cmd *exec.Cmd) string { env := make(map[string]string) for _, kv := range cmd.Env { - split := strings.Split(kv, "=") + split := strings.SplitN(kv, "=", 2) k, v := split[0], split[1] env[k] = v } - return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v go %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], cmd.Args) + var args []string + for _, arg := range cmd.Args { + quoted := strconv.Quote(arg) + if quoted[1:len(quoted)-1] != arg || strings.Contains(arg, " ") { + args = append(args, quoted) + } else { + args = append(args, arg) + } + } + return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v GOPROXY=%v PWD=%v %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["GOPROXY"], env["PWD"], strings.Join(args, " ")) } diff --git a/vendor/golang.org/x/tools/internal/gocommand/vendor.go b/vendor/golang.org/x/tools/internal/gocommand/vendor.go index 1cd8d8473e9..5e75bd6d8fa 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/vendor.go +++ b/vendor/golang.org/x/tools/internal/gocommand/vendor.go @@ -12,6 +12,7 @@ import ( "path/filepath" "regexp" "strings" + "time" "golang.org/x/mod/semver" ) @@ -19,11 +20,15 @@ import ( // ModuleJSON holds information about a module. type ModuleJSON struct { Path string // module path + Version string // module version + Versions []string // available module versions (with -versions) Replace *ModuleJSON // replaced by this module + Time *time.Time // time version was created + Update *ModuleJSON // available update, if any (with -u) Main bool // is this the main module? Indirect bool // is this module only an indirect dependency of main module? Dir string // directory holding files for this module, if any - GoMod string // path to go.mod file for this module, if any + GoMod string // path to go.mod file used when loading this module, if any GoVersion string // go version used in module } diff --git a/vendor/golang.org/x/tools/internal/gocommand/version.go b/vendor/golang.org/x/tools/internal/gocommand/version.go index 60d45ac0e64..71304368020 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/version.go +++ b/vendor/golang.org/x/tools/internal/gocommand/version.go @@ -14,11 +14,22 @@ import ( // It returns the X in Go 1.X. func GoVersion(ctx context.Context, inv Invocation, r *Runner) (int, error) { inv.Verb = "list" - inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`} + inv.Args = []string{"-e", "-f", `{{context.ReleaseTags}}`, `--`, `unsafe`} inv.Env = append(append([]string{}, inv.Env...), "GO111MODULE=off") - // Unset any unneeded flags. + // Unset any unneeded flags, and remove them from BuildFlags, if they're + // present. inv.ModFile = "" inv.ModFlag = "" + var buildFlags []string + for _, flag := range inv.BuildFlags { + // Flags can be prefixed by one or two dashes. + f := strings.TrimPrefix(strings.TrimPrefix(flag, "-"), "-") + if strings.HasPrefix(f, "mod=") || strings.HasPrefix(f, "modfile=") { + continue + } + buildFlags = append(buildFlags, flag) + } + inv.BuildFlags = buildFlags stdoutBytes, err := r.Run(ctx, inv) if err != nil { return 0, err diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go index 1335a5eed8a..9702094c59e 100644 --- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go +++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go @@ -1,3 +1,7 @@ +// Copyright 2020 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 packagesinternal exposes internal-only fields from go/packages. package packagesinternal @@ -6,6 +10,13 @@ import ( ) var GetForTest = func(p interface{}) string { return "" } +var GetDepsErrors = func(p interface{}) []*PackageError { return nil } + +type PackageError struct { + ImportStack []string // shortest path from package named on command line to this one + Pos string // position of error (if present, file:line:col) + Err string // the error itself +} var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil } diff --git a/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go b/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go new file mode 100644 index 00000000000..fa2834e2ab8 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/typesinternal/errorcode.go @@ -0,0 +1,1368 @@ +// Copyright 2020 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 typesinternal + +//go:generate stringer -type=ErrorCode + +type ErrorCode int + +// This file defines the error codes that can be produced during type-checking. +// Collectively, these codes provide an identifier that may be used to +// implement special handling for certain types of errors. +// +// Error codes should be fine-grained enough that the exact nature of the error +// can be easily determined, but coarse enough that they are not an +// implementation detail of the type checking algorithm. As a rule-of-thumb, +// errors should be considered equivalent if there is a theoretical refactoring +// of the type checker in which they are emitted in exactly one place. For +// example, the type checker emits different error messages for "too many +// arguments" and "too few arguments", but one can imagine an alternative type +// checker where this check instead just emits a single "wrong number of +// arguments", so these errors should have the same code. +// +// Error code names should be as brief as possible while retaining accuracy and +// distinctiveness. In most cases names should start with an adjective +// describing the nature of the error (e.g. "invalid", "unused", "misplaced"), +// and end with a noun identifying the relevant language object. For example, +// "DuplicateDecl" or "InvalidSliceExpr". For brevity, naming follows the +// convention that "bad" implies a problem with syntax, and "invalid" implies a +// problem with types. + +const ( + _ ErrorCode = iota + + // Test is reserved for errors that only apply while in self-test mode. + Test + + /* package names */ + + // BlankPkgName occurs when a package name is the blank identifier "_". + // + // Per the spec: + // "The PackageName must not be the blank identifier." + BlankPkgName + + // MismatchedPkgName occurs when a file's package name doesn't match the + // package name already established by other files. + MismatchedPkgName + + // InvalidPkgUse occurs when a package identifier is used outside of a + // selector expression. + // + // Example: + // import "fmt" + // + // var _ = fmt + InvalidPkgUse + + /* imports */ + + // BadImportPath occurs when an import path is not valid. + BadImportPath + + // BrokenImport occurs when importing a package fails. + // + // Example: + // import "amissingpackage" + BrokenImport + + // ImportCRenamed occurs when the special import "C" is renamed. "C" is a + // pseudo-package, and must not be renamed. + // + // Example: + // import _ "C" + ImportCRenamed + + // UnusedImport occurs when an import is unused. + // + // Example: + // import "fmt" + // + // func main() {} + UnusedImport + + /* initialization */ + + // InvalidInitCycle occurs when an invalid cycle is detected within the + // initialization graph. + // + // Example: + // var x int = f() + // + // func f() int { return x } + InvalidInitCycle + + /* decls */ + + // DuplicateDecl occurs when an identifier is declared multiple times. + // + // Example: + // var x = 1 + // var x = 2 + DuplicateDecl + + // InvalidDeclCycle occurs when a declaration cycle is not valid. + // + // Example: + // import "unsafe" + // + // type T struct { + // a [n]int + // } + // + // var n = unsafe.Sizeof(T{}) + InvalidDeclCycle + + // InvalidTypeCycle occurs when a cycle in type definitions results in a + // type that is not well-defined. + // + // Example: + // import "unsafe" + // + // type T [unsafe.Sizeof(T{})]int + InvalidTypeCycle + + /* decls > const */ + + // InvalidConstInit occurs when a const declaration has a non-constant + // initializer. + // + // Example: + // var x int + // const _ = x + InvalidConstInit + + // InvalidConstVal occurs when a const value cannot be converted to its + // target type. + // + // TODO(findleyr): this error code and example are not very clear. Consider + // removing it. + // + // Example: + // const _ = 1 << "hello" + InvalidConstVal + + // InvalidConstType occurs when the underlying type in a const declaration + // is not a valid constant type. + // + // Example: + // const c *int = 4 + InvalidConstType + + /* decls > var (+ other variable assignment codes) */ + + // UntypedNil occurs when the predeclared (untyped) value nil is used to + // initialize a variable declared without an explicit type. + // + // Example: + // var x = nil + UntypedNil + + // WrongAssignCount occurs when the number of values on the right-hand side + // of an assignment or or initialization expression does not match the number + // of variables on the left-hand side. + // + // Example: + // var x = 1, 2 + WrongAssignCount + + // UnassignableOperand occurs when the left-hand side of an assignment is + // not assignable. + // + // Example: + // func f() { + // const c = 1 + // c = 2 + // } + UnassignableOperand + + // NoNewVar occurs when a short variable declaration (':=') does not declare + // new variables. + // + // Example: + // func f() { + // x := 1 + // x := 2 + // } + NoNewVar + + // MultiValAssignOp occurs when an assignment operation (+=, *=, etc) does + // not have single-valued left-hand or right-hand side. + // + // Per the spec: + // "In assignment operations, both the left- and right-hand expression lists + // must contain exactly one single-valued expression" + // + // Example: + // func f() int { + // x, y := 1, 2 + // x, y += 1 + // return x + y + // } + MultiValAssignOp + + // InvalidIfaceAssign occurs when a value of type T is used as an + // interface, but T does not implement a method of the expected interface. + // + // Example: + // type I interface { + // f() + // } + // + // type T int + // + // var x I = T(1) + InvalidIfaceAssign + + // InvalidChanAssign occurs when a chan assignment is invalid. + // + // Per the spec, a value x is assignable to a channel type T if: + // "x is a bidirectional channel value, T is a channel type, x's type V and + // T have identical element types, and at least one of V or T is not a + // defined type." + // + // Example: + // type T1 chan int + // type T2 chan int + // + // var x T1 + // // Invalid assignment because both types are named + // var _ T2 = x + InvalidChanAssign + + // IncompatibleAssign occurs when the type of the right-hand side expression + // in an assignment cannot be assigned to the type of the variable being + // assigned. + // + // Example: + // var x []int + // var _ int = x + IncompatibleAssign + + // UnaddressableFieldAssign occurs when trying to assign to a struct field + // in a map value. + // + // Example: + // func f() { + // m := make(map[string]struct{i int}) + // m["foo"].i = 42 + // } + UnaddressableFieldAssign + + /* decls > type (+ other type expression codes) */ + + // NotAType occurs when the identifier used as the underlying type in a type + // declaration or the right-hand side of a type alias does not denote a type. + // + // Example: + // var S = 2 + // + // type T S + NotAType + + // InvalidArrayLen occurs when an array length is not a constant value. + // + // Example: + // var n = 3 + // var _ = [n]int{} + InvalidArrayLen + + // BlankIfaceMethod occurs when a method name is '_'. + // + // Per the spec: + // "The name of each explicitly specified method must be unique and not + // blank." + // + // Example: + // type T interface { + // _(int) + // } + BlankIfaceMethod + + // IncomparableMapKey occurs when a map key type does not support the == and + // != operators. + // + // Per the spec: + // "The comparison operators == and != must be fully defined for operands of + // the key type; thus the key type must not be a function, map, or slice." + // + // Example: + // var x map[T]int + // + // type T []int + IncomparableMapKey + + // InvalidIfaceEmbed occurs when a non-interface type is embedded in an + // interface. + // + // Example: + // type T struct {} + // + // func (T) m() + // + // type I interface { + // T + // } + InvalidIfaceEmbed + + // InvalidPtrEmbed occurs when an embedded field is of the pointer form *T, + // and T itself is itself a pointer, an unsafe.Pointer, or an interface. + // + // Per the spec: + // "An embedded field must be specified as a type name T or as a pointer to + // a non-interface type name *T, and T itself may not be a pointer type." + // + // Example: + // type T *int + // + // type S struct { + // *T + // } + InvalidPtrEmbed + + /* decls > func and method */ + + // BadRecv occurs when a method declaration does not have exactly one + // receiver parameter. + // + // Example: + // func () _() {} + BadRecv + + // InvalidRecv occurs when a receiver type expression is not of the form T + // or *T, or T is a pointer type. + // + // Example: + // type T struct {} + // + // func (**T) m() {} + InvalidRecv + + // DuplicateFieldAndMethod occurs when an identifier appears as both a field + // and method name. + // + // Example: + // type T struct { + // m int + // } + // + // func (T) m() {} + DuplicateFieldAndMethod + + // DuplicateMethod occurs when two methods on the same receiver type have + // the same name. + // + // Example: + // type T struct {} + // func (T) m() {} + // func (T) m(i int) int { return i } + DuplicateMethod + + /* decls > special */ + + // InvalidBlank occurs when a blank identifier is used as a value or type. + // + // Per the spec: + // "The blank identifier may appear as an operand only on the left-hand side + // of an assignment." + // + // Example: + // var x = _ + InvalidBlank + + // InvalidIota occurs when the predeclared identifier iota is used outside + // of a constant declaration. + // + // Example: + // var x = iota + InvalidIota + + // MissingInitBody occurs when an init function is missing its body. + // + // Example: + // func init() + MissingInitBody + + // InvalidInitSig occurs when an init function declares parameters or + // results. + // + // Example: + // func init() int { return 1 } + InvalidInitSig + + // InvalidInitDecl occurs when init is declared as anything other than a + // function. + // + // Example: + // var init = 1 + InvalidInitDecl + + // InvalidMainDecl occurs when main is declared as anything other than a + // function, in a main package. + InvalidMainDecl + + /* exprs */ + + // TooManyValues occurs when a function returns too many values for the + // expression context in which it is used. + // + // Example: + // func ReturnTwo() (int, int) { + // return 1, 2 + // } + // + // var x = ReturnTwo() + TooManyValues + + // NotAnExpr occurs when a type expression is used where a value expression + // is expected. + // + // Example: + // type T struct {} + // + // func f() { + // T + // } + NotAnExpr + + /* exprs > const */ + + // TruncatedFloat occurs when a float constant is truncated to an integer + // value. + // + // Example: + // var _ int = 98.6 + TruncatedFloat + + // NumericOverflow occurs when a numeric constant overflows its target type. + // + // Example: + // var x int8 = 1000 + NumericOverflow + + /* exprs > operation */ + + // UndefinedOp occurs when an operator is not defined for the type(s) used + // in an operation. + // + // Example: + // var c = "a" - "b" + UndefinedOp + + // MismatchedTypes occurs when operand types are incompatible in a binary + // operation. + // + // Example: + // var a = "hello" + // var b = 1 + // var c = a - b + MismatchedTypes + + // DivByZero occurs when a division operation is provable at compile + // time to be a division by zero. + // + // Example: + // const divisor = 0 + // var x int = 1/divisor + DivByZero + + // NonNumericIncDec occurs when an increment or decrement operator is + // applied to a non-numeric value. + // + // Example: + // func f() { + // var c = "c" + // c++ + // } + NonNumericIncDec + + /* exprs > ptr */ + + // UnaddressableOperand occurs when the & operator is applied to an + // unaddressable expression. + // + // Example: + // var x = &1 + UnaddressableOperand + + // InvalidIndirection occurs when a non-pointer value is indirected via the + // '*' operator. + // + // Example: + // var x int + // var y = *x + InvalidIndirection + + /* exprs > [] */ + + // NonIndexableOperand occurs when an index operation is applied to a value + // that cannot be indexed. + // + // Example: + // var x = 1 + // var y = x[1] + NonIndexableOperand + + // InvalidIndex occurs when an index argument is not of integer type, + // negative, or out-of-bounds. + // + // Example: + // var s = [...]int{1,2,3} + // var x = s[5] + // + // Example: + // var s = []int{1,2,3} + // var _ = s[-1] + // + // Example: + // var s = []int{1,2,3} + // var i string + // var _ = s[i] + InvalidIndex + + // SwappedSliceIndices occurs when constant indices in a slice expression + // are decreasing in value. + // + // Example: + // var _ = []int{1,2,3}[2:1] + SwappedSliceIndices + + /* operators > slice */ + + // NonSliceableOperand occurs when a slice operation is applied to a value + // whose type is not sliceable, or is unaddressable. + // + // Example: + // var x = [...]int{1, 2, 3}[:1] + // + // Example: + // var x = 1 + // var y = 1[:1] + NonSliceableOperand + + // InvalidSliceExpr occurs when a three-index slice expression (a[x:y:z]) is + // applied to a string. + // + // Example: + // var s = "hello" + // var x = s[1:2:3] + InvalidSliceExpr + + /* exprs > shift */ + + // InvalidShiftCount occurs when the right-hand side of a shift operation is + // either non-integer, negative, or too large. + // + // Example: + // var ( + // x string + // y int = 1 << x + // ) + InvalidShiftCount + + // InvalidShiftOperand occurs when the shifted operand is not an integer. + // + // Example: + // var s = "hello" + // var x = s << 2 + InvalidShiftOperand + + /* exprs > chan */ + + // InvalidReceive occurs when there is a channel receive from a value that + // is either not a channel, or is a send-only channel. + // + // Example: + // func f() { + // var x = 1 + // <-x + // } + InvalidReceive + + // InvalidSend occurs when there is a channel send to a value that is not a + // channel, or is a receive-only channel. + // + // Example: + // func f() { + // var x = 1 + // x <- "hello!" + // } + InvalidSend + + /* exprs > literal */ + + // DuplicateLitKey occurs when an index is duplicated in a slice, array, or + // map literal. + // + // Example: + // var _ = []int{0:1, 0:2} + // + // Example: + // var _ = map[string]int{"a": 1, "a": 2} + DuplicateLitKey + + // MissingLitKey occurs when a map literal is missing a key expression. + // + // Example: + // var _ = map[string]int{1} + MissingLitKey + + // InvalidLitIndex occurs when the key in a key-value element of a slice or + // array literal is not an integer constant. + // + // Example: + // var i = 0 + // var x = []string{i: "world"} + InvalidLitIndex + + // OversizeArrayLit occurs when an array literal exceeds its length. + // + // Example: + // var _ = [2]int{1,2,3} + OversizeArrayLit + + // MixedStructLit occurs when a struct literal contains a mix of positional + // and named elements. + // + // Example: + // var _ = struct{i, j int}{i: 1, 2} + MixedStructLit + + // InvalidStructLit occurs when a positional struct literal has an incorrect + // number of values. + // + // Example: + // var _ = struct{i, j int}{1,2,3} + InvalidStructLit + + // MissingLitField occurs when a struct literal refers to a field that does + // not exist on the struct type. + // + // Example: + // var _ = struct{i int}{j: 2} + MissingLitField + + // DuplicateLitField occurs when a struct literal contains duplicated + // fields. + // + // Example: + // var _ = struct{i int}{i: 1, i: 2} + DuplicateLitField + + // UnexportedLitField occurs when a positional struct literal implicitly + // assigns an unexported field of an imported type. + UnexportedLitField + + // InvalidLitField occurs when a field name is not a valid identifier. + // + // Example: + // var _ = struct{i int}{1: 1} + InvalidLitField + + // UntypedLit occurs when a composite literal omits a required type + // identifier. + // + // Example: + // type outer struct{ + // inner struct { i int } + // } + // + // var _ = outer{inner: {1}} + UntypedLit + + // InvalidLit occurs when a composite literal expression does not match its + // type. + // + // Example: + // type P *struct{ + // x int + // } + // var _ = P {} + InvalidLit + + /* exprs > selector */ + + // AmbiguousSelector occurs when a selector is ambiguous. + // + // Example: + // type E1 struct { i int } + // type E2 struct { i int } + // type T struct { E1; E2 } + // + // var x T + // var _ = x.i + AmbiguousSelector + + // UndeclaredImportedName occurs when a package-qualified identifier is + // undeclared by the imported package. + // + // Example: + // import "go/types" + // + // var _ = types.NotAnActualIdentifier + UndeclaredImportedName + + // UnexportedName occurs when a selector refers to an unexported identifier + // of an imported package. + // + // Example: + // import "reflect" + // + // type _ reflect.flag + UnexportedName + + // UndeclaredName occurs when an identifier is not declared in the current + // scope. + // + // Example: + // var x T + UndeclaredName + + // MissingFieldOrMethod occurs when a selector references a field or method + // that does not exist. + // + // Example: + // type T struct {} + // + // var x = T{}.f + MissingFieldOrMethod + + /* exprs > ... */ + + // BadDotDotDotSyntax occurs when a "..." occurs in a context where it is + // not valid. + // + // Example: + // var _ = map[int][...]int{0: {}} + BadDotDotDotSyntax + + // NonVariadicDotDotDot occurs when a "..." is used on the final argument to + // a non-variadic function. + // + // Example: + // func printArgs(s []string) { + // for _, a := range s { + // println(a) + // } + // } + // + // func f() { + // s := []string{"a", "b", "c"} + // printArgs(s...) + // } + NonVariadicDotDotDot + + // MisplacedDotDotDot occurs when a "..." is used somewhere other than the + // final argument to a function call. + // + // Example: + // func printArgs(args ...int) { + // for _, a := range args { + // println(a) + // } + // } + // + // func f() { + // a := []int{1,2,3} + // printArgs(0, a...) + // } + MisplacedDotDotDot + + // InvalidDotDotDotOperand occurs when a "..." operator is applied to a + // single-valued operand. + // + // Example: + // func printArgs(args ...int) { + // for _, a := range args { + // println(a) + // } + // } + // + // func f() { + // a := 1 + // printArgs(a...) + // } + // + // Example: + // func args() (int, int) { + // return 1, 2 + // } + // + // func printArgs(args ...int) { + // for _, a := range args { + // println(a) + // } + // } + // + // func g() { + // printArgs(args()...) + // } + InvalidDotDotDotOperand + + // InvalidDotDotDot occurs when a "..." is used in a non-variadic built-in + // function. + // + // Example: + // var s = []int{1, 2, 3} + // var l = len(s...) + InvalidDotDotDot + + /* exprs > built-in */ + + // UncalledBuiltin occurs when a built-in function is used as a + // function-valued expression, instead of being called. + // + // Per the spec: + // "The built-in functions do not have standard Go types, so they can only + // appear in call expressions; they cannot be used as function values." + // + // Example: + // var _ = copy + UncalledBuiltin + + // InvalidAppend occurs when append is called with a first argument that is + // not a slice. + // + // Example: + // var _ = append(1, 2) + InvalidAppend + + // InvalidCap occurs when an argument to the cap built-in function is not of + // supported type. + // + // See https://golang.org/ref/spec#Lengthand_capacity for information on + // which underlying types are supported as arguments to cap and len. + // + // Example: + // var s = 2 + // var x = cap(s) + InvalidCap + + // InvalidClose occurs when close(...) is called with an argument that is + // not of channel type, or that is a receive-only channel. + // + // Example: + // func f() { + // var x int + // close(x) + // } + InvalidClose + + // InvalidCopy occurs when the arguments are not of slice type or do not + // have compatible type. + // + // See https://golang.org/ref/spec#Appendingand_copying_slices for more + // information on the type requirements for the copy built-in. + // + // Example: + // func f() { + // var x []int + // y := []int64{1,2,3} + // copy(x, y) + // } + InvalidCopy + + // InvalidComplex occurs when the complex built-in function is called with + // arguments with incompatible types. + // + // Example: + // var _ = complex(float32(1), float64(2)) + InvalidComplex + + // InvalidDelete occurs when the delete built-in function is called with a + // first argument that is not a map. + // + // Example: + // func f() { + // m := "hello" + // delete(m, "e") + // } + InvalidDelete + + // InvalidImag occurs when the imag built-in function is called with an + // argument that does not have complex type. + // + // Example: + // var _ = imag(int(1)) + InvalidImag + + // InvalidLen occurs when an argument to the len built-in function is not of + // supported type. + // + // See https://golang.org/ref/spec#Lengthand_capacity for information on + // which underlying types are supported as arguments to cap and len. + // + // Example: + // var s = 2 + // var x = len(s) + InvalidLen + + // SwappedMakeArgs occurs when make is called with three arguments, and its + // length argument is larger than its capacity argument. + // + // Example: + // var x = make([]int, 3, 2) + SwappedMakeArgs + + // InvalidMake occurs when make is called with an unsupported type argument. + // + // See https://golang.org/ref/spec#Makingslices_maps_and_channels for + // information on the types that may be created using make. + // + // Example: + // var x = make(int) + InvalidMake + + // InvalidReal occurs when the real built-in function is called with an + // argument that does not have complex type. + // + // Example: + // var _ = real(int(1)) + InvalidReal + + /* exprs > assertion */ + + // InvalidAssert occurs when a type assertion is applied to a + // value that is not of interface type. + // + // Example: + // var x = 1 + // var _ = x.(float64) + InvalidAssert + + // ImpossibleAssert occurs for a type assertion x.(T) when the value x of + // interface cannot have dynamic type T, due to a missing or mismatching + // method on T. + // + // Example: + // type T int + // + // func (t *T) m() int { return int(*t) } + // + // type I interface { m() int } + // + // var x I + // var _ = x.(T) + ImpossibleAssert + + /* exprs > conversion */ + + // InvalidConversion occurs when the argument type cannot be converted to the + // target. + // + // See https://golang.org/ref/spec#Conversions for the rules of + // convertibility. + // + // Example: + // var x float64 + // var _ = string(x) + InvalidConversion + + // InvalidUntypedConversion occurs when an there is no valid implicit + // conversion from an untyped value satisfying the type constraints of the + // context in which it is used. + // + // Example: + // var _ = 1 + "" + InvalidUntypedConversion + + /* offsetof */ + + // BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument + // that is not a selector expression. + // + // Example: + // import "unsafe" + // + // var x int + // var _ = unsafe.Offsetof(x) + BadOffsetofSyntax + + // InvalidOffsetof occurs when unsafe.Offsetof is called with a method + // selector, rather than a field selector, or when the field is embedded via + // a pointer. + // + // Per the spec: + // + // "If f is an embedded field, it must be reachable without pointer + // indirections through fields of the struct. " + // + // Example: + // import "unsafe" + // + // type T struct { f int } + // type S struct { *T } + // var s S + // var _ = unsafe.Offsetof(s.f) + // + // Example: + // import "unsafe" + // + // type S struct{} + // + // func (S) m() {} + // + // var s S + // var _ = unsafe.Offsetof(s.m) + InvalidOffsetof + + /* control flow > scope */ + + // UnusedExpr occurs when a side-effect free expression is used as a + // statement. Such a statement has no effect. + // + // Example: + // func f(i int) { + // i*i + // } + UnusedExpr + + // UnusedVar occurs when a variable is declared but unused. + // + // Example: + // func f() { + // x := 1 + // } + UnusedVar + + // MissingReturn occurs when a function with results is missing a return + // statement. + // + // Example: + // func f() int {} + MissingReturn + + // WrongResultCount occurs when a return statement returns an incorrect + // number of values. + // + // Example: + // func ReturnOne() int { + // return 1, 2 + // } + WrongResultCount + + // OutOfScopeResult occurs when the name of a value implicitly returned by + // an empty return statement is shadowed in a nested scope. + // + // Example: + // func factor(n int) (i int) { + // for i := 2; i < n; i++ { + // if n%i == 0 { + // return + // } + // } + // return 0 + // } + OutOfScopeResult + + /* control flow > if */ + + // InvalidCond occurs when an if condition is not a boolean expression. + // + // Example: + // func checkReturn(i int) { + // if i { + // panic("non-zero return") + // } + // } + InvalidCond + + /* control flow > for */ + + // InvalidPostDecl occurs when there is a declaration in a for-loop post + // statement. + // + // Example: + // func f() { + // for i := 0; i < 10; j := 0 {} + // } + InvalidPostDecl + + // InvalidChanRange occurs when a send-only channel used in a range + // expression. + // + // Example: + // func sum(c chan<- int) { + // s := 0 + // for i := range c { + // s += i + // } + // } + InvalidChanRange + + // InvalidIterVar occurs when two iteration variables are used while ranging + // over a channel. + // + // Example: + // func f(c chan int) { + // for k, v := range c { + // println(k, v) + // } + // } + InvalidIterVar + + // InvalidRangeExpr occurs when the type of a range expression is not array, + // slice, string, map, or channel. + // + // Example: + // func f(i int) { + // for j := range i { + // println(j) + // } + // } + InvalidRangeExpr + + /* control flow > switch */ + + // MisplacedBreak occurs when a break statement is not within a for, switch, + // or select statement of the innermost function definition. + // + // Example: + // func f() { + // break + // } + MisplacedBreak + + // MisplacedContinue occurs when a continue statement is not within a for + // loop of the innermost function definition. + // + // Example: + // func sumeven(n int) int { + // proceed := func() { + // continue + // } + // sum := 0 + // for i := 1; i <= n; i++ { + // if i % 2 != 0 { + // proceed() + // } + // sum += i + // } + // return sum + // } + MisplacedContinue + + // MisplacedFallthrough occurs when a fallthrough statement is not within an + // expression switch. + // + // Example: + // func typename(i interface{}) string { + // switch i.(type) { + // case int64: + // fallthrough + // case int: + // return "int" + // } + // return "unsupported" + // } + MisplacedFallthrough + + // DuplicateCase occurs when a type or expression switch has duplicate + // cases. + // + // Example: + // func printInt(i int) { + // switch i { + // case 1: + // println("one") + // case 1: + // println("One") + // } + // } + DuplicateCase + + // DuplicateDefault occurs when a type or expression switch has multiple + // default clauses. + // + // Example: + // func printInt(i int) { + // switch i { + // case 1: + // println("one") + // default: + // println("One") + // default: + // println("1") + // } + // } + DuplicateDefault + + // BadTypeKeyword occurs when a .(type) expression is used anywhere other + // than a type switch. + // + // Example: + // type I interface { + // m() + // } + // var t I + // var _ = t.(type) + BadTypeKeyword + + // InvalidTypeSwitch occurs when .(type) is used on an expression that is + // not of interface type. + // + // Example: + // func f(i int) { + // switch x := i.(type) {} + // } + InvalidTypeSwitch + + // InvalidExprSwitch occurs when a switch expression is not comparable. + // + // Example: + // func _() { + // var a struct{ _ func() } + // switch a /* ERROR cannot switch on a */ { + // } + // } + InvalidExprSwitch + + /* control flow > select */ + + // InvalidSelectCase occurs when a select case is not a channel send or + // receive. + // + // Example: + // func checkChan(c <-chan int) bool { + // select { + // case c: + // return true + // default: + // return false + // } + // } + InvalidSelectCase + + /* control flow > labels and jumps */ + + // UndeclaredLabel occurs when an undeclared label is jumped to. + // + // Example: + // func f() { + // goto L + // } + UndeclaredLabel + + // DuplicateLabel occurs when a label is declared more than once. + // + // Example: + // func f() int { + // L: + // L: + // return 1 + // } + DuplicateLabel + + // MisplacedLabel occurs when a break or continue label is not on a for, + // switch, or select statement. + // + // Example: + // func f() { + // L: + // a := []int{1,2,3} + // for _, e := range a { + // if e > 10 { + // break L + // } + // println(a) + // } + // } + MisplacedLabel + + // UnusedLabel occurs when a label is declared but not used. + // + // Example: + // func f() { + // L: + // } + UnusedLabel + + // JumpOverDecl occurs when a label jumps over a variable declaration. + // + // Example: + // func f() int { + // goto L + // x := 2 + // L: + // x++ + // return x + // } + JumpOverDecl + + // JumpIntoBlock occurs when a forward jump goes to a label inside a nested + // block. + // + // Example: + // func f(x int) { + // goto L + // if x > 0 { + // L: + // print("inside block") + // } + // } + JumpIntoBlock + + /* control flow > calls */ + + // InvalidMethodExpr occurs when a pointer method is called but the argument + // is not addressable. + // + // Example: + // type T struct {} + // + // func (*T) m() int { return 1 } + // + // var _ = T.m(T{}) + InvalidMethodExpr + + // WrongArgCount occurs when too few or too many arguments are passed by a + // function call. + // + // Example: + // func f(i int) {} + // var x = f() + WrongArgCount + + // InvalidCall occurs when an expression is called that is not of function + // type. + // + // Example: + // var x = "x" + // var y = x() + InvalidCall + + /* control flow > suspended */ + + // UnusedResults occurs when a restricted expression-only built-in function + // is suspended via go or defer. Such a suspension discards the results of + // these side-effect free built-in functions, and therefore is ineffectual. + // + // Example: + // func f(a []int) int { + // defer len(a) + // return i + // } + UnusedResults + + // InvalidDefer occurs when a deferred expression is not a function call, + // for example if the expression is a type conversion. + // + // Example: + // func f(i int) int { + // defer int32(i) + // return i + // } + InvalidDefer + + // InvalidGo occurs when a go expression is not a function call, for example + // if the expression is a type conversion. + // + // Example: + // func f(i int) int { + // go int32(i) + // return i + // } + InvalidGo +) diff --git a/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go b/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go new file mode 100644 index 00000000000..3e5842a5f0f --- /dev/null +++ b/vendor/golang.org/x/tools/internal/typesinternal/errorcode_string.go @@ -0,0 +1,153 @@ +// Code generated by "stringer -type=ErrorCode"; DO NOT EDIT. + +package typesinternal + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Test-1] + _ = x[BlankPkgName-2] + _ = x[MismatchedPkgName-3] + _ = x[InvalidPkgUse-4] + _ = x[BadImportPath-5] + _ = x[BrokenImport-6] + _ = x[ImportCRenamed-7] + _ = x[UnusedImport-8] + _ = x[InvalidInitCycle-9] + _ = x[DuplicateDecl-10] + _ = x[InvalidDeclCycle-11] + _ = x[InvalidTypeCycle-12] + _ = x[InvalidConstInit-13] + _ = x[InvalidConstVal-14] + _ = x[InvalidConstType-15] + _ = x[UntypedNil-16] + _ = x[WrongAssignCount-17] + _ = x[UnassignableOperand-18] + _ = x[NoNewVar-19] + _ = x[MultiValAssignOp-20] + _ = x[InvalidIfaceAssign-21] + _ = x[InvalidChanAssign-22] + _ = x[IncompatibleAssign-23] + _ = x[UnaddressableFieldAssign-24] + _ = x[NotAType-25] + _ = x[InvalidArrayLen-26] + _ = x[BlankIfaceMethod-27] + _ = x[IncomparableMapKey-28] + _ = x[InvalidIfaceEmbed-29] + _ = x[InvalidPtrEmbed-30] + _ = x[BadRecv-31] + _ = x[InvalidRecv-32] + _ = x[DuplicateFieldAndMethod-33] + _ = x[DuplicateMethod-34] + _ = x[InvalidBlank-35] + _ = x[InvalidIota-36] + _ = x[MissingInitBody-37] + _ = x[InvalidInitSig-38] + _ = x[InvalidInitDecl-39] + _ = x[InvalidMainDecl-40] + _ = x[TooManyValues-41] + _ = x[NotAnExpr-42] + _ = x[TruncatedFloat-43] + _ = x[NumericOverflow-44] + _ = x[UndefinedOp-45] + _ = x[MismatchedTypes-46] + _ = x[DivByZero-47] + _ = x[NonNumericIncDec-48] + _ = x[UnaddressableOperand-49] + _ = x[InvalidIndirection-50] + _ = x[NonIndexableOperand-51] + _ = x[InvalidIndex-52] + _ = x[SwappedSliceIndices-53] + _ = x[NonSliceableOperand-54] + _ = x[InvalidSliceExpr-55] + _ = x[InvalidShiftCount-56] + _ = x[InvalidShiftOperand-57] + _ = x[InvalidReceive-58] + _ = x[InvalidSend-59] + _ = x[DuplicateLitKey-60] + _ = x[MissingLitKey-61] + _ = x[InvalidLitIndex-62] + _ = x[OversizeArrayLit-63] + _ = x[MixedStructLit-64] + _ = x[InvalidStructLit-65] + _ = x[MissingLitField-66] + _ = x[DuplicateLitField-67] + _ = x[UnexportedLitField-68] + _ = x[InvalidLitField-69] + _ = x[UntypedLit-70] + _ = x[InvalidLit-71] + _ = x[AmbiguousSelector-72] + _ = x[UndeclaredImportedName-73] + _ = x[UnexportedName-74] + _ = x[UndeclaredName-75] + _ = x[MissingFieldOrMethod-76] + _ = x[BadDotDotDotSyntax-77] + _ = x[NonVariadicDotDotDot-78] + _ = x[MisplacedDotDotDot-79] + _ = x[InvalidDotDotDotOperand-80] + _ = x[InvalidDotDotDot-81] + _ = x[UncalledBuiltin-82] + _ = x[InvalidAppend-83] + _ = x[InvalidCap-84] + _ = x[InvalidClose-85] + _ = x[InvalidCopy-86] + _ = x[InvalidComplex-87] + _ = x[InvalidDelete-88] + _ = x[InvalidImag-89] + _ = x[InvalidLen-90] + _ = x[SwappedMakeArgs-91] + _ = x[InvalidMake-92] + _ = x[InvalidReal-93] + _ = x[InvalidAssert-94] + _ = x[ImpossibleAssert-95] + _ = x[InvalidConversion-96] + _ = x[InvalidUntypedConversion-97] + _ = x[BadOffsetofSyntax-98] + _ = x[InvalidOffsetof-99] + _ = x[UnusedExpr-100] + _ = x[UnusedVar-101] + _ = x[MissingReturn-102] + _ = x[WrongResultCount-103] + _ = x[OutOfScopeResult-104] + _ = x[InvalidCond-105] + _ = x[InvalidPostDecl-106] + _ = x[InvalidChanRange-107] + _ = x[InvalidIterVar-108] + _ = x[InvalidRangeExpr-109] + _ = x[MisplacedBreak-110] + _ = x[MisplacedContinue-111] + _ = x[MisplacedFallthrough-112] + _ = x[DuplicateCase-113] + _ = x[DuplicateDefault-114] + _ = x[BadTypeKeyword-115] + _ = x[InvalidTypeSwitch-116] + _ = x[InvalidExprSwitch-117] + _ = x[InvalidSelectCase-118] + _ = x[UndeclaredLabel-119] + _ = x[DuplicateLabel-120] + _ = x[MisplacedLabel-121] + _ = x[UnusedLabel-122] + _ = x[JumpOverDecl-123] + _ = x[JumpIntoBlock-124] + _ = x[InvalidMethodExpr-125] + _ = x[WrongArgCount-126] + _ = x[InvalidCall-127] + _ = x[UnusedResults-128] + _ = x[InvalidDefer-129] + _ = x[InvalidGo-130] +} + +const _ErrorCode_name = "TestBlankPkgNameMismatchedPkgNameInvalidPkgUseBadImportPathBrokenImportImportCRenamedUnusedImportInvalidInitCycleDuplicateDeclInvalidDeclCycleInvalidTypeCycleInvalidConstInitInvalidConstValInvalidConstTypeUntypedNilWrongAssignCountUnassignableOperandNoNewVarMultiValAssignOpInvalidIfaceAssignInvalidChanAssignIncompatibleAssignUnaddressableFieldAssignNotATypeInvalidArrayLenBlankIfaceMethodIncomparableMapKeyInvalidIfaceEmbedInvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDotInvalidDotDotDotOperandInvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDeclInvalidChanRangeInvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGo" + +var _ErrorCode_index = [...]uint16{0, 4, 16, 33, 46, 59, 71, 85, 97, 113, 126, 142, 158, 174, 189, 205, 215, 231, 250, 258, 274, 292, 309, 327, 351, 359, 374, 390, 408, 425, 440, 447, 458, 481, 496, 508, 519, 534, 548, 563, 578, 591, 600, 614, 629, 640, 655, 664, 680, 700, 718, 737, 749, 768, 787, 803, 820, 839, 853, 864, 879, 892, 907, 923, 937, 953, 968, 985, 1003, 1018, 1028, 1038, 1055, 1077, 1091, 1105, 1125, 1143, 1163, 1181, 1204, 1220, 1235, 1248, 1258, 1270, 1281, 1295, 1308, 1319, 1329, 1344, 1355, 1366, 1379, 1395, 1412, 1436, 1453, 1468, 1478, 1487, 1500, 1516, 1532, 1543, 1558, 1574, 1588, 1604, 1618, 1635, 1655, 1668, 1684, 1698, 1715, 1732, 1749, 1764, 1778, 1792, 1803, 1815, 1828, 1845, 1858, 1869, 1882, 1894, 1903} + +func (i ErrorCode) String() string { + i -= 1 + if i < 0 || i >= ErrorCode(len(_ErrorCode_index)-1) { + return "ErrorCode(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]] +} diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go index a5bb408e2f1..c3e1a397dbf 100644 --- a/vendor/golang.org/x/tools/internal/typesinternal/types.go +++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -2,9 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package typesinternal provides access to internal go/types APIs that are not +// yet exported. package typesinternal import ( + "go/token" "go/types" "reflect" "unsafe" @@ -26,3 +29,17 @@ func SetUsesCgo(conf *types.Config) bool { return true } + +func ReadGo116ErrorData(terr types.Error) (ErrorCode, token.Pos, token.Pos, bool) { + var data [3]int + // By coincidence all of these fields are ints, which simplifies things. + v := reflect.ValueOf(terr) + for i, name := range []string{"go116code", "go116start", "go116end"} { + f := v.FieldByName(name) + if !f.IsValid() { + return 0, 0, 0, false + } + data[i] = int(f.Int()) + } + return ErrorCode(data[0]), token.Pos(data[1]), token.Pos(data[2]), true +} diff --git a/vendor/golang.org/x/xerrors/go.mod b/vendor/golang.org/x/xerrors/go.mod deleted file mode 100644 index 870d4f612db..00000000000 --- a/vendor/golang.org/x/xerrors/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module golang.org/x/xerrors - -go 1.11 diff --git a/vendor/modules.txt b/vendor/modules.txt index 0a7c6f0bb4a..4b567fe9635 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,11 +1,14 @@ -# golang.org/x/mod v0.3.0 -## explicit +# golang.org/x/mod v0.5.0 +## explicit; go 1.17 golang.org/x/mod/internal/lazyregexp golang.org/x/mod/modfile golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 -## explicit +# golang.org/x/sys v0.0.0-20210510120138-977fb7262007 +## explicit; go 1.17 +golang.org/x/sys/execabs +# golang.org/x/tools v0.1.5 +## explicit; go 1.17 golang.org/x/tools/go/gcexportdata golang.org/x/tools/go/internal/gcimporter golang.org/x/tools/go/internal/packagesdriver @@ -18,5 +21,6 @@ golang.org/x/tools/internal/gocommand golang.org/x/tools/internal/packagesinternal golang.org/x/tools/internal/typesinternal # golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 +## explicit; go 1.11 golang.org/x/xerrors golang.org/x/xerrors/internal