Inspect post-evaluation exported variables to obtain rule names.
This is a much cleaner, more elegant approach than previous regex matching.
This still leaves room for unknown-name rule definitions, in case, for example, a user namespaces their rule definition not at the top level.
For example: "foo.bar = rule(...)"
RELNOTES: None.
PiperOrigin-RevId: 202380975
diff --git a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java
index dcae202..16635fc 100644
--- a/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java
+++ b/src/main/java/com/google/devtools/build/skydoc/fakebuildapi/FakeSkylarkRuleFunctionsApi.java
@@ -27,18 +27,20 @@
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.FuncallExpression;
+import com.google.devtools.build.lib.syntax.Runtime;
import com.google.devtools.build.lib.syntax.SkylarkDict;
import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.skydoc.rendering.RuleInfo;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.annotation.Nullable;
/**
* Fake implementation of {@link SkylarkRuleFunctionsApi}.
*
- * <p>This fake hooks into the global {@code rule()} function, noting calls of that function
- * with a {@link RuleInfoCollector} given in the class constructor.</p>
+ * <p>This fake hooks into the global {@code rule()} function, adding descriptors of calls of that
+ * function to a {@link List} given in the class constructor.</p>
*/
public class FakeSkylarkRuleFunctionsApi implements SkylarkRuleFunctionsApi<FileApi> {
@@ -67,7 +69,7 @@
Boolean executionPlatformConstraintsAllowed, SkylarkList<?> execCompatibleWith,
FuncallExpression ast, Environment funcallEnv) throws EvalException {
Set<String> attrNames;
- if (attrs != null) {
+ if (attrs != null && attrs != Runtime.NONE) {
SkylarkDict<?, ?> attrsDict = (SkylarkDict<?, ?>) attrs;
Map<String, Descriptor> attrsMap =
attrsDict.getContents(String.class, Descriptor.class, "attrs");
@@ -76,9 +78,10 @@
attrNames = ImmutableSet.of();
}
+ RuleDefinitionIdentifier functionIdentifier = new RuleDefinitionIdentifier();
// TODO(cparsons): Improve details given to RuleInfo (for example, attribute types).
- ruleInfoList.add(new RuleInfo(ast.getLocation(), doc, attrNames));
- return implementation;
+ ruleInfoList.add(new RuleInfo(functionIdentifier, ast.getLocation(), doc, attrNames));
+ return functionIdentifier;
}
@Override
@@ -100,4 +103,24 @@
FuncallExpression ast, Environment funcallEnv) throws EvalException {
return null;
}
+
+ /**
+ * A fake {@link BaseFunction} implementation which serves as an identifier for a rule definition.
+ * A skylark invocation of 'rule()' should spawn a unique instance of this class and return it.
+ * Thus, skylark code such as 'foo = rule()' will result in 'foo' being assigned to a unique
+ * identifier, which can later be matched to a registered rule() invocation saved by the fake
+ * build API implementation.
+ */
+ private static class RuleDefinitionIdentifier extends BaseFunction {
+
+ public RuleDefinitionIdentifier() {
+ super("RuleDefinitionIdentifier");
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ // Use exact object matching.
+ return this == other;
+ }
+ }
}