Skip to content

Commit 37a74a7

Browse files
tetrominocopybara-github
authored andcommitted
Refactor Starlark API docgen to not refer to Java annotations directly
Prerequisite for supporting .bzl-defined entities in Starlark API docgen. PiperOrigin-RevId: 808670253 Change-Id: I73d7fbed1803a5ce37953aabe0e3f3254f830696
1 parent 820ad5d commit 37a74a7

File tree

10 files changed

+262
-157
lines changed

10 files changed

+262
-157
lines changed

src/main/java/com/google/devtools/build/docgen/ApiExporter.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@
2222
import com.google.devtools.build.docgen.builtin.BuiltinProtos.Param;
2323
import com.google.devtools.build.docgen.builtin.BuiltinProtos.Type;
2424
import com.google.devtools.build.docgen.builtin.BuiltinProtos.Value;
25-
import com.google.devtools.build.docgen.starlark.AnnotParamDoc;
26-
import com.google.devtools.build.docgen.starlark.AnnotStarlarkConstructorMethodDoc;
27-
import com.google.devtools.build.docgen.starlark.AnnotStarlarkMethodDoc;
25+
import com.google.devtools.build.docgen.starlark.MemberDoc;
26+
import com.google.devtools.build.docgen.starlark.ParamDoc;
2827
import com.google.devtools.build.docgen.starlark.StarlarkDocExpander;
2928
import com.google.devtools.build.docgen.starlark.StarlarkDocPage;
3029
import com.google.devtools.common.options.OptionsParser;
@@ -34,6 +33,7 @@
3433
import java.lang.reflect.Method;
3534
import java.util.ArrayList;
3635
import java.util.Collections;
36+
import java.util.Comparator;
3737
import java.util.HashMap;
3838
import java.util.Iterator;
3939
import java.util.List;
@@ -59,10 +59,13 @@ private static void appendTypes(
5959
Type.Builder type = Type.newBuilder();
6060
type.setName(docPage.getName());
6161
type.setDoc(docPage.getDocumentation());
62-
for (AnnotStarlarkMethodDoc meth : docPage.getJavaMethods()) {
62+
// Sort members in case-sensitive name order.
63+
for (MemberDoc member :
64+
ImmutableList.sortedCopyOf(
65+
Comparator.comparing(MemberDoc::getName), docPage.getMembers())) {
6366
// Constructors are exported as global symbols.
64-
if (!(meth instanceof AnnotStarlarkConstructorMethodDoc)) {
65-
Value.Builder value = collectMethodInfo(meth);
67+
if (!member.isConstructor()) {
68+
Value.Builder value = collectMethodInfo(member);
6669
if (type.getName().equals("native")) {
6770
// Methods from the native package are available as top level functions in BUILD files.
6871
value.setApiContext(ApiContext.BUILD);
@@ -89,8 +92,8 @@ private static void appendTypes(
8992
private static void appendGlobals(
9093
Builtins.Builder builtins,
9194
Map<String, Object> globals,
92-
Map<String, AnnotStarlarkMethodDoc> globalToDoc,
93-
Map<String, AnnotStarlarkConstructorMethodDoc> typeNameToConstructor,
95+
Map<String, MemberDoc> globalToDoc,
96+
Map<String, MemberDoc> typeNameToConstructor,
9497
ApiContext context) {
9598
for (Entry<String, Object> entry : globals.entrySet()) {
9699
String name = entry.getKey();
@@ -101,7 +104,7 @@ private static void appendGlobals(
101104

102105
Value.Builder value = Value.newBuilder();
103106
if (obj instanceof StarlarkCallable) {
104-
AnnotStarlarkMethodDoc meth = globalToDoc.get(name);
107+
MemberDoc meth = globalToDoc.get(name);
105108
if (meth != null) {
106109
value = collectMethodInfo(meth);
107110
} else {
@@ -117,8 +120,7 @@ private static void appendGlobals(
117120
StarlarkMethod annotation = StarlarkAnnotations.getStarlarkMethod(selfCallMethod);
118121
value = valueFromAnnotation(annotation);
119122
// For constructors, we can also set the return type.
120-
AnnotStarlarkConstructorMethodDoc constructor =
121-
typeNameToConstructor.get(entry.getKey());
123+
MemberDoc constructor = typeNameToConstructor.get(entry.getKey());
122124
if (constructor != null && value.hasCallable()) {
123125
value.getCallableBuilder().setReturnType(constructor.getReturnType());
124126
}
@@ -242,13 +244,13 @@ private static Value.Builder signatureToValue(Signature sig) {
242244
return value;
243245
}
244246

245-
private static Value.Builder collectMethodInfo(AnnotStarlarkMethodDoc meth) {
247+
private static Value.Builder collectMethodInfo(MemberDoc meth) {
246248
Value.Builder field = Value.newBuilder();
247249
field.setName(meth.getShortName());
248250
field.setDoc(meth.getDocumentation());
249251
if (meth.isCallable()) {
250252
Callable.Builder callable = Callable.newBuilder();
251-
for (AnnotParamDoc par : meth.getParams()) {
253+
for (ParamDoc par : meth.getParams()) {
252254
Param.Builder param = newParam(par.getName(), par.getDefaultValue().isEmpty());
253255
param.setType(par.getType());
254256
param.setDoc(par.getDocumentation());
@@ -352,9 +354,9 @@ public static void main(String[] args) {
352354
Builtins.Builder builtins = Builtins.newBuilder();
353355

354356
ImmutableList<StarlarkDocPage> globalPages = allDocPages.get(Category.GLOBAL_FUNCTION);
355-
Map<String, AnnotStarlarkMethodDoc> globalToDoc = new HashMap<>();
357+
Map<String, MemberDoc> globalToDoc = new HashMap<>();
356358
for (StarlarkDocPage globalPage : globalPages) {
357-
for (AnnotStarlarkMethodDoc meth : globalPage.getJavaMethods()) {
359+
for (MemberDoc meth : globalPage.getMembers()) {
358360
globalToDoc.put(meth.getShortName(), meth);
359361
}
360362
}
@@ -364,7 +366,7 @@ public static void main(String[] args) {
364366
.filter(e -> !e.getKey().equals(Category.GLOBAL_FUNCTION))
365367
.flatMap(e -> e.getValue().stream())
366368
.iterator();
367-
Map<String, AnnotStarlarkConstructorMethodDoc> typeNameToConstructor = new HashMap<>();
369+
Map<String, MemberDoc> typeNameToConstructor = new HashMap<>();
368370
while (typesIterator.hasNext()) {
369371
StarlarkDocPage typeDocPage = typesIterator.next();
370372
appendTypes(builtins, typeDocPage, symbols.getNativeRules());

src/main/java/com/google/devtools/build/docgen/StarlarkDocumentationCollector.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ private static void collectBuiltinMethods(
213213
javaMethod = selfCall;
214214
}
215215
}
216-
builtinDoc.addMethod(
216+
builtinDoc.addMember(
217217
new AnnotStarlarkOrdinaryMethodDoc(
218218
builtinDoc.getName(), javaMethod, starlarkMethod, expander));
219219
}
@@ -246,7 +246,7 @@ private static void collectGlobalMethods(
246246
// Only add non-constructor global library methods. Constructors are added later.
247247
// TODO(wyv): add a redirect instead
248248
if (!entry.getKey().isAnnotationPresent(StarlarkConstructor.class)) {
249-
page.addMethod(
249+
page.addMember(
250250
new AnnotStarlarkOrdinaryMethodDoc("", entry.getKey(), entry.getValue(), expander));
251251
}
252252
}

src/main/java/com/google/devtools/build/docgen/starlark/AnnotParamDoc.java

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,9 @@
2020
* A class containing the documentation for a parameter of a {@link
2121
* net.starlark.java.annot.StarlarkMethod}-annotated Java method callable from Starlark.
2222
*/
23-
public final class AnnotParamDoc extends StarlarkDoc {
24-
/** Repesents the param kind, whether it's a normal param or *arg or **kwargs. */
25-
public static enum Kind {
26-
NORMAL,
27-
// TODO: https://github.com/bazelbuild/stardoc/issues/225 - NORMAL needs to be split into
28-
// NORMAL and KEYWORD_ONLY, since EXTRA_KEYWORDS (or a `*` separator) go before keyword-only
29-
// params, not necessarily immediately before kwargs.
30-
EXTRA_POSITIONALS,
31-
EXTRA_KEYWORDS,
32-
}
33-
23+
public final class AnnotParamDoc extends ParamDoc {
3424
private final AnnotStarlarkMethodDoc method;
3525
private final Param param;
36-
private final Kind kind;
3726
private final int paramIndex;
3827

3928
public AnnotParamDoc(
@@ -42,22 +31,13 @@ public AnnotParamDoc(
4231
StarlarkDocExpander expander,
4332
Kind kind,
4433
int paramIndex) {
45-
super(expander);
34+
super(expander, kind);
4635
this.method = method;
4736
this.param = param;
48-
this.kind = kind;
4937
this.paramIndex = paramIndex;
5038
}
5139

52-
/**
53-
* Returns the string representing the type of this parameter with the link to the documentation
54-
* for the type if available.
55-
*
56-
* <p>If the parameter type is Object, then returns the empty string. If the parameter type is not
57-
* a generic, then this method returns a string representing the type name with a link to the
58-
* documentation for the type if available. If the parameter type is a generic, then this method
59-
* returns a string "CONTAINER of TYPE" (with HTML link markup).
60-
*/
40+
@Override
6141
public String getType() {
6242
StringBuilder sb = new StringBuilder();
6343
if (param.allowedTypes().length == 0) {
@@ -86,10 +66,6 @@ public String getType() {
8666
return sb.toString();
8767
}
8868

89-
public Kind getKind() {
90-
return kind;
91-
}
92-
9369
public AnnotStarlarkMethodDoc getMethod() {
9470
return method;
9571
}
@@ -99,6 +75,7 @@ public String getName() {
9975
return param.name();
10076
}
10177

78+
@Override
10279
public String getDefaultValue() {
10380
return param.defaultValue();
10481
}

src/main/java/com/google/devtools/build/docgen/starlark/AnnotStarlarkConstructorMethodDoc.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ public AnnotStarlarkConstructorMethodDoc(
3434
this.fullyQualifiedName = fullyQualifiedName;
3535
}
3636

37+
@Override
38+
public boolean isConstructor() {
39+
return true;
40+
}
41+
3742
@Override
3843
public String getName() {
3944
return fullyQualifiedName;

src/main/java/com/google/devtools/build/docgen/starlark/AnnotStarlarkMethodDoc.java

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* An abstract class containing documentation for a {@link StarlarkMethod}-annotated Java method
2727
* callable from Starlark.
2828
*/
29-
public abstract class AnnotStarlarkMethodDoc extends StarlarkDoc {
29+
public abstract class AnnotStarlarkMethodDoc extends MemberDoc {
3030
protected final Method javaMethod;
3131
protected final StarlarkMethod annotation;
3232
protected final ImmutableList<AnnotParamDoc> params;
@@ -39,16 +39,12 @@ public AnnotStarlarkMethodDoc(
3939
this.params = determineParams();
4040
}
4141

42-
/** Returns whether the Starlark method is documented. */
42+
@Override
4343
public final boolean documented() {
4444
return annotation.documented();
4545
}
4646

47-
/**
48-
* Returns a string containing additional documentation about the method's return value.
49-
*
50-
* <p>Returns an empty string by default.
51-
*/
47+
@Override
5248
public final String getReturnTypeExtraMessage() {
5349
if (annotation.allowReturnNones()) {
5450
return " May return <code>None</code>.\n";
@@ -61,35 +57,19 @@ public final Method getMethod() {
6157
return javaMethod;
6258
}
6359

64-
/** Returns a string containing a name for the method's return type. */
65-
public abstract String getReturnType();
66-
67-
/**
68-
* Returns whether a method can be called as a function.
69-
*
70-
* <p>E.g. ctx.label is not callable.
71-
*/
60+
@Override
7261
public final boolean isCallable() {
7362
return !annotation.structField();
7463
}
7564

76-
/**
77-
* Returns a string containing the method's name. GetName() returns the complete signature in case
78-
* of overloaded methods. This is used to extract only the name of the method.
79-
*
80-
* <p>E.g. ctx.new_file is overloaded. In this case getName() returns "new_file(filename)", while
81-
* getShortName() returns only "new_file".
82-
*/
83-
public String getShortName() {
84-
return getName();
85-
}
86-
8765
/** Returns a list containing the documentation for each of the method's parameters. */
66+
@Override
8867
public final ImmutableList<AnnotParamDoc> getParams() {
8968
return params;
9069
}
9170

92-
private String getParameterString() {
71+
@Override
72+
protected String getParameterString() {
9373
List<String> argList = new ArrayList<>();
9474

9575
boolean named = false;
@@ -120,7 +100,7 @@ private ImmutableList<AnnotParamDoc> determineParams() {
120100
for (int i = getStartIndexForParams(); i < annotation.parameters().length; i++) {
121101
Param param = annotation.parameters()[i];
122102
if (param.documented()) {
123-
paramsBuilder.add(new AnnotParamDoc(this, param, expander, AnnotParamDoc.Kind.NORMAL, i));
103+
paramsBuilder.add(new AnnotParamDoc(this, param, expander, ParamDoc.Kind.NORMAL, i));
124104
}
125105
}
126106
if (!annotation.extraPositionals().name().isEmpty()) {
@@ -129,7 +109,7 @@ private ImmutableList<AnnotParamDoc> determineParams() {
129109
this,
130110
annotation.extraPositionals(),
131111
expander,
132-
AnnotParamDoc.Kind.EXTRA_POSITIONALS,
112+
ParamDoc.Kind.EXTRA_POSITIONALS,
133113
/* paramIndex= */ -1));
134114
}
135115
if (!annotation.extraKeywords().name().isEmpty()) {
@@ -138,18 +118,12 @@ private ImmutableList<AnnotParamDoc> determineParams() {
138118
this,
139119
annotation.extraKeywords(),
140120
expander,
141-
AnnotParamDoc.Kind.EXTRA_KEYWORDS,
121+
ParamDoc.Kind.EXTRA_KEYWORDS,
142122
/* paramIndex= */ -1));
143123
}
144124
return paramsBuilder.build();
145125
}
146126

147-
/**
148-
* Returns a string representing the method signature of the Starlark method, which contains HTML
149-
* links to the documentation of parameter types if available.
150-
*/
151-
public abstract String getSignature();
152-
153127
protected String getSignature(String fullyQualifiedMethodName) {
154128
String args = isCallable() ? "(" + getParameterString() + ")" : "";
155129

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright 2025 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.devtools.build.docgen.starlark;
16+
17+
import com.google.common.collect.ImmutableList;
18+
19+
/**
20+
* Documentation for a method or struct field of a Java class annotated with {@link
21+
* net.starlark.java.annot.StarlarkBuiltin}, or for a field of a Starlark-defined struct.
22+
*/
23+
public abstract class MemberDoc extends StarlarkDoc {
24+
25+
protected MemberDoc(StarlarkDocExpander expander) {
26+
super(expander);
27+
}
28+
29+
/** Returns whether the value is documented. */
30+
public abstract boolean documented();
31+
32+
/**
33+
* Returns whether the value can be called as a function.
34+
*
35+
* <p>For example, {@code ctx.label} is not callable.
36+
*/
37+
public abstract boolean isCallable();
38+
39+
/**
40+
* For a callable value, returns the name for the return type; or the name of the value's own type
41+
* otherwise.
42+
*/
43+
public abstract String getReturnType();
44+
45+
/**
46+
* For a callable value, returns a string containing additional documentation about the return
47+
* value.
48+
*
49+
* <p>Returns an empty string by default.
50+
*/
51+
public String getReturnTypeExtraMessage() {
52+
return "";
53+
}
54+
55+
/** Returns true if the value is callable and is a constructor of its type. */
56+
public boolean isConstructor() {
57+
return false;
58+
}
59+
60+
/**
61+
* Returns the value's name within its module.
62+
*
63+
* <p>In most cases, this is the same as {@link #getName}. The exception is for overloaded methods
64+
* in a {@link net.starlark.java.annot.StarlarkBuiltin}-annotated Java class. In that case, this
65+
* method would return the name of the method, while {@link #getName} would return the method
66+
* signature with parameters, e.g. {@code method_name(arg1, arg2)}.
67+
*/
68+
public String getShortName() {
69+
return getName();
70+
}
71+
72+
/**
73+
* For a callable value, returns a list containing the documentation for each of the method's
74+
* parameters; or an empty list otherwise.
75+
*/
76+
public abstract ImmutableList<? extends ParamDoc> getParams();
77+
78+
/**
79+
* For a callable value, returns the string representation of the parameters, for example {@code
80+
* "arg1, arg2=None, **kwargs"}; or an empty string otherwise.
81+
*/
82+
protected abstract String getParameterString();
83+
84+
/**
85+
* For a callable value, returns the string representing the method signature of the Starlark
86+
* method, which contains HTML links to the documentation of parameter types if available. For a
87+
* non-callable value, returns the string representation of the value's type (with HTML links to
88+
* the type's documentation, if available) and name.
89+
*/
90+
public abstract String getSignature();
91+
}

0 commit comments

Comments
 (0)