Skip to content

Commit cd829ae

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 cd829ae

File tree

3 files changed

+64
-41
lines changed

3 files changed

+64
-41
lines changed

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

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

111+
public IList<ClassFile> ClassFiles => classFiles;
112+
111113
public ReadOnlyDictionary<string, List<ClassFile>> GetPackages ()
112114
{
113115
return new ReadOnlyDictionary<string, List<ClassFile>> (classFiles
@@ -356,9 +358,6 @@ public XElement ToXElement ()
356358
if (AutoRename)
357359
FixUpParametersFromClasses ();
358360

359-
KotlinFixups.Fixup (classFiles);
360-
FixupModuleVisibility ();
361-
362361
var packagesDictionary = GetPackages ();
363362
var api = new XElement ("api",
364363
GetApiSource (),
@@ -373,8 +372,10 @@ packagesDictionary [p].OrderBy (c => c.ThisClass.Name.Value, StringComparer.Ordi
373372
return api;
374373
}
375374

376-
void FixupModuleVisibility ()
375+
public void FixupModuleVisibility (bool removeModules)
377376
{
377+
KotlinFixups.Fixup (classFiles);
378+
378379
var publicPackages = new HashSet<string> ();
379380

380381
var moduleFiles = classFiles.Where (c => c.AccessFlags == ClassAccessFlags.Module)
@@ -383,7 +384,9 @@ void FixupModuleVisibility ()
383384
return;
384385
}
385386
foreach (var moduleFile in moduleFiles) {
386-
classFiles.Remove (moduleFile);
387+
if (removeModules) {
388+
classFiles.Remove (moduleFile);
389+
}
387390
foreach (var moduleAttr in moduleFile.Attributes.OfType<ModuleAttribute> ()) {
388391
foreach (var export in moduleAttr.Exports) {
389392
publicPackages.Add (export.Exports);

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: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -71,59 +71,66 @@ 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;
98+
globalClassPath.FixupModuleVisibility (removeModules: !dump);
99+
foreach (var cp in classPaths) {
100+
cp.FixupModuleVisibility (removeModules: !dump);
101+
foreach (var c in cp.ClassFiles) {
102+
globalClassPath.Add (c);
107103
}
108104
}
109-
if (ClassPath.IsJmodFile (file) || ClassPath.IsJarFile (file)) {
110-
jar.Load (file);
111-
return;
105+
if (!dump) {
106+
globalClassPath.SaveXmlDescription (output);
107+
} else {
108+
bool first = true;
109+
foreach (var c in globalClassPath.ClassFiles) {
110+
if (!first) {
111+
output.WriteLine ();
112+
}
113+
first = false;
114+
DumpClassFile (c, output);
115+
}
112116
}
113-
Console.Error.WriteLine ("class-parse: Unable to read file '{0}': Unknown file format.");
114-
Environment.ExitCode = 1;
117+
if (outputFile != null)
118+
output.Close ();
115119
}
116120

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

124-
static void DumpClassFile (string file, TextWriter output)
131+
static void DumpClassFile (ClassFile c, TextWriter output)
125132
{
126-
var c = LoadClassFile (file);
133+
output.WriteLine ($"-- Begin {c.FullJniName} --");
127134
output.WriteLine (".class version: {0}.{1}", c.MajorVersion, c.MinorVersion);
128135
output.WriteLine ("ConstantPool Count: {0}", c.ConstantPool.Count);
129136
for (int i = 0; i < c.ConstantPool.Count; ++i) {

0 commit comments

Comments
 (0)