diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java | 184 |
1 files changed, 65 insertions, 119 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java index 5e38598317..cd7b72b867 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java @@ -69,19 +69,18 @@ import com.google.devtools.build.lib.packages.NativeClassObjectConstructor; import com.google.devtools.build.lib.packages.OutputFile; import com.google.devtools.build.lib.packages.PackageSpecification; import com.google.devtools.build.lib.packages.RawAttributeMapper; +import com.google.devtools.build.lib.packages.RequiredProviders; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.RuleErrorConsumer; import com.google.devtools.build.lib.packages.SkylarkClassObject; -import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.rules.AliasProvider; import com.google.devtools.build.lib.rules.MakeVariableProvider; import com.google.devtools.build.lib.rules.fileset.FilesetProvider; import com.google.devtools.build.lib.shell.ShellUtils; -import com.google.devtools.build.lib.syntax.ClassObject; import com.google.devtools.build.lib.syntax.EvalException; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.syntax.Type.LabelClass; @@ -719,7 +718,7 @@ public final class RuleContext extends TargetContext Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> map = getSplitPrerequisites(attributeName); return map.isEmpty() - ? ImmutableList.<TransitiveInfoCollection>of() + ? ImmutableList.of() : map.entrySet().iterator().next().getValue(); } @@ -1978,153 +1977,100 @@ public final class RuleContext extends TargetContext } } - private String getMissingMandatoryProviders(ConfiguredTarget prerequisite, Attribute attribute){ - ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList = - attribute.getMandatoryProvidersList(); - if (mandatoryProvidersList.isEmpty()) { - return null; - } - List<List<String>> missingProvidersList = new ArrayList<>(); - for (ImmutableSet<SkylarkProviderIdentifier> providers : mandatoryProvidersList) { - List<String> missing = new ArrayList<>(); - for (SkylarkProviderIdentifier provider : providers) { - // A rule may require a built-in provider that is always implicitly provided, e.g. "files" - ImmutableSet<String> availableKeys = - ImmutableSet.copyOf(((ClassObject) prerequisite).getKeys()); - if ((prerequisite.get(provider) == null) - && !(provider.isLegacy() && availableKeys.contains(provider.getLegacyId()))) { - missing.add(provider.toString()); - } - } - if (missing.isEmpty()) { - return null; - } else { - missingProvidersList.add(missing); - } - } - StringBuilder missingProviders = new StringBuilder(); - Joiner joinProvider = Joiner.on("', '"); - for (List<String> providers : missingProvidersList) { - if (missingProviders.length() > 0) { - missingProviders.append(" or "); - } - missingProviders.append((providers.size() > 1) ? "[" : "") - .append("'"); - joinProvider.appendTo(missingProviders, providers); - missingProviders.append("'") - .append((providers.size() > 1) ? "]" : ""); + /** + * Because some rules still have to use allowedRuleClasses to do rule dependency validation. + * A dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers + * in requiredProviders are provided by the target. + */ + private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) { + + Set<String> unfulfilledRequirements = new LinkedHashSet<>(); + if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) { + return; } - return missingProviders.toString(); - } - private String getMissingMandatoryNativeProviders( - ConfiguredTarget prerequisite, Attribute attribute) { - List<ImmutableList<Class<? extends TransitiveInfoProvider>>> mandatoryProvidersList = - attribute.getMandatoryNativeProvidersList(); - if (mandatoryProvidersList.isEmpty()) { - return null; + if (checkRuleDependencyClassWarnings(prerequisite, attribute)) { + return; } - List<List<String>> missingProvidersList = new ArrayList<>(); - for (ImmutableList<Class<? extends TransitiveInfoProvider>> providers - : mandatoryProvidersList) { - List<String> missing = new ArrayList<>(); - for (Class<? extends TransitiveInfoProvider> provider : providers) { - if (prerequisite.getProvider(provider) == null) { - missing.add(provider.getSimpleName()); - } - } - if (missing.isEmpty()) { - return null; - } else { - missingProvidersList.add(missing); - } + + if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, + unfulfilledRequirements)) { + return; } - StringBuilder missingProviders = new StringBuilder(); - Joiner joinProvider = Joiner.on(", "); - for (List<String> providers : missingProvidersList) { - if (missingProviders.length() > 0) { - missingProviders.append(" or "); - } - missingProviders.append((providers.size() > 1) ? "[" : ""); - joinProvider.appendTo(missingProviders, providers); - missingProviders.append((providers.size() > 1) ? "]" : ""); + + // not allowed rule class and some mandatory providers missing => reject. + if (!unfulfilledRequirements.isEmpty()) { + attributeError( + attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and")); } - return missingProviders.toString(); } /** - * Because some rules still have to use allowedRuleClasses to do rule dependency validation. - * A dependency is valid if it is from a rule in allowedRuleClasses, OR if all of the providers - * in mandatoryNativeProviders AND mandatoryProvidersList are provided by the target. + * Check if prerequisite should be allowed based on its rule class. */ - private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) { - Target prerequisiteTarget = prerequisite.getTarget(); - RuleClass ruleClass = ((Rule) prerequisiteTarget).getRuleClassObject(); - String notAllowedRuleClassesMessage = null; - + private boolean checkRuleDependencyClass(ConfiguredTarget prerequisite, Attribute attribute, + Set<String> unfulfilledRequirements) { if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) { - if (attribute.getAllowedRuleClassesPredicate().apply(ruleClass)) { + if (attribute.getAllowedRuleClassesPredicate().apply( + ((Rule) prerequisite.getTarget()).getRuleClassObject())) { // prerequisite has an allowed rule class => accept. - return; + return true; } // remember that the rule class that was not allowed; // but maybe prerequisite provides required providers? do not reject yet. - notAllowedRuleClassesMessage = + unfulfilledRequirements.add( badPrerequisiteMessage( - prerequisiteTarget.getTargetKind(), + prerequisite.getTarget().getTargetKind(), prerequisite, "expected " + attribute.getAllowedRuleClassesPredicate(), - false); + false)); } + return false; + } - if (attribute.getAllowedRuleClassesWarningPredicate().apply(ruleClass)) { + /** + * Check if prerequisite should be allowed with warning based on its rule class. + * + * If yes, also issues said warning. + */ + private boolean checkRuleDependencyClassWarnings(ConfiguredTarget prerequisite, + Attribute attribute) { + if (attribute.getAllowedRuleClassesWarningPredicate().apply( + ((Rule) prerequisite.getTarget()).getRuleClassObject())) { Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate(); - reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisite, + reportBadPrerequisite(attribute, prerequisite.getTarget().getTargetKind(), prerequisite, allowedRuleClasses == Predicates.<RuleClass>alwaysTrue() ? null : "expected " + allowedRuleClasses, true); // prerequisite has a rule class allowed with a warning => accept, emitting a warning. - return; + return true; } + return false; + } - // If we get here, we have no allowed rule class. - // If mandatory providers are specified, try them. - Set<String> unfulfilledRequirements = new LinkedHashSet<>(); - if (!attribute.getMandatoryNativeProvidersList().isEmpty() - || !attribute.getMandatoryProvidersList().isEmpty()) { - boolean hadAllMandatoryProviders = true; - - String missingNativeProviders = getMissingMandatoryNativeProviders(prerequisite, attribute); - if (missingNativeProviders != null) { - unfulfilledRequirements.add( - "'" + prerequisite.getLabel() + "' does not have mandatory providers: " - + missingNativeProviders); - hadAllMandatoryProviders = false; - } - - String missingProviders = getMissingMandatoryProviders(prerequisite, attribute); - if (missingProviders != null) { - unfulfilledRequirements.add( - "'" + prerequisite.getLabel() + "' does not have mandatory providers: " - + missingProviders); - hadAllMandatoryProviders = false; - } + /** + * Check if prerequisite should be allowed based on required providers on + * the attribute. + */ + private boolean checkRuleDependencyMandatoryProviders(ConfiguredTarget prerequisite, + Attribute attribute, Set<String> unfulfilledRequirements) { + RequiredProviders requiredProviders = attribute.getRequiredProviders(); - if (hadAllMandatoryProviders) { - // all mandatory providers are present => accept. - return; - } + if (requiredProviders.acceptsAny()) { + // If no required providers specified, we do not know if we should accept. + return false; } - // not allowed rule class and some mandatory providers missing => reject. - if (notAllowedRuleClassesMessage != null) { - unfulfilledRequirements.add(notAllowedRuleClassesMessage); + if (prerequisite.satisfies(requiredProviders)) { + return true; } - if (!unfulfilledRequirements.isEmpty()) { - attributeError( - attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and")); - } + unfulfilledRequirements.add( + String.format("'%s' does not have mandatory providers: %s", + prerequisite.getLabel(), + prerequisite.missingProviders(requiredProviders).getDescription())); + + return false; } private void validateDirectPrerequisite(Attribute attribute, ConfiguredTarget prerequisite) { |