Add --check_third_party_targets_have_licenses.

When on, all rules and files declared with exports_file() under //third_party must declare licenses().

This is the flag's default, and also status quo semantics. The point of this flag is to let users turn off that
checking when they don't want to treat //third_party as special.

Fixes #3639

Closes #7262.

PiperOrigin-RevId: 231645495
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
index b501ac5..ba52ce8 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -734,7 +734,9 @@
               String.format("licenses for exported file '%s' declared twice",
                   inputFile.getName()));
         }
-        if (license == null && !pkgBuilder.getDefaultLicense().isSpecified()
+        if (env.getSemantics().checkThirdPartyTargetsHaveLicenses()
+            && license == null
+            && !pkgBuilder.getDefaultLicense().isSpecified()
             && RuleClass.isThirdPartyPackage(pkgBuilder.getPackageIdentifier())) {
           throw new EvalException(ast.getLocation(),
               "third-party file '" + inputFile.getName() + "' lacks a license declaration "
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index c5152ed..d61cc4a 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -1806,7 +1806,8 @@
       EventHandler eventHandler,
       @Nullable FuncallExpression ast,
       Location location,
-      AttributeContainer attributeContainer)
+      AttributeContainer attributeContainer,
+      boolean checkThirdPartyRulesHaveLicenses)
       throws LabelSyntaxException, InterruptedException, CannotPrecomputeDefaultsException {
     Rule rule = pkgBuilder.createRule(ruleLabel, this, location, attributeContainer);
     populateRuleAttributeValues(rule, pkgBuilder, attributeValues, eventHandler);
@@ -1816,7 +1817,9 @@
       populateAttributeLocations(rule, ast);
     }
     checkForDuplicateLabels(rule, eventHandler);
-    checkThirdPartyRuleHasLicense(rule, pkgBuilder, eventHandler);
+    if (checkThirdPartyRulesHaveLicenses) {
+      checkThirdPartyRuleHasLicense(rule, pkgBuilder, eventHandler);
+    }
     checkForValidSizeAndTimeoutValues(rule, eventHandler);
     rule.checkValidityPredicate(eventHandler);
     rule.checkForNullLabels();
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java b/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java
index 3bd6498..1bbb1de 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java
@@ -135,7 +135,8 @@
           eventHandler,
           ast,
           generator.location,
-          attributeContainer);
+          attributeContainer,
+          env == null ? false : env.getSemantics().checkThirdPartyTargetsHaveLicenses());
     } catch (LabelSyntaxException | CannotPrecomputeDefaultsException e) {
       throw new RuleFactory.InvalidRuleException(ruleClass + " " + e.getMessage());
     }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkSemanticsOptions.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkSemanticsOptions.java
index 2d8e930..9cfdb6f 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkSemanticsOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkSemanticsOptions.java
@@ -62,6 +62,16 @@
 
   // <== Add new options here in alphabetic order ==>
 
+  // TODO(gregce): remove license checking completely from Bazel. aiuto@ is working on replacing
+  // this with a new and more useful model.
+  @Option(
+      name = "check_third_party_targets_have_licenses",
+      defaultValue = "true",
+      documentationCategory = OptionDocumentationCategory.SKYLARK_SEMANTICS,
+      effectTags = OptionEffectTag.BUILD_FILE_SEMANTICS,
+      help = "If true, all rules and files under //third_party must declare licenses([])")
+  public boolean checkThirdPartyTargetsHaveLicenses;
+
   @Option(
       name = "experimental_build_setting_api",
       defaultValue = "false",
@@ -523,6 +533,7 @@
   public SkylarkSemantics toSkylarkSemantics() {
     return SkylarkSemantics.builder()
         // <== Add new options here in alphabetic order ==>
+        .checkThirdPartyTargetsHaveLicenses(checkThirdPartyTargetsHaveLicenses)
         .experimentalBuildSettingApi(experimentalBuildSettingApi)
         .experimentalCcSkylarkApiEnabledPackages(experimentalCcSkylarkApiEnabledPackages)
         .experimentalEnableAndroidMigrationApis(experimentalEnableAndroidMigrationApis)
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemantics.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemantics.java
index ded1307..03bbef6 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkSemantics.java
@@ -116,6 +116,8 @@
       AutoValue_SkylarkSemantics.class;
 
   // <== Add new options here in alphabetic order ==>
+  public abstract boolean checkThirdPartyTargetsHaveLicenses();
+
   public abstract boolean experimentalBuildSettingApi();
 
   public abstract ImmutableList<String> experimentalCcSkylarkApiEnabledPackages();
@@ -201,6 +203,7 @@
   public static final SkylarkSemantics DEFAULT_SEMANTICS =
       builder()
           // <== Add new options here in alphabetic order ==>
+          .checkThirdPartyTargetsHaveLicenses(true)
           .experimentalBuildSettingApi(false)
           .experimentalCcSkylarkApiEnabledPackages(ImmutableList.of())
           .experimentalEnableAndroidMigrationApis(false)
@@ -243,6 +246,8 @@
   public abstract static class Builder {
 
     // <== Add new options here in alphabetic order ==>
+    public abstract Builder checkThirdPartyTargetsHaveLicenses(boolean value);
+
     public abstract Builder experimentalBuildSettingApi(boolean value);
 
     public abstract Builder experimentalCcSkylarkApiEnabledPackages(List<String> value);
diff --git a/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java b/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java
index d99c5f8..ea11633 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/PackageFactoryTest.java
@@ -374,6 +374,29 @@
   }
 
   @Test
+  public void testThirdPartyNoLicenseChecking() throws Exception {
+    Path buildFile =
+        scratch.file("/third_party/foo/BUILD", "# line 1", "cc_library(name='bar')", "# line 3");
+    Package pkg =
+        packages.createPackage(
+            "third_party/foo",
+            RootedPath.toRootedPath(root, buildFile),
+            "--nocheck_third_party_targets_have_licenses");
+    assertThat(pkg.containsErrors()).isFalse();
+  }
+
+  @Test
+  public void testThirdPartyExportsFileNoLicenseChecking() throws Exception {
+    Path buildFile = scratch.file("/third_party/foo/BUILD", "exports_files(['bar'])");
+    Package pkg =
+        packages.createPackage(
+            "third_party/foo",
+            RootedPath.toRootedPath(root, buildFile),
+            "--nocheck_third_party_targets_have_licenses");
+    assertThat(pkg.containsErrors()).isFalse();
+  }
+
+  @Test
   public void testDuplicateRuleIsNotAddedToPackage() throws Exception {
     events.setFailFast(false);
     Path path =
diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
index c43ff8a..8c70e2b 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
@@ -786,7 +786,8 @@
         reporter,
         /*ast=*/ null,
         location,
-        new AttributeContainer(ruleClass));
+        new AttributeContainer(ruleClass),
+        /*checkThirdPartyRulesHaveLicenses=*/ true);
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
index f2bd547..55065d5 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/SkylarkSemanticsConsistencyTest.java
@@ -118,6 +118,7 @@
   private static SkylarkSemanticsOptions buildRandomOptions(Random rand) throws Exception {
     return parseOptions(
         // <== Add new options here in alphabetic order ==>
+        "--check_third_party_targets_have_licenses=" + rand.nextBoolean(),
         "--experimental_build_setting_api=" + rand.nextBoolean(),
         "--experimental_cc_skylark_api_enabled_packages="
             + rand.nextDouble()
@@ -168,6 +169,7 @@
   private static SkylarkSemantics buildRandomSemantics(Random rand) {
     return SkylarkSemantics.builder()
         // <== Add new options here in alphabetic order ==>
+        .checkThirdPartyTargetsHaveLicenses(rand.nextBoolean())
         .experimentalBuildSettingApi(rand.nextBoolean())
         .experimentalCcSkylarkApiEnabledPackages(
             ImmutableList.of(String.valueOf(rand.nextDouble()), String.valueOf(rand.nextDouble())))