diff --git a/MODULE.bazel b/MODULE.bazel index 8dd50d33c3f8..46b7a7583555 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -276,7 +276,7 @@ use_repo( ) go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk") -go_sdk.download(version = "1.26.5") +go_sdk.download(version = "1.27rc2") go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") go_deps.from_file(go_mod = "//go/extractor:go.mod") diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst index 7a88dd035c2a..cb5ca45c5c08 100644 --- a/docs/codeql/reusables/supported-versions-compilers.rst +++ b/docs/codeql/reusables/supported-versions-compilers.rst @@ -17,7 +17,7 @@ .NET 5, .NET 6, .NET 7, .NET 8, .NET 9, .NET 10","``.sln``, ``.slnx``, ``.csproj``, ``.cs``, ``.cshtml``, ``.xaml``" GitHub Actions,"Not applicable",Not applicable,"``.github/workflows/*.yml``, ``.github/workflows/*.yaml``, ``**/action.yml``, ``**/action.yaml``" - Go (aka Golang), "Go up to 1.26", "Go 1.11 or more recent", ``.go`` + Go (aka Golang), "Go up to 1.27", "Go 1.11 or more recent", ``.go`` Java,"Java 7 to 26 [6]_","javac (OpenJDK and Oracle JDK), Eclipse compiler for Java (ECJ) [7]_",``.java`` diff --git a/go/actions/test/action.yml b/go/actions/test/action.yml index d4c391cd0103..751c18c8aa2f 100644 --- a/go/actions/test/action.yml +++ b/go/actions/test/action.yml @@ -4,7 +4,7 @@ inputs: go-test-version: description: Which Go version to use for running the tests required: false - default: "~1.26.5" + default: "1.27.0-rc.2" run-code-checks: description: Whether to run formatting, code and qhelp generation checks required: false diff --git a/go/extractor/autobuilder/build-environment.go b/go/extractor/autobuilder/build-environment.go index c660373205b2..bd7fc0adabe1 100644 --- a/go/extractor/autobuilder/build-environment.go +++ b/go/extractor/autobuilder/build-environment.go @@ -12,7 +12,7 @@ import ( ) var minGoVersion = util.NewSemVer("1.11") -var maxGoVersion = util.NewSemVer("1.26") +var maxGoVersion = util.NewSemVer("1.27") type versionInfo struct { goModVersion util.SemVer // The version of Go found in the go directive in the `go.mod` file. diff --git a/go/extractor/extractor.go b/go/extractor/extractor.go index 8c2178376141..fbe10ef7a33b 100644 --- a/go/extractor/extractor.go +++ b/go/extractor/extractor.go @@ -1657,8 +1657,30 @@ func extractType(tw *trap.Writer, tp types.Type) trap.Label { // parent scope, so they are not dealt with by `extractScopes` for i := 0; i < origintp.NumMethods(); i++ { meth := origintp.Method(i).Origin() - extractMethod(tw, meth) + + // Consider a generic struct and a generic method: + // + // type S[P any] struct{} + // func (*S[P]) m[Q any](x Q) {} + // + // If we have a variable 's' of type 'S[int]' and the expression + // 's.m[string]("")', then the type of the selector expression 's.m' + // is ' func(Q)'. The method 'm' here is an instantiation of the + // declaration, which has its own type with type parameter 'Q'. + // As we do not extract method instantiations, 'populateTypeParamParents' + // does not automatically get called for the type parameter 'Q' + // from the instantiation of 'm'. To compensate, we add the type + // parameters here. + // + // As a parent we use the origin method. This suffices, as the name + // and index of the type parameter in the instantiation will be + // identical to those of the uninstantiated method, and as only + // these two properties will be extracted for a type parameter. + if tp.Method(i) != meth { + signature := tp.Method(i).Type().(*types.Signature) + populateTypeParamParents(signature.TypeParams(), meth, false) + } } underlyingInterface, underlyingIsInterface := underlying.(*types.Interface) diff --git a/go/extractor/go.mod b/go/extractor/go.mod index b45815abbc95..011449e8cc52 100644 --- a/go/extractor/go.mod +++ b/go/extractor/go.mod @@ -1,8 +1,8 @@ module github.com/github/codeql-go/extractor -go 1.26 +go 1.27 -toolchain go1.26.5 +toolchain go1.27rc2 // when updating this, run // bazel run @rules_go//go -- mod tidy diff --git a/go/extractor/toolchain/toolchain_test.go b/go/extractor/toolchain/toolchain_test.go index 8a6b38318cb9..a62c9016a700 100644 --- a/go/extractor/toolchain/toolchain_test.go +++ b/go/extractor/toolchain/toolchain_test.go @@ -8,9 +8,9 @@ import ( func TestParseGoVersion(t *testing.T) { tests := map[string]string{ - "go version go1.18.9 linux/amd64": "go1.18.9", - "go version go1.26.3-X:nodwarf5 linux/amd64": "go1.26.3", - "go version go1.26.3rc1 linux/amd64": "go1.26.3rc1", + "go version go1.18.9 linux/amd64": "go1.18.9", + "go version go1.26.3-X:nodwarf5 linux/amd64": "go1.26.3", + "go version go1.26.3rc1 linux/amd64": "go1.26.3rc1", "warning: GOPATH set to GOROOT (/usr/local/go) has no effect\ngo version go1.18.9 linux/amd64": "go1.18.9", } for input, expected := range tests { diff --git a/go/extractor/trap/labels.go b/go/extractor/trap/labels.go index 473e2e761f2e..ca43bc370252 100644 --- a/go/extractor/trap/labels.go +++ b/go/extractor/trap/labels.go @@ -187,7 +187,7 @@ func findMethodOnTypeWithGivenReceiver(tp types.Type, object types.Object) *type if definedType, ok := tp.(*types.Named); ok { for i := 0; i < definedType.NumMethods(); i++ { meth := definedType.Method(i) - if object == meth.Type().(*types.Signature).Recv() { + if object == meth.Type().(*types.Signature).Recv().Origin() { return meth } } diff --git a/go/ql/lib/change-notes/2026-06-25-go-1.27.md b/go/ql/lib/change-notes/2026-06-25-go-1.27.md new file mode 100644 index 000000000000..b1998aee7f54 --- /dev/null +++ b/go/ql/lib/change-notes/2026-06-25-go-1.27.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Go 1.27 is now supported. diff --git a/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected b/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected index 6528a0ae7f3d..5c01d626b28a 100644 --- a/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected +++ b/go/ql/test/library-tests/semmle/go/Function/GenericFunctionInstantiationExpr.expected @@ -6,3 +6,5 @@ | genericFunctions.go:45:6:45:50 | generic function instantiation expression | genericFunctions.go:45:6:45:33 | GenericFunctionTwoTypeParams | 1 | genericFunctions.go:45:43:45:49 | float64 | | genericFunctions.go:141:6:141:41 | generic function instantiation expression | genericFunctions.go:141:6:141:33 | GenericFunctionInAnotherFile | 0 | genericFunctions.go:141:35:141:40 | string | | genericFunctions.go:146:6:146:55 | generic function instantiation expression | genericFunctions.go:146:6:146:47 | selection of GenericFunctionInAnotherPackage | 0 | genericFunctions.go:146:49:146:54 | string | +| genericMethods.go:13:2:13:23 | generic function instantiation expression | genericMethods.go:13:2:13:18 | selection of GenericMethod1 | 0 | genericMethods.go:13:20:13:22 | int | +| genericMethods.go:14:2:14:26 | generic function instantiation expression | genericMethods.go:14:2:14:18 | selection of GenericMethod2 | 0 | genericMethods.go:14:20:14:25 | string | diff --git a/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected b/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected index 4addfa50f349..a04289ef71b7 100644 --- a/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected +++ b/go/ql/test/library-tests/semmle/go/Function/TypeParamType.expected @@ -19,6 +19,9 @@ numberOfTypeParameters | genericFunctions.go:150:6:150:36 | multipleAnonymousTypeParamsFunc | 3 | | genericFunctions.go:152:6:152:36 | multipleAnonymousTypeParamsType | 3 | | genericFunctions.go:154:51:154:51 | f | 3 | +| genericMethods.go:5:33:5:46 | GenericMethod1 | 1 | +| genericMethods.go:7:6:7:28 | StructForGenericMethod2 | 1 | +| genericMethods.go:9:37:9:50 | GenericMethod2 | 2 | #select | codeql-go-tests/function.EdgeConstraint | 0 | | Node | interface { } | | codeql-go-tests/function.Element | 0 | | S | interface { } | @@ -44,6 +47,10 @@ numberOfTypeParameters | codeql-go-tests/function.New | 0 | | Node | NodeConstraint | | codeql-go-tests/function.New | 1 | | Edge | EdgeConstraint | | codeql-go-tests/function.NodeConstraint | 0 | | Edge | interface { } | +| codeql-go-tests/function.StructForGenericMethod1.GenericMethod1 | 0 | | P1 | interface { } | +| codeql-go-tests/function.StructForGenericMethod2 | 0 | | P2 | interface { } | +| codeql-go-tests/function.StructForGenericMethod2.GenericMethod2 | 0 | | P4 | interface { } | +| codeql-go-tests/function.StructForGenericMethod2.GenericMethod2 | 0 | from receiver | P3 | interface { } | | codeql-go-tests/function.multipleAnonymousTypeParamsFunc | 0 | | _ | interface { } | | codeql-go-tests/function.multipleAnonymousTypeParamsFunc | 1 | | _ | interface { string } | | codeql-go-tests/function.multipleAnonymousTypeParamsFunc | 2 | | _ | interface { } | diff --git a/go/ql/test/library-tests/semmle/go/Function/genericMethods.go b/go/ql/test/library-tests/semmle/go/Function/genericMethods.go new file mode 100644 index 000000000000..54bd4135da2f --- /dev/null +++ b/go/ql/test/library-tests/semmle/go/Function/genericMethods.go @@ -0,0 +1,19 @@ +package main + +type StructForGenericMethod1 struct{} + +func (*StructForGenericMethod1) GenericMethod1[P1 any](x P1) {} + +type StructForGenericMethod2[P2 any] struct{} + +func (*StructForGenericMethod2[P3]) GenericMethod2[P4 any](x P4) {} + +func generic_methods(s1 StructForGenericMethod1, s2 StructForGenericMethod2[int]) { + // Call the generic method specifying the type + s1.GenericMethod1[int](1) + s2.GenericMethod2[string]("hello") + + // Call the generic method without specifying the type + s1.GenericMethod1("hello") + s2.GenericMethod2(42) +} diff --git a/go/ql/test/library-tests/semmle/go/Function/getParameter.expected b/go/ql/test/library-tests/semmle/go/Function/getParameter.expected index 80171d5e79a6..55fb6e4a9579 100644 --- a/go/ql/test/library-tests/semmle/go/Function/getParameter.expected +++ b/go/ql/test/library-tests/semmle/go/Function/getParameter.expected @@ -11,6 +11,10 @@ | genericFunctions.go:138:29:138:40 | ShortestPath | 1 | genericFunctions.go:138:48:138:49 | to | | genericFunctions.go:138:29:138:40 | ShortestPath | -1 | genericFunctions.go:138:7:138:7 | g | | genericFunctions.go:154:51:154:51 | f | -1 | genericFunctions.go:154:7:154:7 | x | +| genericMethods.go:5:33:5:46 | GenericMethod1 | 0 | genericMethods.go:5:56:5:56 | x | +| genericMethods.go:9:37:9:50 | GenericMethod2 | 0 | genericMethods.go:9:60:9:60 | x | +| genericMethods.go:11:6:11:20 | generic_methods | 0 | genericMethods.go:11:22:11:23 | s1 | +| genericMethods.go:11:6:11:20 | generic_methods | 1 | genericMethods.go:11:50:11:51 | s2 | | main.go:7:6:7:7 | f1 | 0 | main.go:7:9:7:9 | x | | main.go:9:12:9:13 | f2 | 0 | main.go:9:15:9:15 | x | | main.go:9:12:9:13 | f2 | 1 | main.go:9:18:9:18 | y | diff --git a/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected b/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected index 27a89adf95e2..9f758d14ee88 100644 --- a/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected +++ b/go/ql/test/library-tests/semmle/go/Function/getTypeParameter.expected @@ -19,3 +19,6 @@ | genericFunctions.go:152:6:152:69 | type declaration specifier | TypeSpec | 0 | genericFunctions.go:152:38:152:42 | type parameter declaration | 0 | genericFunctions.go:152:38:152:38 | _ | genericFunctions.go:152:40:152:42 | any | interface { } | | genericFunctions.go:152:6:152:69 | type declaration specifier | TypeSpec | 1 | genericFunctions.go:152:45:152:52 | type parameter declaration | 0 | genericFunctions.go:152:45:152:45 | _ | genericFunctions.go:152:47:152:52 | string | interface { string } | | genericFunctions.go:152:6:152:69 | type declaration specifier | TypeSpec | 2 | genericFunctions.go:152:55:152:59 | type parameter declaration | 0 | genericFunctions.go:152:55:152:55 | _ | genericFunctions.go:152:57:152:59 | any | interface { } | +| genericMethods.go:5:1:5:63 | function declaration | MethodDecl | 0 | genericMethods.go:5:48:5:53 | type parameter declaration | 0 | genericMethods.go:5:48:5:49 | P1 | genericMethods.go:5:51:5:53 | any | interface { } | +| genericMethods.go:7:6:7:45 | type declaration specifier | TypeSpec | 0 | genericMethods.go:7:30:7:35 | type parameter declaration | 0 | genericMethods.go:7:30:7:31 | P2 | genericMethods.go:7:33:7:35 | any | interface { } | +| genericMethods.go:9:1:9:67 | function declaration | MethodDecl | 0 | genericMethods.go:9:52:9:57 | type parameter declaration | 0 | genericMethods.go:9:52:9:53 | P4 | genericMethods.go:9:55:9:57 | any | interface { } | diff --git a/go/ql/test/library-tests/semmle/go/Function/go.mod b/go/ql/test/library-tests/semmle/go/Function/go.mod index 85d3db5c5a37..1ce69dff1160 100644 --- a/go/ql/test/library-tests/semmle/go/Function/go.mod +++ b/go/ql/test/library-tests/semmle/go/Function/go.mod @@ -1,6 +1,8 @@ module codeql-go-tests/function -go 1.18 +go 1.27 + +toolchain go1.27rc2 require github.com/anotherpkg v0.0.0-20200203000000-0000000000000