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