/** * If the rule was created by a macro, this method sets the appropriate values for the attributes * generator_{name, function, location} and returns all attributes. * * <p>Otherwise, it returns the given attributes without any changes. */ private static AttributesAndLocation generatorAttributesForMacros( BuildLangTypedAttributeValuesMap args, @Nullable Environment env, Location location, Label label) { // Returns the original arguments if a) there is only the rule itself on the stack // trace (=> no macro) or b) the attributes have already been set by Python pre-processing. if (env == null) { return new AttributesAndLocation(args, location); } boolean hasName = args.containsAttributeNamed("generator_name"); boolean hasFunc = args.containsAttributeNamed("generator_function"); // TODO(bazel-team): resolve cases in our code where hasName && !hasFunc, or hasFunc && !hasName if (hasName || hasFunc) { return new AttributesAndLocation(args, location); } Pair<FuncallExpression, BaseFunction> topCall = env.getTopCall(); if (topCall == null || !(topCall.second instanceof UserDefinedFunction)) { return new AttributesAndLocation(args, location); } FuncallExpression generator = topCall.first; BaseFunction function = topCall.second; String name = generator.getNameArg(); ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder(); for (String attributeName : args.getAttributeNames()) { builder.put(attributeName, args.getAttributeValue(attributeName)); } builder.put("generator_name", (name == null) ? args.getAttributeValue("name") : name); builder.put("generator_function", function.getName()); if (generator.getLocation() != null) { location = generator.getLocation(); } String relativePath = maybeGetRelativeLocation(location, label); if (relativePath != null) { builder.put("generator_location", relativePath); } try { return new AttributesAndLocation( new BuildLangTypedAttributeValuesMap(builder.build()), location); } catch (IllegalArgumentException ex) { // We just fall back to the default case and swallow any messages. return new AttributesAndLocation(args, location); } }
/** * Creates a {@link Rule} instance, adds it to the {@link Package.Builder} and returns it. * * @param context the package-building context in which this rule was declared * @param ruleClass the {@link RuleClass} of the rule * @param attributeValues a {@link BuildLangTypedAttributeValuesMap} mapping attribute names to * attribute values of build-language type. Each attribute must be defined for this class of * rule, and have a build-language-typed value which can be converted to the appropriate * native type of the attribute (i.e. via {@link BuildType#selectableConvert}). There must be * a map entry for each non-optional attribute of this class of rule. * @param ast the abstract syntax tree of the rule expression (mandatory because this looks up a * {@link Location} from the {@code ast}) * @param env the lexical environment of the function call which declared this rule (optional) * @throws InvalidRuleException if the rule could not be constructed for any reason (e.g. no * {@code name} attribute is defined) * @throws NameConflictException if the rule's name or output files conflict with others in this * package * @throws InterruptedException if interrupted */ public static Rule createAndAddRule( PackageContext context, RuleClass ruleClass, BuildLangTypedAttributeValuesMap attributeValues, FuncallExpression ast, @Nullable Environment env) throws InvalidRuleException, NameConflictException, InterruptedException { return createAndAddRule( context.pkgBuilder, ruleClass, attributeValues, context.eventHandler, ast, ast.getLocation(), env); }