一、build/make/core/base_rules.mk:232: error: packages/services/Car/service: LOCAL_BUILT_MODULE and LOCAL_INSTALLED_MODULE must not be defined by component makefiles

出现此错误时,需要检查Android.mk中include $(CLEAR_VARS)及include $(BUILD_XXX...)是否一一对应了,如果有类似下边的写法,就需要修正

  1. 错误:
  2. ......
  3. include $(CLEAR_VARS)
  4. ......
  5. include $(BUILD_MULTI_PREBUILT)
  6. ......
  7. include $(BUILD_STATIC_JAVA_LIBRARY)
  8. ......
  9. include $(BUILD_PACKAGE)
  10. include $(CLEAR_VARS)
  11.  
  12. 正确:
  13. include $(CLEAR_VARS)
  14. ......
  15. include $(BUILD_MULTI_PREBUILT)
  16.  
  17. include $(CLEAR_VARS)
  18. ......
  19. include $(BUILD_STATIC_JAVA_LIBRARY)
  20.  
  21. include $(CLEAR_VARS)
  22. ......
  23. include $(BUILD_PACKAGE)

二、错误: 程序包androidx.annotation不存在,需要在 Android.mk 中添加如下,根据自己的依赖进行添加

  1. LOCAL_STATIC_ANDROID_LIBRARIES := \
  2. androidx.recyclerview_recyclerview \
  3. androidx.preference_preference \
  4. androidx.appcompat_appcompat \
  5. androidx.annotation_annotation \
  6. androidx.legacy_legacy-preference-v14 \
  7. androidx.leanback_leanback-preference \
  8. androidx.leanback_leanback \

三、javadoc: 错误 - 在 doclet 类com.google.doclava.Doclava中, 方法start已抛出异常错误java.lang.reflect.InvocationTargetException

java.lang.IllegalArgumentException: Unable to find IBtMusicCmd.java. This is usually because doclava has been asked to generate stubs for a file that isn't present in the list of input source files but exists in the input classpath.

IBtMusicCmd是我的aidl文件,代码都编译通过了,没有出现依赖问题,但是最后报出这个错,查了两天才发现这个问题应该是javadoc的版本太低了,我找到了这个系统文件进行了暴力修改后编译正常,但是是否存在隐患还不确定

  1. 解决办法:
  2. 直接找到external\doclava\src\com\google\doclava\Stubs.java,然后在53行添加if(true) return;如下!目的就是不执行此文件的操作
  1. public class Stubs {
  2. public static void writeStubsAndApi(String stubsDir, String apiFile, String dexApiFile,
  3. String keepListFile, String removedApiFile, String removedDexApiFile, String exactApiFile,
  4. String privateApiFile, String privateDexApiFile, HashSet<String> stubPackages,
  5. HashSet<String> stubImportPackages, boolean stubSourceOnly) {
  6. if(true) return;

如果为了安全一点,也可以按照下边的方式,只判断是自己的这个模块就跳过就好了,源代码里三个地方添加以下代码,“android.car.xxxx.bt”需要替换为自己冲突的模块包名

  1. if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
  2. System.out.println("=======android.car.xxxx.bt=============continue");
  3. continue;
  4. }

  1. 1 /*
  2. 2 * Copyright (C) 2010 Google Inc.
  3. 3 *
  4. 4 * Licensed under the Apache License, Version 2.0 (the "License");
  5. 5 * you may not use this file except in compliance with the License.
  6. 6 * You may obtain a copy of the License at
  7. 7 *
  8. 8 * http://www.apache.org/licenses/LICENSE-2.0
  9. 9 *
  10. 10 * Unless required by applicable law or agreed to in writing, software
  11. 11 * distributed under the License is distributed on an "AS IS" BASIS,
  12. 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. 13 * See the License for the specific language governing permissions and
  14. 14 * limitations under the License.
  15. 15 */
  16. 16
  17. 17 package com.google.doclava;
  18. 18
  19. 19 import java.io.BufferedOutputStream;
  20. 20 import java.io.BufferedReader;
  21. 21 import java.io.ByteArrayOutputStream;
  22. 22 import java.io.File;
  23. 23 import java.io.FileInputStream;
  24. 24 import java.io.FileNotFoundException;
  25. 25 import java.io.FileOutputStream;
  26. 26 import java.io.IOException;
  27. 27 import java.io.InputStream;
  28. 28 import java.io.InputStreamReader;
  29. 29 import java.io.PrintStream;
  30. 30 import java.nio.charset.StandardCharsets;
  31. 31 import java.nio.file.Files;
  32. 32 import java.nio.file.Paths;
  33. 33 import java.util.ArrayList;
  34. 34 import java.util.Arrays;
  35. 35 import java.util.Collection;
  36. 36 import java.util.Collections;
  37. 37 import java.util.HashMap;
  38. 38 import java.util.HashSet;
  39. 39 import java.util.Iterator;
  40. 40 import java.util.List;
  41. 41 import java.util.Map;
  42. 42 import java.util.Scanner;
  43. 43 import java.util.Set;
  44. 44 import java.util.function.Predicate;
  45. 45 import java.util.regex.Pattern;
  46. 46 import java.util.stream.Collectors;
  47. 47
  48. 48 public class Stubs {
  49. 49 public static void writeStubsAndApi(String stubsDir, String apiFile, String dexApiFile,
  50. 50 String keepListFile, String removedApiFile, String removedDexApiFile, String exactApiFile,
  51. 51 String privateApiFile, String privateDexApiFile, HashSet<String> stubPackages,
  52. 52 HashSet<String> stubImportPackages, boolean stubSourceOnly) {
  53. 53 //if(true) return;
  54. 54 // figure out which classes we need
  55. 55 final HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
  56. 56 Collection<ClassInfo> all = Converter.allClasses();
  57. 57 Map<PackageInfo, List<ClassInfo>> allClassesByPackage = null;
  58. 58 PrintStream apiWriter = null;
  59. 59 PrintStream dexApiWriter = null;
  60. 60 PrintStream keepListWriter = null;
  61. 61 PrintStream removedApiWriter = null;
  62. 62 PrintStream removedDexApiWriter = null;
  63. 63 PrintStream exactApiWriter = null;
  64. 64 PrintStream privateApiWriter = null;
  65. 65 PrintStream privateDexApiWriter = null;
  66. 66
  67. 67 if (apiFile != null) {
  68. 68 try {
  69. 69 File xml = new File(apiFile);
  70. 70 xml.getParentFile().mkdirs();
  71. 71 apiWriter = new PrintStream(new BufferedOutputStream(new FileOutputStream(xml)));
  72. 72 } catch (FileNotFoundException e) {
  73. 73 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(apiFile, 0, 0),
  74. 74 "Cannot open file for write.");
  75. 75 }
  76. 76 }
  77. 77 if (dexApiFile != null) {
  78. 78 try {
  79. 79 File dexApi = new File(dexApiFile);
  80. 80 dexApi.getParentFile().mkdirs();
  81. 81 dexApiWriter = new PrintStream(new BufferedOutputStream(new FileOutputStream(dexApi)));
  82. 82 } catch (FileNotFoundException e) {
  83. 83 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(dexApiFile, 0, 0),
  84. 84 "Cannot open file for write.");
  85. 85 }
  86. 86 }
  87. 87 if (keepListFile != null) {
  88. 88 try {
  89. 89 File keepList = new File(keepListFile);
  90. 90 keepList.getParentFile().mkdirs();
  91. 91 keepListWriter = new PrintStream(new BufferedOutputStream(new FileOutputStream(keepList)));
  92. 92 } catch (FileNotFoundException e) {
  93. 93 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(keepListFile, 0, 0),
  94. 94 "Cannot open file for write.");
  95. 95 }
  96. 96 }
  97. 97 if (removedApiFile != null) {
  98. 98 try {
  99. 99 File removedApi = new File(removedApiFile);
  100. 100 removedApi.getParentFile().mkdirs();
  101. 101 removedApiWriter = new PrintStream(
  102. 102 new BufferedOutputStream(new FileOutputStream(removedApi)));
  103. 103 } catch (FileNotFoundException e) {
  104. 104 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(removedApiFile, 0, 0),
  105. 105 "Cannot open file for write");
  106. 106 }
  107. 107 }
  108. 108 if (removedDexApiFile != null) {
  109. 109 try {
  110. 110 File removedDexApi = new File(removedDexApiFile);
  111. 111 removedDexApi.getParentFile().mkdirs();
  112. 112 removedDexApiWriter = new PrintStream(
  113. 113 new BufferedOutputStream(new FileOutputStream(removedDexApi)));
  114. 114 } catch (FileNotFoundException e) {
  115. 115 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(removedDexApiFile, 0, 0),
  116. 116 "Cannot open file for write");
  117. 117 }
  118. 118 }
  119. 119 if (exactApiFile != null) {
  120. 120 try {
  121. 121 File exactApi = new File(exactApiFile);
  122. 122 exactApi.getParentFile().mkdirs();
  123. 123 exactApiWriter = new PrintStream(
  124. 124 new BufferedOutputStream(new FileOutputStream(exactApi)));
  125. 125 } catch (FileNotFoundException e) {
  126. 126 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(exactApiFile, 0, 0),
  127. 127 "Cannot open file for write");
  128. 128 }
  129. 129 }
  130. 130 if (privateApiFile != null) {
  131. 131 try {
  132. 132 File privateApi = new File(privateApiFile);
  133. 133 privateApi.getParentFile().mkdirs();
  134. 134 privateApiWriter = new PrintStream(
  135. 135 new BufferedOutputStream(new FileOutputStream(privateApi)));
  136. 136 } catch (FileNotFoundException e) {
  137. 137 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(privateApiFile, 0, 0),
  138. 138 "Cannot open file for write");
  139. 139 }
  140. 140 }
  141. 141 if (privateDexApiFile != null) {
  142. 142 try {
  143. 143 File privateDexApi = new File(privateDexApiFile);
  144. 144 privateDexApi.getParentFile().mkdirs();
  145. 145 privateDexApiWriter = new PrintStream(
  146. 146 new BufferedOutputStream(new FileOutputStream(privateDexApi)));
  147. 147 } catch (FileNotFoundException e) {
  148. 148 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(privateDexApiFile, 0, 0),
  149. 149 "Cannot open file for write");
  150. 150 }
  151. 151 }
  152. 152 // If a class is public or protected, not hidden, not imported and marked as included,
  153. 153 // then we can't strip it
  154. 154 for (ClassInfo cl : all) {
  155. 155 if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
  156. 156 System.out.println("=======android.car.xxxx.bt=============continue");
  157. 157 continue;
  158. 158 }
  159. 159 if (cl.checkLevel() && cl.isIncluded()) {
  160. 160 cantStripThis(cl, notStrippable, "0:0", stubImportPackages);
  161. 161 }
  162. 162 }
  163. 163
  164. 164 // complain about anything that looks includeable but is not supposed to
  165. 165 // be written, e.g. hidden things
  166. 166 for (ClassInfo cl : notStrippable) {
  167. 167 if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
  168. 168 System.out.println("=======android.car.xxxx.bt=============continue");
  169. 169 continue;
  170. 170 }
  171. 171 if (!cl.isHiddenOrRemoved()) {
  172. 172 for (MethodInfo m : cl.selfMethods()) {
  173. 173 if (m.isHiddenOrRemoved()) {
  174. 174 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to unavailable method "
  175. 175 + m.name());
  176. 176 } else if (m.isDeprecated()) {
  177. 177 // don't bother reporting deprecated methods
  178. 178 // unless they are public
  179. 179 Errors.error(Errors.DEPRECATED, m.position(), "Method " + cl.qualifiedName() + "."
  180. 180 + m.name() + " is deprecated");
  181. 181 }
  182. 182
  183. 183 ClassInfo hiddenClass = findHiddenClasses(m.returnType(), stubImportPackages);
  184. 184 if (null != hiddenClass) {
  185. 185 if (hiddenClass.qualifiedName() == m.returnType().asClassInfo().qualifiedName()) {
  186. 186 // Return type is hidden
  187. 187 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
  188. 188 + "." + m.name() + " returns unavailable type " + hiddenClass.name());
  189. 189 } else {
  190. 190 // Return type contains a generic parameter
  191. 191 Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(), "Method " + cl.qualifiedName()
  192. 192 + "." + m.name() + " returns unavailable type " + hiddenClass.name()
  193. 193 + " as a type parameter");
  194. 194 }
  195. 195 }
  196. 196
  197. 197 for (ParameterInfo p : m.parameters()) {
  198. 198 TypeInfo t = p.type();
  199. 199 if (!t.isPrimitive()) {
  200. 200 hiddenClass = findHiddenClasses(t, stubImportPackages);
  201. 201 if (null != hiddenClass) {
  202. 202 if (hiddenClass.qualifiedName() == t.asClassInfo().qualifiedName()) {
  203. 203 // Parameter type is hidden
  204. 204 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(),
  205. 205 "Parameter of unavailable type " + t.fullName() + " in " + cl.qualifiedName()
  206. 206 + "." + m.name() + "()");
  207. 207 } else {
  208. 208 // Parameter type contains a generic parameter
  209. 209 Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(),
  210. 210 "Parameter uses type parameter of unavailable type " + t.fullName() + " in "
  211. 211 + cl.qualifiedName() + "." + m.name() + "()");
  212. 212 }
  213. 213 }
  214. 214 }
  215. 215 }
  216. 216 }
  217. 217
  218. 218 // annotations are handled like methods
  219. 219 for (MethodInfo m : cl.annotationElements()) {
  220. 220 if (m.isHiddenOrRemoved()) {
  221. 221 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to unavailable annotation "
  222. 222 + m.name());
  223. 223 }
  224. 224
  225. 225 ClassInfo returnClass = m.returnType().asClassInfo();
  226. 226 if (returnClass != null && returnClass.isHiddenOrRemoved()) {
  227. 227 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Annotation '" + m.name()
  228. 228 + "' returns unavailable type " + returnClass.name());
  229. 229 }
  230. 230
  231. 231 for (ParameterInfo p : m.parameters()) {
  232. 232 TypeInfo t = p.type();
  233. 233 if (!t.isPrimitive()) {
  234. 234 if (t.asClassInfo().isHiddenOrRemoved()) {
  235. 235 Errors.error(Errors.UNAVAILABLE_SYMBOL, p.position(),
  236. 236 "Reference to unavailable annotation class " + t.fullName());
  237. 237 }
  238. 238 }
  239. 239 }
  240. 240 }
  241. 241 } else if (cl.isDeprecated()) {
  242. 242 // not hidden, but deprecated
  243. 243 Errors.error(Errors.DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
  244. 244 + " is deprecated");
  245. 245 }
  246. 246 }
  247. 247
  248. 248 // packages contains all the notStrippable classes mapped by their containing packages
  249. 249 HashMap<PackageInfo, List<ClassInfo>> packages = new HashMap<PackageInfo, List<ClassInfo>>();
  250. 250 final HashSet<Pattern> stubPackageWildcards = extractWildcards(stubPackages);
  251. 251 for (ClassInfo cl : notStrippable) {
  252. 252 if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
  253. 253 System.out.println("=======android.car.xxxx.bt=============continue");
  254. 254 continue;
  255. 255 }
  256. 256 if (!cl.isDocOnly()) {
  257. 257 if (stubSourceOnly && !Files.exists(Paths.get(cl.position().file))) {
  258. 258 continue;
  259. 259 }
  260. 260 if (shouldWriteStub(cl.containingPackage().name(), stubPackages, stubPackageWildcards)) {
  261. 261 // write out the stubs
  262. 262 if (stubsDir != null) {
  263. 263 writeClassFile(stubsDir, notStrippable, cl);
  264. 264 }
  265. 265 // build class list for api file or keep list file
  266. 266 if (apiWriter != null || dexApiWriter != null || keepListWriter != null) {
  267. 267 if (packages.containsKey(cl.containingPackage())) {
  268. 268 packages.get(cl.containingPackage()).add(cl);
  269. 269 } else {
  270. 270 ArrayList<ClassInfo> classes = new ArrayList<ClassInfo>();
  271. 271 classes.add(cl);
  272. 272 packages.put(cl.containingPackage(), classes);
  273. 273 }
  274. 274 }
  275. 275 }
  276. 276 }
  277. 277 }
  278. 278
  279. 279 if (privateApiWriter != null || privateDexApiWriter != null || removedApiWriter != null
  280. 280 || removedDexApiWriter != null) {
  281. 281 allClassesByPackage = Converter.allClasses().stream()
  282. 282 // Make sure that the files only contains information from the required packages.
  283. 283 .filter(ci -> stubPackages == null
  284. 284 || stubPackages.contains(ci.containingPackage().qualifiedName()))
  285. 285 .collect(Collectors.groupingBy(ClassInfo::containingPackage));
  286. 286 }
  287. 287
  288. 288 final boolean ignoreShown = Doclava.showUnannotated;
  289. 289
  290. 290 Predicate<MemberInfo> memberIsNotCloned = (x -> !x.isCloned());
  291. 291
  292. 292 FilterPredicate apiFilter = new FilterPredicate(new ApiPredicate().setIgnoreShown(ignoreShown));
  293. 293 ApiPredicate apiReference = new ApiPredicate().setIgnoreShown(true);
  294. 294 Predicate<MemberInfo> apiEmit = apiFilter.and(new ElidingPredicate(apiReference));
  295. 295 Predicate<MemberInfo> dexApiEmit = memberIsNotCloned.and(apiFilter);
  296. 296
  297. 297 Predicate<MemberInfo> privateEmit = memberIsNotCloned.and(apiFilter.negate());
  298. 298 Predicate<MemberInfo> privateReference = (x -> true);
  299. 299
  300. 300 FilterPredicate removedFilter =
  301. 301 new FilterPredicate(new ApiPredicate().setIgnoreShown(ignoreShown).setMatchRemoved(true));
  302. 302 ApiPredicate removedReference = new ApiPredicate().setIgnoreShown(true).setIgnoreRemoved(true);
  303. 303 Predicate<MemberInfo> removedEmit = removedFilter.and(new ElidingPredicate(removedReference));
  304. 304 Predicate<MemberInfo> removedDexEmit = memberIsNotCloned.and(removedFilter);
  305. 305
  306. 306 // Write out the current API
  307. 307 if (apiWriter != null) {
  308. 308 writeApi(apiWriter, packages, apiEmit, apiReference);
  309. 309 apiWriter.close();
  310. 310 }
  311. 311
  312. 312 // Write out the current DEX API
  313. 313 if (dexApiWriter != null) {
  314. 314 writeDexApi(dexApiWriter, packages, dexApiEmit);
  315. 315 dexApiWriter.close();
  316. 316 }
  317. 317
  318. 318 // Write out the keep list
  319. 319 if (keepListWriter != null) {
  320. 320 writeKeepList(keepListWriter, packages, notStrippable);
  321. 321 keepListWriter.close();
  322. 322 }
  323. 323
  324. 324 // Write out the private API
  325. 325 if (privateApiWriter != null) {
  326. 326 writeApi(privateApiWriter, allClassesByPackage, privateEmit, privateReference);
  327. 327 privateApiWriter.close();
  328. 328 }
  329. 329
  330. 330 // Write out the private API
  331. 331 if (privateDexApiWriter != null) {
  332. 332 writeDexApi(privateDexApiWriter, allClassesByPackage, privateEmit);
  333. 333 privateDexApiWriter.close();
  334. 334 }
  335. 335
  336. 336 // Write out the removed API
  337. 337 if (removedApiWriter != null) {
  338. 338 writeApi(removedApiWriter, allClassesByPackage, removedEmit, removedReference);
  339. 339 removedApiWriter.close();
  340. 340 }
  341. 341
  342. 342 // Write out the removed DEX API
  343. 343 if (removedDexApiWriter != null) {
  344. 344 writeDexApi(removedDexApiWriter, allClassesByPackage, removedDexEmit);
  345. 345 removedDexApiWriter.close();
  346. 346 }
  347. 347 }
  348. 348
  349. 349 private static boolean shouldWriteStub(final String packageName,
  350. 350 final HashSet<String> stubPackages, final HashSet<Pattern> stubPackageWildcards) {
  351. 351 if (stubPackages == null) {
  352. 352 // There aren't any stub packages set, write all stubs
  353. 353 return true;
  354. 354 }
  355. 355 if (stubPackages.contains(packageName)) {
  356. 356 // Stub packages contains package, return true
  357. 357 return true;
  358. 358 }
  359. 359 if (stubPackageWildcards != null) {
  360. 360 // Else, we will iterate through the wildcards to see if there's a match
  361. 361 for (Pattern wildcard : stubPackageWildcards) {
  362. 362 if (wildcard.matcher(packageName).matches()) {
  363. 363 return true;
  364. 364 }
  365. 365 }
  366. 366 }
  367. 367 return false;
  368. 368 }
  369. 369
  370. 370 private static HashSet<Pattern> extractWildcards(HashSet<String> stubPackages) {
  371. 371 HashSet<Pattern> wildcards = null;
  372. 372 if (stubPackages != null) {
  373. 373 for (Iterator<String> i = stubPackages.iterator(); i.hasNext();) {
  374. 374 final String pkg = i.next();
  375. 375 if (pkg.indexOf('*') != -1) {
  376. 376 if (wildcards == null) {
  377. 377 wildcards = new HashSet<Pattern>();
  378. 378 }
  379. 379 // Add the compiled wildcard, replacing * with the regex equivalent
  380. 380 wildcards.add(Pattern.compile(pkg.replace("*", ".*?")));
  381. 381 // And remove the raw wildcard from the packages
  382. 382 i.remove();
  383. 383 }
  384. 384 }
  385. 385 }
  386. 386 return wildcards;
  387. 387 }
  388. 388
  389. 389 /**
  390. 390 * Find references to hidden classes.
  391. 391 *
  392. 392 * <p>This finds hidden classes that are used by public parts of the API in order to ensure the
  393. 393 * API is self consistent and does not reference classes that are not included in
  394. 394 * the stubs. Any such references cause an error to be reported.
  395. 395 *
  396. 396 * <p>A reference to an imported class is not treated as an error, even though imported classes
  397. 397 * are hidden from the stub generation. That is because imported classes are, by definition,
  398. 398 * excluded from the set of classes for which stubs are required.
  399. 399 *
  400. 400 * @param ti the type information to examine for references to hidden classes.
  401. 401 * @param stubImportPackages the possibly null set of imported package names.
  402. 402 * @return a reference to a hidden class or null if there are none
  403. 403 */
  404. 404 private static ClassInfo findHiddenClasses(TypeInfo ti, HashSet<String> stubImportPackages) {
  405. 405 ClassInfo ci = ti.asClassInfo();
  406. 406 if (ci == null) return null;
  407. 407 if (stubImportPackages != null
  408. 408 && stubImportPackages.contains(ci.containingPackage().qualifiedName())) {
  409. 409 return null;
  410. 410 }
  411. 411 if (ci.isHiddenOrRemoved()) return ci;
  412. 412 if (ti.typeArguments() != null) {
  413. 413 for (TypeInfo tii : ti.typeArguments()) {
  414. 414 // Avoid infinite recursion in the case of Foo<T extends Foo>
  415. 415 if (tii.qualifiedTypeName() != ti.qualifiedTypeName()) {
  416. 416 ClassInfo hiddenClass = findHiddenClasses(tii, stubImportPackages);
  417. 417 if (hiddenClass != null) return hiddenClass;
  418. 418 }
  419. 419 }
  420. 420 }
  421. 421 return null;
  422. 422 }
  423. 423
  424. 424 public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why,
  425. 425 HashSet<String> stubImportPackages) {
  426. 426
  427. 427 if (stubImportPackages != null
  428. 428 && stubImportPackages.contains(cl.containingPackage().qualifiedName())) {
  429. 429 // if the package is imported then it does not need stubbing.
  430. 430 return;
  431. 431 }
  432. 432
  433. 433 if (!notStrippable.add(cl)) {
  434. 434 // slight optimization: if it already contains cl, it already contains
  435. 435 // all of cl's parents
  436. 436 return;
  437. 437 }
  438. 438 cl.setReasonIncluded(why);
  439. 439
  440. 440 // cant strip annotations
  441. 441 /*
  442. 442 * if (cl.annotations() != null){ for (AnnotationInstanceInfo ai : cl.annotations()){ if
  443. 443 * (ai.type() != null){ cantStripThis(ai.type(), notStrippable, "1:" + cl.qualifiedName()); } }
  444. 444 * }
  445. 445 */
  446. 446 // cant strip any public fields or their generics
  447. 447 if (cl.selfFields() != null) {
  448. 448 for (FieldInfo fInfo : cl.selfFields()) {
  449. 449 if (fInfo.type() != null) {
  450. 450 if (fInfo.type().asClassInfo() != null) {
  451. 451 cantStripThis(fInfo.type().asClassInfo(), notStrippable, "2:" + cl.qualifiedName(),
  452. 452 stubImportPackages);
  453. 453 }
  454. 454 if (fInfo.type().typeArguments() != null) {
  455. 455 for (TypeInfo tTypeInfo : fInfo.type().typeArguments()) {
  456. 456 if (tTypeInfo.asClassInfo() != null) {
  457. 457 cantStripThis(tTypeInfo.asClassInfo(), notStrippable, "3:" + cl.qualifiedName(),
  458. 458 stubImportPackages);
  459. 459 }
  460. 460 }
  461. 461 }
  462. 462 }
  463. 463 }
  464. 464 }
  465. 465 // cant strip any of the type's generics
  466. 466 if (cl.asTypeInfo() != null) {
  467. 467 if (cl.asTypeInfo().typeArguments() != null) {
  468. 468 for (TypeInfo tInfo : cl.asTypeInfo().typeArguments()) {
  469. 469 if (tInfo.asClassInfo() != null) {
  470. 470 cantStripThis(tInfo.asClassInfo(), notStrippable, "4:" + cl.qualifiedName(),
  471. 471 stubImportPackages);
  472. 472 }
  473. 473 }
  474. 474 }
  475. 475 }
  476. 476 // cant strip any of the annotation elements
  477. 477 // cantStripThis(cl.annotationElements(), notStrippable);
  478. 478 // take care of methods
  479. 479 cantStripThis(cl.allSelfMethods(), notStrippable, stubImportPackages);
  480. 480 cantStripThis(cl.allConstructors(), notStrippable, stubImportPackages);
  481. 481 // blow the outer class open if this is an inner class
  482. 482 if (cl.containingClass() != null) {
  483. 483 cantStripThis(cl.containingClass(), notStrippable, "5:" + cl.qualifiedName(),
  484. 484 stubImportPackages);
  485. 485 }
  486. 486 // blow open super class and interfaces
  487. 487 ClassInfo supr = cl.realSuperclass();
  488. 488 if (supr != null) {
  489. 489 if (supr.isHiddenOrRemoved()) {
  490. 490 // cl is a public class declared as extending a hidden superclass.
  491. 491 // this is not a desired practice but it's happened, so we deal
  492. 492 // with it by finding the first super class which passes checklevel for purposes of
  493. 493 // generating the doc & stub information, and proceeding normally.
  494. 494 ClassInfo publicSuper = cl.superclass();
  495. 495 cl.init(cl.asTypeInfo(), cl.realInterfaces(), cl.realInterfaceTypes(), cl.innerClasses(),
  496. 496 cl.allConstructors(), cl.allSelfMethods(), cl.annotationElements(), cl.allSelfFields(),
  497. 497 cl.enumConstants(), cl.containingPackage(), cl.containingClass(),
  498. 498 publicSuper, publicSuper.asTypeInfo(), cl.annotations());
  499. 499 Errors.error(Errors.HIDDEN_SUPERCLASS, cl.position(), "Public class " + cl.qualifiedName()
  500. 500 + " stripped of unavailable superclass " + supr.qualifiedName());
  501. 501 } else {
  502. 502 cantStripThis(supr, notStrippable, "6:" + cl.realSuperclass().name() + cl.qualifiedName(),
  503. 503 stubImportPackages);
  504. 504 if (supr.isPrivate()) {
  505. 505 Errors.error(Errors.PRIVATE_SUPERCLASS, cl.position(), "Public class "
  506. 506 + cl.qualifiedName() + " extends private class " + supr.qualifiedName());
  507. 507 }
  508. 508 }
  509. 509 }
  510. 510 }
  511. 511
  512. 512 private static void cantStripThis(ArrayList<MethodInfo> mInfos, HashSet<ClassInfo> notStrippable,
  513. 513 HashSet<String> stubImportPackages) {
  514. 514 // for each method, blow open the parameters, throws and return types. also blow open their
  515. 515 // generics
  516. 516 if (mInfos != null) {
  517. 517 for (MethodInfo mInfo : mInfos) {
  518. 518 if (mInfo.getTypeParameters() != null) {
  519. 519 for (TypeInfo tInfo : mInfo.getTypeParameters()) {
  520. 520 if (tInfo.asClassInfo() != null) {
  521. 521 cantStripThis(tInfo.asClassInfo(), notStrippable, "8:"
  522. 522 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
  523. 523 stubImportPackages);
  524. 524 }
  525. 525 }
  526. 526 }
  527. 527 if (mInfo.parameters() != null) {
  528. 528 for (ParameterInfo pInfo : mInfo.parameters()) {
  529. 529 if (pInfo.type() != null && pInfo.type().asClassInfo() != null) {
  530. 530 cantStripThis(pInfo.type().asClassInfo(), notStrippable, "9:"
  531. 531 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
  532. 532 stubImportPackages);
  533. 533 if (pInfo.type().typeArguments() != null) {
  534. 534 for (TypeInfo tInfoType : pInfo.type().typeArguments()) {
  535. 535 if (tInfoType.asClassInfo() != null) {
  536. 536 ClassInfo tcl = tInfoType.asClassInfo();
  537. 537 if (tcl.isHiddenOrRemoved()) {
  538. 538 Errors
  539. 539 .error(Errors.UNAVAILABLE_SYMBOL, mInfo.position(),
  540. 540 "Parameter of hidden type " + tInfoType.fullName() + " in "
  541. 541 + mInfo.containingClass().qualifiedName() + '.' + mInfo.name()
  542. 542 + "()");
  543. 543 } else {
  544. 544 cantStripThis(tcl, notStrippable, "10:"
  545. 545 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
  546. 546 stubImportPackages);
  547. 547 }
  548. 548 }
  549. 549 }
  550. 550 }
  551. 551 }
  552. 552 }
  553. 553 }
  554. 554 for (ClassInfo thrown : mInfo.thrownExceptions()) {
  555. 555 cantStripThis(thrown, notStrippable, "11:" + mInfo.realContainingClass().qualifiedName()
  556. 556 + ":" + mInfo.name(), stubImportPackages);
  557. 557 }
  558. 558 if (mInfo.returnType() != null && mInfo.returnType().asClassInfo() != null) {
  559. 559 cantStripThis(mInfo.returnType().asClassInfo(), notStrippable, "12:"
  560. 560 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
  561. 561 stubImportPackages);
  562. 562 if (mInfo.returnType().typeArguments() != null) {
  563. 563 for (TypeInfo tyInfo : mInfo.returnType().typeArguments()) {
  564. 564 if (tyInfo.asClassInfo() != null) {
  565. 565 cantStripThis(tyInfo.asClassInfo(), notStrippable, "13:"
  566. 566 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
  567. 567 stubImportPackages);
  568. 568 }
  569. 569 }
  570. 570 }
  571. 571 }
  572. 572 }
  573. 573 }
  574. 574 }
  575. 575
  576. 576 static String javaFileName(ClassInfo cl) {
  577. 577 String dir = "";
  578. 578 PackageInfo pkg = cl.containingPackage();
  579. 579 if (pkg != null) {
  580. 580 dir = pkg.name();
  581. 581 dir = dir.replace('.', '/') + '/';
  582. 582 }
  583. 583 return dir + cl.name() + ".java";
  584. 584 }
  585. 585
  586. 586 static void writeClassFile(String stubsDir, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
  587. 587 // inner classes are written by their containing class
  588. 588 if (cl.containingClass() != null) {
  589. 589 return;
  590. 590 }
  591. 591
  592. 592 // Work around the bogus "Array" class we invent for
  593. 593 // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
  594. 594 if (cl.containingPackage() != null
  595. 595 && cl.containingPackage().name().equals(PackageInfo.DEFAULT_PACKAGE)) {
  596. 596 return;
  597. 597 }
  598. 598
  599. 599 String filename = stubsDir + '/' + javaFileName(cl);
  600. 600 File file = new File(filename);
  601. 601 ClearPage.ensureDirectory(file);
  602. 602
  603. 603 PrintStream stream = null;
  604. 604 try {
  605. 605 stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
  606. 606 writeClassFile(stream, notStrippable, cl);
  607. 607 } catch (FileNotFoundException e) {
  608. 608 System.err.println("error writing file: " + filename);
  609. 609 } finally {
  610. 610 if (stream != null) {
  611. 611 stream.close();
  612. 612 }
  613. 613 }
  614. 614 }
  615. 615
  616. 616 static void writeClassFile(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
  617. 617 PackageInfo pkg = cl.containingPackage();
  618. 618 if (cl.containingClass() == null) {
  619. 619 stream.print(parseLicenseHeader(cl.position()));
  620. 620 }
  621. 621 if (pkg != null) {
  622. 622 stream.println("package " + pkg.name() + ";");
  623. 623 }
  624. 624 writeClass(stream, notStrippable, cl);
  625. 625 }
  626. 626
  627. 627 private static String parseLicenseHeader(/* @Nonnull */ SourcePositionInfo positionInfo) {
  628. 628 if (positionInfo == null) {
  629. 629 throw new NullPointerException("positionInfo == null");
  630. 630 }
  631. 631
  632. 632 try {
  633. 633 final File sourceFile = new File(positionInfo.file);
  634. 634 if (!sourceFile.exists()) {
  635. 635 throw new IllegalArgumentException("Unable to find " + sourceFile +
  636. 636 ". This is usually because doclava has been asked to generate stubs for a file " +
  637. 637 "that isn't present in the list of input source files but exists in the input " +
  638. 638 "classpath.");
  639. 639 }
  640. 640 return parseLicenseHeader(new FileInputStream(sourceFile));
  641. 641 } catch (IOException ioe) {
  642. 642 throw new RuntimeException("Unable to parse license header for: " + positionInfo.file, ioe);
  643. 643 }
  644. 644 }
  645. 645
  646. 646 /* @VisibleForTesting */
  647. 647 static String parseLicenseHeader(InputStream input) throws IOException {
  648. 648 StringBuilder builder = new StringBuilder(8192);
  649. 649 try (Scanner scanner = new Scanner(
  650. 650 new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)))) {
  651. 651 String line;
  652. 652 while (scanner.hasNextLine()) {
  653. 653 line = scanner.nextLine().trim();
  654. 654 // Use an extremely simple strategy for parsing license headers : assume that
  655. 655 // all file content before the first "package " or "import " directive is a license
  656. 656 // header. In some cases this might contain more than just the license header, but we
  657. 657 // don't care.
  658. 658 if (line.startsWith("package ") || line.startsWith("import ")) {
  659. 659 break;
  660. 660 }
  661. 661 builder.append(line);
  662. 662 builder.append("\n");
  663. 663 }
  664. 664
  665. 665 // We've reached the end of the file without reaching any package or import
  666. 666 // directives.
  667. 667 if (!scanner.hasNextLine()) {
  668. 668 throw new IOException("Unable to parse license header");
  669. 669 }
  670. 670 }
  671. 671
  672. 672 return builder.toString();
  673. 673 }
  674. 674
  675. 675 static void writeClass(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
  676. 676 writeAnnotations(stream, cl.annotations(), cl.isDeprecated());
  677. 677
  678. 678 stream.print(cl.scope() + " ");
  679. 679 if (cl.isAbstract() && !cl.isAnnotation() && !cl.isInterface()) {
  680. 680 stream.print("abstract ");
  681. 681 }
  682. 682 if (cl.isStatic()) {
  683. 683 stream.print("static ");
  684. 684 }
  685. 685 if (cl.isFinal() && !cl.isEnum()) {
  686. 686 stream.print("final ");
  687. 687 }
  688. 688 if (false) {
  689. 689 stream.print("strictfp ");
  690. 690 }
  691. 691
  692. 692 HashSet<String> classDeclTypeVars = new HashSet();
  693. 693 String leafName = cl.asTypeInfo().fullName(classDeclTypeVars);
  694. 694 int bracket = leafName.indexOf('<');
  695. 695 if (bracket < 0) bracket = leafName.length() - 1;
  696. 696 int period = leafName.lastIndexOf('.', bracket);
  697. 697 if (period < 0) period = -1;
  698. 698 leafName = leafName.substring(period + 1);
  699. 699
  700. 700 String kind = cl.kind();
  701. 701 stream.println(kind + " " + leafName);
  702. 702
  703. 703 TypeInfo base = cl.superclassType();
  704. 704
  705. 705 if (!"enum".equals(kind)) {
  706. 706 if (base != null && !"java.lang.Object".equals(base.qualifiedTypeName())) {
  707. 707 stream.println(" extends " + base.fullName(classDeclTypeVars));
  708. 708 }
  709. 709 }
  710. 710
  711. 711 List<TypeInfo> usedInterfaces = new ArrayList<TypeInfo>();
  712. 712 for (TypeInfo iface : cl.realInterfaceTypes()) {
  713. 713 if (notStrippable.contains(iface.asClassInfo()) && !iface.asClassInfo().isDocOnly()) {
  714. 714 usedInterfaces.add(iface);
  715. 715 }
  716. 716 }
  717. 717 if (usedInterfaces.size() > 0 && !cl.isAnnotation()) {
  718. 718 // can java annotations extend other ones?
  719. 719 if (cl.isInterface() || cl.isAnnotation()) {
  720. 720 stream.print(" extends ");
  721. 721 } else {
  722. 722 stream.print(" implements ");
  723. 723 }
  724. 724 String comma = "";
  725. 725 for (TypeInfo iface : usedInterfaces) {
  726. 726 stream.print(comma + iface.fullName(classDeclTypeVars));
  727. 727 comma = ", ";
  728. 728 }
  729. 729 stream.println();
  730. 730 }
  731. 731
  732. 732 stream.println("{");
  733. 733
  734. 734 ArrayList<FieldInfo> enumConstants = cl.enumConstants();
  735. 735 int N = enumConstants.size();
  736. 736 int i = 0;
  737. 737 for (FieldInfo field : enumConstants) {
  738. 738 writeAnnotations(stream, field.annotations(), field.isDeprecated());
  739. 739 if (!field.constantLiteralValue().equals("null")) {
  740. 740 stream.println(field.name() + "(" + field.constantLiteralValue()
  741. 741 + (i == N - 1 ? ");" : "),"));
  742. 742 } else {
  743. 743 stream.println(field.name() + "(" + (i == N - 1 ? ");" : "),"));
  744. 744 }
  745. 745 i++;
  746. 746 }
  747. 747
  748. 748 for (ClassInfo inner : cl.getRealInnerClasses()) {
  749. 749 if (notStrippable.contains(inner) && !inner.isDocOnly()) {
  750. 750 writeClass(stream, notStrippable, inner);
  751. 751 }
  752. 752 }
  753. 753
  754. 754
  755. 755 for (MethodInfo method : cl.constructors()) {
  756. 756 if (!method.isDocOnly()) {
  757. 757 writeMethod(stream, method, true);
  758. 758 }
  759. 759 }
  760. 760
  761. 761 boolean fieldNeedsInitialization = false;
  762. 762 boolean staticFieldNeedsInitialization = false;
  763. 763 for (FieldInfo field : cl.selfFields()) {
  764. 764 if (!field.isDocOnly()) {
  765. 765 if (!field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
  766. 766 fieldNeedsInitialization = true;
  767. 767 }
  768. 768 if (field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
  769. 769 staticFieldNeedsInitialization = true;
  770. 770 }
  771. 771 }
  772. 772 }
  773. 773
  774. 774 // The compiler includes a default public constructor that calls the super classes
  775. 775 // default constructor in the case where there are no written constructors.
  776. 776 // So, if we hide all the constructors, java may put in a constructor
  777. 777 // that calls a nonexistent super class constructor. So, if there are no constructors,
  778. 778 // and the super class doesn't have a default constructor, write in a private constructor
  779. 779 // that works. TODO -- we generate this as protected, but we really should generate
  780. 780 // it as private unless it also exists in the real code.
  781. 781 if ((cl.constructors().isEmpty() && (!cl.getNonWrittenConstructors().isEmpty() ||
  782. 782 fieldNeedsInitialization)) && !cl.isAnnotation() && !cl.isInterface() && !cl.isEnum()) {
  783. 783 // Errors.error(Errors.HIDDEN_CONSTRUCTOR,
  784. 784 // cl.position(), "No constructors " +
  785. 785 // "found and superclass has no parameterless constructor. A constructor " +
  786. 786 // "that calls an appropriate superclass constructor " +
  787. 787 // "was automatically written to stubs.\n");
  788. 788 stream.println(cl.leafName() + "() { " + superCtorCall(cl, null) + "throw new"
  789. 789 + " RuntimeException(\"Stub!\"); }");
  790. 790 }
  791. 791
  792. 792 for (MethodInfo method : cl.allSelfMethods()) {
  793. 793 if (cl.isEnum()) {
  794. 794 if (("values".equals(method.name()) && "()".equals(method.signature())) ||
  795. 795 ("valueOf".equals(method.name()) &&
  796. 796 "(java.lang.String)".equals(method.signature()))) {
  797. 797 // skip these two methods on enums, because they're synthetic,
  798. 798 // although for some reason javadoc doesn't mark them as synthetic,
  799. 799 // maybe because they still want them documented
  800. 800 continue;
  801. 801 }
  802. 802 }
  803. 803 if (!method.isDocOnly()) {
  804. 804 writeMethod(stream, method, false);
  805. 805 }
  806. 806 }
  807. 807 // Write all methods that are hidden or removed, but override abstract methods or interface methods.
  808. 808 // These can't be hidden.
  809. 809 List<MethodInfo> hiddenAndRemovedMethods = cl.getHiddenMethods();
  810. 810 hiddenAndRemovedMethods.addAll(cl.getRemovedMethods());
  811. 811 for (MethodInfo method : hiddenAndRemovedMethods) {
  812. 812 MethodInfo overriddenMethod =
  813. 813 method.findRealOverriddenMethod(method.name(), method.signature(), notStrippable);
  814. 814 ClassInfo classContainingMethod =
  815. 815 method.findRealOverriddenClass(method.name(), method.signature());
  816. 816 if (overriddenMethod != null && !overriddenMethod.isHiddenOrRemoved() &&
  817. 817 !overriddenMethod.isDocOnly() &&
  818. 818 (overriddenMethod.isAbstract() || overriddenMethod.containingClass().isInterface())) {
  819. 819 method.setReason("1:" + classContainingMethod.qualifiedName());
  820. 820 cl.addMethod(method);
  821. 821 writeMethod(stream, method, false);
  822. 822 }
  823. 823 }
  824. 824
  825. 825 for (MethodInfo element : cl.annotationElements()) {
  826. 826 if (!element.isDocOnly()) {
  827. 827 writeAnnotationElement(stream, element);
  828. 828 }
  829. 829 }
  830. 830
  831. 831 for (FieldInfo field : cl.selfFields()) {
  832. 832 if (!field.isDocOnly()) {
  833. 833 writeField(stream, field);
  834. 834 }
  835. 835 }
  836. 836
  837. 837 if (staticFieldNeedsInitialization) {
  838. 838 stream.print("static { ");
  839. 839 for (FieldInfo field : cl.selfFields()) {
  840. 840 if (!field.isDocOnly() && field.isStatic() && field.isFinal() && !fieldIsInitialized(field)
  841. 841 && field.constantValue() == null) {
  842. 842 stream.print(field.name() + " = " + field.type().defaultValue() + "; ");
  843. 843 }
  844. 844 }
  845. 845 stream.println("}");
  846. 846 }
  847. 847
  848. 848 stream.println("}");
  849. 849 }
  850. 850
  851. 851 static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor) {
  852. 852 String comma;
  853. 853
  854. 854 writeAnnotations(stream, method.annotations(), method.isDeprecated());
  855. 855
  856. 856 if (method.isDefault()) {
  857. 857 stream.print("default ");
  858. 858 }
  859. 859 stream.print(method.scope() + " ");
  860. 860 if (method.isStatic()) {
  861. 861 stream.print("static ");
  862. 862 }
  863. 863 if (method.isFinal()) {
  864. 864 stream.print("final ");
  865. 865 }
  866. 866 if (method.isAbstract()) {
  867. 867 stream.print("abstract ");
  868. 868 }
  869. 869 if (method.isSynchronized()) {
  870. 870 stream.print("synchronized ");
  871. 871 }
  872. 872 if (method.isNative()) {
  873. 873 stream.print("native ");
  874. 874 }
  875. 875 if (false /* method.isStictFP() */) {
  876. 876 stream.print("strictfp ");
  877. 877 }
  878. 878
  879. 879 stream.print(method.typeArgumentsName(new HashSet()) + " ");
  880. 880
  881. 881 if (!isConstructor) {
  882. 882 stream.print(method.returnType().fullName(method.typeVariables()) + " ");
  883. 883 }
  884. 884 String n = method.name();
  885. 885 int pos = n.lastIndexOf('.');
  886. 886 if (pos >= 0) {
  887. 887 n = n.substring(pos + 1);
  888. 888 }
  889. 889 stream.print(n + "(");
  890. 890 comma = "";
  891. 891 int count = 1;
  892. 892 int size = method.parameters().size();
  893. 893 for (ParameterInfo param : method.parameters()) {
  894. 894 stream.print(comma);
  895. 895 writeAnnotations(stream, param.annotations(), false);
  896. 896 stream.print(fullParameterTypeName(method, param.type(), count == size) + " "
  897. 897 + param.name());
  898. 898 comma = ", ";
  899. 899 count++;
  900. 900 }
  901. 901 stream.print(")");
  902. 902
  903. 903 comma = "";
  904. 904 if (method.thrownExceptions().size() > 0) {
  905. 905 stream.print(" throws ");
  906. 906 for (ClassInfo thrown : method.thrownExceptions()) {
  907. 907 stream.print(comma + thrown.qualifiedName());
  908. 908 comma = ", ";
  909. 909 }
  910. 910 }
  911. 911 if (method.isAbstract() || method.isNative() || (method.containingClass().isInterface() && (!method.isDefault() && !method.isStatic()))) {
  912. 912 stream.println(";");
  913. 913 } else {
  914. 914 stream.print(" { ");
  915. 915 if (isConstructor) {
  916. 916 stream.print(superCtorCall(method.containingClass(), method.thrownExceptions()));
  917. 917 }
  918. 918 stream.println("throw new RuntimeException(\"Stub!\"); }");
  919. 919 }
  920. 920 }
  921. 921
  922. 922 static void writeField(PrintStream stream, FieldInfo field) {
  923. 923 writeAnnotations(stream, field.annotations(), field.isDeprecated());
  924. 924
  925. 925 stream.print(field.scope() + " ");
  926. 926 if (field.isStatic()) {
  927. 927 stream.print("static ");
  928. 928 }
  929. 929 if (field.isFinal()) {
  930. 930 stream.print("final ");
  931. 931 }
  932. 932 if (field.isTransient()) {
  933. 933 stream.print("transient ");
  934. 934 }
  935. 935 if (field.isVolatile()) {
  936. 936 stream.print("volatile ");
  937. 937 }
  938. 938
  939. 939 stream.print(field.type().fullName());
  940. 940 stream.print(" ");
  941. 941 stream.print(field.name());
  942. 942
  943. 943 if (fieldIsInitialized(field)) {
  944. 944 stream.print(" = " + field.constantLiteralValue());
  945. 945 }
  946. 946
  947. 947 stream.println(";");
  948. 948 }
  949. 949
  950. 950 static boolean fieldIsInitialized(FieldInfo field) {
  951. 951 return (field.isFinal() && field.constantValue() != null)
  952. 952 || !field.type().dimension().equals("") || field.containingClass().isInterface();
  953. 953 }
  954. 954
  955. 955 static boolean canCallMethod(ClassInfo from, MethodInfo m) {
  956. 956 if (m.isPublic() || m.isProtected()) {
  957. 957 return true;
  958. 958 }
  959. 959 if (m.isPackagePrivate()) {
  960. 960 String fromPkg = from.containingPackage().name();
  961. 961 String pkg = m.containingClass().containingPackage().name();
  962. 962 if (fromPkg.equals(pkg)) {
  963. 963 return true;
  964. 964 }
  965. 965 }
  966. 966 return false;
  967. 967 }
  968. 968
  969. 969 // call a constructor, any constructor on this class's superclass.
  970. 970 static String superCtorCall(ClassInfo cl, ArrayList<ClassInfo> thrownExceptions) {
  971. 971 ClassInfo base = cl.realSuperclass();
  972. 972 if (base == null) {
  973. 973 return "";
  974. 974 }
  975. 975 HashSet<String> exceptionNames = new HashSet<String>();
  976. 976 if (thrownExceptions != null) {
  977. 977 for (ClassInfo thrown : thrownExceptions) {
  978. 978 exceptionNames.add(thrown.name());
  979. 979 }
  980. 980 }
  981. 981 ArrayList<MethodInfo> ctors = base.constructors();
  982. 982 MethodInfo ctor = null;
  983. 983 // bad exception indicates that the exceptions thrown by the super constructor
  984. 984 // are incompatible with the constructor we're using for the sub class.
  985. 985 Boolean badException = false;
  986. 986 for (MethodInfo m : ctors) {
  987. 987 if (canCallMethod(cl, m)) {
  988. 988 if (m.thrownExceptions() != null) {
  989. 989 for (ClassInfo thrown : m.thrownExceptions()) {
  990. 990 if (thrownExceptions != null && !exceptionNames.contains(thrown.name())) {
  991. 991 badException = true;
  992. 992 }
  993. 993 }
  994. 994 }
  995. 995 if (badException) {
  996. 996 badException = false;
  997. 997 continue;
  998. 998 }
  999. 999 // if it has no args, we're done
  1000. 1000 if (m.parameters().isEmpty()) {
  1001. 1001 return "";
  1002. 1002 }
  1003. 1003 ctor = m;
  1004. 1004 }
  1005. 1005 }
  1006. 1006 if (ctor != null) {
  1007. 1007 String result = "";
  1008. 1008 result += "super(";
  1009. 1009 ArrayList<ParameterInfo> params = ctor.parameters();
  1010. 1010 for (ParameterInfo param : params) {
  1011. 1011 TypeInfo t = param.type();
  1012. 1012 if (t.isPrimitive() && t.dimension().equals("")) {
  1013. 1013 String n = t.simpleTypeName();
  1014. 1014 if (("byte".equals(n) || "short".equals(n) || "int".equals(n) || "long".equals(n)
  1015. 1015 || "float".equals(n) || "double".equals(n))
  1016. 1016 && t.dimension().equals("")) {
  1017. 1017 result += "0";
  1018. 1018 } else if ("char".equals(n)) {
  1019. 1019 result += "'\\0'";
  1020. 1020 } else if ("boolean".equals(n)) {
  1021. 1021 result += "false";
  1022. 1022 } else {
  1023. 1023 result += "<<unknown-" + n + ">>";
  1024. 1024 }
  1025. 1025 } else {
  1026. 1026 // put null in each super class method. Cast null to the correct type
  1027. 1027 // to avoid collisions with other constructors. If the type is generic
  1028. 1028 // don't cast it
  1029. 1029 result +=
  1030. 1030 (!t.isTypeVariable() ? "(" + t.qualifiedTypeName() + t.dimension() + ")" : "")
  1031. 1031 + "null";
  1032. 1032 }
  1033. 1033 if (param != params.get(params.size()-1)) {
  1034. 1034 result += ",";
  1035. 1035 }
  1036. 1036 }
  1037. 1037 result += "); ";
  1038. 1038 return result;
  1039. 1039 } else {
  1040. 1040 return "";
  1041. 1041 }
  1042. 1042 }
  1043. 1043
  1044. 1044 /**
  1045. 1045 * Write out the given list of annotations. If the {@code isDeprecated}
  1046. 1046 * flag is true also write out a {@code @Deprecated} annotation if it did not
  1047. 1047 * already appear in the list of annotations. (This covers APIs that mention
  1048. 1048 * {@code @deprecated} in their documentation but fail to add
  1049. 1049 * {@code @Deprecated} as an annotation.
  1050. 1050 * <p>
  1051. 1051 * {@code @Override} annotations are deliberately skipped.
  1052. 1052 */
  1053. 1053 static void writeAnnotations(PrintStream stream, List<AnnotationInstanceInfo> annotations,
  1054. 1054 boolean isDeprecated) {
  1055. 1055 assert annotations != null;
  1056. 1056 for (AnnotationInstanceInfo ann : annotations) {
  1057. 1057 // Skip @Override annotations: the stubs do not need it and in some cases it leads
  1058. 1058 // to compilation errors with the way the stubs are generated
  1059. 1059 if (ann.type() != null && ann.type().qualifiedName().equals("java.lang.Override")) {
  1060. 1060 continue;
  1061. 1061 }
  1062. 1062 if (!ann.type().isHiddenOrRemoved()) {
  1063. 1063 stream.println(ann.toString());
  1064. 1064 if (isDeprecated && ann.type() != null
  1065. 1065 && ann.type().qualifiedName().equals("java.lang.Deprecated")) {
  1066. 1066 isDeprecated = false; // Prevent duplicate annotations
  1067. 1067 }
  1068. 1068 }
  1069. 1069 }
  1070. 1070 if (isDeprecated) {
  1071. 1071 stream.println("@Deprecated");
  1072. 1072 }
  1073. 1073 }
  1074. 1074
  1075. 1075 static void writeAnnotationElement(PrintStream stream, MethodInfo ann) {
  1076. 1076 stream.print(ann.returnType().fullName());
  1077. 1077 stream.print(" ");
  1078. 1078 stream.print(ann.name());
  1079. 1079 stream.print("()");
  1080. 1080 AnnotationValueInfo def = ann.defaultAnnotationElementValue();
  1081. 1081 if (def != null) {
  1082. 1082 stream.print(" default ");
  1083. 1083 stream.print(def.valueString());
  1084. 1084 }
  1085. 1085 stream.println(";");
  1086. 1086 }
  1087. 1087
  1088. 1088 public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs, boolean strip) {
  1089. 1089 if (strip) {
  1090. 1090 Stubs.writeXml(xmlWriter, pkgs);
  1091. 1091 } else {
  1092. 1092 Stubs.writeXml(xmlWriter, pkgs, c -> true);
  1093. 1093 }
  1094. 1094 }
  1095. 1095
  1096. 1096 public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs,
  1097. 1097 Predicate<ClassInfo> notStrippable) {
  1098. 1098
  1099. 1099 final PackageInfo[] packages = pkgs.toArray(new PackageInfo[pkgs.size()]);
  1100. 1100 Arrays.sort(packages, PackageInfo.comparator);
  1101. 1101
  1102. 1102 xmlWriter.println("<api>");
  1103. 1103 for (PackageInfo pkg: packages) {
  1104. 1104 writePackageXML(xmlWriter, pkg, pkg.allClasses().values(), notStrippable);
  1105. 1105 }
  1106. 1106 xmlWriter.println("</api>");
  1107. 1107 }
  1108. 1108
  1109. 1109 public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs) {
  1110. 1110 HashSet<ClassInfo> allClasses = new HashSet<>();
  1111. 1111 for (PackageInfo pkg: pkgs) {
  1112. 1112 allClasses.addAll(pkg.allClasses().values());
  1113. 1113 }
  1114. 1114 Predicate<ClassInfo> notStrippable = allClasses::contains;
  1115. 1115 writeXml(xmlWriter, pkgs, notStrippable);
  1116. 1116 }
  1117. 1117
  1118. 1118 static void writePackageXML(PrintStream xmlWriter, PackageInfo pack,
  1119. 1119 Collection<ClassInfo> classList, Predicate<ClassInfo> notStrippable) {
  1120. 1120 ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
  1121. 1121 Arrays.sort(classes, ClassInfo.comparator);
  1122. 1122 // Work around the bogus "Array" class we invent for
  1123. 1123 // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
  1124. 1124 if (pack.name().equals(PackageInfo.DEFAULT_PACKAGE)) {
  1125. 1125 return;
  1126. 1126 }
  1127. 1127 xmlWriter.println("<package name=\"" + pack.name() + "\"\n"
  1128. 1128 // + " source=\"" + pack.position() + "\"\n"
  1129. 1129 + ">");
  1130. 1130 for (ClassInfo cl : classes) {
  1131. 1131 writeClassXML(xmlWriter, cl, notStrippable);
  1132. 1132 }
  1133. 1133 xmlWriter.println("</package>");
  1134. 1134
  1135. 1135
  1136. 1136 }
  1137. 1137
  1138. 1138 static void writeClassXML(PrintStream xmlWriter, ClassInfo cl, Predicate<ClassInfo> notStrippable) {
  1139. 1139 String scope = cl.scope();
  1140. 1140 String deprecatedString = "";
  1141. 1141 String declString = (cl.isInterface()) ? "interface" : "class";
  1142. 1142 if (cl.isDeprecated()) {
  1143. 1143 deprecatedString = "deprecated";
  1144. 1144 } else {
  1145. 1145 deprecatedString = "not deprecated";
  1146. 1146 }
  1147. 1147 xmlWriter.println("<" + declString + " name=\"" + cl.name() + "\"");
  1148. 1148 if (!cl.isInterface() && !cl.qualifiedName().equals("java.lang.Object")) {
  1149. 1149 xmlWriter.println(" extends=\""
  1150. 1150 + ((cl.realSuperclass() == null) ? "java.lang.Object" : cl.realSuperclass()
  1151. 1151 .qualifiedName()) + "\"");
  1152. 1152 }
  1153. 1153 xmlWriter.println(" abstract=\"" + cl.isAbstract() + "\"\n" + " static=\"" + cl.isStatic()
  1154. 1154 + "\"\n" + " final=\"" + cl.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString
  1155. 1155 + "\"\n" + " visibility=\"" + scope + "\"\n"
  1156. 1156 // + " source=\"" + cl.position() + "\"\n"
  1157. 1157 + ">");
  1158. 1158
  1159. 1159 ArrayList<ClassInfo> interfaces = cl.realInterfaces();
  1160. 1160 Collections.sort(interfaces, ClassInfo.comparator);
  1161. 1161 for (ClassInfo iface : interfaces) {
  1162. 1162 if (notStrippable.test(iface)) {
  1163. 1163 xmlWriter.println("<implements name=\"" + iface.qualifiedName() + "\">");
  1164. 1164 xmlWriter.println("</implements>");
  1165. 1165 }
  1166. 1166 }
  1167. 1167
  1168. 1168 ArrayList<MethodInfo> constructors = cl.constructors();
  1169. 1169 Collections.sort(constructors, MethodInfo.comparator);
  1170. 1170 for (MethodInfo mi : constructors) {
  1171. 1171 writeConstructorXML(xmlWriter, mi);
  1172. 1172 }
  1173. 1173
  1174. 1174 ArrayList<MethodInfo> methods = cl.allSelfMethods();
  1175. 1175 Collections.sort(methods, MethodInfo.comparator);
  1176. 1176 for (MethodInfo mi : methods) {
  1177. 1177 writeMethodXML(xmlWriter, mi);
  1178. 1178 }
  1179. 1179
  1180. 1180 ArrayList<FieldInfo> fields = cl.selfFields();
  1181. 1181 Collections.sort(fields, FieldInfo.comparator);
  1182. 1182 for (FieldInfo fi : fields) {
  1183. 1183 writeFieldXML(xmlWriter, fi);
  1184. 1184 }
  1185. 1185 xmlWriter.println("</" + declString + ">");
  1186. 1186
  1187. 1187 }
  1188. 1188
  1189. 1189 static void writeMethodXML(PrintStream xmlWriter, MethodInfo mi) {
  1190. 1190 String scope = mi.scope();
  1191. 1191
  1192. 1192 String deprecatedString = "";
  1193. 1193 if (mi.isDeprecated()) {
  1194. 1194 deprecatedString = "deprecated";
  1195. 1195 } else {
  1196. 1196 deprecatedString = "not deprecated";
  1197. 1197 }
  1198. 1198 xmlWriter.println("<method name=\""
  1199. 1199 + mi.name()
  1200. 1200 + "\"\n"
  1201. 1201 + ((mi.returnType() != null) ? " return=\""
  1202. 1202 + makeXMLcompliant(fullParameterTypeName(mi, mi.returnType(), false)) + "\"\n" : "")
  1203. 1203 + " abstract=\"" + mi.isAbstract() + "\"\n" + " native=\"" + mi.isNative() + "\"\n"
  1204. 1204 + " synchronized=\"" + mi.isSynchronized() + "\"\n" + " static=\"" + mi.isStatic() + "\"\n"
  1205. 1205 + " final=\"" + mi.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString + "\"\n"
  1206. 1206 + " visibility=\"" + scope + "\"\n"
  1207. 1207 // + " source=\"" + mi.position() + "\"\n"
  1208. 1208 + ">");
  1209. 1209
  1210. 1210 // write parameters in declaration order
  1211. 1211 int numParameters = mi.parameters().size();
  1212. 1212 int count = 0;
  1213. 1213 for (ParameterInfo pi : mi.parameters()) {
  1214. 1214 count++;
  1215. 1215 writeParameterXML(xmlWriter, mi, pi, count == numParameters);
  1216. 1216 }
  1217. 1217
  1218. 1218 // but write exceptions in canonicalized order
  1219. 1219 ArrayList<ClassInfo> exceptions = mi.thrownExceptions();
  1220. 1220 Collections.sort(exceptions, ClassInfo.comparator);
  1221. 1221 for (ClassInfo pi : exceptions) {
  1222. 1222 xmlWriter.println("<exception name=\"" + pi.name() + "\" type=\"" + pi.qualifiedName()
  1223. 1223 + "\">");
  1224. 1224 xmlWriter.println("</exception>");
  1225. 1225 }
  1226. 1226 xmlWriter.println("</method>");
  1227. 1227 }
  1228. 1228
  1229. 1229 static void writeConstructorXML(PrintStream xmlWriter, MethodInfo mi) {
  1230. 1230 String scope = mi.scope();
  1231. 1231 String deprecatedString = "";
  1232. 1232 if (mi.isDeprecated()) {
  1233. 1233 deprecatedString = "deprecated";
  1234. 1234 } else {
  1235. 1235 deprecatedString = "not deprecated";
  1236. 1236 }
  1237. 1237 xmlWriter.println("<constructor name=\"" + mi.name() + "\"\n" + " type=\""
  1238. 1238 + mi.containingClass().qualifiedName() + "\"\n" + " static=\"" + mi.isStatic() + "\"\n"
  1239. 1239 + " final=\"" + mi.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString + "\"\n"
  1240. 1240 + " visibility=\"" + scope + "\"\n"
  1241. 1241 // + " source=\"" + mi.position() + "\"\n"
  1242. 1242 + ">");
  1243. 1243
  1244. 1244 int numParameters = mi.parameters().size();
  1245. 1245 int count = 0;
  1246. 1246 for (ParameterInfo pi : mi.parameters()) {
  1247. 1247 count++;
  1248. 1248 writeParameterXML(xmlWriter, mi, pi, count == numParameters);
  1249. 1249 }
  1250. 1250
  1251. 1251 ArrayList<ClassInfo> exceptions = mi.thrownExceptions();
  1252. 1252 Collections.sort(exceptions, ClassInfo.comparator);
  1253. 1253 for (ClassInfo pi : exceptions) {
  1254. 1254 xmlWriter.println("<exception name=\"" + pi.name() + "\" type=\"" + pi.qualifiedName()
  1255. 1255 + "\">");
  1256. 1256 xmlWriter.println("</exception>");
  1257. 1257 }
  1258. 1258 xmlWriter.println("</constructor>");
  1259. 1259 }
  1260. 1260
  1261. 1261 static void writeParameterXML(PrintStream xmlWriter, MethodInfo method, ParameterInfo pi,
  1262. 1262 boolean isLast) {
  1263. 1263 xmlWriter.println("<parameter name=\"" + pi.name() + "\" type=\""
  1264. 1264 + makeXMLcompliant(fullParameterTypeName(method, pi.type(), isLast)) + "\">");
  1265. 1265 xmlWriter.println("</parameter>");
  1266. 1266 }
  1267. 1267
  1268. 1268 static void writeFieldXML(PrintStream xmlWriter, FieldInfo fi) {
  1269. 1269 String scope = fi.scope();
  1270. 1270 String deprecatedString = "";
  1271. 1271 if (fi.isDeprecated()) {
  1272. 1272 deprecatedString = "deprecated";
  1273. 1273 } else {
  1274. 1274 deprecatedString = "not deprecated";
  1275. 1275 }
  1276. 1276 // need to make sure value is valid XML
  1277. 1277 String value = makeXMLcompliant(fi.constantLiteralValue());
  1278. 1278
  1279. 1279 String fullTypeName = makeXMLcompliant(fi.type().fullName());
  1280. 1280
  1281. 1281 xmlWriter.println("<field name=\"" + fi.name() + "\"\n" + " type=\"" + fullTypeName + "\"\n"
  1282. 1282 + " transient=\"" + fi.isTransient() + "\"\n" + " volatile=\"" + fi.isVolatile() + "\"\n"
  1283. 1283 + (fieldIsInitialized(fi) ? " value=\"" + value + "\"\n" : "") + " static=\""
  1284. 1284 + fi.isStatic() + "\"\n" + " final=\"" + fi.isFinal() + "\"\n" + " deprecated=\""
  1285. 1285 + deprecatedString + "\"\n" + " visibility=\"" + scope + "\"\n"
  1286. 1286 // + " source=\"" + fi.position() + "\"\n"
  1287. 1287 + ">");
  1288. 1288 xmlWriter.println("</field>");
  1289. 1289 }
  1290. 1290
  1291. 1291 static String makeXMLcompliant(String s) {
  1292. 1292 String returnString = "";
  1293. 1293 returnString = s.replaceAll("&", "&");
  1294. 1294 returnString = returnString.replaceAll("<", "<");
  1295. 1295 returnString = returnString.replaceAll(">", ">");
  1296. 1296 returnString = returnString.replaceAll("\"", """);
  1297. 1297 returnString = returnString.replaceAll("'", "&apos;");
  1298. 1298 return returnString;
  1299. 1299 }
  1300. 1300
  1301. 1301 /**
  1302. 1302 * Predicate that decides if the given member should be considered part of an
  1303. 1303 * API surface area. To make the most accurate decision, it searches for
  1304. 1304 * signals on the member, all containing classes, and all containing packages.
  1305. 1305 */
  1306. 1306 public static class ApiPredicate implements Predicate<MemberInfo> {
  1307. 1307 public boolean ignoreShown;
  1308. 1308 public boolean ignoreRemoved;
  1309. 1309 public boolean matchRemoved;
  1310. 1310
  1311. 1311 /**
  1312. 1312 * Set if the value of {@link MemberInfo#hasShowAnnotation()} should be
  1313. 1313 * ignored. That is, this predicate will assume that all encountered members
  1314. 1314 * match the "shown" requirement.
  1315. 1315 * <p>
  1316. 1316 * This is typically useful when generating "current.txt", when no
  1317. 1317 * {@link Doclava#showAnnotations} have been defined.
  1318. 1318 */
  1319. 1319 public ApiPredicate setIgnoreShown(boolean ignoreShown) {
  1320. 1320 this.ignoreShown = ignoreShown;
  1321. 1321 return this;
  1322. 1322 }
  1323. 1323
  1324. 1324 /**
  1325. 1325 * Set if the value of {@link MemberInfo#isRemoved()} should be ignored.
  1326. 1326 * That is, this predicate will assume that all encountered members match
  1327. 1327 * the "removed" requirement.
  1328. 1328 * <p>
  1329. 1329 * This is typically useful when generating "removed.txt", when it's okay to
  1330. 1330 * reference both current and removed APIs.
  1331. 1331 */
  1332. 1332 public ApiPredicate setIgnoreRemoved(boolean ignoreRemoved) {
  1333. 1333 this.ignoreRemoved = ignoreRemoved;
  1334. 1334 return this;
  1335. 1335 }
  1336. 1336
  1337. 1337 /**
  1338. 1338 * Set what the value of {@link MemberInfo#isRemoved()} must be equal to in
  1339. 1339 * order for a member to match.
  1340. 1340 * <p>
  1341. 1341 * This is typically useful when generating "removed.txt", when you only
  1342. 1342 * want to match members that have actually been removed.
  1343. 1343 */
  1344. 1344 public ApiPredicate setMatchRemoved(boolean matchRemoved) {
  1345. 1345 this.matchRemoved = matchRemoved;
  1346. 1346 return this;
  1347. 1347 }
  1348. 1348
  1349. 1349 private static PackageInfo containingPackage(PackageInfo pkg) {
  1350. 1350 String name = pkg.name();
  1351. 1351 final int lastDot = name.lastIndexOf('.');
  1352. 1352 if (lastDot == -1) {
  1353. 1353 return null;
  1354. 1354 } else {
  1355. 1355 name = name.substring(0, lastDot);
  1356. 1356 return Converter.obtainPackage(name);
  1357. 1357 }
  1358. 1358 }
  1359. 1359
  1360. 1360 @Override
  1361. 1361 public boolean test(MemberInfo member) {
  1362. 1362 boolean visible = member.isPublic() || member.isProtected();
  1363. 1363 boolean hasShowAnnotation = member.hasShowAnnotation();
  1364. 1364 boolean hidden = member.isHidden();
  1365. 1365 boolean docOnly = member.isDocOnly();
  1366. 1366 boolean removed = member.isRemoved();
  1367. 1367
  1368. 1368 ClassInfo clazz = member.containingClass();
  1369. 1369 if (clazz != null) {
  1370. 1370 PackageInfo pkg = clazz.containingPackage();
  1371. 1371 while (pkg != null) {
  1372. 1372 hidden |= pkg.isHidden();
  1373. 1373 docOnly |= pkg.isDocOnly();
  1374. 1374 removed |= pkg.isRemoved();
  1375. 1375 pkg = containingPackage(pkg);
  1376. 1376 }
  1377. 1377 }
  1378. 1378 while (clazz != null) {
  1379. 1379 visible &= clazz.isPublic() || clazz.isProtected();
  1380. 1380 hasShowAnnotation |= clazz.hasShowAnnotation();
  1381. 1381 hidden |= clazz.isHidden();
  1382. 1382 docOnly |= clazz.isDocOnly();
  1383. 1383 removed |= clazz.isRemoved();
  1384. 1384 clazz = clazz.containingClass();
  1385. 1385 }
  1386. 1386
  1387. 1387 if (ignoreShown) {
  1388. 1388 hasShowAnnotation = true;
  1389. 1389 }
  1390. 1390 if (ignoreRemoved) {
  1391. 1391 removed = matchRemoved;
  1392. 1392 }
  1393. 1393
  1394. 1394 return visible && hasShowAnnotation && !hidden && !docOnly && (removed == matchRemoved);
  1395. 1395 }
  1396. 1396 }
  1397. 1397
  1398. 1398 /**
  1399. 1399 * Filter that will elide exact duplicate members that are already included
  1400. 1400 * in another superclass/interfaces.
  1401. 1401 */
  1402. 1402 public static class ElidingPredicate implements Predicate<MemberInfo> {
  1403. 1403 private final Predicate<MemberInfo> wrapped;
  1404. 1404
  1405. 1405 public ElidingPredicate(Predicate<MemberInfo> wrapped) {
  1406. 1406 this.wrapped = wrapped;
  1407. 1407 }
  1408. 1408
  1409. 1409 @Override
  1410. 1410 public boolean test(MemberInfo member) {
  1411. 1411 // This member should be included, but if it's an exact duplicate
  1412. 1412 // override then we can elide it.
  1413. 1413 if (member instanceof MethodInfo) {
  1414. 1414 MethodInfo method = (MethodInfo) member;
  1415. 1415 if (method.returnType() != null) { // not a constructor
  1416. 1416 String methodRaw = writeMethodApiWithoutDefault(method);
  1417. 1417 return (method.findPredicateOverriddenMethod(new Predicate<MemberInfo>() {
  1418. 1418 @Override
  1419. 1419 public boolean test(MemberInfo test) {
  1420. 1420 // We're looking for included and perfect signature
  1421. 1421 return (wrapped.test(test)
  1422. 1422 && writeMethodApiWithoutDefault((MethodInfo) test).equals(methodRaw));
  1423. 1423 }
  1424. 1424 }) == null);
  1425. 1425 }
  1426. 1426 }
  1427. 1427 return true;
  1428. 1428 }
  1429. 1429 }
  1430. 1430
  1431. 1431 public static class FilterPredicate implements Predicate<MemberInfo> {
  1432. 1432 private final Predicate<MemberInfo> wrapped;
  1433. 1433
  1434. 1434 public FilterPredicate(Predicate<MemberInfo> wrapped) {
  1435. 1435 this.wrapped = wrapped;
  1436. 1436 }
  1437. 1437
  1438. 1438 @Override
  1439. 1439 public boolean test(MemberInfo member) {
  1440. 1440 if (wrapped.test(member)) {
  1441. 1441 return true;
  1442. 1442 } else if (member instanceof MethodInfo) {
  1443. 1443 MethodInfo method = (MethodInfo) member;
  1444. 1444 return method.returnType() != null && // not a constructor
  1445. 1445 method.findPredicateOverriddenMethod(wrapped) != null;
  1446. 1446 } else {
  1447. 1447 return false;
  1448. 1448 }
  1449. 1449 }
  1450. 1450 }
  1451. 1451
  1452. 1452 static void writeApi(PrintStream apiWriter, Map<PackageInfo, List<ClassInfo>> classesByPackage,
  1453. 1453 Predicate<MemberInfo> filterEmit, Predicate<MemberInfo> filterReference) {
  1454. 1454 for (PackageInfo pkg : classesByPackage.keySet().stream().sorted(PackageInfo.comparator)
  1455. 1455 .collect(Collectors.toList())) {
  1456. 1456 if (pkg.name().equals(PackageInfo.DEFAULT_PACKAGE)) continue;
  1457. 1457
  1458. 1458 boolean hasWrittenPackageHead = false;
  1459. 1459 for (ClassInfo clazz : classesByPackage.get(pkg).stream().sorted(ClassInfo.comparator)
  1460. 1460 .collect(Collectors.toList())) {
  1461. 1461 hasWrittenPackageHead = writeClassApi(apiWriter, clazz, filterEmit, filterReference,
  1462. 1462 hasWrittenPackageHead);
  1463. 1463 }
  1464. 1464
  1465. 1465 if (hasWrittenPackageHead) {
  1466. 1466 apiWriter.print("}\n\n");
  1467. 1467 }
  1468. 1468 }
  1469. 1469 }
  1470. 1470
  1471. 1471 static void writeDexApi(PrintStream apiWriter, Map<PackageInfo, List<ClassInfo>> classesByPackage,
  1472. 1472 Predicate<MemberInfo> filterEmit) {
  1473. 1473 for (PackageInfo pkg : classesByPackage.keySet().stream().sorted(PackageInfo.comparator)
  1474. 1474 .collect(Collectors.toList())) {
  1475. 1475 if (pkg.name().equals(PackageInfo.DEFAULT_PACKAGE)) continue;
  1476. 1476
  1477. 1477 for (ClassInfo clazz : classesByPackage.get(pkg).stream().sorted(ClassInfo.comparator)
  1478. 1478 .collect(Collectors.toList())) {
  1479. 1479 writeClassDexApi(apiWriter, clazz, filterEmit);
  1480. 1480 }
  1481. 1481 }
  1482. 1482 }
  1483. 1483
  1484. 1484 /**
  1485. 1485 * Write the removed members of the class to removed.txt
  1486. 1486 */
  1487. 1487 private static boolean writeClassApi(PrintStream apiWriter, ClassInfo cl,
  1488. 1488 Predicate<MemberInfo> filterEmit, Predicate<MemberInfo> filterReference,
  1489. 1489 boolean hasWrittenPackageHead) {
  1490. 1490
  1491. 1491 List<MethodInfo> constructors = cl.getExhaustiveConstructors().stream().filter(filterEmit)
  1492. 1492 .sorted(MethodInfo.comparator).collect(Collectors.toList());
  1493. 1493 List<MethodInfo> methods = cl.getExhaustiveMethods().stream().filter(filterEmit)
  1494. 1494 .sorted(MethodInfo.comparator).collect(Collectors.toList());
  1495. 1495 List<FieldInfo> enums = cl.getExhaustiveEnumConstants().stream().filter(filterEmit)
  1496. 1496 .sorted(FieldInfo.comparator).collect(Collectors.toList());
  1497. 1497 List<FieldInfo> fields = cl.filteredFields(filterEmit).stream()
  1498. 1498 .sorted(FieldInfo.comparator).collect(Collectors.toList());
  1499. 1499
  1500. 1500 final boolean classEmpty = (constructors.isEmpty() && methods.isEmpty() && enums.isEmpty()
  1501. 1501 && fields.isEmpty());
  1502. 1502 final boolean emit;
  1503. 1503 if (filterEmit.test(cl.asMemberInfo())) {
  1504. 1504 emit = true;
  1505. 1505 } else if (!classEmpty) {
  1506. 1506 emit = filterReference.test(cl.asMemberInfo());
  1507. 1507 } else {
  1508. 1508 emit = false;
  1509. 1509 }
  1510. 1510 if (!emit) {
  1511. 1511 return hasWrittenPackageHead;
  1512. 1512 }
  1513. 1513
  1514. 1514 // Look for Android @SystemApi exposed outside the normal SDK; we require
  1515. 1515 // that they're protected with a system permission.
  1516. 1516 if (Doclava.android && Doclava.showAnnotations.contains("android.annotation.SystemApi")) {
  1517. 1517 boolean systemService = "android.content.pm.PackageManager".equals(cl.qualifiedName());
  1518. 1518 for (AnnotationInstanceInfo a : cl.annotations()) {
  1519. 1519 if (a.type().qualifiedNameMatches("android", "annotation.SystemService")) {
  1520. 1520 systemService = true;
  1521. 1521 }
  1522. 1522 }
  1523. 1523 if (systemService) {
  1524. 1524 for (MethodInfo mi : methods) {
  1525. 1525 checkSystemPermissions(mi);
  1526. 1526 }
  1527. 1527 }
  1528. 1528 }
  1529. 1529
  1530. 1530 for (MethodInfo method : methods) {
  1531. 1531 checkHiddenTypes(method, filterReference);
  1532. 1532 }
  1533. 1533 for (FieldInfo field : fields) {
  1534. 1534 checkHiddenTypes(field, filterReference);
  1535. 1535 }
  1536. 1536
  1537. 1537 if (!hasWrittenPackageHead) {
  1538. 1538 hasWrittenPackageHead = true;
  1539. 1539 apiWriter.print("package ");
  1540. 1540 apiWriter.print(cl.containingPackage().qualifiedName());
  1541. 1541 apiWriter.print(" {\n\n");
  1542. 1542 }
  1543. 1543
  1544. 1544 apiWriter.print(" ");
  1545. 1545 apiWriter.print(cl.scope());
  1546. 1546 if (cl.isStatic()) {
  1547. 1547 apiWriter.print(" static");
  1548. 1548 }
  1549. 1549 if (cl.isFinal()) {
  1550. 1550 apiWriter.print(" final");
  1551. 1551 }
  1552. 1552 if (cl.isAbstract()) {
  1553. 1553 apiWriter.print(" abstract");
  1554. 1554 }
  1555. 1555 if (cl.isDeprecated()) {
  1556. 1556 apiWriter.print(" deprecated");
  1557. 1557 }
  1558. 1558 apiWriter.print(" ");
  1559. 1559 apiWriter.print(cl.isInterface() ? "interface" : "class");
  1560. 1560 apiWriter.print(" ");
  1561. 1561 apiWriter.print(cl.name());
  1562. 1562 if (cl.hasTypeParameters()) {
  1563. 1563 apiWriter.print(TypeInfo.typeArgumentsName(cl.asTypeInfo().typeArguments(),
  1564. 1564 new HashSet<String>()));
  1565. 1565 }
  1566. 1566
  1567. 1567 if (!cl.isInterface()
  1568. 1568 && !"java.lang.Object".equals(cl.qualifiedName())) {
  1569. 1569 final ClassInfo superclass = cl.filteredSuperclass(filterReference);
  1570. 1570 if (superclass != null && !"java.lang.Object".equals(superclass.qualifiedName())) {
  1571. 1571 apiWriter.print(" extends ");
  1572. 1572 apiWriter.print(superclass.qualifiedName());
  1573. 1573 }
  1574. 1574 }
  1575. 1575
  1576. 1576 List<ClassInfo> interfaces = cl.filteredInterfaces(filterReference).stream()
  1577. 1577 .sorted(ClassInfo.comparator).collect(Collectors.toList());
  1578. 1578 boolean first = true;
  1579. 1579 for (ClassInfo iface : interfaces) {
  1580. 1580 if (first) {
  1581. 1581 apiWriter.print(" implements");
  1582. 1582 first = false;
  1583. 1583 }
  1584. 1584 apiWriter.print(" ");
  1585. 1585 apiWriter.print(iface.qualifiedName());
  1586. 1586 }
  1587. 1587
  1588. 1588 apiWriter.print(" {\n");
  1589. 1589
  1590. 1590 for (MethodInfo mi : constructors) {
  1591. 1591 writeConstructorApi(apiWriter, mi);
  1592. 1592 }
  1593. 1593 for (MethodInfo mi : methods) {
  1594. 1594 writeMethodApi(apiWriter, mi);
  1595. 1595 }
  1596. 1596 for (FieldInfo fi : enums) {
  1597. 1597 writeFieldApi(apiWriter, fi, "enum_constant");
  1598. 1598 }
  1599. 1599 for (FieldInfo fi : fields) {
  1600. 1600 writeFieldApi(apiWriter, fi, "field");
  1601. 1601 }
  1602. 1602
  1603. 1603 apiWriter.print(" }\n\n");
  1604. 1604 return hasWrittenPackageHead;
  1605. 1605 }
  1606. 1606
  1607. 1607 private static void writeClassDexApi(PrintStream apiWriter, ClassInfo cl,
  1608. 1608 Predicate<MemberInfo> filterEmit) {
  1609. 1609 if (filterEmit.test(cl.asMemberInfo())) {
  1610. 1610 apiWriter.print(toSlashFormat(cl.qualifiedName()));
  1611. 1611 apiWriter.print("\n");
  1612. 1612 }
  1613. 1613
  1614. 1614 List<MethodInfo> constructors = cl.getExhaustiveConstructors().stream().filter(filterEmit)
  1615. 1615 .sorted(MethodInfo.comparator).collect(Collectors.toList());
  1616. 1616 List<MethodInfo> methods = cl.getExhaustiveMethods().stream().filter(filterEmit)
  1617. 1617 .sorted(MethodInfo.comparator).collect(Collectors.toList());
  1618. 1618 List<FieldInfo> enums = cl.getExhaustiveEnumConstants().stream().filter(filterEmit)
  1619. 1619 .sorted(FieldInfo.comparator).collect(Collectors.toList());
  1620. 1620 List<FieldInfo> fields = cl.getExhaustiveFields().stream().filter(filterEmit)
  1621. 1621 .sorted(FieldInfo.comparator).collect(Collectors.toList());
  1622. 1622
  1623. 1623 for (MethodInfo mi : constructors) {
  1624. 1624 writeMethodDexApi(apiWriter, cl, mi);
  1625. 1625 }
  1626. 1626 for (MethodInfo mi : methods) {
  1627. 1627 writeMethodDexApi(apiWriter, cl, mi);
  1628. 1628 }
  1629. 1629 for (FieldInfo fi : enums) {
  1630. 1630 writeFieldDexApi(apiWriter, cl, fi);
  1631. 1631 }
  1632. 1632 for (FieldInfo fi : fields) {
  1633. 1633 writeFieldDexApi(apiWriter, cl, fi);
  1634. 1634 }
  1635. 1635 }
  1636. 1636
  1637. 1637 private static void checkSystemPermissions(MethodInfo mi) {
  1638. 1638 boolean hasAnnotation = false;
  1639. 1639 for (AnnotationInstanceInfo a : mi.annotations()) {
  1640. 1640 if (a.type().qualifiedNameMatches("android", "annotation.RequiresPermission")) {
  1641. 1641 hasAnnotation = true;
  1642. 1642 for (AnnotationValueInfo val : a.elementValues()) {
  1643. 1643 ArrayList<AnnotationValueInfo> values = new ArrayList<>();
  1644. 1644 boolean any = false;
  1645. 1645 switch (val.element().name()) {
  1646. 1646 case "value":
  1647. 1647 values.add(val);
  1648. 1648 break;
  1649. 1649 case "allOf":
  1650. 1650 values = (ArrayList<AnnotationValueInfo>) val.value();
  1651. 1651 break;
  1652. 1652 case "anyOf":
  1653. 1653 any = true;
  1654. 1654 values = (ArrayList<AnnotationValueInfo>) val.value();
  1655. 1655 break;
  1656. 1656 }
  1657. 1657 if (values.isEmpty()) continue;
  1658. 1658
  1659. 1659 ArrayList<String> system = new ArrayList<>();
  1660. 1660 ArrayList<String> nonSystem = new ArrayList<>();
  1661. 1661 for (AnnotationValueInfo value : values) {
  1662. 1662 final String perm = String.valueOf(value.value());
  1663. 1663 final String level = Doclava.manifestPermissions.getOrDefault(perm, null);
  1664. 1664 if (level == null) {
  1665. 1665 Errors.error(Errors.REMOVED_FIELD, mi.position(),
  1666. 1666 "Permission '" + perm + "' is not defined by AndroidManifest.xml.");
  1667. 1667 continue;
  1668. 1668 }
  1669. 1669 if (level.contains("normal") || level.contains("dangerous")
  1670. 1670 || level.contains("ephemeral")) {
  1671. 1671 nonSystem.add(perm);
  1672. 1672 } else {
  1673. 1673 system.add(perm);
  1674. 1674 }
  1675. 1675 }
  1676. 1676
  1677. 1677 if (system.isEmpty() && nonSystem.isEmpty()) {
  1678. 1678 hasAnnotation = false;
  1679. 1679 } else if ((any && !nonSystem.isEmpty()) || (!any && system.isEmpty())) {
  1680. 1680 Errors.error(Errors.REQUIRES_PERMISSION, mi, "Method '" + mi.name()
  1681. 1681 + "' must be protected with a system permission; it currently"
  1682. 1682 + " allows non-system callers holding " + nonSystem.toString());
  1683. 1683 }
  1684. 1684 }
  1685. 1685 }
  1686. 1686 }
  1687. 1687 if (!hasAnnotation) {
  1688. 1688 Errors.error(Errors.REQUIRES_PERMISSION, mi, "Method '" + mi.name()
  1689. 1689 + "' must be protected with a system permission.");
  1690. 1690 }
  1691. 1691 }
  1692. 1692
  1693. 1693 private static void checkHiddenTypes(MethodInfo method, Predicate<MemberInfo> filterReference) {
  1694. 1694 checkHiddenTypes(method.returnType(), method, filterReference);
  1695. 1695 List<ParameterInfo> params = method.parameters();
  1696. 1696 if (params != null) {
  1697. 1697 for (ParameterInfo param : params) {
  1698. 1698 checkHiddenTypes(param.type(), method, filterReference);
  1699. 1699 }
  1700. 1700 }
  1701. 1701 }
  1702. 1702
  1703. 1703 private static void checkHiddenTypes(FieldInfo field, Predicate<MemberInfo> filterReference) {
  1704. 1704 checkHiddenTypes(field.type(), field, filterReference);
  1705. 1705 }
  1706. 1706
  1707. 1707 private static void checkHiddenTypes(TypeInfo type, MemberInfo member,
  1708. 1708 Predicate<MemberInfo> filterReference) {
  1709. 1709 if (type == null || type.isPrimitive()) {
  1710. 1710 return;
  1711. 1711 }
  1712. 1712
  1713. 1713 ClassInfo clazz = type.asClassInfo();
  1714. 1714 if (clazz == null || !filterReference.test(clazz.asMemberInfo())) {
  1715. 1715 Errors.error(Errors.HIDDEN_TYPE_PARAMETER, member.position(),
  1716. 1716 "Member " + member + " references hidden type " + type.qualifiedTypeName() + ".");
  1717. 1717 }
  1718. 1718
  1719. 1719 List<TypeInfo> args = type.typeArguments();
  1720. 1720 if (args != null) {
  1721. 1721 for (TypeInfo arg : args) {
  1722. 1722 checkHiddenTypes(arg, member, filterReference);
  1723. 1723 }
  1724. 1724 }
  1725. 1725 }
  1726. 1726
  1727. 1727 static void writeConstructorApi(PrintStream apiWriter, MethodInfo mi) {
  1728. 1728 apiWriter.print(" ctor ");
  1729. 1729 apiWriter.print(mi.scope());
  1730. 1730 if (mi.isDeprecated()) {
  1731. 1731 apiWriter.print(" deprecated");
  1732. 1732 }
  1733. 1733 apiWriter.print(" ");
  1734. 1734 apiWriter.print(mi.name());
  1735. 1735
  1736. 1736 writeParametersApi(apiWriter, mi, mi.parameters());
  1737. 1737 writeThrowsApi(apiWriter, mi.thrownExceptions());
  1738. 1738 apiWriter.print(";\n");
  1739. 1739 }
  1740. 1740
  1741. 1741 static String writeMethodApiWithoutDefault(MethodInfo mi) {
  1742. 1742 final ByteArrayOutputStream out = new ByteArrayOutputStream();
  1743. 1743 writeMethodApi(new PrintStream(out), mi, false);
  1744. 1744 return out.toString();
  1745. 1745 }
  1746. 1746
  1747. 1747 static void writeMethodApi(PrintStream apiWriter, MethodInfo mi) {
  1748. 1748 writeMethodApi(apiWriter, mi, true);
  1749. 1749 }
  1750. 1750
  1751. 1751 static void writeMethodApi(PrintStream apiWriter, MethodInfo mi, boolean withDefault) {
  1752. 1752 apiWriter.print(" method ");
  1753. 1753 apiWriter.print(mi.scope());
  1754. 1754 if (mi.isDefault() && withDefault) {
  1755. 1755 apiWriter.print(" default");
  1756. 1756 }
  1757. 1757 if (mi.isStatic()) {
  1758. 1758 apiWriter.print(" static");
  1759. 1759 }
  1760. 1760 if (mi.isFinal()) {
  1761. 1761 apiWriter.print(" final");
  1762. 1762 }
  1763. 1763 if (mi.isAbstract()) {
  1764. 1764 apiWriter.print(" abstract");
  1765. 1765 }
  1766. 1766 if (mi.isDeprecated()) {
  1767. 1767 apiWriter.print(" deprecated");
  1768. 1768 }
  1769. 1769 if (mi.isSynchronized()) {
  1770. 1770 apiWriter.print(" synchronized");
  1771. 1771 }
  1772. 1772 if (mi.hasTypeParameters()) {
  1773. 1773 apiWriter.print(" " + mi.typeArgumentsName(new HashSet<String>()));
  1774. 1774 }
  1775. 1775 apiWriter.print(" ");
  1776. 1776 if (mi.returnType() == null) {
  1777. 1777 apiWriter.print("void");
  1778. 1778 } else {
  1779. 1779 apiWriter.print(fullParameterTypeName(mi, mi.returnType(), false));
  1780. 1780 }
  1781. 1781 apiWriter.print(" ");
  1782. 1782 apiWriter.print(mi.name());
  1783. 1783
  1784. 1784 writeParametersApi(apiWriter, mi, mi.parameters());
  1785. 1785 writeThrowsApi(apiWriter, mi.thrownExceptions());
  1786. 1786
  1787. 1787 apiWriter.print(";\n");
  1788. 1788 }
  1789. 1789
  1790. 1790 static void writeMethodDexApi(PrintStream apiWriter, ClassInfo cl, MethodInfo mi) {
  1791. 1791 apiWriter.print(toSlashFormat(cl.qualifiedName()));
  1792. 1792 apiWriter.print("->");
  1793. 1793 if (mi.returnType() == null) {
  1794. 1794 apiWriter.print("<init>");
  1795. 1795 } else {
  1796. 1796 apiWriter.print(mi.name());
  1797. 1797 }
  1798. 1798 writeParametersDexApi(apiWriter, mi, mi.parameters());
  1799. 1799 if (mi.returnType() == null) { // constructor
  1800. 1800 apiWriter.print("V");
  1801. 1801 } else {
  1802. 1802 apiWriter.print(toSlashFormat(mi.returnType().dexName()));
  1803. 1803 }
  1804. 1804 apiWriter.print("\n");
  1805. 1805 }
  1806. 1806
  1807. 1807 static void writeParametersApi(PrintStream apiWriter, MethodInfo method,
  1808. 1808 ArrayList<ParameterInfo> params) {
  1809. 1809 apiWriter.print("(");
  1810. 1810
  1811. 1811 for (ParameterInfo pi : params) {
  1812. 1812 if (pi != params.get(0)) {
  1813. 1813 apiWriter.print(", ");
  1814. 1814 }
  1815. 1815 apiWriter.print(fullParameterTypeName(method, pi.type(), pi == params.get(params.size()-1)));
  1816. 1816 // turn on to write the names too
  1817. 1817 if (false) {
  1818. 1818 apiWriter.print(" ");
  1819. 1819 apiWriter.print(pi.name());
  1820. 1820 }
  1821. 1821 }
  1822. 1822
  1823. 1823 apiWriter.print(")");
  1824. 1824 }
  1825. 1825
  1826. 1826 static void writeParametersDexApi(PrintStream apiWriter, MethodInfo method,
  1827. 1827 ArrayList<ParameterInfo> params) {
  1828. 1828 apiWriter.print("(");
  1829. 1829 for (ParameterInfo pi : params) {
  1830. 1830 String typeName = pi.type().dexName();
  1831. 1831 if (method.isVarArgs() && pi == params.get(params.size() - 1)) {
  1832. 1832 typeName += "[]";
  1833. 1833 }
  1834. 1834 apiWriter.print(toSlashFormat(typeName));
  1835. 1835 }
  1836. 1836 apiWriter.print(")");
  1837. 1837 }
  1838. 1838
  1839. 1839 static void writeThrowsApi(PrintStream apiWriter, ArrayList<ClassInfo> exceptions) {
  1840. 1840 // write in a canonical order
  1841. 1841 exceptions = (ArrayList<ClassInfo>) exceptions.clone();
  1842. 1842 Collections.sort(exceptions, ClassInfo.comparator);
  1843. 1843 //final int N = exceptions.length;
  1844. 1844 boolean first = true;
  1845. 1845 for (ClassInfo ex : exceptions) {
  1846. 1846 // Turn this off, b/c we need to regenrate the old xml files.
  1847. 1847 if (true || !"java.lang.RuntimeException".equals(ex.qualifiedName())
  1848. 1848 && !ex.isDerivedFrom("java.lang.RuntimeException")) {
  1849. 1849 if (first) {
  1850. 1850 apiWriter.print(" throws ");
  1851. 1851 first = false;
  1852. 1852 } else {
  1853. 1853 apiWriter.print(", ");
  1854. 1854 }
  1855. 1855 apiWriter.print(ex.qualifiedName());
  1856. 1856 }
  1857. 1857 }
  1858. 1858 }
  1859. 1859
  1860. 1860 static void writeFieldApi(PrintStream apiWriter, FieldInfo fi, String label) {
  1861. 1861 apiWriter.print(" ");
  1862. 1862 apiWriter.print(label);
  1863. 1863 apiWriter.print(" ");
  1864. 1864 apiWriter.print(fi.scope());
  1865. 1865 if (fi.isStatic()) {
  1866. 1866 apiWriter.print(" static");
  1867. 1867 }
  1868. 1868 if (fi.isFinal()) {
  1869. 1869 apiWriter.print(" final");
  1870. 1870 }
  1871. 1871 if (fi.isDeprecated()) {
  1872. 1872 apiWriter.print(" deprecated");
  1873. 1873 }
  1874. 1874 if (fi.isTransient()) {
  1875. 1875 apiWriter.print(" transient");
  1876. 1876 }
  1877. 1877 if (fi.isVolatile()) {
  1878. 1878 apiWriter.print(" volatile");
  1879. 1879 }
  1880. 1880
  1881. 1881 apiWriter.print(" ");
  1882. 1882 apiWriter.print(fi.type().fullName(fi.typeVariables()));
  1883. 1883
  1884. 1884 apiWriter.print(" ");
  1885. 1885 apiWriter.print(fi.name());
  1886. 1886
  1887. 1887 Object val = null;
  1888. 1888 if (fi.isConstant() && fieldIsInitialized(fi)) {
  1889. 1889 apiWriter.print(" = ");
  1890. 1890 apiWriter.print(fi.constantLiteralValue());
  1891. 1891 val = fi.constantValue();
  1892. 1892 }
  1893. 1893
  1894. 1894 apiWriter.print(";");
  1895. 1895
  1896. 1896 if (val != null) {
  1897. 1897 if (val instanceof Integer && "char".equals(fi.type().qualifiedTypeName())) {
  1898. 1898 apiWriter.format(" // 0x%04x '%s'", val,
  1899. 1899 FieldInfo.javaEscapeString("" + ((char)((Integer)val).intValue())));
  1900. 1900 } else if (val instanceof Byte || val instanceof Short || val instanceof Integer) {
  1901. 1901 apiWriter.format(" // 0x%x", val);
  1902. 1902 } else if (val instanceof Long) {
  1903. 1903 apiWriter.format(" // 0x%xL", val);
  1904. 1904 }
  1905. 1905 }
  1906. 1906
  1907. 1907 apiWriter.print("\n");
  1908. 1908 }
  1909. 1909
  1910. 1910 static void writeFieldDexApi(PrintStream apiWriter, ClassInfo cl, FieldInfo fi) {
  1911. 1911 apiWriter.print(toSlashFormat(cl.qualifiedName()));
  1912. 1912 apiWriter.print("->");
  1913. 1913 apiWriter.print(fi.name());
  1914. 1914 apiWriter.print(":");
  1915. 1915 apiWriter.print(toSlashFormat(fi.type().dexName()));
  1916. 1916 apiWriter.print("\n");
  1917. 1917 }
  1918. 1918
  1919. 1919 static void writeKeepList(PrintStream keepListWriter,
  1920. 1920 HashMap<PackageInfo, List<ClassInfo>> allClasses, HashSet<ClassInfo> notStrippable) {
  1921. 1921 // extract the set of packages, sort them by name, and write them out in that order
  1922. 1922 Set<PackageInfo> allClassKeys = allClasses.keySet();
  1923. 1923 PackageInfo[] allPackages = allClassKeys.toArray(new PackageInfo[allClassKeys.size()]);
  1924. 1924 Arrays.sort(allPackages, PackageInfo.comparator);
  1925. 1925
  1926. 1926 for (PackageInfo pack : allPackages) {
  1927. 1927 writePackageKeepList(keepListWriter, pack, allClasses.get(pack), notStrippable);
  1928. 1928 }
  1929. 1929 }
  1930. 1930
  1931. 1931 static void writePackageKeepList(PrintStream keepListWriter, PackageInfo pack,
  1932. 1932 Collection<ClassInfo> classList, HashSet<ClassInfo> notStrippable) {
  1933. 1933 // Work around the bogus "Array" class we invent for
  1934. 1934 // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
  1935. 1935 if (pack.name().equals(PackageInfo.DEFAULT_PACKAGE)) {
  1936. 1936 return;
  1937. 1937 }
  1938. 1938
  1939. 1939 ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
  1940. 1940 Arrays.sort(classes, ClassInfo.comparator);
  1941. 1941 for (ClassInfo cl : classes) {
  1942. 1942 writeClassKeepList(keepListWriter, cl, notStrippable);
  1943. 1943 }
  1944. 1944 }
  1945. 1945
  1946. 1946 static void writeClassKeepList(PrintStream keepListWriter, ClassInfo cl,
  1947. 1947 HashSet<ClassInfo> notStrippable) {
  1948. 1948 keepListWriter.print("-keep class ");
  1949. 1949 keepListWriter.print(to$Class(cl.qualifiedName()));
  1950. 1950
  1951. 1951 keepListWriter.print(" {\n");
  1952. 1952
  1953. 1953 ArrayList<MethodInfo> constructors = cl.constructors();
  1954. 1954 Collections.sort(constructors, MethodInfo.comparator);
  1955. 1955 for (MethodInfo mi : constructors) {
  1956. 1956 writeConstructorKeepList(keepListWriter, mi);
  1957. 1957 }
  1958. 1958
  1959. 1959 keepListWriter.print("\n");
  1960. 1960
  1961. 1961 ArrayList<MethodInfo> methods = cl.allSelfMethods();
  1962. 1962 Collections.sort(methods, MethodInfo.comparator);
  1963. 1963 for (MethodInfo mi : methods) {
  1964. 1964 // allSelfMethods is the non-hidden and visible methods. See Doclava.checkLevel.
  1965. 1965 writeMethodKeepList(keepListWriter, mi);
  1966. 1966 }
  1967. 1967
  1968. 1968 keepListWriter.print("\n");
  1969. 1969
  1970. 1970 ArrayList<FieldInfo> enums = cl.enumConstants();
  1971. 1971 Collections.sort(enums, FieldInfo.comparator);
  1972. 1972 for (FieldInfo fi : enums) {
  1973. 1973 writeFieldKeepList(keepListWriter, fi);
  1974. 1974 }
  1975. 1975
  1976. 1976 keepListWriter.print("\n");
  1977. 1977
  1978. 1978 ArrayList<FieldInfo> fields = cl.selfFields();
  1979. 1979 Collections.sort(fields, FieldInfo.comparator);
  1980. 1980 for (FieldInfo fi : fields) {
  1981. 1981 writeFieldKeepList(keepListWriter, fi);
  1982. 1982 }
  1983. 1983
  1984. 1984 keepListWriter.print("}\n\n");
  1985. 1985 }
  1986. 1986
  1987. 1987 static void writeConstructorKeepList(PrintStream keepListWriter, MethodInfo mi) {
  1988. 1988 keepListWriter.print(" ");
  1989. 1989 keepListWriter.print("<init>");
  1990. 1990
  1991. 1991 writeParametersKeepList(keepListWriter, mi, mi.parameters());
  1992. 1992 keepListWriter.print(";\n");
  1993. 1993 }
  1994. 1994
  1995. 1995 static void writeMethodKeepList(PrintStream keepListWriter, MethodInfo mi) {
  1996. 1996 keepListWriter.print(" ");
  1997. 1997 keepListWriter.print(mi.scope());
  1998. 1998 if (mi.isStatic()) {
  1999. 1999 keepListWriter.print(" static");
  2000. 2000 }
  2001. 2001 if (mi.isAbstract()) {
  2002. 2002 keepListWriter.print(" abstract");
  2003. 2003 }
  2004. 2004 if (mi.isSynchronized()) {
  2005. 2005 keepListWriter.print(" synchronized");
  2006. 2006 }
  2007. 2007 keepListWriter.print(" ");
  2008. 2008 if (mi.returnType() == null) {
  2009. 2009 keepListWriter.print("void");
  2010. 2010 } else {
  2011. 2011 keepListWriter.print(getCleanTypeName(mi.returnType()));
  2012. 2012 }
  2013. 2013 keepListWriter.print(" ");
  2014. 2014 keepListWriter.print(mi.name());
  2015. 2015
  2016. 2016 writeParametersKeepList(keepListWriter, mi, mi.parameters());
  2017. 2017
  2018. 2018 keepListWriter.print(";\n");
  2019. 2019 }
  2020. 2020
  2021. 2021 static void writeParametersKeepList(PrintStream keepListWriter, MethodInfo method,
  2022. 2022 ArrayList<ParameterInfo> params) {
  2023. 2023 keepListWriter.print("(");
  2024. 2024
  2025. 2025 for (ParameterInfo pi : params) {
  2026. 2026 if (pi != params.get(0)) {
  2027. 2027 keepListWriter.print(", ");
  2028. 2028 }
  2029. 2029 keepListWriter.print(getCleanTypeName(pi.type()));
  2030. 2030 }
  2031. 2031
  2032. 2032 keepListWriter.print(")");
  2033. 2033 }
  2034. 2034
  2035. 2035 static void writeFieldKeepList(PrintStream keepListWriter, FieldInfo fi) {
  2036. 2036 keepListWriter.print(" ");
  2037. 2037 keepListWriter.print(fi.scope());
  2038. 2038 if (fi.isStatic()) {
  2039. 2039 keepListWriter.print(" static");
  2040. 2040 }
  2041. 2041 if (fi.isTransient()) {
  2042. 2042 keepListWriter.print(" transient");
  2043. 2043 }
  2044. 2044 if (fi.isVolatile()) {
  2045. 2045 keepListWriter.print(" volatile");
  2046. 2046 }
  2047. 2047
  2048. 2048 keepListWriter.print(" ");
  2049. 2049 keepListWriter.print(getCleanTypeName(fi.type()));
  2050. 2050
  2051. 2051 keepListWriter.print(" ");
  2052. 2052 keepListWriter.print(fi.name());
  2053. 2053
  2054. 2054 keepListWriter.print(";\n");
  2055. 2055 }
  2056. 2056
  2057. 2057 static String fullParameterTypeName(MethodInfo method, TypeInfo type, boolean isLast) {
  2058. 2058 String fullTypeName = type.fullName(method.typeVariables());
  2059. 2059 if (isLast && method.isVarArgs()) {
  2060. 2060 // TODO: note that this does not attempt to handle hypothetical
  2061. 2061 // vararg methods whose last parameter is a list of arrays, e.g.
  2062. 2062 // "Object[]...".
  2063. 2063 fullTypeName = type.fullNameNoDimension(method.typeVariables()) + "...";
  2064. 2064 }
  2065. 2065 return fullTypeName;
  2066. 2066 }
  2067. 2067
  2068. 2068 static String to$Class(String name) {
  2069. 2069 int pos = 0;
  2070. 2070 while ((pos = name.indexOf('.', pos)) > 0) {
  2071. 2071 String n = name.substring(0, pos);
  2072. 2072 if (Converter.obtainClass(n) != null) {
  2073. 2073 return n + (name.substring(pos).replace('.', '$'));
  2074. 2074 }
  2075. 2075 pos = pos + 1;
  2076. 2076 }
  2077. 2077 return name;
  2078. 2078 }
  2079. 2079
  2080. 2080 static String toSlashFormat(String name) {
  2081. 2081 String dimension = "";
  2082. 2082 while (name.endsWith("[]")) {
  2083. 2083 dimension += "[";
  2084. 2084 name = name.substring(0, name.length() - 2);
  2085. 2085 }
  2086. 2086
  2087. 2087 final String base;
  2088. 2088 if (name.equals("void")) {
  2089. 2089 base = "V";
  2090. 2090 } else if (name.equals("byte")) {
  2091. 2091 base = "B";
  2092. 2092 } else if (name.equals("boolean")) {
  2093. 2093 base = "Z";
  2094. 2094 } else if (name.equals("char")) {
  2095. 2095 base = "C";
  2096. 2096 } else if (name.equals("short")) {
  2097. 2097 base = "S";
  2098. 2098 } else if (name.equals("int")) {
  2099. 2099 base = "I";
  2100. 2100 } else if (name.equals("long")) {
  2101. 2101 base = "J";
  2102. 2102 } else if (name.equals("float")) {
  2103. 2103 base = "F";
  2104. 2104 } else if (name.equals("double")) {
  2105. 2105 base = "D";
  2106. 2106 } else {
  2107. 2107 base = "L" + to$Class(name).replace(".", "/") + ";";
  2108. 2108 }
  2109. 2109
  2110. 2110 return dimension + base;
  2111. 2111 }
  2112. 2112
  2113. 2113 static String getCleanTypeName(TypeInfo t) {
  2114. 2114 return t.isPrimitive() ? t.simpleTypeName() + t.dimension() :
  2115. 2115 to$Class(t.asClassInfo().qualifiedName() + t.dimension());
  2116. 2116 }
  2117. 2117 }

android系统源码编译报错问题分析处理--持续更新的更多相关文章

  1. [odroid-pc] ubuntu12.04 64bit Android4.0.3 源码编译报错及解决的方法

    第一个错误:         host Executable: cmu2nuance (out/host/linux-x86/obj/EXECUTABLES/cmu2nuance_intermedia ...

  2. 【转】编译Android系统源码和内核源码

    原文网址:http://blog.csdn.net/jiangwei0910410003/article/details/37988637 好长时间没有写blog了,之所以没有写,主要还是工作上的事, ...

  3. FW 编译Android系统源码和内核源码

    编译Android系统源码和内核源码 分类: Android2014-07-21 20:58 7287人阅读 评论(28) 收藏 举报 好长时间没有写blog了,之所以没有写,主要还是工作上的事,发现 ...

  4. 编译Android系统源码和内核源码

    [日期:2016-01-11] 来源:Linux社区  作者:jiangwei [字体:大 中 小]     把我之前编译Android系统源码和内核源码的过程记录一下,因为这个过程真的是受益匪浅,看 ...

  5. 【流媒体开发】VLC Media Player - Android 平台源码编译 与 二次开发详解 (提供详细800M下载好的编译源码及eclipse可调试播放器源码下载)

    作者 : 韩曙亮  博客地址 : http://blog.csdn.net/shulianghan/article/details/42707293 转载请注明出处 : http://blog.csd ...

  6. Android FrameWork 学习之Android 系统源码调试

    这是很久以前访问掘金的时候 无意间看到的一个关于Android的文章,作者更细心,分阶段的将学习步骤记录在自己博客中,我觉得很有用,想作为分享同时也是留下自己知识的一些欠缺收藏起来,今后做项目的时候会 ...

  7. 【安卓本卓】Android系统源码篇之(一)源码获取、源码目录结构及源码阅读工具简介

    前言        古人常说,“熟读唐诗三百首,不会作诗也会吟”,说明了大量阅读诗歌名篇对学习作诗有非常大的帮助.做开发也一样,Android源码是全世界最优秀的Android工程师编写的代码,也是A ...

  8. 如何阅读Android系统源码-收藏必备

    对于任何一个对Android开发感兴趣的人而言,对于android系统的学习必不可少.而学习系统最佳的方法就如linus所言:"RTFSC"(Read The Fucking So ...

  9. 将Android系统源码导入Android studio的方法

    Android源码目录结构如下: |-- Makefile|-- abi (applicationbinary interface,应用程序二进制接口,生成libgabi++.so相关库文件)|-- ...

  10. Android系统源码目录

    Android系统源码目录 我们要先了解Android系统源码目录,为后期源码学习打下基础.关于源码的阅读,你可以访问http://androidxref.com/来阅读系统源码.当然,最好是将源码下 ...

随机推荐

  1. JZOJ 3889

    \(\text{Problem}\) 小H是个善于思考的学生,她正在思考一个有关序列的问题. 她的面前浮现出了一个长度为 \(n\) 的序列 \({ai}\),她想找出两个非空的集合 \(S.T\). ...

  2. 通过Rsync实现文件远程备份

    转载:博客园 https://www.cnblogs.com/huligong1234/p/13513395.html

  3. 钓鱼攻击之:OFFICE 宏后门文件钓鱼

    钓鱼攻击之:OFFICE 宏后门文件钓鱼 目录 钓鱼攻击之:OFFICE 宏后门文件钓鱼 1 宏病毒介绍 1.1 Word 宏 1.2 Excel 4.0宏 2 生成 Word 宏后门 3 利用DOC ...

  4. PostgreSQL cache lookup failed for type XXXX 错误

    一.错误信息 执行 pg_dump 命令备份,提示 cache lookup failed for type- 错误. 二.错误分析 根据上面日志中的提示信息,可以确定 222222 这个 ID 号, ...

  5. torch.nn.Embedding使用详解

    torch.nn.Embedding: 随机初始化词向量,词向量值在正态分布N(0,1)中随机取值.输入:torch.nn.Embedding(num_embeddings, – 词典的大小尺寸,比如 ...

  6. (五) Mysql 之锁详细篇

    一.锁的分类1.范围:全局锁.表级锁.行级锁2.功能分类:共享锁.排它锁 二.数据库的全局锁 加锁:mysql> flush tables with read lock; 释放锁:mysql&g ...

  7. vue模板三目运算判断报错

    问题: 关于vue三目运算符提示报错 1.三目运算符等于判断 {{ a==b ? '是' : '否'}} 2.其他三目运算符 <代表小于号(<) >代表大于符号(>) ≤表示小 ...

  8. linux 操作命令大全

    mysql 授权远程访问 1.进入cd /usr/local/mysql/bin 下执行 ./mysql -uroot -pInfosec@2020  (-p后面是数据库密码) 2.use mysql ...

  9. 两步解决php超时问题

    tp的报错很模糊,需要自己判断是不是超时问题 首先给Apache的配置文件httpd.conf添加几行: <IfModule mod_fcgid.c> FcgidProcessLifeTi ...

  10. 查电脑并修改IP地址,你晓得吗?

    查电脑并修改IP地址,你晓得吗?   好记性不如烂笔头,古人的话,浅显却好有深意,越品越有味道.   每次都会忘记怎么查电脑IP,那么今天就写下来吧! 方法一:通过命令行查询IP地址   快捷键Win ...