Esempio n. 1
0
  /**
   * 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);
    }
  }
Esempio n. 2
0
 /**
  * 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);
 }
  /**
   * Collects and returns all the Java objects reachable in Skylark from (and including)
   * firstClassObject with the corresponding SkylarkSignature annotations.
   *
   * <p>Note that the {@link SkylarkSignature} annotation for firstClassObject - firstAnnotation -
   * is also an input parameter, because some top level Skylark built-in objects and methods are not
   * annotated on the class, but on a field referencing them.
   */
  void collect(
      SkylarkModule firstModule, Class<?> firstClass, Map<String, SkylarkModuleDoc> modules) {
    Set<Class<?>> processedClasses = new HashSet<>();
    LinkedList<Class<?>> classesToProcess = new LinkedList<>();
    Map<Class<?>, SkylarkModule> annotations = new HashMap<>();

    classesToProcess.addLast(firstClass);
    annotations.put(firstClass, firstModule);

    while (!classesToProcess.isEmpty()) {
      Class<?> classObject = classesToProcess.removeFirst();
      SkylarkModule annotation = annotations.get(classObject);
      processedClasses.add(classObject);
      if (!modules.containsKey(annotation.name())) {
        modules.put(annotation.name(), new SkylarkModuleDoc(annotation, classObject));
      }
      SkylarkModuleDoc module = modules.get(annotation.name());

      if (module.javaMethodsNotCollected()) {
        ImmutableMap<Method, SkylarkCallable> methods =
            FuncallExpression.collectSkylarkMethodsWithAnnotation(classObject);
        ArrayList<SkylarkJavaMethod> methodList = new ArrayList<>();
        for (Map.Entry<Method, SkylarkCallable> entry : methods.entrySet()) {
          methodList.add(new SkylarkJavaMethod(entry.getKey(), entry.getValue()));
        }
        module.setJavaMethods(methodList);

        for (Map.Entry<Method, SkylarkCallable> method : methods.entrySet()) {
          Class<?> returnClass = method.getKey().getReturnType();
          if (returnClass.isAnnotationPresent(SkylarkModule.class)
              && !processedClasses.contains(returnClass)) {
            classesToProcess.addLast(returnClass);
            annotations.put(returnClass, returnClass.getAnnotation(SkylarkModule.class));
          }
        }
      }
    }
  }