25
25
import java .io .InputStream ;
26
26
import java .io .InputStreamReader ;
27
27
import java .util .ArrayList ;
28
+ import java .util .Deque ;
28
29
import java .util .HashMap ;
30
+ import java .util .LinkedList ;
29
31
import java .util .List ;
30
32
import java .util .Map ;
31
33
import java .util .regex .Matcher ;
41
43
import de .siegmar .fastcsv .reader .CsvContainer ;
42
44
import de .siegmar .fastcsv .reader .CsvReader ;
43
45
import de .siegmar .fastcsv .reader .CsvRow ;
46
+ import org .apache .commons .lang3 .tuple .Pair ;
44
47
45
48
public class McpNames {
46
49
private static final String NEWLINE = System .getProperty ("line.separator" );
47
50
private static final Pattern SRG_FINDER = Pattern .compile ("func_[0-9]+_[a-zA-Z_]+|field_[0-9]+_[a-zA-Z_]+|p_[\\ w]+_\\ d+_\\ b" );
48
51
private static final Pattern METHOD_JAVADOC_PATTERN = Pattern .compile ("^(?<indent>(?: {3})+|\\ t+)(?!return)(?:\\ w+\\ s+)*(?<generic><[\\ w\\ W]*>\\ s+)?(?<return>\\ w+[\\ w$.]*(?:<[\\ w\\ W]*>)?[\\ [\\ ]]*)\\ s+(?<name>func_[0-9]+_[a-zA-Z_]+)\\ (" );
49
52
private static final Pattern FIELD_JAVADOC_PATTERN = Pattern .compile ("^(?<indent>(?: {3})+|\\ t+)(?!return)(?:\\ w+\\ s+)*(?:\\ w+[\\ w$.]*(?:<[\\ w\\ W]*>)?[\\ [\\ ]]*)\\ s+(?<name>field_[0-9]+_[a-zA-Z_]+) *(?:=|;)" );
53
+ private static final Pattern CLASS_JAVADOC_PATTERN = Pattern .compile ("^(?<indent>(?: )*|\\ t*)([\\ w|@]*\\ s)*(class|interface|@interface|enum) (?<name>[\\ w]+)" );
54
+ private static final Pattern CLOSING_CURLY_BRACE = Pattern .compile ("^(?<indent>(?: )*|\\ t*)}" );
55
+ private static final Pattern PACKAGE_DECL = Pattern .compile ("^[\\ s]*package(\\ s)*(?<name>[\\ w|.]+);$" );
50
56
51
57
public static McpNames load (File data ) throws IOException {
52
58
Map <String , String > names = new HashMap <>();
@@ -84,9 +90,15 @@ private McpNames(String hash, Map<String, String> names, Map<String, String> doc
84
90
85
91
public String rename (InputStream stream , boolean javadocs ) throws IOException {
86
92
List <String > lines = new ArrayList <>();
93
+ Deque <Pair <String , Integer >> innerClasses = new LinkedList <>(); //pair of inner class name & indentation
94
+ String _package = "" ; //default package
87
95
for (String line : CharStreams .readLines (new InputStreamReader (stream ))) {
96
+ Matcher m = PACKAGE_DECL .matcher (line );
97
+ if (m .find ())
98
+ _package = m .group ("name" ) + "." ;
99
+
88
100
if (javadocs )
89
- injectJavadoc (lines , line );
101
+ injectJavadoc (lines , line , _package , innerClasses );
90
102
lines .add (replaceInLine (line ));
91
103
}
92
104
return Joiner .on (NEWLINE ).join (lines );
@@ -99,13 +111,12 @@ public String rename(String entry) {
99
111
/**
100
112
* Injects a javadoc into the given list of lines, if the given line is a
101
113
* method or field declaration.
102
- *
103
114
* @param lines The current file content (to be modified by this method)
104
115
* @param line The line that was just read (will not be in the list)
105
- * @param methodFunc A function that takes a method SRG id and returns its javadoc
106
- * @param fieldFunc A function that takes a field SRG id and returns its javadoc
116
+ * @param _package the name of the package this file is declared to be in, in com.example format;
117
+ * @param innerClasses current position in inner class
107
118
*/
108
- private void injectJavadoc (List <String > lines , String line ) {
119
+ private void injectJavadoc (List <String > lines , String line , String _package , Deque < Pair < String , Integer >> innerClasses ) {
109
120
// methods
110
121
Matcher matcher = METHOD_JAVADOC_PATTERN .matcher (line );
111
122
if (matcher .find ()) {
@@ -123,6 +134,36 @@ private void injectJavadoc(List<String> lines, String line) {
123
134
String javadoc = docs .get (matcher .group ("name" ));
124
135
if (!Strings .isNullOrEmpty (javadoc ))
125
136
insertAboveAnnotations (lines , JavadocAdder .buildJavadoc (matcher .group ("indent" ), javadoc , false ));
137
+
138
+ return ;
139
+ }
140
+
141
+ //classes
142
+ matcher = CLASS_JAVADOC_PATTERN .matcher (line );
143
+ if (matcher .find ()) {
144
+ //we maintain a stack of the current (inner) class in com.example.ClassName$Inner format (along with indentation)
145
+ //if the stack is not empty we are entering a new inner class
146
+ String currentClass = (innerClasses .isEmpty () ? _package : innerClasses .peek ().getLeft () + "$" ) + matcher .group ("name" );
147
+ innerClasses .push (Pair .of (currentClass , matcher .group ("indent" ).length ()));
148
+ String javadoc = docs .get (currentClass );
149
+ if (!Strings .isNullOrEmpty (javadoc )) {
150
+ insertAboveAnnotations (lines , JavadocAdder .buildJavadoc (matcher .group ("indent" ), javadoc , true ));
151
+ }
152
+
153
+ return ;
154
+ }
155
+
156
+ //detect curly braces for inner class stacking/end identification
157
+ matcher = CLOSING_CURLY_BRACE .matcher (line );
158
+ if (matcher .find ()){
159
+ if (!innerClasses .isEmpty ()) {
160
+ int len = matcher .group ("indent" ).length ();
161
+ if (len == innerClasses .peek ().getRight ()) {
162
+ innerClasses .pop ();
163
+ } else if (len < innerClasses .peek ().getRight ()) {
164
+ throw new IllegalArgumentException ("Failed to properly track class blocks around class " + innerClasses .peek ().getLeft () + ":" + (lines .size () + 1 ));
165
+ }
166
+ }
126
167
}
127
168
}
128
169
0 commit comments