| /* |
| Copyright 2020 Google LLC |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| https://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package warn |
| |
| import ( |
| "fmt" |
| "testing" |
| |
| "github.com/bazelbuild/buildtools/tables" |
| ) |
| |
| func TestAttrDataConfigurationWarning(t *testing.T) { |
| checkFindingsAndFix(t, "attr-cfg", ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(mandatory = True, cfg = "data"), |
| } |
| ) |
| |
| attr.label_list(mandatory = True, cfg = "exec")`, ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(mandatory = True), |
| } |
| ) |
| |
| attr.label_list(mandatory = True, cfg = "exec")`, |
| []string{`:3: cfg = "data" for attr definitions has no effect and should be removed.`}, |
| scopeBzl) |
| } |
| |
| func TestAttrHostConfigurationWarning(t *testing.T) { |
| checkFindingsAndFix(t, "attr-cfg", ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(mandatory = True, cfg = "host"), |
| } |
| ) |
| |
| attr.label_list(mandatory = True, cfg = "exec")`, ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(mandatory = True, cfg = "exec"), |
| } |
| ) |
| |
| attr.label_list(mandatory = True, cfg = "exec")`, |
| []string{`:3: cfg = "host" for attr definitions should be replaced by cfg = "exec".`}, |
| scopeBzl) |
| } |
| |
| func TestDepsetItemsWarning(t *testing.T) { |
| checkFindings(t, "depset-items", ` |
| def f(): |
| depset(items=foo) |
| a = depset() |
| depset(a) |
| `, []string{ |
| `:2: Parameter "items" is deprecated, use "direct" and/or "transitive" instead.`, |
| `:4: Giving a depset as first unnamed parameter to depset() is deprecated, use the "transitive" parameter instead.`, |
| }, |
| scopeEverywhere) |
| } |
| |
| func TestAttrNonEmptyWarning(t *testing.T) { |
| checkFindingsAndFix(t, "attr-non-empty", ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(mandatory = True, non_empty = True), |
| "bar": attr.label_list(mandatory = True, non_empty = False), |
| "baz": attr.label_list(mandatory = True, non_empty = foo.bar()), |
| "qux": attr.label_list(mandatory = True, non_empty = not foo.bar()), |
| "aaa": attr.label_list(mandatory = True, non_empty = (foo.bar())), |
| "bbb": attr.label_list(mandatory = True, non_empty = ( |
| not foo.bar() |
| )), |
| } |
| )`, ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(mandatory = True, allow_empty = False), |
| "bar": attr.label_list(mandatory = True, allow_empty = True), |
| "baz": attr.label_list(mandatory = True, allow_empty = not foo.bar()), |
| "qux": attr.label_list(mandatory = True, allow_empty = foo.bar()), |
| "aaa": attr.label_list(mandatory = True, allow_empty = (not foo.bar())), |
| "bbb": attr.label_list(mandatory = True, allow_empty = ( |
| foo.bar() |
| )), |
| } |
| )`, |
| []string{ |
| ":3: non_empty attributes for attr definitions are deprecated in favor of allow_empty.", |
| ":4: non_empty attributes for attr definitions are deprecated in favor of allow_empty.", |
| ":5: non_empty attributes for attr definitions are deprecated in favor of allow_empty.", |
| ":6: non_empty attributes for attr definitions are deprecated in favor of allow_empty.", |
| ":7: non_empty attributes for attr definitions are deprecated in favor of allow_empty.", |
| ":8: non_empty attributes for attr definitions are deprecated in favor of allow_empty.", |
| }, |
| scopeBzl) |
| } |
| |
| func TestAttrSingleFileWarning(t *testing.T) { |
| checkFindingsAndFix(t, "attr-single-file", ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(single_file = True, allow_files = [".cc"], mandatory = True), |
| "bar": attr.label_list(single_file = True, mandatory = True), |
| "baz": attr.label_list(single_file = False, mandatory = True), |
| } |
| )`, ` |
| rule( |
| attrs = { |
| "foo": attr.label_list(allow_single_file = [".cc"], mandatory = True), |
| "bar": attr.label_list(allow_single_file = True, mandatory = True), |
| "baz": attr.label_list(mandatory = True), |
| } |
| )`, |
| []string{ |
| ":3: single_file is deprecated in favor of allow_single_file.", |
| ":4: single_file is deprecated in favor of allow_single_file.", |
| ":5: single_file is deprecated in favor of allow_single_file.", |
| }, |
| scopeBzl) |
| } |
| |
| func TestCtxActionsWarning(t *testing.T) { |
| checkFindingsAndFix(t, "ctx-actions", ` |
| def impl(ctx): |
| ctx.new_file(foo) |
| ctx.new_file(foo, "foo %s " % bar) |
| ctx.new_file(foo, name = bar) |
| ctx.new_file(foo, bar, baz) |
| ctx.experimental_new_directory(foo, bar) |
| ctx.file_action(foo, bar) |
| ctx.file_action(foo, bar, executable = True) |
| ctx.action(foo, bar, command = "foo") |
| ctx.action(foo, bar, executable = "bar") |
| ctx.empty_action(foo, bar) |
| ctx.template_action(foo, bar) |
| ctx.template_action(foo, bar, executable = True) |
| ctx.foobar(foo, bar) |
| `, ` |
| def impl(ctx): |
| ctx.actions.declare_file(foo) |
| ctx.actions.declare_file("foo %s " % bar, sibling = foo) |
| ctx.actions.declare_file(bar, sibling = foo) |
| ctx.new_file(foo, bar, baz) |
| ctx.actions.declare_directory(foo, bar) |
| ctx.actions.write(foo, bar) |
| ctx.actions.write(foo, bar, is_executable = True) |
| ctx.actions.run_shell(foo, bar, command = "foo") |
| ctx.actions.run(foo, bar, executable = "bar") |
| ctx.actions.do_nothing(foo, bar) |
| ctx.actions.expand_template(foo, bar) |
| ctx.actions.expand_template(foo, bar, is_executable = True) |
| ctx.foobar(foo, bar) |
| `, |
| []string{ |
| `:2: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`, |
| `:3: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`, |
| `:4: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`, |
| `:5: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`, |
| `:6: "ctx.experimental_new_directory" is deprecated in favor of "ctx.actions.declare_directory".`, |
| `:7: "ctx.file_action" is deprecated in favor of "ctx.actions.write".`, |
| `:8: "ctx.file_action" is deprecated in favor of "ctx.actions.write".`, |
| `:9: "ctx.action" is deprecated in favor of "ctx.actions.run_shell".`, |
| `:10: "ctx.action" is deprecated in favor of "ctx.actions.run".`, |
| `:11: "ctx.empty_action" is deprecated in favor of "ctx.actions.do_nothing".`, |
| `:12: "ctx.template_action" is deprecated in favor of "ctx.actions.expand_template".`, |
| `:13: "ctx.template_action" is deprecated in favor of "ctx.actions.expand_template".`, |
| }, |
| scopeBzl) |
| |
| checkFindings(t, "ctx-actions", ` |
| def impl(ctx): |
| ctx.new_file(foo, bar, baz) |
| `, []string{ |
| `:2: "ctx.new_file" is deprecated in favor of "ctx.actions.declare_file".`, |
| }, scopeBzl) |
| } |
| |
| func TestPackageNameWarning(t *testing.T) { |
| checkFindingsAndFix(t, "package-name", ` |
| foo(a = PACKAGE_NAME) |
| |
| def f(PACKAGE_NAME): |
| foo(a = PACKAGE_NAME) |
| |
| def g(): |
| foo(a = PACKAGE_NAME) |
| `, ` |
| foo(a = native.package_name()) |
| |
| def f(PACKAGE_NAME): |
| foo(a = PACKAGE_NAME) |
| |
| def g(): |
| foo(a = native.package_name()) |
| `, |
| []string{ |
| `:1: Global variable "PACKAGE_NAME" is deprecated in favor of "native.package_name()". Please rename it.`, |
| `:7: Global variable "PACKAGE_NAME" is deprecated in favor of "native.package_name()". Please rename it.`, |
| }, |
| scopeBzl) |
| |
| checkFindings(t, "package-name", ` |
| PACKAGE_NAME = "foo" |
| foo(a = PACKAGE_NAME) |
| `, []string{}, scopeBzl) |
| |
| checkFindings(t, "package-name", ` |
| load(":foo.bzl", "PACKAGE_NAME") |
| foo(a = PACKAGE_NAME) |
| `, []string{}, scopeBzl) |
| } |
| |
| func TestRepositoryNameWarning(t *testing.T) { |
| checkFindingsAndFix(t, "repository-name", ` |
| foo(a = REPOSITORY_NAME) |
| |
| def f(REPOSITORY_NAME): |
| foo(a = REPOSITORY_NAME) |
| |
| def g(): |
| foo(a = REPOSITORY_NAME) |
| `, ` |
| foo(a = native.repository_name()) |
| |
| def f(REPOSITORY_NAME): |
| foo(a = REPOSITORY_NAME) |
| |
| def g(): |
| foo(a = native.repository_name()) |
| `, |
| []string{ |
| `:1: Global variable "REPOSITORY_NAME" is deprecated in favor of "native.repository_name()". Please rename it.`, |
| `:7: Global variable "REPOSITORY_NAME" is deprecated in favor of "native.repository_name()". Please rename it.`, |
| }, scopeBzl) |
| |
| checkFindings(t, "repository-name", ` |
| REPOSITORY_NAME = "foo" |
| foo(a = REPOSITORY_NAME) |
| `, []string{}, scopeBzl) |
| |
| checkFindings(t, "repository-name", ` |
| load(":foo.bzl", "REPOSITORY_NAME") |
| foo(a = REPOSITORY_NAME) |
| `, []string{}, scopeBzl) |
| } |
| |
| func TestFileTypeNameWarning(t *testing.T) { |
| checkFindings(t, "filetype", ` |
| rule1(types=FileType([".cc", ".h"])) |
| rule2(types=FileType(types=[".cc", ".h"])) |
| |
| FileType(foobar) |
| |
| def macro1(): |
| a = FileType([".py"]) |
| |
| def macro2(): |
| FileType = foo |
| b = FileType([".java"]) |
| `, []string{ |
| ":1: The FileType function is deprecated.", |
| ":2: The FileType function is deprecated.", |
| ":4: The FileType function is deprecated.", |
| ":7: The FileType function is deprecated.", |
| }, scopeBzl) |
| |
| checkFindings(t, "filetype", ` |
| FileType = foo |
| |
| rule1(types=FileType([".cc", ".h"])) |
| rule2(types=FileType(types=[".cc", ".h"])) |
| `, []string{}, scopeBzl) |
| } |
| |
| func TestOutputGroupWarning(t *testing.T) { |
| checkFindingsAndFix(t, "output-group", ` |
| def _impl(ctx): |
| bin = ctx.attr.my_dep.output_group.bin |
| `, ` |
| def _impl(ctx): |
| bin = ctx.attr.my_dep[OutputGroupInfo].bin |
| `, |
| []string{ |
| `:2: "ctx.attr.dep.output_group" is deprecated in favor of "ctx.attr.dep[OutputGroupInfo]".`, |
| }, |
| scopeBzl) |
| } |
| |
| func TestNativeGitRepositoryWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "git-repository", ` |
| """My file""" |
| |
| def macro(): |
| git_repository(foo, bar) |
| `, ` |
| """My file""" |
| |
| load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") |
| |
| def macro(): |
| git_repository(foo, bar) |
| `, |
| []string{ |
| `:4: Function "git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`, |
| }, |
| scopeBzl) |
| |
| checkFindingsAndFix(t, "git-repository", ` |
| """My file""" |
| |
| def macro(): |
| git_repository(foo, bar) |
| new_git_repository(foo, bar) |
| `, ` |
| """My file""" |
| |
| load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") |
| |
| def macro(): |
| git_repository(foo, bar) |
| new_git_repository(foo, bar) |
| `, |
| []string{ |
| `:4: Function "git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`, |
| `:5: Function "new_git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`, |
| }, |
| scopeBzl) |
| |
| checkFindingsAndFix(t, "git-repository", ` |
| """My file""" |
| |
| load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") |
| |
| def macro(): |
| git_repository(foo, bar) |
| new_git_repository(foo, bar) |
| `, ` |
| """My file""" |
| |
| load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository", "new_git_repository") |
| |
| def macro(): |
| git_repository(foo, bar) |
| new_git_repository(foo, bar) |
| `, |
| []string{ |
| `:7: Function "new_git_repository" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:git.bzl".`, |
| }, |
| scopeBzl) |
| } |
| |
| func TestNativeHttpArchiveWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "http-archive", ` |
| """My file""" |
| |
| def macro(): |
| http_archive(foo, bar) |
| `, ` |
| """My file""" |
| |
| load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") |
| |
| def macro(): |
| http_archive(foo, bar) |
| `, |
| []string{ |
| `:4: Function "http_archive" is not global anymore and needs to be loaded from "@bazel_tools//tools/build_defs/repo:http.bzl".`, |
| }, |
| scopeBzl) |
| } |
| |
| func TestContextArgsAPIWarning(t *testing.T) { |
| checkFindingsAndFix(t, "ctx-args", ` |
| def impl(ctx): |
| args = ctx.actions.args() |
| args.add(foo, bar) |
| args.add(foo, bar, before_each = aaa) |
| args.add(foo, bar, join_with = bbb) |
| args.add(foo, bar, before_each = ccc, join_with = ddd) |
| args.add(foo, bar, map_fn = eee) |
| args.add(foo, bar, map_fn = fff, before_each = ggg) |
| args.add(foo, bar, map_fn = hhh, join_with = iii) |
| args.add(foo, bar, map_fn = jjj, before_each = kkk, join_with = lll) |
| `, ` |
| def impl(ctx): |
| args = ctx.actions.args() |
| args.add(foo, bar) |
| args.add_all(foo, bar, before_each = aaa) |
| args.add_joined(foo, bar, join_with = bbb) |
| args.add_joined(foo, bar, format_each = ccc + "%s", join_with = ddd) |
| args.add_all(foo, bar, map_each = eee) |
| args.add_all(foo, bar, map_each = fff, before_each = ggg) |
| args.add_joined(foo, bar, map_each = hhh, join_with = iii) |
| args.add_joined(foo, bar, map_each = jjj, format_each = kkk + "%s", join_with = lll) |
| `, |
| []string{ |
| `:4: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| `:5: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| `:6: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| `:7: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| `:8: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| `:9: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| `:10: "ctx.actions.args().add()" for multiple arguments is deprecated in favor of "add_all()" or "add_joined()".`, |
| }, |
| scopeBzl) |
| } |
| |
| func TestAttrOutputDefault(t *testing.T) { |
| checkFindings(t, "attr-output-default", ` |
| rule( |
| attrs = { |
| "foo": attr.output(default="foo"), |
| "bar": attr.output(not_default="foo"), |
| "baz": attr.string(default="foo"), |
| } |
| ) |
| `, |
| []string{ |
| `:3: The "default" parameter for attr.output() is deprecated.`, |
| }, |
| scopeBzl) |
| } |
| |
| func TestAttrLicense(t *testing.T) { |
| checkFindings(t, "attr-license", ` |
| rule( |
| attrs = { |
| "foo": attr.license(foo), |
| "bar": attr.license(), |
| "baz": attr.no_license(), |
| } |
| ) |
| `, []string{ |
| `:3: "attr.license()" is deprecated and shouldn't be used.`, |
| `:4: "attr.license()" is deprecated and shouldn't be used.`, |
| }, scopeBzl) |
| } |
| |
| func TestRuleImplReturn(t *testing.T) { |
| checkFindings(t, "rule-impl-return", ` |
| def _impl(ctx): |
| return struct() |
| |
| rule(implementation=_impl) |
| `, []string{ |
| `:2: Avoid using the legacy provider syntax.`, |
| }, scopeBzl) |
| |
| checkFindings(t, "rule-impl-return", ` |
| def _impl(ctx): |
| if True: |
| return struct() |
| return |
| |
| x = rule(_impl, attrs = {}) |
| `, []string{ |
| `:3: Avoid using the legacy provider syntax.`, |
| }, scopeBzl) |
| |
| checkFindings(t, "rule-impl-return", ` |
| def _impl(ctx): |
| pass # no return statements |
| |
| x = rule(_impl, attrs = {}) |
| `, []string{}, scopeBzl) |
| |
| checkFindings(t, "rule-impl-return", ` |
| def _impl1(): # not used as a rule implementation function |
| return struct() |
| |
| def _impl2(): # no structs returned |
| if x: |
| return [] |
| elif y: |
| return foo() |
| return |
| |
| x = rule( |
| implementation=_impl2, |
| ) |
| |
| rule( |
| _impl3, # not defined here |
| ) |
| |
| rule( |
| _impl1(), # not an identifier |
| ) |
| |
| rule() # no parameters |
| rule(foo = bar) # no matching parameters |
| `, []string{}, scopeBzl) |
| } |
| |
| func TestNativeAndroidWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "native-android", ` |
| """My file""" |
| |
| def macro(): |
| aar_import() |
| android_library() |
| native.android_library() |
| native.android_local_test() |
| |
| android_binary() |
| `, fmt.Sprintf(` |
| """My file""" |
| |
| load(%q, "aar_import", "android_binary", "android_library", "android_local_test") |
| |
| def macro(): |
| aar_import() |
| android_library() |
| android_library() |
| android_local_test() |
| |
| android_binary() |
| `, tables.AndroidLoadPath), |
| []string{ |
| fmt.Sprintf(`:4: Function "aar_import" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath), |
| fmt.Sprintf(`:5: Function "android_library" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath), |
| fmt.Sprintf(`:6: Function "android_library" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath), |
| fmt.Sprintf(`:7: Function "android_local_test" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath), |
| fmt.Sprintf(`:9: Function "android_binary" is not global anymore and needs to be loaded from "%s".`, tables.AndroidLoadPath), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeCcWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| expectedLoadPrefix := "@rules_cc//cc" |
| checkFindingsAndFix(t, "native-cc-binary,native-cc-import,native-cc-library,native-cc-test,native-cc-fdo-prefetch-hints,native-cc-objc-import,native-cc-objc-library,native-cc-toolchain,native-cc-toolchain-suite,native-cc-fdo-profile", ` |
| """My file""" |
| |
| def macro(): |
| cc_library() |
| native.cc_binary() |
| cc_test() |
| native.fdo_prefetch_hints() |
| native.objc_library() |
| objc_import() |
| cc_toolchain() |
| native.cc_toolchain_suite() |
| |
| fdo_profile() |
| cc_import() |
| `, fmt.Sprintf(` |
| """My file""" |
| |
| load("%[1]s:cc_binary.bzl", "cc_binary") |
| load("%[1]s:cc_import.bzl", "cc_import") |
| load("%[1]s:cc_library.bzl", "cc_library") |
| load("%[1]s:cc_test.bzl", "cc_test") |
| load("%[1]s:objc_import.bzl", "objc_import") |
| load("%[1]s:objc_library.bzl", "objc_library") |
| load("%[1]s/toolchains:cc_toolchain.bzl", "cc_toolchain") |
| load("%[1]s/toolchains:cc_toolchain_suite.bzl", "cc_toolchain_suite") |
| load("%[1]s/toolchains:fdo_prefetch_hints.bzl", "fdo_prefetch_hints") |
| load("%[1]s/toolchains:fdo_profile.bzl", "fdo_profile") |
| |
| def macro(): |
| cc_library() |
| cc_binary() |
| cc_test() |
| fdo_prefetch_hints() |
| objc_library() |
| objc_import() |
| cc_toolchain() |
| cc_toolchain_suite() |
| |
| fdo_profile() |
| cc_import() |
| `, expectedLoadPrefix), |
| []string{ |
| fmt.Sprintf(`:4: Function "cc_library" is not global anymore and needs to be loaded from "%s:cc_library.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:5: Function "cc_binary" is not global anymore and needs to be loaded from "%s:cc_binary.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:6: Function "cc_test" is not global anymore and needs to be loaded from "%s:cc_test.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:7: Function "fdo_prefetch_hints" is not global anymore and needs to be loaded from "%s/toolchains:fdo_prefetch_hints.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:8: Function "objc_library" is not global anymore and needs to be loaded from "%s:objc_library.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:9: Function "objc_import" is not global anymore and needs to be loaded from "%s:objc_import.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:10: Function "cc_toolchain" is not global anymore and needs to be loaded from "%s/toolchains:cc_toolchain.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:11: Function "cc_toolchain_suite" is not global anymore and needs to be loaded from "%s/toolchains:cc_toolchain_suite.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:13: Function "fdo_profile" is not global anymore and needs to be loaded from "%s/toolchains:fdo_profile.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:14: Function "cc_import" is not global anymore and needs to be loaded from "%s:cc_import.bzl".`, expectedLoadPrefix), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeJavaWarning(t *testing.T) { |
| defer setUpFileReader(map[string]string{ |
| "MODULE.bazel": ` |
| include("//my/pkg:java.MODULE.bazel") |
| `, |
| "my/pkg/java.MODULE.bazel": ` |
| bazel_dep(name = "rules_java", version = "1.2.3", repo_name = "my_rules_java") |
| `, |
| })() |
| |
| expectedLoadPrefix := "@my_rules_java//java" |
| checkFindingsAndFix(t, "native-java-binary,native-java-import,native-java-library,native-java-plugin,native-java-test,native-java-package-config,native-java-runtime,native-java-toolchain,native-java-common,native-java-info,native-java-plugin-info", ` |
| """My file""" |
| |
| def macro(): |
| java_import() |
| java_library() |
| native.java_library() |
| native.java_binary() |
| native.java_plugin() |
| native.java_package_configuration() |
| native.java_runtime() |
| native.java_toolchain() |
| |
| JavaInfo |
| JavaPluginInfo |
| java_common |
| |
| java_test() |
| `, fmt.Sprintf(` |
| """My file""" |
| |
| load("%[1]s:java_binary.bzl", "java_binary") |
| load("%[1]s:java_import.bzl", "java_import") |
| load("%[1]s:java_library.bzl", "java_library") |
| load("%[1]s:java_plugin.bzl", "java_plugin") |
| load("%[1]s:java_test.bzl", "java_test") |
| load("%[1]s/common:java_common.bzl", "java_common") |
| load("%[1]s/common:java_info.bzl", "JavaInfo") |
| load("%[1]s/common:java_plugin_info.bzl", "JavaPluginInfo") |
| load("%[1]s/toolchains:java_package_configuration.bzl", "java_package_configuration") |
| load("%[1]s/toolchains:java_runtime.bzl", "java_runtime") |
| load("%[1]s/toolchains:java_toolchain.bzl", "java_toolchain") |
| |
| def macro(): |
| java_import() |
| java_library() |
| java_library() |
| java_binary() |
| java_plugin() |
| java_package_configuration() |
| java_runtime() |
| java_toolchain() |
| |
| JavaInfo |
| JavaPluginInfo |
| java_common |
| |
| java_test() |
| `, expectedLoadPrefix), |
| []string{ |
| fmt.Sprintf(`:4: Function "java_import" is not global anymore and needs to be loaded from "%s:java_import.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:5: Function "java_library" is not global anymore and needs to be loaded from "%s:java_library.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:6: Function "java_library" is not global anymore and needs to be loaded from "%s:java_library.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:7: Function "java_binary" is not global anymore and needs to be loaded from "%s:java_binary.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:8: Function "java_plugin" is not global anymore and needs to be loaded from "%s:java_plugin.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:9: Function "java_package_configuration" is not global anymore and needs to be loaded from "%s/toolchains:java_package_configuration.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:10: Function "java_runtime" is not global anymore and needs to be loaded from "%s/toolchains:java_runtime.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:11: Function "java_toolchain" is not global anymore and needs to be loaded from "%s/toolchains:java_toolchain.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:13: Symbol "JavaInfo" is not global anymore and needs to be loaded from "%s/common:java_info.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:14: Symbol "JavaPluginInfo" is not global anymore and needs to be loaded from "%s/common:java_plugin_info.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:15: Symbol "java_common" is not global anymore and needs to be loaded from "%s/common:java_common.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:17: Function "java_test" is not global anymore and needs to be loaded from "%s:java_test.bzl".`, expectedLoadPrefix), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativePyWarning(t *testing.T) { |
| defer setUpFileReader(map[string]string{ |
| "MODULE.bazel": ` |
| bazel_dep(name = "rules_python", repo_name = "my_rules_python") |
| `, |
| })() |
| |
| expectedLoadPath := "@my_rules_python//python:defs.bzl" |
| checkFindingsAndFix(t, "native-py", ` |
| """My file""" |
| |
| def macro(): |
| py_library() |
| py_binary() |
| native.py_test() |
| native.py_runtime() |
| |
| py_test() |
| `, fmt.Sprintf(` |
| """My file""" |
| |
| load(%q, "py_binary", "py_library", "py_runtime", "py_test") |
| |
| def macro(): |
| py_library() |
| py_binary() |
| py_test() |
| py_runtime() |
| |
| py_test() |
| `, expectedLoadPath), |
| []string{ |
| fmt.Sprintf(`:4: Function "py_library" is not global anymore and needs to be loaded from "%s".`, expectedLoadPath), |
| fmt.Sprintf(`:5: Function "py_binary" is not global anymore and needs to be loaded from "%s".`, expectedLoadPath), |
| fmt.Sprintf(`:6: Function "py_test" is not global anymore and needs to be loaded from "%s".`, expectedLoadPath), |
| fmt.Sprintf(`:7: Function "py_runtime" is not global anymore and needs to be loaded from "%s".`, expectedLoadPath), |
| fmt.Sprintf(`:9: Function "py_test" is not global anymore and needs to be loaded from "%s".`, expectedLoadPath), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeProtoWarning(t *testing.T) { |
| // No MODULE.bazel file, so loads should use the legacy protobuf repo name. |
| defer setUpFileReader(nil)() |
| |
| expectedLoadPrefix := "@com_google_protobuf//bazel" |
| checkFindingsAndFix(t, "native-proto,native-proto-lang-toolchain,native-proto-info,native-proto-common", ` |
| """My file""" |
| |
| def macro(): |
| proto_library() |
| proto_lang_toolchain() |
| native.proto_lang_toolchain() |
| native.proto_library() |
| |
| ProtoInfo |
| proto_common |
| `, fmt.Sprintf(` |
| """My file""" |
| |
| load("%[1]s:proto_library.bzl", "proto_library") |
| load("%[1]s/common:proto_common.bzl", "proto_common") |
| load("%[1]s/common:proto_info.bzl", "ProtoInfo") |
| load("%[1]s/toolchains:proto_lang_toolchain.bzl", "proto_lang_toolchain") |
| |
| def macro(): |
| proto_library() |
| proto_lang_toolchain() |
| proto_lang_toolchain() |
| proto_library() |
| |
| ProtoInfo |
| proto_common |
| `, expectedLoadPrefix), |
| []string{ |
| fmt.Sprintf(`:4: Function "proto_library" is not global anymore and needs to be loaded from "%s:proto_library.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:5: Function "proto_lang_toolchain" is not global anymore and needs to be loaded from "%s/toolchains:proto_lang_toolchain.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:6: Function "proto_lang_toolchain" is not global anymore and needs to be loaded from "%s/toolchains:proto_lang_toolchain.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:7: Function "proto_library" is not global anymore and needs to be loaded from "%s:proto_library.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:9: Symbol "ProtoInfo" is not global anymore and needs to be loaded from "%s/common:proto_info.bzl".`, expectedLoadPrefix), |
| fmt.Sprintf(`:10: Symbol "proto_common" is not global anymore and needs to be loaded from "%s/common:proto_common.bzl".`, expectedLoadPrefix), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeShBinaryWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "native-sh-binary", ` |
| """My file""" |
| |
| def macro(): |
| native.sh_binary() |
| |
| sh_binary() |
| `, ` |
| """My file""" |
| |
| load("@rules_shell//shell:sh_binary.bzl", "sh_binary") |
| |
| def macro(): |
| sh_binary() |
| |
| sh_binary() |
| `, |
| []string{ |
| fmt.Sprintf(`:4: Function "sh_binary" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_binary.bzl".`), |
| fmt.Sprintf(`:6: Function "sh_binary" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_binary.bzl".`), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeShLibraryWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "native-sh-library", ` |
| """My file""" |
| |
| def macro(): |
| native.sh_library() |
| |
| sh_library() |
| `, ` |
| """My file""" |
| |
| load("@rules_shell//shell:sh_library.bzl", "sh_library") |
| |
| def macro(): |
| sh_library() |
| |
| sh_library() |
| `, |
| []string{ |
| fmt.Sprintf(`:4: Function "sh_library" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_library.bzl".`), |
| fmt.Sprintf(`:6: Function "sh_library" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_library.bzl".`), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeShTestWarning(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "native-sh-test", ` |
| """My file""" |
| |
| def macro(): |
| native.sh_test() |
| |
| sh_test() |
| `, ` |
| """My file""" |
| |
| load("@rules_shell//shell:sh_test.bzl", "sh_test") |
| |
| def macro(): |
| sh_test() |
| |
| sh_test() |
| `, |
| []string{ |
| fmt.Sprintf(`:4: Function "sh_test" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_test.bzl".`), |
| fmt.Sprintf(`:6: Function "sh_test" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_test.bzl".`), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestNativeWarningLoadPlacedAfterFileDocstringWithComment(t *testing.T) { |
| defer setUpFileReader(nil)() |
| |
| checkFindingsAndFix(t, "native-sh-binary,native-java-binary", ` |
| # Copyright 2020 Google LLC |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """My file""" |
| |
| def macro(): |
| native.sh_binary() |
| native.java_binary() |
| |
| java_binary() |
| sh_binary() |
| `, ` |
| # Copyright 2020 Google LLC |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """My file""" |
| |
| load("@rules_java//java:java_binary.bzl", "java_binary") |
| load("@rules_shell//shell:sh_binary.bzl", "sh_binary") |
| |
| def macro(): |
| sh_binary() |
| java_binary() |
| |
| java_binary() |
| sh_binary() |
| `, |
| []string{ |
| fmt.Sprintf(`:18: Function "sh_binary" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_binary.bzl".`), |
| fmt.Sprintf(`:19: Function "java_binary" is not global anymore and needs to be loaded from "@rules_java//java:java_binary.bzl".`), |
| fmt.Sprintf(`:21: Function "java_binary" is not global anymore and needs to be loaded from "@rules_java//java:java_binary.bzl".`), |
| fmt.Sprintf(`:22: Function "sh_binary" is not global anymore and needs to be loaded from "@rules_shell//shell:sh_binary.bzl".`), |
| }, |
| scopeBzl|scopeBuild) |
| } |
| |
| func TestKeywordParameters(t *testing.T) { |
| checkFindingsAndFix(t, "keyword-positional-params", ` |
| foo(key = value) |
| all(elements = [True, False]) |
| any(elements = [True, False]) |
| tuple(x = [1, 2, 3]) |
| list(x = [1, 2, 3]) |
| len(x = [1, 2, 3]) |
| str(x = foo) |
| repr(x = foo) |
| bool(x = 3) |
| int(x = "3") |
| int(x = "13", base = 8) |
| dir(x = foo) |
| type(x = foo) |
| select(x = {}) |
| `, ` |
| foo(key = value) |
| all([True, False]) |
| any([True, False]) |
| tuple([1, 2, 3]) |
| list([1, 2, 3]) |
| len([1, 2, 3]) |
| str(foo) |
| repr(foo) |
| bool(3) |
| int("3") |
| int("13", base = 8) |
| dir(foo) |
| type(foo) |
| select({}) |
| `, []string{ |
| `:2: Keyword parameter "elements" for "all" should be positional.`, |
| `:3: Keyword parameter "elements" for "any" should be positional.`, |
| `:4: Keyword parameter "x" for "tuple" should be positional.`, |
| `:5: Keyword parameter "x" for "list" should be positional.`, |
| `:6: Keyword parameter "x" for "len" should be positional.`, |
| `:7: Keyword parameter "x" for "str" should be positional.`, |
| `:8: Keyword parameter "x" for "repr" should be positional.`, |
| `:9: Keyword parameter "x" for "bool" should be positional.`, |
| `:10: Keyword parameter "x" for "int" should be positional.`, |
| `:11: Keyword parameter "x" for "int" should be positional.`, |
| `:12: Keyword parameter "x" for "dir" should be positional.`, |
| `:13: Keyword parameter "x" for "type" should be positional.`, |
| `:14: Keyword parameter "x" for "select" should be positional.`, |
| }, scopeEverywhere) |
| |
| checkFindingsAndFix(t, "keyword-positional-params", ` |
| hasattr( |
| x = foo, |
| name = "bar", |
| ) |
| getattr( |
| x = foo, |
| name = "bar", |
| ) |
| getattr( |
| x = foo, |
| name = "bar", |
| default = "baz", |
| ) |
| `, ` |
| hasattr( |
| foo, |
| "bar", |
| ) |
| getattr( |
| foo, |
| "bar", |
| ) |
| getattr( |
| foo, |
| "bar", |
| "baz", |
| ) |
| `, []string{ |
| `:2: Keyword parameter "x" for "hasattr" should be positional.`, |
| `:3: Keyword parameter "name" for "hasattr" should be positional.`, |
| `:6: Keyword parameter "x" for "getattr" should be positional.`, |
| `:7: Keyword parameter "name" for "getattr" should be positional.`, |
| `:10: Keyword parameter "x" for "getattr" should be positional.`, |
| `:11: Keyword parameter "name" for "getattr" should be positional.`, |
| `:12: Keyword parameter "default" for "getattr" should be positional.`, |
| }, scopeEverywhere) |
| } |
| |
| func TestProvider(t *testing.T) { |
| checkFindings(t, "provider-params", `provider(doc = "doc", fields = [])`, []string{}, scopeBzl) |
| checkFindings(t, "provider-params", `provider("doc", fields = [])`, []string{}, scopeBzl) |
| checkFindings(t, "provider-params", `provider(fields = None, doc = "doc")`, []string{}, scopeBzl) |
| |
| checkFindings(t, "provider-params", `provider(fields = [])`, |
| []string{`1: Calls to 'provider' should provide a documentation`}, scopeBzl) |
| checkFindings(t, "provider-params", `provider(doc = "doc")`, |
| []string{`1: Calls to 'provider' should provide a list of fields:`}, scopeBzl) |
| checkFindings(t, "provider-params", `p = provider()`, |
| []string{`1: Calls to 'provider' should provide a list of fields and a documentation:`}, scopeBzl) |
| } |
| |
| func TestAttributeNameWarning(t *testing.T) { |
| checkFindings(t, "attr-licenses", ` |
| def _impl(ctx): |
| pass |
| |
| foo = rule( |
| implementation = _impl, |
| attrs = { |
| "license": attr.string(), |
| "licenses": attr.string(), |
| }, |
| ) |
| `, []string{ |
| ":6: Do not use 'licenses' as an attribute name. It may cause unexpected behavior.", |
| }, scopeBzl) |
| |
| checkFindings(t, "attr-applicable_licenses", ` |
| def _impl(ctx): |
| pass |
| |
| foo = rule( |
| implementation = _impl, |
| attrs = { |
| "applicable_licenses": attr.string(), |
| "package_metadata": attr.string(), |
| }, |
| ) |
| `, []string{ |
| ":6: Do not use 'applicable_licenses' as an attribute name. It may cause unexpected behavior.", |
| ":6: Do not use 'package_metadata' as an attribute name. It may cause unexpected behavior.", |
| }, scopeBzl) |
| } |