1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tools.metalava
18 
19 const val COMPAT_MODE_BY_DEFAULT = true
20 
21 /**
22  * The old API generator code had a number of quirks. Initially we want to simulate these
23  * quirks to produce compatible signature files and APIs, but we want to track what these quirks
24  * are and be able to turn them off eventually. This class offers more fine grained control
25  * of these compatibility behaviors such that we can enable/disable them selectively
26  */
27 var compatibility: Compatibility = Compatibility()
28 
29 class Compatibility(
30     /** Whether compatibility is generally on */
31     val compat: Boolean = COMPAT_MODE_BY_DEFAULT
32 ) {
33 
34     /** Whether to inline fields from implemented interfaces into concrete classes */
35     var inlineInterfaceFields: Boolean = compat
36 
37     /** In signature files, use "implements" instead of "extends" for the super class of
38      * an interface */
39     var extendsForInterfaceSuperClass: Boolean = compat
40 
41     /** In signature files, refer to annotations as an "abstract class" instead of an "@interface"
42      * and implementing this interface: java.lang.annotation.Annotation */
43     var classForAnnotations: Boolean = compat
44 
45     /** Add in explicit `valueOf` and `values` methods into annotation classes  */
46     var defaultAnnotationMethods: Boolean = compat
47 
48     /** In signature files, refer to enums as "class" instead of "enum" */
49     var classForEnums: Boolean = compat
50 
51     /** Whether to use a nonstandard, compatibility modifier order instead of the Java canonical order.
52      * ("deprecated" isn't a real modifier, so in "standard" mode it's listed first, as if it was the
53      * `@Deprecated` annotation before the modifier list */
54     var nonstandardModifierOrder: Boolean = compat
55 
56     /** In signature files, skip the native modifier from the modifier lists */
57     var skipNativeModifier: Boolean = nonstandardModifierOrder
58 
59     /** In signature files, skip the strictfp modifier from the modifier lists */
60     var skipStrictFpModifier: Boolean = nonstandardModifierOrder
61 
62     /** Whether to include instance methods in annotation classes for the annotation properties */
63     var skipAnnotationInstanceMethods: Boolean = compat
64 
65     /** Include spaces after commas in type strings */
66     var spacesAfterCommas: Boolean = compat
67 
68     /** Use two spaces after type for package private elements in signature files */
69     var doubleSpaceForPackagePrivate: Boolean = compat
70 
71     /**
72      * In signature files, whether interfaces should also be described as "abstract"
73      */
74     var abstractInInterfaces: Boolean = compat
75 
76     /**
77      * In signature files, whether annotation types should also be described as "abstract"
78      */
79     var abstractInAnnotations: Boolean = compat
80 
81     /**
82      * In signature files, whether interfaces can be listed as final
83      */
84     var finalInInterfaces: Boolean = compat
85 
86     /**
87      * In this signature
88      *        public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
89      *  doclava1 would treat this as "throws Throwable" instead of "throws X". This variable turns on
90      *  this compat behavior.
91      * */
92     var useErasureInThrows: Boolean = compat
93 
94     /**
95      * Whether throws classes in methods should be filtered. This should definitely
96      * be the case, but doclava1 doesn't. Note that this only applies to signature
97      * files, not stub files.
98      */
99     var filterThrowsClasses: Boolean = !compat
100 
101     /**
102      * Include a single space in front of package private classes with no other modifiers
103      * (this doesn't align well, but is supported to make the output 100% identical to the
104      * doclava1 format
105      */
106     var extraSpaceForEmptyModifiers: Boolean = compat
107 
108     /** Format `Map<K,V>` as `Map<K, V>` */
109     var spaceAfterCommaInTypes: Boolean = compat
110 
111     /**
112      * Doclava1 sorts classes/interfaces by class name instead of qualified name
113      */
114     var sortClassesBySimpleName: Boolean = compat
115 
116     /**
117      * Doclava1 omits type parameters in interfaces (in signature files, not in stubs)
118      */
119     var omitTypeParametersInInterfaces: Boolean = compat
120 
121     /**
122      * Doclava1 sorted the methods like this:
123      *
124      *      public final class RoundingMode extends java.lang.Enum {
125      *          method public static java.math.RoundingMode valueOf(java.lang.String);
126      *          method public static java.math.RoundingMode valueOf(int);
127      *          ...
128      *
129      * Note how the two valueOf methods are out of order. With this compatibility mode,
130      * we try to perform the same sorting.
131      */
132     var sortEnumValueOfMethodFirst: Boolean = compat
133 
134     /**
135      * Whether packages should be treated as recursive for documentation. In other words,
136      * if a directory has a `packages.html` file containing a `@hide` comment, then
137      * all "sub" packages (directories below this one) will also inherit the same comment.
138      * Java packages aren't supposed to work that way, but doclava does.
139      */
140     var inheritPackageDocs: Boolean = compat
141 
142     /** Force methods named "values" in enums to be marked final. This was done by
143      * doclava1 with this comment:
144      *
145      *     Explicitly coerce 'final' state of Java6-compiled enum values() method,
146      *     to match the Java5-emitted base API description.
147      *
148      **/
149     var forceFinalInEnumValueMethods: Boolean = compat
150 
151     /** Whether signature files and stubs should contain annotations */
152     var annotationsInSignatures: Boolean = !compat
153 
154     /** Emit errors in the old API diff format */
155     var oldErrorOutputFormat: Boolean = false
156 
157     /**
158      * When a public class implementing a public interface inherits the implementation
159      * of a method in that interface from a hidden super class, the method must be
160      * included in the stubs etc (since otherwise subclasses would believe they need
161      * to implement that method and can't just inherit it). However, doclava1 does not
162      * list these methods. This flag controls this compatibility behavior.
163      * Not that this refers only to the signature files, not the stub file generation.
164      *
165      * An example is StringBuilder#setLength.
166      */
167     var skipInheritedMethods: Boolean = compat
168 
169     /**
170      * Whether to include parameter names in the signature file
171      */
172     var parameterNames: Boolean = true
173 
174     /**
175      * *Some* signatures for doclava1 wrote "<?>" as "<? extends java.lang.Object>",
176      * which is equivalent. Metalava does not do that. This flags ensures that the
177      * signature files look like the old ones for the specific methods which did this.
178      */
179     var includeExtendsObjectInWildcard = compat
180 
181     // Other examples: sometimes we sort by qualified name, sometimes by full name
182 }