• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
3  * Copyright (C) 2011, 2013-2016 The JavaParser Team.
4  *
5  * This file is part of JavaParser.
6  *
7  * JavaParser can be used either under the terms of
8  * a) the GNU Lesser General Public License as published by
9  *     the Free Software Foundation, either version 3 of the License, or
10  *     (at your option) any later version.
11  * b) the terms of the Apache License
12  *
13  * You should have received a copy of both licenses in LICENCE.LGPL and
14  * LICENCE.APACHE. Please refer to those files for details.
15  *
16  * JavaParser is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  */
21 package com.github.javaparser.ast;
22 
23 import com.github.javaparser.JavaParser;
24 import com.github.javaparser.ParseResult;
25 import com.github.javaparser.ParseStart;
26 import com.github.javaparser.TokenRange;
27 import com.github.javaparser.ast.body.AnnotationDeclaration;
28 import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
29 import com.github.javaparser.ast.body.EnumDeclaration;
30 import com.github.javaparser.ast.body.TypeDeclaration;
31 import com.github.javaparser.ast.comments.Comment;
32 import com.github.javaparser.ast.comments.JavadocComment;
33 import com.github.javaparser.ast.expr.Name;
34 import com.github.javaparser.ast.modules.ModuleDeclaration;
35 import com.github.javaparser.ast.nodeTypes.NodeWithName;
36 import com.github.javaparser.ast.observer.ObservableProperty;
37 import com.github.javaparser.ast.visitor.CloneVisitor;
38 import com.github.javaparser.ast.visitor.GenericVisitor;
39 import com.github.javaparser.ast.visitor.VoidVisitor;
40 import com.github.javaparser.metamodel.CompilationUnitMetaModel;
41 import com.github.javaparser.metamodel.InternalProperty;
42 import com.github.javaparser.metamodel.JavaParserMetaModel;
43 import com.github.javaparser.metamodel.OptionalProperty;
44 import com.github.javaparser.printer.PrettyPrinter;
45 import com.github.javaparser.utils.ClassUtils;
46 import com.github.javaparser.utils.CodeGenerationUtils;
47 import com.github.javaparser.utils.Utils;
48 import javax.annotation.Generated;
49 import java.io.IOException;
50 import java.nio.file.Files;
51 import java.nio.file.Path;
52 import java.nio.file.Paths;
53 import java.util.Arrays;
54 import java.util.EnumSet;
55 import java.util.List;
56 import java.util.Optional;
57 import java.util.function.Function;
58 import java.util.stream.Collectors;
59 import static com.github.javaparser.JavaParser.parseName;
60 import static com.github.javaparser.Providers.UTF8;
61 import static com.github.javaparser.Providers.provider;
62 import static com.github.javaparser.utils.CodeGenerationUtils.subtractPaths;
63 import static com.github.javaparser.utils.Utils.assertNotNull;
64 import com.github.javaparser.ast.Node;
65 
66 /**
67  * <p>
68  * This class represents the entire compilation unit. Each java file denotes a
69  * compilation unit.
70  * </p>
71  * A compilation unit start with an optional package declaration,
72  * followed by zero or more import declarations,
73  * followed by zero or more type declarations.
74  *
75  * @author Julio Vilmar Gesser
76  * @see PackageDeclaration
77  * @see ImportDeclaration
78  * @see TypeDeclaration
79  * @see Storage
80  */
81 public final class CompilationUnit extends Node {
82 
83     @OptionalProperty
84     private PackageDeclaration packageDeclaration;
85 
86     private NodeList<ImportDeclaration> imports;
87 
88     private NodeList<TypeDeclaration<?>> types;
89 
90     @OptionalProperty
91     private ModuleDeclaration module;
92 
93     @InternalProperty
94     private Storage storage;
95 
CompilationUnit()96     public CompilationUnit() {
97         this(null, null, new NodeList<>(), new NodeList<>(), null);
98     }
99 
CompilationUnit(String packageDeclaration)100     public CompilationUnit(String packageDeclaration) {
101         this(null, new PackageDeclaration(new Name(packageDeclaration)), new NodeList<>(), new NodeList<>(), null);
102     }
103 
104     @AllFieldsConstructor
CompilationUnit(PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module)105     public CompilationUnit(PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module) {
106         this(null, packageDeclaration, imports, types, module);
107     }
108 
109     /**
110      * This constructor is used by the parser and is considered private.
111      */
112     @Generated("com.github.javaparser.generator.core.node.MainConstructorGenerator")
CompilationUnit(TokenRange tokenRange, PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module)113     public CompilationUnit(TokenRange tokenRange, PackageDeclaration packageDeclaration, NodeList<ImportDeclaration> imports, NodeList<TypeDeclaration<?>> types, ModuleDeclaration module) {
114         super(tokenRange);
115         setPackageDeclaration(packageDeclaration);
116         setImports(imports);
117         setTypes(types);
118         setModule(module);
119         customInitialization();
120     }
121 
122     @Override
123     @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
accept(final GenericVisitor<R, A> v, final A arg)124     public <R, A> R accept(final GenericVisitor<R, A> v, final A arg) {
125         return v.visit(this, arg);
126     }
127 
128     @Override
129     @Generated("com.github.javaparser.generator.core.node.AcceptGenerator")
accept(final VoidVisitor<A> v, final A arg)130     public <A> void accept(final VoidVisitor<A> v, final A arg) {
131         v.visit(this, arg);
132     }
133 
134     /**
135      * Return a list containing all comments declared in this compilation unit.
136      * Including javadocs, line comments and block comments of all types,
137      * inner-classes and other members.<br>
138      * If there is no comment, an empty list is returned.
139      *
140      * @return list with all comments of this compilation unit.
141      * @see JavadocComment
142      * @see com.github.javaparser.ast.comments.LineComment
143      * @see com.github.javaparser.ast.comments.BlockComment
144      */
getComments()145     public List<Comment> getComments() {
146         return this.getAllContainedComments();
147     }
148 
149     /**
150      * Retrieves the list of imports declared in this compilation unit or
151      * <code>null</code> if there is no import.
152      *
153      * @return the list of imports or <code>none</code> if there is no import
154      */
155     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
getImports()156     public NodeList<ImportDeclaration> getImports() {
157         return imports;
158     }
159 
getImport(int i)160     public ImportDeclaration getImport(int i) {
161         return getImports().get(i);
162     }
163 
164     /**
165      * Retrieves the package declaration of this compilation unit.<br>
166      * If this compilation unit has no package declaration (default package),
167      * <code>Optional.none()</code> is returned.
168      *
169      * @return the package declaration or <code>none</code>
170      */
171     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
getPackageDeclaration()172     public Optional<PackageDeclaration> getPackageDeclaration() {
173         return Optional.ofNullable(packageDeclaration);
174     }
175 
176     /**
177      * Return the list of top level types declared in this compilation unit.<br>
178      * If there are no types declared, <code>none</code> is returned.
179      *
180      * @return the list of types or <code>none</code> null if there is no type
181      * @see AnnotationDeclaration
182      * @see ClassOrInterfaceDeclaration
183      * @see EnumDeclaration
184      */
185     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
getTypes()186     public NodeList<TypeDeclaration<?>> getTypes() {
187         return types;
188     }
189 
190     /**
191      * Convenience method that wraps <code>getTypes()</code>.<br>
192      * If <code>i</code> is out of bounds, throws <code>IndexOutOfBoundsException.</code>
193      *
194      * @param i the index of the type declaration to retrieve
195      */
getType(int i)196     public TypeDeclaration<?> getType(int i) {
197         return getTypes().get(i);
198     }
199 
200     /**
201      * Sets the list of imports of this compilation unit. The list is initially
202      * <code>null</code>.
203      *
204      * @param imports the list of imports
205      */
206     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
setImports(final NodeList<ImportDeclaration> imports)207     public CompilationUnit setImports(final NodeList<ImportDeclaration> imports) {
208         assertNotNull(imports);
209         if (imports == this.imports) {
210             return (CompilationUnit) this;
211         }
212         notifyPropertyChange(ObservableProperty.IMPORTS, this.imports, imports);
213         if (this.imports != null)
214             this.imports.setParentNode(null);
215         this.imports = imports;
216         setAsParentNodeOf(imports);
217         return this;
218     }
219 
setImport(int i, ImportDeclaration imports)220     public CompilationUnit setImport(int i, ImportDeclaration imports) {
221         getImports().set(i, imports);
222         return this;
223     }
224 
addImport(ImportDeclaration imports)225     public CompilationUnit addImport(ImportDeclaration imports) {
226         getImports().add(imports);
227         return this;
228     }
229 
230     /**
231      * Sets or clear the package declarations of this compilation unit.
232      *
233      * @param packageDeclaration the packageDeclaration declaration to set or <code>null</code> to default package
234      */
235     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
setPackageDeclaration(final PackageDeclaration packageDeclaration)236     public CompilationUnit setPackageDeclaration(final PackageDeclaration packageDeclaration) {
237         if (packageDeclaration == this.packageDeclaration) {
238             return (CompilationUnit) this;
239         }
240         notifyPropertyChange(ObservableProperty.PACKAGE_DECLARATION, this.packageDeclaration, packageDeclaration);
241         if (this.packageDeclaration != null)
242             this.packageDeclaration.setParentNode(null);
243         this.packageDeclaration = packageDeclaration;
244         setAsParentNodeOf(packageDeclaration);
245         return this;
246     }
247 
248     /**
249      * Sets the list of types declared in this compilation unit.
250      */
251     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
setTypes(final NodeList<TypeDeclaration<?>> types)252     public CompilationUnit setTypes(final NodeList<TypeDeclaration<?>> types) {
253         assertNotNull(types);
254         if (types == this.types) {
255             return (CompilationUnit) this;
256         }
257         notifyPropertyChange(ObservableProperty.TYPES, this.types, types);
258         if (this.types != null)
259             this.types.setParentNode(null);
260         this.types = types;
261         setAsParentNodeOf(types);
262         return this;
263     }
264 
setType(int i, TypeDeclaration<?> type)265     public CompilationUnit setType(int i, TypeDeclaration<?> type) {
266         NodeList<TypeDeclaration<?>> copy = new NodeList<>();
267         copy.addAll(getTypes());
268         getTypes().set(i, type);
269         notifyPropertyChange(ObservableProperty.TYPES, copy, types);
270         return this;
271     }
272 
addType(TypeDeclaration<?> type)273     public CompilationUnit addType(TypeDeclaration<?> type) {
274         NodeList<TypeDeclaration<?>> copy = new NodeList<>();
275         copy.addAll(getTypes());
276         getTypes().add(type);
277         notifyPropertyChange(ObservableProperty.TYPES, copy, types);
278         return this;
279     }
280 
281     /**
282      * sets the package declaration of this compilation unit
283      *
284      * @param name the name of the package
285      * @return this, the {@link CompilationUnit}
286      */
setPackageDeclaration(String name)287     public CompilationUnit setPackageDeclaration(String name) {
288         setPackageDeclaration(new PackageDeclaration(parseName(name)));
289         return this;
290     }
291 
292     /**
293      * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
294      * shorthand for {@link #addImport(String, boolean, boolean)} with name,false,false
295      *
296      * @param name the import name
297      * @return this, the {@link CompilationUnit}
298      */
addImport(String name)299     public CompilationUnit addImport(String name) {
300         return addImport(name, false, false);
301     }
302 
303     /**
304      * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
305      * shorthand for {@link #addImport(String)} with clazz.getName()
306      *
307      * @param clazz the class to import
308      * @return this, the {@link CompilationUnit}
309      * @throws RuntimeException if clazz is an anonymous or local class
310      */
addImport(Class<?> clazz)311     public CompilationUnit addImport(Class<?> clazz) {
312         if (ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.getName().startsWith("java.lang"))
313             return this;
314         else if (clazz.isMemberClass())
315             return addImport(clazz.getName().replace("$", "."));
316         else if (clazz.isArray() && !ClassUtils.isPrimitiveOrWrapper(clazz.getComponentType()) && !clazz.getComponentType().getName().startsWith("java.lang"))
317             return addImport(clazz.getComponentType().getName());
318         else if (clazz.isAnonymousClass() || clazz.isLocalClass())
319             throw new RuntimeException(clazz.getName() + " is an anonymous or local class therefore it can't be added with addImport");
320         return addImport(clazz.getName());
321     }
322 
323     /**
324      * Add an import to the list of {@link ImportDeclaration} of this compilation unit<br>
325      * <b>This method check if no import with the same name is already in the list</b>
326      *
327      * @param name the import name
328      * @param isStatic is it an "import static"
329      * @param isAsterisk does the import end with ".*"
330      * @return this, the {@link CompilationUnit}
331      */
addImport(String name, boolean isStatic, boolean isAsterisk)332     public CompilationUnit addImport(String name, boolean isStatic, boolean isAsterisk) {
333         final StringBuilder i = new StringBuilder("import ");
334         if (isStatic) {
335             i.append("static ");
336         }
337         i.append(name);
338         if (isAsterisk) {
339             i.append(".*");
340         }
341         i.append(";");
342         ImportDeclaration importDeclaration = JavaParser.parseImport(i.toString());
343         if (getImports().stream().anyMatch(im -> im.toString().equals(importDeclaration.toString())))
344             return this;
345         else {
346             getImports().add(importDeclaration);
347             return this;
348         }
349     }
350 
351     /**
352      * Add a public class to the types of this compilation unit
353      *
354      * @param name the class name
355      * @return the newly created class
356      */
addClass(String name)357     public ClassOrInterfaceDeclaration addClass(String name) {
358         return addClass(name, Modifier.PUBLIC);
359     }
360 
361     /**
362      * Add a class to the types of this compilation unit
363      *
364      * @param name the class name
365      * @param modifiers the modifiers (like Modifier.PUBLIC)
366      * @return the newly created class
367      */
addClass(String name, Modifier... modifiers)368     public ClassOrInterfaceDeclaration addClass(String name, Modifier... modifiers) {
369         ClassOrInterfaceDeclaration classOrInterfaceDeclaration = new ClassOrInterfaceDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), false, name);
370         getTypes().add(classOrInterfaceDeclaration);
371         return classOrInterfaceDeclaration;
372     }
373 
374     /**
375      * Add a public interface class to the types of this compilation unit
376      *
377      * @param name the interface name
378      * @return the newly created class
379      */
addInterface(String name)380     public ClassOrInterfaceDeclaration addInterface(String name) {
381         return addInterface(name, Modifier.PUBLIC);
382     }
383 
384     /**
385      * Add an interface to the types of this compilation unit
386      *
387      * @param name the interface name
388      * @param modifiers the modifiers (like Modifier.PUBLIC)
389      * @return the newly created class
390      */
addInterface(String name, Modifier... modifiers)391     public ClassOrInterfaceDeclaration addInterface(String name, Modifier... modifiers) {
392         ClassOrInterfaceDeclaration classOrInterfaceDeclaration = new ClassOrInterfaceDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), true, name);
393         getTypes().add(classOrInterfaceDeclaration);
394         return classOrInterfaceDeclaration;
395     }
396 
397     /**
398      * Add a public enum to the types of this compilation unit
399      *
400      * @param name the enum name
401      * @return the newly created class
402      */
addEnum(String name)403     public EnumDeclaration addEnum(String name) {
404         return addEnum(name, Modifier.PUBLIC);
405     }
406 
407     /**
408      * Add an enum to the types of this compilation unit
409      *
410      * @param name the enum name
411      * @param modifiers the modifiers (like Modifier.PUBLIC)
412      * @return the newly created class
413      */
addEnum(String name, Modifier... modifiers)414     public EnumDeclaration addEnum(String name, Modifier... modifiers) {
415         EnumDeclaration enumDeclaration = new EnumDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), name);
416         getTypes().add(enumDeclaration);
417         return enumDeclaration;
418     }
419 
420     /**
421      * Add a public annotation declaration to the types of this compilation unit
422      *
423      * @param name the annotation name
424      * @return the newly created class
425      */
addAnnotationDeclaration(String name)426     public AnnotationDeclaration addAnnotationDeclaration(String name) {
427         return addAnnotationDeclaration(name, Modifier.PUBLIC);
428     }
429 
430     /**
431      * Add an annotation declaration to the types of this compilation unit
432      *
433      * @param name the annotation name
434      * @param modifiers the modifiers (like Modifier.PUBLIC)
435      * @return the newly created class
436      */
addAnnotationDeclaration(String name, Modifier... modifiers)437     public AnnotationDeclaration addAnnotationDeclaration(String name, Modifier... modifiers) {
438         AnnotationDeclaration annotationDeclaration = new AnnotationDeclaration(Arrays.stream(modifiers).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class))), name);
439         getTypes().add(annotationDeclaration);
440         return annotationDeclaration;
441     }
442 
443     /**
444      * Try to get a top level class declaration by its name
445      *
446      * @param className the class name (case-sensitive)
447      */
getClassByName(String className)448     public Optional<ClassOrInterfaceDeclaration> getClassByName(String className) {
449         return getTypes().stream().filter(type -> type.getNameAsString().equals(className) && type instanceof ClassOrInterfaceDeclaration && !((ClassOrInterfaceDeclaration) type).isInterface()).findFirst().map(t -> (ClassOrInterfaceDeclaration) t);
450     }
451 
452     /**
453      * Try to get a top level interface declaration by its name
454      *
455      * @param interfaceName the interface name (case-sensitive)
456      */
getInterfaceByName(String interfaceName)457     public Optional<ClassOrInterfaceDeclaration> getInterfaceByName(String interfaceName) {
458         return getTypes().stream().filter(type -> type.getNameAsString().equals(interfaceName) && type instanceof ClassOrInterfaceDeclaration && ((ClassOrInterfaceDeclaration) type).isInterface()).findFirst().map(t -> (ClassOrInterfaceDeclaration) t);
459     }
460 
461     /**
462      * Try to get a top level enum declaration by its name
463      *
464      * @param enumName the enum name (case-sensitive)
465      */
getEnumByName(String enumName)466     public Optional<EnumDeclaration> getEnumByName(String enumName) {
467         return getTypes().stream().filter(type -> type.getNameAsString().equals(enumName) && type instanceof EnumDeclaration).findFirst().map(t -> (EnumDeclaration) t);
468     }
469 
470     /**
471      * @return the name that the primary type in this file should have, according to the filename in {@link Storage#getFileName()}.
472      * Empty if no file information is present (when this compilation unit wasn't parsed from a file.)
473      */
getPrimaryTypeName()474     public Optional<String> getPrimaryTypeName() {
475         return getStorage().map(Storage::getFileName).map(Utils::removeFileExtension);
476     }
477 
478     /**
479      * @return the type whose name corresponds to the file name.
480      * Empty if no file information is present (when this compilation unit wasn't parsed from a file.)
481      * If for some strange reason there are multiple types of this name, the first one is returned.
482      */
getPrimaryType()483     public Optional<TypeDeclaration<?>> getPrimaryType() {
484         return getPrimaryTypeName().flatMap(name -> getTypes().stream().filter(t -> t.getNameAsString().equals(name)).findFirst());
485     }
486 
487     /**
488      * Try to get a top level annotation type declaration by its name
489      *
490      * @param annotationName the annotation name (case-sensitive)
491      */
getAnnotationDeclarationByName(String annotationName)492     public Optional<AnnotationDeclaration> getAnnotationDeclarationByName(String annotationName) {
493         return getTypes().stream().filter(type -> type.getNameAsString().equals(annotationName) && type instanceof AnnotationDeclaration).findFirst().map(t -> (AnnotationDeclaration) t);
494     }
495 
496     @Override
497     @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
remove(Node node)498     public boolean remove(Node node) {
499         if (node == null)
500             return false;
501         for (int i = 0; i < imports.size(); i++) {
502             if (imports.get(i) == node) {
503                 imports.remove(i);
504                 return true;
505             }
506         }
507         if (module != null) {
508             if (node == module) {
509                 removeModule();
510                 return true;
511             }
512         }
513         if (packageDeclaration != null) {
514             if (node == packageDeclaration) {
515                 removePackageDeclaration();
516                 return true;
517             }
518         }
519         for (int i = 0; i < types.size(); i++) {
520             if (types.get(i) == node) {
521                 types.remove(i);
522                 return true;
523             }
524         }
525         return super.remove(node);
526     }
527 
528     @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
removePackageDeclaration()529     public CompilationUnit removePackageDeclaration() {
530         return setPackageDeclaration((PackageDeclaration) null);
531     }
532 
533     /**
534      * @return the module declared in this compilation unit.
535      */
536     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
getModule()537     public Optional<ModuleDeclaration> getModule() {
538         return Optional.ofNullable(module);
539     }
540 
541     @Generated("com.github.javaparser.generator.core.node.PropertyGenerator")
setModule(final ModuleDeclaration module)542     public CompilationUnit setModule(final ModuleDeclaration module) {
543         if (module == this.module) {
544             return (CompilationUnit) this;
545         }
546         notifyPropertyChange(ObservableProperty.MODULE, this.module, module);
547         if (this.module != null)
548             this.module.setParentNode(null);
549         this.module = module;
550         setAsParentNodeOf(module);
551         return this;
552     }
553 
554     @Generated("com.github.javaparser.generator.core.node.RemoveMethodGenerator")
removeModule()555     public CompilationUnit removeModule() {
556         return setModule((ModuleDeclaration) null);
557     }
558 
559     /**
560      * @return information about where this compilation unit was loaded from, or empty if it wasn't loaded from a file.
561      */
getStorage()562     public Optional<Storage> getStorage() {
563         return Optional.ofNullable(storage);
564     }
565 
setStorage(Path path)566     public CompilationUnit setStorage(Path path) {
567         this.storage = new Storage(this, path);
568         return this;
569     }
570 
571     /**
572      * Information about where this compilation unit was loaded from.
573      * This class only stores the absolute location.
574      * For more flexibility use SourceRoot.
575      */
576     public static class Storage {
577 
578         private final CompilationUnit compilationUnit;
579 
580         private final Path path;
581 
Storage(CompilationUnit compilationUnit, Path path)582         private Storage(CompilationUnit compilationUnit, Path path) {
583             this.compilationUnit = compilationUnit;
584             this.path = path.toAbsolutePath();
585         }
586 
587         /**
588          * @return the path to the source for this CompilationUnit
589          */
getPath()590         public Path getPath() {
591             return path;
592         }
593 
594         /**
595          * @return the CompilationUnit this Storage is about.
596          */
getCompilationUnit()597         public CompilationUnit getCompilationUnit() {
598             return compilationUnit;
599         }
600 
601         /**
602          * @return the source root directory, calculated from the path of this compiation unit, and the package
603          * declaration of this compilation unit. If the package declaration is invalid (when it does not match the end
604          * of the path) a RuntimeException is thrown.
605          */
getSourceRoot()606         public Path getSourceRoot() {
607             final Optional<String> pkgAsString = compilationUnit.getPackageDeclaration().map(NodeWithName::getNameAsString);
608             return pkgAsString.map(p -> Paths.get(CodeGenerationUtils.packageToPath(p))).map(pkg -> subtractPaths(getDirectory(), pkg)).orElse(getDirectory());
609         }
610 
getFileName()611         public String getFileName() {
612             return path.getFileName().toString();
613         }
614 
getDirectory()615         public Path getDirectory() {
616             return path.getParent();
617         }
618 
619         /**
620          * Saves the compilation unit to its original location
621          */
save()622         public void save() {
623             save(cu -> new PrettyPrinter().print(cu));
624         }
625 
626         /**
627          * Saves a compilation unit to its original location with formatting according to the function
628          * passed as a parameter.
629          *
630          * @param makeOutput a function that formats the compilation unit
631          */
save(Function<CompilationUnit, String> makeOutput)632         public void save(Function<CompilationUnit, String> makeOutput) {
633             try {
634                 Files.createDirectories(path.getParent());
635                 final String code = makeOutput.apply(getCompilationUnit());
636                 Files.write(path, code.getBytes(UTF8));
637             } catch (IOException e) {
638                 throw new RuntimeException(e);
639             }
640         }
641 
reparse(JavaParser javaParser)642         public ParseResult<CompilationUnit> reparse(JavaParser javaParser) {
643             try {
644                 return javaParser.parse(ParseStart.COMPILATION_UNIT, provider(getPath()));
645             } catch (IOException e) {
646                 throw new RuntimeException(e);
647             }
648         }
649     }
650 
651     @Override
652     @Generated("com.github.javaparser.generator.core.node.CloneGenerator")
clone()653     public CompilationUnit clone() {
654         return (CompilationUnit) accept(new CloneVisitor(), null);
655     }
656 
657     @Override
658     @Generated("com.github.javaparser.generator.core.node.GetMetaModelGenerator")
getMetaModel()659     public CompilationUnitMetaModel getMetaModel() {
660         return JavaParserMetaModel.compilationUnitMetaModel;
661     }
662 
663     @Override
664     @Generated("com.github.javaparser.generator.core.node.ReplaceMethodGenerator")
replace(Node node, Node replacementNode)665     public boolean replace(Node node, Node replacementNode) {
666         if (node == null)
667             return false;
668         for (int i = 0; i < imports.size(); i++) {
669             if (imports.get(i) == node) {
670                 imports.set(i, (ImportDeclaration) replacementNode);
671                 return true;
672             }
673         }
674         if (module != null) {
675             if (node == module) {
676                 setModule((ModuleDeclaration) replacementNode);
677                 return true;
678             }
679         }
680         if (packageDeclaration != null) {
681             if (node == packageDeclaration) {
682                 setPackageDeclaration((PackageDeclaration) replacementNode);
683                 return true;
684             }
685         }
686         for (int i = 0; i < types.size(); i++) {
687             if (types.get(i) == node) {
688                 types.set(i, (TypeDeclaration) replacementNode);
689                 return true;
690             }
691         }
692         return super.replace(node, replacementNode);
693     }
694 }
695