16
16
17
17
package com .google .googlejavaformat .java ;
18
18
19
+ import static com .google .common .base .Preconditions .checkState ;
20
+ import static com .google .common .collect .Iterables .getLast ;
21
+
19
22
import com .google .common .collect .ImmutableList ;
20
23
import com .google .common .collect .Ordering ;
21
24
import com .google .common .collect .Range ;
26
29
import com .sun .tools .javac .parser .Tokens .TokenKind ;
27
30
import java .util .ArrayList ;
28
31
import java .util .Collection ;
29
- import java .util .Collections ;
30
32
import java .util .Iterator ;
31
33
import java .util .List ;
32
34
import java .util .Map ;
33
35
import java .util .Map .Entry ;
34
36
import javax .lang .model .element .Modifier ;
37
+ import org .jspecify .annotations .Nullable ;
35
38
36
39
/** Fixes sequences of modifiers to be in JLS order. */
37
40
final class ModifierOrderer {
@@ -42,6 +45,71 @@ static JavaInput reorderModifiers(String text) throws FormatterException {
42
45
new JavaInput (text ), ImmutableList .of (Range .closedOpen (0 , text .length ())));
43
46
}
44
47
48
+ /**
49
+ * A class that contains the tokens corresponding to a modifier. This is usually a single token
50
+ * (e.g. for {@code public}), but may be multiple tokens for modifiers containing {@code -} (e.g.
51
+ * {@code non-sealed}).
52
+ */
53
+ static class ModifierTokens implements Comparable <ModifierTokens > {
54
+ private final ImmutableList <Token > tokens ;
55
+ private final Modifier modifier ;
56
+
57
+ static ModifierTokens create (ImmutableList <Token > tokens ) {
58
+ return new ModifierTokens (tokens , asModifier (tokens ));
59
+ }
60
+
61
+ static ModifierTokens empty () {
62
+ return new ModifierTokens (ImmutableList .of (), null );
63
+ }
64
+
65
+ ModifierTokens (ImmutableList <Token > tokens , Modifier modifier ) {
66
+ this .tokens = tokens ;
67
+ this .modifier = modifier ;
68
+ }
69
+
70
+ boolean isEmpty () {
71
+ return tokens .isEmpty () || modifier == null ;
72
+ }
73
+
74
+ Modifier modifier () {
75
+ return modifier ;
76
+ }
77
+
78
+ ImmutableList <Token > tokens () {
79
+ return tokens ;
80
+ }
81
+
82
+ private Token first () {
83
+ return tokens .get (0 );
84
+ }
85
+
86
+ private Token last () {
87
+ return getLast (tokens );
88
+ }
89
+
90
+ int startPosition () {
91
+ return first ().getTok ().getPosition ();
92
+ }
93
+
94
+ int endPosition () {
95
+ return last ().getTok ().getPosition () + last ().getTok ().getText ().length ();
96
+ }
97
+
98
+ ImmutableList <? extends Tok > getToksBefore () {
99
+ return first ().getToksBefore ();
100
+ }
101
+
102
+ ImmutableList <? extends Tok > getToksAfter () {
103
+ return last ().getToksAfter ();
104
+ }
105
+
106
+ @ Override
107
+ public int compareTo (ModifierTokens o ) {
108
+ checkState (!isEmpty ()); // empty ModifierTokens are filtered out prior to sorting
109
+ return modifier .compareTo (o .modifier );
110
+ }
111
+ }
112
+
45
113
/**
46
114
* Reorders all modifiers in the given text and within the given character ranges to be in JLS
47
115
* order.
@@ -57,43 +125,37 @@ static JavaInput reorderModifiers(JavaInput javaInput, Collection<Range<Integer>
57
125
Iterator <? extends Token > it = javaInput .getTokens ().iterator ();
58
126
TreeRangeMap <Integer , String > replacements = TreeRangeMap .create ();
59
127
while (it .hasNext ()) {
60
- Token token = it .next ();
61
- if (!tokenRanges .contains (token .getTok ().getIndex ())) {
62
- continue ;
63
- }
64
- Modifier mod = asModifier (token );
65
- if (mod == null ) {
128
+ ModifierTokens tokens = getModifierTokens (it );
129
+ if (tokens .isEmpty ()
130
+ || !tokens .tokens ().stream ()
131
+ .allMatch (token -> tokenRanges .contains (token .getTok ().getIndex ()))) {
66
132
continue ;
67
133
}
68
134
69
- List <Token > modifierTokens = new ArrayList <>();
70
- List <Modifier > mods = new ArrayList <>();
135
+ List <ModifierTokens > modifierTokens = new ArrayList <>();
71
136
72
- int begin = token .getTok ().getPosition ();
73
- mods .add (mod );
74
- modifierTokens .add (token );
137
+ int begin = tokens .startPosition ();
138
+ modifierTokens .add (tokens );
75
139
76
140
int end = -1 ;
77
141
while (it .hasNext ()) {
78
- token = it .next ();
79
- mod = asModifier (token );
80
- if (mod == null ) {
142
+ tokens = getModifierTokens (it );
143
+ if (tokens .isEmpty ()) {
81
144
break ;
82
145
}
83
- mods .add (mod );
84
- modifierTokens .add (token );
85
- end = token .getTok ().getPosition () + token .getTok ().length ();
146
+ modifierTokens .add (tokens );
147
+ end = tokens .endPosition ();
86
148
}
87
149
88
- if (!Ordering .natural ().isOrdered (mods )) {
89
- Collections . sort ( mods );
150
+ if (!Ordering .natural ().isOrdered (modifierTokens )) {
151
+ List < ModifierTokens > sorted = Ordering . natural (). sortedCopy ( modifierTokens );
90
152
StringBuilder replacement = new StringBuilder ();
91
- for (int i = 0 ; i < mods .size (); i ++) {
153
+ for (int i = 0 ; i < sorted .size (); i ++) {
92
154
if (i > 0 ) {
93
155
addTrivia (replacement , modifierTokens .get (i ).getToksBefore ());
94
156
}
95
- replacement .append (mods .get (i ));
96
- if (i < (modifierTokens .size () - 1 )) {
157
+ replacement .append (sorted .get (i ). modifier ( ));
158
+ if (i < (sorted .size () - 1 )) {
97
159
addTrivia (replacement , modifierTokens .get (i ).getToksAfter ());
98
160
}
99
161
}
@@ -109,11 +171,41 @@ private static void addTrivia(StringBuilder replacement, ImmutableList<? extends
109
171
}
110
172
}
111
173
174
+ private static @ Nullable ModifierTokens getModifierTokens (Iterator <? extends Token > it ) {
175
+ Token token = it .next ();
176
+ ImmutableList .Builder <Token > result = ImmutableList .builder ();
177
+ result .add (token );
178
+ if (!token .getTok ().getText ().equals ("non" )) {
179
+ return ModifierTokens .create (result .build ());
180
+ }
181
+ if (!it .hasNext ()) {
182
+ return ModifierTokens .empty ();
183
+ }
184
+ Token dash = it .next ();
185
+ result .add (dash );
186
+ if (!dash .getTok ().getText ().equals ("-" ) || !it .hasNext ()) {
187
+ return ModifierTokens .empty ();
188
+ }
189
+ result .add (it .next ());
190
+ return ModifierTokens .create (result .build ());
191
+ }
192
+
193
+ private static @ Nullable Modifier asModifier (ImmutableList <Token > tokens ) {
194
+ if (tokens .size () == 1 ) {
195
+ return asModifier (tokens .get (0 ));
196
+ }
197
+ Modifier modifier = asModifier (getLast (tokens ));
198
+ if (modifier == null ) {
199
+ return null ;
200
+ }
201
+ return Modifier .valueOf ("NON_" + modifier .name ());
202
+ }
203
+
112
204
/**
113
205
* Returns the given token as a {@link javax.lang.model.element.Modifier}, or {@code null} if it
114
206
* is not a modifier.
115
207
*/
116
- private static Modifier asModifier (Token token ) {
208
+ private static @ Nullable Modifier asModifier (Token token ) {
117
209
TokenKind kind = ((JavaInput .Tok ) token .getTok ()).kind ();
118
210
if (kind != null ) {
119
211
switch (kind ) {
@@ -145,8 +237,6 @@ private static Modifier asModifier(Token token) {
145
237
}
146
238
}
147
239
switch (token .getTok ().getText ()) {
148
- case "non-sealed" :
149
- return Modifier .valueOf ("NON_SEALED" );
150
240
case "sealed" :
151
241
return Modifier .valueOf ("SEALED" );
152
242
default :
0 commit comments