Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

Commit d3f0c5c

Browse files
authored
[generator] Fix parameter string in ref doc links (#935)
Fixes: #931Fixes: #932 We have a handful of issues in the https://developer.android.com/ links that are generated for various type members with complex parameters. Collections, varargs, and generics are some examples of items that are not translated correctly when generating the parameter portion of the reference documentation URL. The XML generated by `java-source-utils` when processing `android-stubs-src.jar` contains `<parameter/>` elements under all methods. The `<parameter/>` elements contain attributes with additional type data; for instance: <method jni-return="Landroid/animation/ObjectAnimator;" jni-signature="(Ljava/lang/Object;Landroid/util/Property;Landroid/util/Property;Landroid/graphics/Path;)Landroid/animation/ObjectAnimator;" name="ofFloat" return="android.animation.ObjectAnimator"> <parameter jni-type="Ljava/lang/Object;" name="target" type="T"/> <parameter jni-type="Landroid/util/Property;" name="xProperty" type="android.util.Property&lt;T, java.lang.Float&gt;"/> <parameter jni-type="Landroid/util/Property;" name="yProperty" type="android.util.Property&lt;T, java.lang.Float&gt;"/> <parameter jni-type="Landroid/graphics/Path;" name="path" type="android.graphics.Path"/> <javadoc> <![CDATA[Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code> using two properties. A <code>Path</code></> animation moves in two dimensions, animating coordinates <code>(x, y)</code> together to follow the line. In this variation, the coordinates are floats that are set to separate properties, <code>xProperty</code> and <code>yProperty</code>. @PARAM target The object whose properties are to be animated. @PARAM xProperty The property for the x coordinate being animated. @PARAM yProperty The property for the y coordinate being animated. @PARAM path The <code>Path</code> to animate values along. @return An ObjectAnimator object that is set up to animate along <code>path</code>.]]> </javadoc> </method> Rather than processing the `//method/@jni-signature` attribute of the method, use the `//method/parameter/@type` attribute values to create more reliable type information for our reference documentation links. With these changes in place, instead of e.g. https://developer.android.com/reference/android/accounts/AccountManager#addAccount(java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle,%20android.app.Activity,%20android.accounts.AccountManagerCallback,%20android.os.Handler) which doesn't anchor to the intended method documentation, we now emit https://developer.android.com/reference/android/accounts/AccountManager#addAccount(java.lang.String,%20java.lang.String,%20java.lang.String[],%20android.os.Bundle,%20android.app.Activity,%20android.accounts.AccountManagerCallback%3Candroid.os.Bundle%3E,%20android.os.Handler) which *does* anchor to the intended method documentation.
1 parent d64087c commit d3f0c5c

1 file changed

Lines changed: 27 additions & 99 deletions

File tree

  • tools/generator/Java.Interop.Tools.Generator.ObjectModel

‎tools/generator/Java.Interop.Tools.Generator.ObjectModel/JavadocInfo.cs‎

Lines changed: 27 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
3939
vardesc=GetMemberDescription(element);
4040
stringdeclaringJniType=desc.DeclaringJniType;
4141
stringdeclaringMemberName=desc.DeclaringMemberName;
42-
vardeclaringMemberJniSignature=desc.DeclaringMemberJniSignature;
42+
vardeclaringMemberParamString=desc.DeclaringMemberParameterString;
4343

44-
varextras=GetExtra(element,style,declaringJniType,declaringMemberName,declaringMemberJniSignature,appendCopyrightExtra);
44+
varextras=GetExtra(element,style,declaringJniType,declaringMemberName,declaringMemberParamString,appendCopyrightExtra);
4545
XElement[]extra=extras.Extras;
4646
XElement[]copyright=extras.Copyright;
4747

@@ -54,13 +54,13 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
5454
Javadoc=javadoc,
5555
MemberDescription=declaringMemberName==null
5656
?declaringJniType
57-
:$"{declaringJniType}.{declaringMemberName}.{declaringMemberJniSignature}",
57+
:$"{declaringJniType}.{declaringMemberName}{declaringMemberParamString}",
5858
XmldocStyle=style,
5959
};
6060
returninfo;
6161
}
6262

63-
static(stringDeclaringJniType,stringDeclaringMemberName,stringDeclaringMemberJniSignature)GetMemberDescription(XElementelement)
63+
static(stringDeclaringJniType,stringDeclaringMemberName,stringDeclaringMemberParameterString)GetMemberDescription(XElementelement)
6464
{
6565
boolisType=element.Name.LocalName=="class"||
6666
element.Name.LocalName=="interface";
@@ -76,14 +76,26 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
7676
stringdeclaringMemberName=isType
7777
?null
7878
:(string)element.Attribute("name")??declaringJniType.Substring(declaringJniType.LastIndexOf('/')+1);
79+
7980
stringdeclaringMemberJniSignature=isType
8081
?null
8182
:(string)element.Attribute("jni-signature");
8283

83-
return(declaringJniType,declaringMemberName,declaringMemberJniSignature);
84+
85+
stringdeclaringMemberParameterString=null;
86+
if(!isType&&(declaringMemberJniSignature?.StartsWith("(",StringComparison.Ordinal)??false)){
87+
varparameterTypes=element.Elements("parameter")?.Select(e =>e.Attribute("type")?.Value)?.ToList();
88+
if(parameterTypes?.Any()??false){
89+
declaringMemberParameterString=$"({string.Join(", ",parameterTypes)})";
90+
}else{
91+
declaringMemberParameterString="()";
92+
}
93+
}
94+
95+
return(declaringJniType,declaringMemberName,declaringMemberParameterString);
8496
}
8597

86-
static(XElement[]Extras,XElement[]Copyright)GetExtra(XElementelement,XmldocStylestyle,stringdeclaringJniType,stringdeclaringMemberName,stringdeclaringMemberJniSignature,boolappendCopyrightExtra)
98+
static(XElement[]Extras,XElement[]Copyright)GetExtra(XElementelement,XmldocStylestyle,stringdeclaringJniType,stringdeclaringMemberName,stringdeclaringMemberParameterString,boolappendCopyrightExtra)
8799
{
88100
if(!style.HasFlag(XmldocStyle.IntelliSenseAndExtraRemarks))
89101
return(null,null);
@@ -107,7 +119,7 @@ public static JavadocInfo CreateInfo (XElement element, XmldocStyle style, bool
107119

108120
XElementdocLink=null;
109121
if(!string.IsNullOrEmpty(urlPrefix)){
110-
docLink=CreateDocLinkUrl(kind,urlPrefix,declaringJniType,declaringMemberName,declaringMemberJniSignature);
122+
docLink=CreateDocLinkUrl(kind,urlPrefix,declaringJniType,declaringMemberName,declaringMemberParameterString);
111123
}
112124
extra=newList<XElement>();
113125
extra.Add(docLink);
@@ -217,26 +229,26 @@ static List<string> GetLines (string text)
217229
[ApiLinkStyle.DeveloperAndroidComReference_2020Nov]=CreateAndroidDocLinkUri,
218230
};
219231

220-
staticXElementCreateDocLinkUrl(ApiLinkStylestyle,stringprefix,stringdeclaringJniType,stringdeclaringMemberName,stringdeclaringMemberJniSignature)
232+
staticXElementCreateDocLinkUrl(ApiLinkStylestyle,stringprefix,stringdeclaringJniType,stringdeclaringMemberName,stringdeclaringMemberParameterString)
221233
{
222-
;
223234
if(style==ApiLinkStyle.None||prefix==null||declaringJniType==null)
224235
returnnull;
225236
if(UrlCreators.TryGetValue(style,outvarcreator)){
226-
returncreator(prefix,declaringJniType,declaringMemberName,declaringMemberJniSignature);
237+
returncreator(prefix,declaringJniType,declaringMemberName,declaringMemberParameterString);
227238
}
228239
returnnull;
229240
}
230241

231-
staticXElementCreateAndroidDocLinkUri(stringprefix,stringdeclaringJniType,stringdeclaringMemberName,stringdeclaringMemberJniSignature)
242+
staticXElementCreateAndroidDocLinkUri(stringprefix,stringdeclaringJniType,stringdeclaringMemberName,stringdeclaringMemberParameterString)
232243
{
233244
// URL is:
234245
// * {prefix}
235246
// * declaring type in JNI format
236247
// * when `declaringJniMemberName` != null, `#{declaringJniMemberName}`
237248
// * for methods & constructors, a `(`, the arguments in *Java* syntax -- separated by `, ` -- and `)`
238249
//
239-
// Example: https://developer.android.com/reference/android/app/Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener)
250+
// Example: "https://developer.android.com/reference/android/app/Application#registerOnProvideAssistDataListener(android.app.Application.OnProvideAssistDataListener)"
251+
// Example: "https://developer.android.com/reference/android/animation/ObjectAnimator#ofFloat(T,%20android.util.Property%3CT,%20java.lang.Float%3E,%20float...)"
240252

241253
varjava=newStringBuilder(declaringJniType)
242254
.Replace("/",".")
@@ -250,13 +262,9 @@ static XElement CreateAndroidDocLinkUri (string prefix, string declaringJniType,
250262
if(declaringMemberName!=null){
251263
java.Append(".").Append(declaringMemberName);
252264
url.Append("#").Append(declaringMemberName);
253-
if(declaringMemberJniSignature?.StartsWith("(",StringComparison.Ordinal)??false){
254-
java.Append("(");
255-
url.Append("(");
256-
AppendJavaParameterTypes(java,declaringMemberJniSignature);
257-
AppendJavaParameterTypes(url,declaringMemberJniSignature);
258-
java.Append(")");
259-
url.Append(")");
265+
if(declaringMemberParameterString!=null){
266+
java.Append(declaringMemberParameterString);
267+
url.Append(declaringMemberParameterString);
260268
}
261269
}
262270
varformat=newXElement("format",
@@ -270,85 +278,5 @@ static XElement CreateAndroidDocLinkUri (string prefix, string declaringJniType,
270278
returnnewXElement("para",format);
271279
}
272280

273-
staticStringBuilderAppendJavaParameterTypes(StringBuilderbuilder,stringdeclaringMemberJniSignature)
274-
{
275-
if(string.IsNullOrEmpty(declaringMemberJniSignature)||declaringMemberJniSignature[0]!='(')
276-
returnbuilder;
277-
278-
intstartLen=builder.Length;
279-
280-
for(inti=1;i<declaringMemberJniSignature.Length;++i){
281-
if(declaringMemberJniSignature[i]==')')
282-
break;
283-
AppendComma();
284-
AppendJavaParameterType(builder,declaringMemberJniSignature,refi);
285-
}
286-
287-
returnbuilder;
288-
289-
voidAppendComma()
290-
{
291-
if(startLen==builder.Length)
292-
return;
293-
builder.Append(", ");
294-
}
295-
}
296-
297-
staticvoidAppendJavaParameterType(StringBuilderbuilder,stringdeclaringMemberJniSignature,refinti)
298-
{
299-
switch(declaringMemberJniSignature[i]){
300-
case'[':{
301-
++i;
302-
AppendJavaParameterType(builder,declaringMemberJniSignature,refi);
303-
builder.Append("[]");
304-
break;
305-
}
306-
case'B':{
307-
builder.Append("byte");
308-
break;
309-
}
310-
case'C':{
311-
builder.Append("char");
312-
break;
313-
}
314-
case'D':{
315-
builder.Append("double");
316-
break;
317-
}
318-
case'F':{
319-
builder.Append("float");
320-
break;
321-
}
322-
case'I':{
323-
builder.Append("int");
324-
break;
325-
}
326-
case'J':{
327-
builder.Append("long");
328-
break;
329-
}
330-
case'L':{
331-
intend=declaringMemberJniSignature.IndexOf(';',i);
332-
if(end<0)
333-
thrownewInvalidOperationException($"INTERNAL ERROR: Invalid JNI signature '{declaringMemberJniSignature}': no ';' to end 'L' at index {i}!");
334-
vartype=declaringMemberJniSignature.Substring(i+1,end-i-1)
335-
.Replace('/','.')
336-
.Replace('$','.');
337-
builder.Append(type);
338-
i=end;
339-
break;
340-
}
341-
case'S':{
342-
builder.Append("short");
343-
break;
344-
}
345-
case'Z':{
346-
builder.Append("boolean");
347-
break;
348-
}
349-
default:
350-
thrownewNotSupportedException($"INTERNAL ERROR: Don't know what to do with '{declaringMemberJniSignature[i]}' in '{declaringMemberJniSignature}'!");
351-
}
352-
}
353281
}
354282
}

0 commit comments

Comments
 (0)