/** Returns all dependencies that should be constraint-checked against the current rule. */ private static Iterable<TransitiveInfoCollection> getConstraintCheckedDependencies( RuleContext ruleContext) { Set<TransitiveInfoCollection> depsToCheck = new LinkedHashSet<>(); AttributeMap attributes = ruleContext.attributes(); for (String attr : attributes.getAttributeNames()) { Attribute attrDef = attributes.getAttributeDefinition(attr); Type<?> attrType = attributes.getAttributeType(attr); // TODO(bazel-team): support a user-definable API for choosing which attributes are checked if (!attrDef.checkConstraintsOverride()) { if ((attrType != BuildType.LABEL && attrType != BuildType.LABEL_LIST) || RuleClass.isConstraintAttribute(attr) || attr.equals("visibility") // Use the same implicit deps check that query uses. This facilitates running queries to // determine exactly which rules need to be constraint-annotated for depot migrations. || !Rule.NO_IMPLICIT_DEPS.apply(ruleContext.getRule(), attrDef) // We can't identify host deps by calling BuildConfiguration.isHostConfiguration() // because --nodistinct_host_configuration subverts that call. || attrDef.getConfigurationTransition() == Attribute.ConfigurationTransition.HOST) { continue; } } for (TransitiveInfoCollection dep : ruleContext.getPrerequisites(attr, RuleConfiguredTarget.Mode.DONT_CHECK)) { // Output files inherit the environment spec of their generating rule. if (dep instanceof OutputFileConfiguredTarget) { // Note this reassignment means constraint violation errors reference the generating // rule, not the file. This makes the source of the environmental mismatch more clear. dep = ((OutputFileConfiguredTarget) dep).getGeneratingRule(); } // Input files don't support environments. We may subsequently opt them into constraint // checking, but for now just pass them by. if (dep.getProvider(SupportedEnvironmentsProvider.class) != null) { depsToCheck.add(dep); } } } return depsToCheck; }
private void resolveLateBoundAttributes( Rule rule, BuildConfiguration configuration, BuildConfiguration hostConfiguration, AttributeMap attributeMap, Iterable<Attribute> attributes, ImmutableSortedKeyListMultimap.Builder<Attribute, LabelAndConfiguration> builder) throws EvalException, InterruptedException { for (Attribute attribute : attributes) { if (!attribute.isLateBound() || !attribute.getCondition().apply(attributeMap)) { continue; } List<BuildConfiguration> actualConfigurations = ImmutableList.of(configuration); if (attribute.getConfigurationTransition() instanceof SplitTransition<?>) { Preconditions.checkState(attribute.getConfigurator() == null); // TODO(bazel-team): This ends up applying the split transition twice, both here and in the // visitRule method below - this is not currently a problem, because the configuration graph // never contains nested split transitions, so the second application is idempotent. actualConfigurations = configuration.getSplitConfigurations( (SplitTransition<?>) attribute.getConfigurationTransition()); } for (BuildConfiguration actualConfig : actualConfigurations) { @SuppressWarnings("unchecked") LateBoundDefault<BuildConfiguration> lateBoundDefault = (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault(); if (lateBoundDefault.useHostConfiguration()) { actualConfig = hostConfiguration; } // TODO(bazel-team): This might be too expensive - can we cache this somehow? if (!lateBoundDefault.getRequiredConfigurationFragments().isEmpty()) { if (!actualConfig.hasAllFragments(lateBoundDefault.getRequiredConfigurationFragments())) { continue; } } // TODO(bazel-team): We should check if the implementation tries to access an undeclared // fragment. Object actualValue = lateBoundDefault.getDefault(rule, actualConfig); if (EvalUtils.isNullOrNone(actualValue)) { continue; } try { if (attribute.getType() == BuildType.LABEL) { Label label = BuildType.LABEL.cast(actualValue); builder.put(attribute, LabelAndConfiguration.of(label, actualConfig)); } else if (attribute.getType() == BuildType.LABEL_LIST) { for (Label label : BuildType.LABEL_LIST.cast(actualValue)) { builder.put(attribute, LabelAndConfiguration.of(label, actualConfig)); } } else { throw new IllegalStateException( String.format( "Late bound attribute '%s' is not a label or a label list", attribute.getName())); } } catch (ClassCastException e) { throw new EvalException( rule.getLocation(), String.format( "When computing the default value of %s, expected '%s', got '%s'", attribute.getName(), attribute.getType(), EvalUtils.getDataTypeName(actualValue, true))); } } } }