1
1
using System ;
2
2
using System . Collections . Generic ;
3
-
3
+ using System . IO ;
4
+ using System . Linq ;
5
+ using System . Xml . Linq ;
4
6
using Java . Interop . Tools . Cecil ;
5
7
using Java . Interop . Tools . TypeNameMappings ;
6
8
using Microsoft . Android . Build . Tasks ;
@@ -33,7 +35,7 @@ public bool Generate (NativeCodeGenState codeGenState, string acwMapFile)
33
35
bool success = true ;
34
36
35
37
using var acw_map = MemoryStreamPool . Shared . CreateStreamWriter ( ) ;
36
- foreach ( TypeDefinition type in javaTypes ) {
38
+ foreach ( TypeDefinition type in javaTypes . OrderBy ( t => t . FullName . Replace ( '/' , '.' ) ) ) {
37
39
string managedKey = type . FullName . Replace ( '/' , '.' ) ;
38
40
string javaKey = JavaNativeTypeManager . ToJniName ( type , cache ) . Replace ( '/' , '.' ) ;
39
41
@@ -79,7 +81,19 @@ public bool Generate (NativeCodeGenState codeGenState, string acwMapFile)
79
81
}
80
82
81
83
acw_map . Flush ( ) ;
82
- Files . CopyIfStreamChanged ( acw_map . BaseStream , acwMapFile ) ;
84
+
85
+ // If there's conflicts, the "new way" file never got written, and will show up as
86
+ // "changed" in our comparison test, so skip it.
87
+ if ( javaConflicts . Count > 0 ) {
88
+ return false ;
89
+ }
90
+
91
+ if ( Files . HasStreamChanged ( acw_map . BaseStream , acwMapFile ) ) {
92
+ log . LogError ( $ "ACW map file '{ acwMapFile } ' changed") ;
93
+ Files . CopyIfStreamChanged ( acw_map . BaseStream , acwMapFile + "2" ) ;
94
+ } else {
95
+ log . LogDebugMessage ( $ "ACW map file '{ acwMapFile } ' unchanged") ;
96
+ }
83
97
84
98
foreach ( var kvp in managedConflicts ) {
85
99
log . LogCodedWarning ( "XA4214" , Properties . Resources . XA4214 , kvp . Key , string . Join ( ", " , kvp . Value ) ) ;
@@ -99,4 +113,121 @@ public bool Generate (NativeCodeGenState codeGenState, string acwMapFile)
99
113
100
114
return success ;
101
115
}
116
+
117
+ public void Generate ( List < ACWMapEntry > javaTypes , string acwMapFile )
118
+ {
119
+ // We need to save a map of .NET type -> ACW type for resource file fixups
120
+ var managed = new Dictionary < string , ACWMapEntry > ( javaTypes . Count , StringComparer . Ordinal ) ;
121
+ var java = new Dictionary < string , ACWMapEntry > ( javaTypes . Count , StringComparer . Ordinal ) ;
122
+
123
+ var managedConflicts = new Dictionary < string , List < string > > ( 0 , StringComparer . Ordinal ) ;
124
+ var javaConflicts = new Dictionary < string , List < string > > ( 0 , StringComparer . Ordinal ) ;
125
+
126
+ using var acw_map = MemoryStreamPool . Shared . CreateStreamWriter ( ) ;
127
+
128
+ foreach ( var type in javaTypes . OrderBy ( t => t . ManagedKey ) ) {
129
+ string managedKey = type . ManagedKey ;
130
+ string javaKey = type . JavaKey ;
131
+
132
+ acw_map . Write ( type . PartialAssemblyQualifiedName ) ;
133
+ acw_map . Write ( ';' ) ;
134
+ acw_map . Write ( javaKey ) ;
135
+ acw_map . WriteLine ( ) ;
136
+
137
+ ACWMapEntry conflict ;
138
+ bool hasConflict = false ;
139
+
140
+ if ( managed . TryGetValue ( managedKey , out conflict ) ) {
141
+ if ( ! conflict . ModuleName . Equals ( type . ModuleName ) ) {
142
+ if ( ! managedConflicts . TryGetValue ( managedKey , out var list ) )
143
+ managedConflicts . Add ( managedKey , list = new List < string > { conflict . PartialAssemblyName } ) ;
144
+ list . Add ( type . PartialAssemblyName ) ;
145
+ }
146
+ hasConflict = true ;
147
+ }
148
+
149
+ if ( java . TryGetValue ( javaKey , out conflict ) ) {
150
+ if ( ! conflict . ModuleName . Equals ( type . ModuleName ) ) {
151
+ if ( ! javaConflicts . TryGetValue ( javaKey , out var list ) )
152
+ javaConflicts . Add ( javaKey , list = new List < string > { conflict . AssemblyQualifiedName } ) ;
153
+ list . Add ( type . AssemblyQualifiedName ) ;
154
+ }
155
+ hasConflict = true ;
156
+ }
157
+
158
+ if ( ! hasConflict ) {
159
+ managed . Add ( managedKey , type ) ;
160
+ java . Add ( javaKey , type ) ;
161
+
162
+ acw_map . Write ( managedKey ) ;
163
+ acw_map . Write ( ';' ) ;
164
+ acw_map . Write ( javaKey ) ;
165
+ acw_map . WriteLine ( ) ;
166
+
167
+ acw_map . Write ( type . CompatJniName ) ;
168
+ acw_map . Write ( ';' ) ;
169
+ acw_map . Write ( javaKey ) ;
170
+ acw_map . WriteLine ( ) ;
171
+ }
172
+ }
173
+
174
+ acw_map . Flush ( ) ;
175
+
176
+ foreach ( var kvp in managedConflicts ) {
177
+ log . LogCodedWarning ( "XA4214" , Properties . Resources . XA4214 , kvp . Key , string . Join ( ", " , kvp . Value ) ) ;
178
+ log . LogCodedWarning ( "XA4214" , Properties . Resources . XA4214_Result , kvp . Key , kvp . Value [ 0 ] ) ;
179
+ }
180
+
181
+ foreach ( var kvp in javaConflicts ) {
182
+ log . LogCodedError ( "XA4215" , Properties . Resources . XA4215 , kvp . Key ) ;
183
+
184
+ foreach ( var typeName in kvp . Value ) {
185
+ log . LogCodedError ( "XA4215" , Properties . Resources . XA4215_Details , kvp . Key , typeName ) ;
186
+ }
187
+ }
188
+
189
+ // Don't write the output file if there are any errors so that
190
+ // future incremental builds will try again.
191
+ if ( javaConflicts . Count > 0 )
192
+ return ;
193
+
194
+ Files . CopyIfStreamChanged ( acw_map . BaseStream , acwMapFile ) ;
195
+ }
196
+ }
197
+
198
+ class ACWMapEntry
199
+ {
200
+ public string AssemblyQualifiedName { get ; set ; }
201
+ public string CompatJniName { get ; set ; }
202
+ public string JavaKey { get ; set ; }
203
+ public string ManagedKey { get ; set ; }
204
+ public string ModuleName { get ; set ; }
205
+ public string PartialAssemblyName { get ; set ; }
206
+ public string PartialAssemblyQualifiedName { get ; set ; }
207
+
208
+ public static ACWMapEntry Create ( TypeDefinition type , TypeDefinitionCache cache )
209
+ {
210
+ return new ACWMapEntry {
211
+ AssemblyQualifiedName = type . GetAssemblyQualifiedName ( cache ) ,
212
+ CompatJniName = JavaNativeTypeManager . ToCompatJniName ( type , cache ) . Replace ( '/' , '.' ) ,
213
+ JavaKey = JavaNativeTypeManager . ToJniName ( type , cache ) . Replace ( '/' , '.' ) ,
214
+ ManagedKey = type . FullName . Replace ( '/' , '.' ) ,
215
+ ModuleName = type . Module . Name ,
216
+ PartialAssemblyName = type . GetPartialAssemblyName ( cache ) ,
217
+ PartialAssemblyQualifiedName = type . GetPartialAssemblyQualifiedName ( cache ) ,
218
+ } ;
219
+ }
220
+
221
+ public static ACWMapEntry Create ( XElement type , string partialAssemblyName , string moduleName )
222
+ {
223
+ return new ACWMapEntry {
224
+ AssemblyQualifiedName = type . GetAttributeOrDefault ( "assembly-qualified-name" , string . Empty ) ,
225
+ CompatJniName = type . GetAttributeOrDefault ( "compat-jni-name" , string . Empty ) ,
226
+ JavaKey = type . GetAttributeOrDefault ( "java-key" , string . Empty ) ,
227
+ ManagedKey = type . GetAttributeOrDefault ( "managed-key" , string . Empty ) ,
228
+ ModuleName = moduleName ,
229
+ PartialAssemblyName = partialAssemblyName ,
230
+ PartialAssemblyQualifiedName = type . GetAttributeOrDefault ( "partial-assembly-qualified-name" , string . Empty ) ,
231
+ } ;
232
+ }
102
233
}
0 commit comments