View Javadoc
1   package org.djunits.cleanup;
2   
3   import java.io.File;
4   import java.io.FileInputStream;
5   import java.io.IOException;
6   import java.net.URISyntaxException;
7   import java.nio.charset.StandardCharsets;
8   import java.nio.file.Files;
9   import java.nio.file.Paths;
10  import java.util.List;
11  
12  import com.github.javaparser.StaticJavaParser;
13  import com.github.javaparser.ast.CompilationUnit;
14  import com.github.javaparser.ast.body.CallableDeclaration;
15  import com.github.javaparser.ast.body.ConstructorDeclaration;
16  import com.github.javaparser.ast.body.MethodDeclaration;
17  import com.github.javaparser.ast.body.Parameter;
18  import com.github.javaparser.ast.comments.JavadocComment;
19  import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
20  
21  /**
22   * Utility to add or update the type foe each parameter in the javadoc of all java files in /src/main/java in all or in selected
23   * projects in the workspace. Run this utility only from Eclipse!<br>
24   * <br>
25   * Copyright (c) 2003-2020 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
26   * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
27   * source code and binary code of this software is proprietary information of Delft University of Technology.
28   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
29   */
30  public class ParamComments
31  {
32      /** the lines of the file. */
33      private List<String> lines;
34  
35      /** file changed? */
36      private boolean changed;
37  
38      /**
39       * @param args String[]; none
40       * @throws IOException on I/O error
41       * @throws URISyntaxException on I/O error
42       */
43      public static void main(final String[] args) throws IOException, URISyntaxException
44      {
45          new ParamComments();
46      }
47  
48      /**
49       * @throws IOException on I/O error
50       * @throws URISyntaxException on I/O error
51       */
52      public ParamComments() throws IOException, URISyntaxException
53      {
54          File classFolder = new File(ParamComments.class.getResource("/").toURI());
55          File workspaceFolder = classFolder.getParentFile().getParentFile().getParentFile();
56          for (File projectFolder : workspaceFolder.listFiles())
57          {
58              if (projectFolder.isDirectory() && projectFolder.getName().startsWith("djunits")
59                      && new File(projectFolder, "src/main/java").exists())
60              {
61                  File sourcePathFile = new File(projectFolder, "src/main/java");
62                  for (File srcFolder : sourcePathFile.listFiles())
63                  {
64                      processDirOrFile(srcFolder);
65                  }
66              }
67          }
68      }
69  
70      /**
71       * @param srcFolder File; folder to look for subfolders and/or java files
72       * @throws IOException on i/o error
73       */
74      private void processDirOrFile(final File srcFolder) throws IOException
75      {
76          if (srcFolder.isDirectory())
77          {
78              for (File subFile : srcFolder.listFiles())
79              {
80                  if (subFile.isDirectory())
81                  {
82                      processDirOrFile(subFile);
83                  }
84                  else if (subFile.getName().endsWith(".java") && !subFile.getName().startsWith("package-info"))
85                  {
86                      processJavaFile(subFile);
87                  }
88              }
89          }
90      }
91  
92      /**
93       * @param javaFile File; java file to process
94       * @throws IOException on error
95       */
96      private void processJavaFile(final File javaFile) throws IOException
97      {
98          System.out.println("\n" + javaFile.toURI().getPath());
99          this.changed = false;
100         this.lines = Files.readAllLines(Paths.get(javaFile.toURI()), StandardCharsets.UTF_8);
101         FileInputStream in = new FileInputStream(javaFile.toURI().getPath());
102         CompilationUnit cu = StaticJavaParser.parse(in);
103         cu.accept(new CodeVisitor(this), null);
104         if (this.changed)
105         {
106             Files.write(Paths.get(javaFile.toURI()), this.lines);
107             System.out.println("CHANGED AND WRITTEN: " + javaFile.toString());
108         }
109     }
110 
111     /**
112      * @return changed
113      */
114     public final boolean isChanged()
115     {
116         return this.changed;
117     }
118 
119     /**
120      * @param changed boolean; set changed
121      */
122     public final void setChanged(final boolean changed)
123     {
124         this.changed = changed;
125     }
126 
127     /**
128      * @return lines
129      */
130     public final List<String> getLines()
131     {
132         return this.lines;
133     }
134 
135     /**
136      * Simple visitor implementation for visiting MethodDeclaration and ConstructorDeclaration nodes.
137      */
138     protected static class CodeVisitor extends VoidVisitorAdapter<Void>
139     {
140         /** access to the lines of the file and to changed toggle. */
141         private ParamComments paramComments;
142 
143         /**
144          * Constructor of the code visitor.
145          * @param paramComments ParamComments; class to be processed
146          */
147         protected CodeVisitor(final ParamComments paramComments)
148         {
149             this.paramComments = paramComments;
150         }
151 
152         @Override
153         /**
154          * {@inheritDoc} <br>
155          * This method will be called for all constructors in this CompilationUnit, including constructors of inner classes.
156          */
157         public void visit(final ConstructorDeclaration constructorDeclaration, final Void arg)
158         {
159             System.out.println("\n------\nCONSTRUCTOR\n" + "   " + constructorDeclaration.getName() + " : "
160                     + constructorDeclaration.getDeclarationAsString());
161             processDeclaration(constructorDeclaration);
162             super.visit(constructorDeclaration, arg);
163         }
164 
165         @Override
166         /**
167          * {@inheritDoc} <br>
168          * This method will be called for all methods in this CompilationUnit, including inner class methods.
169          */
170         public void visit(final MethodDeclaration methodDeclaration, final Void arg)
171         {
172             System.out
173                     .println("\n------\n" + "   " + methodDeclaration.getName() + " : " + methodDeclaration.getTypeAsString());
174             processDeclaration(methodDeclaration);
175             super.visit(methodDeclaration, arg);
176         }
177 
178         /**
179          * Carry out the changes in the method comments or constructor comments.
180          * @param callableDeclaration CallableDeclaration&lt;?&gt;; the method declaration or constructor declaration
181          */
182         private void processDeclaration(final CallableDeclaration<?> callableDeclaration)
183         {
184             for (Parameter parameter : callableDeclaration.getParameters())
185             {
186                 System.out.println("      " + parameter.getNameAsString() + " : " + parameter.getTypeAsString()
187                         + (parameter.isVarArgs() ? "..." : ""));
188             }
189             if (callableDeclaration.getComment().isPresent())
190             {
191                 System.out.print(callableDeclaration.getComment().get());
192                 String parserComment = callableDeclaration.getComment().get().toString();
193                 if (parserComment.contains("@param"))
194                 {
195                     // see how we would rebuild the comment
196                     if (callableDeclaration.getComment().get().toJavadocComment().isPresent())
197                     {
198                         JavadocComment comment = callableDeclaration.getComment().get().toJavadocComment().get();
199                         String[] commentLines = parserComment.split("\n");
200                         for (String line : commentLines)
201                         {
202                             if (line.contains("@param") && !line.contains("@param <"))
203                             {
204                                 // which line is it in the String[] model?
205                                 int fileLine = -1;
206                                 for (int lnr = 0; lnr < commentLines.length; lnr++)
207                                 {
208                                     if (this.paramComments.getLines().get(comment.getBegin().get().line + lnr).trim()
209                                             .equals(line.trim()))
210                                     {
211                                         fileLine = comment.getBegin().get().line + lnr;
212                                     }
213                                 }
214                                 if (fileLine == -1)
215                                 {
216                                     System.out.println("COULD NOT FIND LINE FROM COMMENT IN FILE LINES...");
217                                     break;
218                                 }
219                                 line = line.replaceAll("&lt;", "<").replaceAll("&gt;", ">");
220                                 // make a line without escaped HTML-sequences
221                                 String noHtmlLine = line.replaceAll("&\\w+;", "");
222                                 // variable name after @param
223                                 int paramIndex = line.indexOf("@param");
224                                 int varEndIndex = line.indexOf(' ', paramIndex + 7) == -1 ? line.length()
225                                         : line.indexOf(' ', paramIndex + 7);
226                                 String varName = line.substring(paramIndex + 6, varEndIndex).trim();
227                                 boolean found = false;
228                                 for (Parameter parameter : callableDeclaration.getParameters())
229                                 {
230                                     if (parameter.getNameAsString().equals(varName))
231                                     {
232                                         // see if type is there with a ; at the end
233                                         String varType = "";
234                                         if (noHtmlLine.indexOf(";", varEndIndex + 1) != -1)
235                                         {
236                                             varType = noHtmlLine
237                                                     .substring(varEndIndex + 1, noHtmlLine.indexOf(';', varEndIndex + 1)).trim()
238                                                     .replaceAll(", ", ",");
239                                             String parameterType =
240                                                     parameter.getType().asString() + (parameter.isVarArgs() ? "..." : "");
241                                             // if there are spaces in the varType, we either have a type with spaces
242                                             // e.g., Type<A, B>, or we have no variable but a ; later in the line,
243                                             // e.g., @param var this is the B&eacute;zier variable. In these cases,
244                                             // we have to be super careful and not replace without warning...
245                                             if (!varType.equals(parameterType))
246                                             {
247                                                 if (varType.contains(" "))
248                                                 {
249                                                     System.out.println("NO CHANGE - SPACES IN TYPE : "
250                                                             + line.replaceAll("<", "&lt;").replaceAll(">", "&gt;").trim());
251                                                 }
252                                                 else
253                                                 {
254                                                     parameterType = parameterType.replaceAll(",", ", ");
255                                                     line = line.substring(0, varEndIndex) + " " + parameterType
256                                                             + line.substring(line.indexOf(";", varEndIndex + 1));
257                                                     line = line.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
258                                                     System.out.println("CHANGED TYPE : " + line.trim());
259                                                     this.paramComments.setChanged(true);
260                                                     this.paramComments.getLines().set(fileLine, line.replaceAll("\\n", ""));
261                                                 }
262                                             }
263                                         }
264                                         else
265                                         {
266                                             String parameterType = parameter.getType().asString()
267                                                     + (parameter.isVarArgs() ? "..." : "").replaceAll(",", ", ");
268                                             line = line.substring(0, varEndIndex) + " " + parameterType + "; "
269                                                     + line.substring(Math.min(varEndIndex + 1, line.length() - 1));
270                                             line = line.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
271                                             System.out.println("ADDED TYPE : " + line.trim());
272                                             this.paramComments.setChanged(true);
273                                             this.paramComments.getLines().set(fileLine, line.replaceAll("\\n", ""));
274                                         }
275                                         found = true;
276                                         break;
277                                     }
278                                 }
279                                 if (!found)
280                                 {
281                                     System.out.println("XXXXXXXX @param comment for " + varName
282                                             + " does not match any parameters in method");
283                                 }
284                             }
285                         }
286                     }
287                 }
288             }
289         }
290     }
291 }