Skip to content

Commit ba8877e

Browse files
committed
[class-parse] Use annotated-visibility
Context: #1097 (comment) Context: #1097 (comment) Context: b274a67 During code review, two questions came to light: 1. Will this cause API breakage in AndroidX/etc., because `module-info.class` will make types "disappear"? (See also b274a67). 2. `class-parse` can accept *multiple* `.jar` files and `.class` files on the command-line. Should `module-info.class` processing apply to *everything*? Address the first concern by keeping `//*/@visibility` as `public`, and instead if we think the type should be "internal" we instead add an `//*/@annotated-visibility` attribute value of `module-info`. If there is *already* an `//*/@annotated-visibility` value, then we *append* ` module-info` to the attribute value. Address the second concern by re-working `class-parse` command-line parsing. There is now a "global `ClassPath`", which will be used to hold `.class` files provided on the command-line. `.jar` and `.jmod` files provided on the command-line will be given their own `ClassPath` instances, and `module-info.class`-based visibility fixups are specific to each `ClassPath` instance. Global files are processed together. There is thus no way for `module-info.class` visibility changes from `a.jar` to impact `b.jar`. After visibilities are fixed up, we then merge everything into the "global" `ClassPath` instance before writing transforming to XML. Additionally, `class-parse --dump` can now accept `.jar` files, and will dump out *all* `.class` filers within the `.jar` file. To make this output easier, each "entry" starts with a "header" of `-- Begin {ClassFile.FullJniName}`, and a blank link will be printed between each entry.
1 parent b18bfdf commit ba8877e

File tree

3 files changed

+69
-40
lines changed

3 files changed

+69
-40
lines changed

src/Xamarin.Android.Tools.Bytecode/ClassPath.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ public void Add (ClassFile classFile)
108108
classFiles.Add (classFile);
109109
}
110110

111+
public void Add (ClassPath classPath, bool removeModules = true)
112+
{
113+
classPath.FixupModuleVisibility (removeModules);
114+
foreach (var c in classPath.classFiles) {
115+
Add (c);
116+
}
117+
}
118+
111119
public ReadOnlyDictionary<string, List<ClassFile>> GetPackages ()
112120
{
113121
return new ReadOnlyDictionary<string, List<ClassFile>> (classFiles
@@ -357,7 +365,7 @@ public XElement ToXElement ()
357365
FixUpParametersFromClasses ();
358366

359367
KotlinFixups.Fixup (classFiles);
360-
FixupModuleVisibility ();
368+
FixupModuleVisibility (removeModules: true);
361369

362370
var packagesDictionary = GetPackages ();
363371
var api = new XElement ("api",
@@ -373,7 +381,7 @@ packagesDictionary [p].OrderBy (c => c.ThisClass.Name.Value, StringComparer.Ordi
373381
return api;
374382
}
375383

376-
void FixupModuleVisibility ()
384+
public void FixupModuleVisibility (bool removeModules)
377385
{
378386
var publicPackages = new HashSet<string> ();
379387

@@ -383,7 +391,9 @@ void FixupModuleVisibility ()
383391
return;
384392
}
385393
foreach (var moduleFile in moduleFiles) {
386-
classFiles.Remove (moduleFile);
394+
if (removeModules) {
395+
classFiles.Remove (moduleFile);
396+
}
387397
foreach (var moduleAttr in moduleFile.Attributes.OfType<ModuleAttribute> ()) {
388398
foreach (var export in moduleAttr.Exports) {
389399
publicPackages.Add (export.Exports);
@@ -427,5 +437,7 @@ public void SaveXmlDescription (TextWriter textWriter)
427437
contents.Save (writer);
428438
textWriter.WriteLine ();
429439
}
440+
441+
public IEnumerable<ClassFile> GetClassFiles () => classFiles;
430442
}
431443
}

src/Xamarin.Android.Tools.Bytecode/XmlClassDeclarationBuilder.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public XElement ToXElement ()
4040
GetSourceFile (),
4141
new XAttribute ("static", classFile.IsStatic),
4242
new XAttribute ("visibility", GetVisibility (classFile.Visibility)),
43-
GetAnnotatedVisibility (classFile.Attributes),
43+
GetAnnotatedVisibility (classFile.Visibility, classFile.Attributes),
4444
GetTypeParmeters (signature == null ? null : signature.TypeParameters),
4545
GetImplementedInterfaces (),
4646
GetConstructors (),
@@ -111,7 +111,7 @@ static string GetVisibility (ClassAccessFlags accessFlags)
111111
if ((accessFlags & ClassAccessFlags.Private) != 0)
112112
return "private";
113113
if (accessFlags.HasFlag (ClassAccessFlags.Internal))
114-
return "kotlin-internal";
114+
return "public"; // TODO: `kotlin-internal` at some point? See also GetAnnotatedVisibility()
115115
return "";
116116
}
117117

@@ -431,6 +431,19 @@ IEnumerable<XElement> GetExceptions (MethodInfo method)
431431
}
432432
}
433433

434+
static XAttribute? GetAnnotatedVisibility (ClassAccessFlags flags, AttributeCollection attributes)
435+
{
436+
var attr = GetAnnotatedVisibility (attributes);
437+
if (flags.HasFlag (ClassAccessFlags.Internal)) {
438+
if (attr == null) {
439+
attr = new XAttribute ("annotated-visibility", "module-info");
440+
} else {
441+
attr.Value += " module-info";
442+
}
443+
}
444+
return attr;
445+
}
446+
434447
static XAttribute? GetAnnotatedVisibility (AttributeCollection attributes)
435448
{
436449
var annotations = attributes?.OfType<RuntimeInvisibleAnnotationsAttribute> ().FirstOrDefault ()?.Annotations;

tools/class-parse/Program.cs

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -71,59 +71,63 @@ public static void Main (string[] args)
7171
Log.OnLog = (t, v, m, a) => {
7272
Console.Error.WriteLine(m, a);
7373
};
74-
var classPath = new ClassPath () {
75-
ApiSource = "class-parse",
76-
AndroidFrameworkPlatform = platform,
77-
DocumentationPaths = docsPaths.Count == 0 ? null : docsPaths,
78-
AutoRename = autorename
79-
};
74+
var globalClassPath = CreateClassPath (platform, docsPaths, autorename);
75+
var classPaths = new List<ClassPath> ();
8076
foreach (var file in files) {
8177
try {
82-
if (dump) {
83-
DumpClassFile (file, output);
78+
if (ClassPath.IsJmodFile (file) || ClassPath.IsJarFile (file)) {
79+
var cp = CreateClassPath (platform, docsPaths, autorename);
80+
cp.Load (file);
81+
classPaths.Add (cp);
8482
continue;
8583
}
86-
DumpFileToXml (classPath, file);
84+
using (var s = File.OpenRead (file)) {
85+
if (!ClassFile.IsClassFile (s)) {
86+
Console.Error.WriteLine ("class-parse: Unable to read file '{0}': Unknown file format.");
87+
Environment.ExitCode = 1;
88+
continue;
89+
}
90+
globalClassPath.Add (new ClassFile (s));
91+
}
8792
} catch (Exception e) {
8893
Console.Error.WriteLine ("class-parse: Unable to read file '{0}': {1}",
8994
file, verbosity == 0 ? e.Message : e.ToString ());
9095
Environment.ExitCode = 1;
9196
}
9297
}
93-
if (!dump)
94-
classPath.SaveXmlDescription (output);
95-
if (outputFile != null)
96-
output.Close ();
97-
}
98-
99-
static void DumpFileToXml (ClassPath jar, string file)
100-
{
101-
using (var s = File.OpenRead (file)) {
102-
if (ClassFile.IsClassFile (s)) {
103-
s.Position = 0;
104-
var c = new ClassFile (s);
105-
jar.Add (c);
106-
return;
107-
}
98+
globalClassPath.FixupModuleVisibility (removeModules: !dump);
99+
foreach (var cp in classPaths) {
100+
globalClassPath.Add (cp, removeModules: !dump);
108101
}
109-
if (ClassPath.IsJmodFile (file) || ClassPath.IsJarFile (file)) {
110-
jar.Load (file);
111-
return;
102+
if (!dump) {
103+
globalClassPath.SaveXmlDescription (output);
104+
} else {
105+
bool first = true;
106+
foreach (var c in globalClassPath.GetClassFiles ()) {
107+
if (!first) {
108+
output.WriteLine ();
109+
}
110+
first = false;
111+
DumpClassFile (c, output);
112+
}
112113
}
113-
Console.Error.WriteLine ("class-parse: Unable to read file '{0}': Unknown file format.");
114-
Environment.ExitCode = 1;
114+
if (outputFile != null)
115+
output.Close ();
115116
}
116117

117-
static ClassFile LoadClassFile (string file)
118+
static ClassPath CreateClassPath (string platform, List<string> docsPaths, bool autoRename)
118119
{
119-
using (var s = File.OpenRead (file)) {
120-
return new ClassFile (s);
121-
}
120+
return new ClassPath () {
121+
ApiSource = "class-parse",
122+
AndroidFrameworkPlatform = platform,
123+
DocumentationPaths = docsPaths.Count == 0 ? null : docsPaths,
124+
AutoRename = autoRename
125+
};
122126
}
123127

124-
static void DumpClassFile (string file, TextWriter output)
128+
static void DumpClassFile (ClassFile c, TextWriter output)
125129
{
126-
var c = LoadClassFile (file);
130+
output.WriteLine ($"-- Begin {c.FullJniName} --");
127131
output.WriteLine (".class version: {0}.{1}", c.MajorVersion, c.MinorVersion);
128132
output.WriteLine ("ConstantPool Count: {0}", c.ConstantPool.Count);
129133
for (int i = 0; i < c.ConstantPool.Count; ++i) {

0 commit comments

Comments
 (0)