001/*
002 * JDrupes MDoclet
003 * Copyright (C) 2021,2022 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jdrupes.mdoclet;
020
021import java.io.IOException;
022import java.text.BreakIterator;
023import java.util.List;
024
025import javax.lang.model.element.AnnotationMirror;
026import javax.lang.model.element.AnnotationValue;
027import javax.lang.model.element.Element;
028import javax.lang.model.element.ExecutableElement;
029import javax.lang.model.element.PackageElement;
030import javax.lang.model.element.TypeElement;
031import javax.lang.model.type.DeclaredType;
032import javax.lang.model.type.ErrorType;
033import javax.lang.model.type.TypeMirror;
034import javax.tools.Diagnostic.Kind;
035import javax.tools.FileObject;
036import javax.tools.ForwardingFileObject;
037
038import com.sun.source.doctree.DocCommentTree;
039import com.sun.source.doctree.DocTree;
040import com.sun.source.doctree.EntityTree;
041import com.sun.source.tree.CatchTree;
042import com.sun.source.tree.ClassTree;
043import com.sun.source.tree.CompilationUnitTree;
044import com.sun.source.tree.MethodTree;
045import com.sun.source.tree.Scope;
046import com.sun.source.tree.Tree;
047import com.sun.source.util.DocSourcePositions;
048import com.sun.source.util.DocTreeFactory;
049import com.sun.source.util.DocTreePath;
050import com.sun.source.util.DocTrees;
051import com.sun.source.util.TreePath;
052
053/**
054 * Wraps the {@link DocTrees} passed to the constructor.
055 * 
056 * The main purpose of the wrapper is to wrap the results from methods
057 * that return a {@link DocCommentTree} for already parsed content
058 * in a {@link DocCommentTreeWrapper}.
059 * 
060 * For method invocations with {@link FileObject}s as argument,
061 * the source is converted from markdown to html if the name ends
062 * with ".md".
063 */
064public class DocTreesWrapper extends DocTrees {
065
066    private final MDoclet doclet;
067    private final MDocletEnvironment environment;
068    private final DocTrees docTrees;
069
070    public DocTreesWrapper(MDoclet doclet, MDocletEnvironment environment,
071            DocTrees docTrees) {
072        super();
073        this.doclet = doclet;
074        this.environment = environment;
075        this.docTrees = docTrees;
076    }
077
078    private DocCommentTree wrap(DocCommentTree tree) {
079        if (tree == null) {
080            return null;
081        }
082        return new DocCommentTreeWrapper(doclet, environment, tree);
083    }
084
085    /**
086     * Delegates to the docTrees passed to the constructor.
087     * 
088     * {@inheritDoc}
089     * @see com.sun.source.util.DocTrees#getBreakIterator()
090     */
091    public BreakIterator getBreakIterator() {
092        return docTrees.getBreakIterator();
093    }
094
095    /**
096     * Substitutes the original doctree with one processed my the markdown
097     * processor.
098     * 
099     * {@inheritDoc}
100     * @see com.sun.source.util.DocTrees#getDocCommentTree(com.sun.source.util.TreePath)
101     */
102    public DocCommentTree getDocCommentTree(TreePath path) {
103        return wrap(docTrees.getDocCommentTree(path));
104    }
105
106    /**
107     * Delegates to the docTrees passed to the constructor.
108     * 
109     * {@inheritDoc}
110     * @see com.sun.source.util.DocTrees#getDocCommentTree(javax.lang.model.element.Element)
111     */
112    public DocCommentTree getDocCommentTree(Element e) {
113        return wrap(docTrees.getDocCommentTree(e));
114    }
115
116    /**
117     * Delegates to the docTrees passed to the constructor.
118     * 
119     * {@inheritDoc}
120     * @see com.sun.source.util.DocTrees#getDocCommentTree(javax.tools.FileObject)
121     */
122    public DocCommentTree getDocCommentTree(FileObject fileObject) {
123        if (!fileObject.getName().endsWith(".md")) {
124            return docTrees.getDocCommentTree(fileObject);
125        }
126        return wrap(docTrees.getDocCommentTree(wrapMdFile(fileObject)));
127    }
128
129    private FileObject wrapMdFile(FileObject fileObject) {
130        return new ForwardingFileObject<>(fileObject) {
131
132            @Override
133            public String getName() {
134                String origName = super.getName();
135                return origName.substring(0, origName.length() - 2) + "html";
136            }
137
138            @Override
139            public CharSequence getCharContent(boolean ignoreEncodingErrors)
140                    throws IOException {
141                String md
142                    = super.getCharContent(ignoreEncodingErrors).toString();
143                return "<body>" + md + "</body>";
144            }
145        };
146    }
147
148    /**
149     * Delegates to the docTrees passed to the constructor.
150     * 
151     * {@inheritDoc}
152     * @see com.sun.source.util.Trees#getTree(javax.lang.model.element.Element)
153     */
154    public Tree getTree(Element element) {
155        return docTrees.getTree(element);
156    }
157
158    /**
159     * Delegates to the docTrees passed to the constructor.
160     * 
161     * {@inheritDoc}
162     * @see com.sun.source.util.DocTrees#getDocCommentTree(javax.lang.model.element.Element, java.lang.String)
163     */
164    public DocCommentTree getDocCommentTree(Element e, String relativePath)
165            throws IOException {
166        return wrap(docTrees.getDocCommentTree(e, relativePath));
167    }
168
169    /**
170     * Delegates to the docTrees passed to the constructor.
171     * 
172     * {@inheritDoc}
173     * @see com.sun.source.util.Trees#getTree(javax.lang.model.element.TypeElement)
174     */
175    public ClassTree getTree(TypeElement element) {
176        return docTrees.getTree(element);
177    }
178
179    /**
180     * Delegates to the docTrees passed to the constructor.
181     * 
182     * {@inheritDoc}
183     * @see com.sun.source.util.Trees#getTree(javax.lang.model.element.ExecutableElement)
184     */
185    public MethodTree getTree(ExecutableElement method) {
186        return docTrees.getTree(method);
187    }
188
189    /**
190     * Delegates to the docTrees passed to the constructor.
191     * 
192     * {@inheritDoc}
193     * @see com.sun.source.util.Trees#getTree(javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror)
194     */
195    public Tree getTree(Element e, AnnotationMirror a) {
196        return docTrees.getTree(e, a);
197    }
198
199    /**
200     * Delegates to the docTrees passed to the constructor.
201     * 
202     * {@inheritDoc}
203     * @see com.sun.source.util.DocTrees#getDocTreePath(javax.tools.FileObject, javax.lang.model.element.PackageElement)
204     */
205    public DocTreePath getDocTreePath(FileObject fileObject,
206            PackageElement packageElement) {
207        if (!fileObject.getName().endsWith(".md")) {
208            return docTrees.getDocTreePath(fileObject, packageElement);
209        }
210        return docTrees.getDocTreePath(wrapMdFile(fileObject), packageElement);
211    }
212
213    /**
214     * Delegates to the docTrees passed to the constructor.
215     * 
216     * {@inheritDoc}
217     * @see com.sun.source.util.Trees#getTree(javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationValue)
218     */
219    public Tree getTree(Element e, AnnotationMirror a, AnnotationValue v) {
220        return docTrees.getTree(e, a, v);
221    }
222
223    /**
224     * Delegates to the docTrees passed to the constructor.
225     * 
226     * {@inheritDoc}
227     * @see com.sun.source.util.Trees#getPath(com.sun.source.tree.CompilationUnitTree, com.sun.source.tree.Tree)
228     */
229    public TreePath getPath(CompilationUnitTree unit, Tree node) {
230        return docTrees.getPath(unit, node);
231    }
232
233    /**
234     * Delegates to the docTrees passed to the constructor.
235     * 
236     * {@inheritDoc}
237     * @see com.sun.source.util.Trees#getPath(javax.lang.model.element.Element)
238     */
239    public TreePath getPath(Element e) {
240        return docTrees.getPath(e);
241    }
242
243    /**
244     * Delegates to the docTrees passed to the constructor.
245     * 
246     * {@inheritDoc}
247     * @see com.sun.source.util.DocTrees#getElement(com.sun.source.util.DocTreePath)
248     */
249    public Element getElement(DocTreePath path) {
250        return docTrees.getElement(path);
251    }
252
253    /**
254     * Delegates to the docTrees passed to the constructor.
255     * 
256     * {@inheritDoc}
257     * @see com.sun.source.util.Trees#getPath(javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror)
258     */
259    public TreePath getPath(Element e, AnnotationMirror a) {
260        return docTrees.getPath(e, a);
261    }
262
263    /**
264     * Delegates to the docTrees passed to the constructor.
265     * 
266     * {@inheritDoc}
267     * @see com.sun.source.util.DocTrees#getFirstSentence(java.util.List)
268     */
269    public List<DocTree> getFirstSentence(List<? extends DocTree> list) {
270        return docTrees.getFirstSentence(list);
271    }
272
273    /**
274     * Delegates to the docTrees passed to the constructor.
275     * 
276     * {@inheritDoc}
277     * @see com.sun.source.util.Trees#getPath(javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationValue)
278     */
279    public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) {
280        return docTrees.getPath(e, a, v);
281    }
282
283    /**
284     * Delegates to the docTrees passed to the constructor.
285     * 
286     * {@inheritDoc}
287     * @see com.sun.source.util.DocTrees#getSourcePositions()
288     */
289    public DocSourcePositions getSourcePositions() {
290        return docTrees.getSourcePositions();
291    }
292
293    /**
294     * Delegates to the docTrees passed to the constructor.
295     * 
296     * {@inheritDoc}
297     * @see com.sun.source.util.Trees#getElement(com.sun.source.util.TreePath)
298     */
299    public Element getElement(TreePath path) {
300        return docTrees.getElement(path);
301    }
302
303    /**
304     * Delegates to the docTrees passed to the constructor.
305     * 
306     * {@inheritDoc}
307     * @see com.sun.source.util.DocTrees#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, com.sun.source.doctree.DocTree, com.sun.source.doctree.DocCommentTree, com.sun.source.tree.CompilationUnitTree)
308     */
309    public void printMessage(Kind kind, CharSequence msg, DocTree t,
310            DocCommentTree c, CompilationUnitTree root) {
311        docTrees.printMessage(kind, msg, t, c, root);
312    }
313
314    /**
315     * Delegates to the docTrees passed to the constructor.
316     * 
317     * {@inheritDoc}
318     * @see com.sun.source.util.Trees#getTypeMirror(com.sun.source.util.TreePath)
319     */
320    public TypeMirror getTypeMirror(TreePath path) {
321        return docTrees.getTypeMirror(path);
322    }
323
324    /**
325     * Delegates to the docTrees passed to the constructor.
326     * 
327     * {@inheritDoc}
328     * @see com.sun.source.util.DocTrees#setBreakIterator(java.text.BreakIterator)
329     */
330    public void setBreakIterator(BreakIterator breakiterator) {
331        docTrees.setBreakIterator(breakiterator);
332    }
333
334    /**
335     * Delegates to the docTrees passed to the constructor.
336     * 
337     * {@inheritDoc}
338     * @see com.sun.source.util.Trees#getScope(com.sun.source.util.TreePath)
339     */
340    public Scope getScope(TreePath path) {
341        return docTrees.getScope(path);
342    }
343
344    /**
345     * Delegates to the docTrees passed to the constructor.
346     * 
347     * {@inheritDoc}
348     * @see com.sun.source.util.DocTrees#getDocTreeFactory()
349     */
350    public DocTreeFactory getDocTreeFactory() {
351        return docTrees.getDocTreeFactory();
352    }
353
354    /**
355     * Delegates to the docTrees passed to the constructor.
356     * 
357     * {@inheritDoc}
358     * @see com.sun.source.util.Trees#getDocComment(com.sun.source.util.TreePath)
359     */
360    public String getDocComment(TreePath path) {
361        return docTrees.getDocComment(path);
362    }
363
364    /**
365     * Delegates to the docTrees passed to the constructor.
366     * 
367     * {@inheritDoc}
368     * @see com.sun.source.util.Trees#isAccessible(com.sun.source.tree.Scope, javax.lang.model.element.TypeElement)
369     */
370    public boolean isAccessible(Scope scope, TypeElement type) {
371        return docTrees.isAccessible(scope, type);
372    }
373
374    /**
375     * Delegates to the docTrees passed to the constructor.
376     * 
377     * {@inheritDoc}
378     * @see com.sun.source.util.Trees#isAccessible(com.sun.source.tree.Scope, javax.lang.model.element.Element, javax.lang.model.type.DeclaredType)
379     */
380    public boolean isAccessible(Scope scope, Element member,
381            DeclaredType type) {
382        return docTrees.isAccessible(scope, member, type);
383    }
384
385    /**
386     * Delegates to the docTrees passed to the constructor.
387     * 
388     * {@inheritDoc}
389     * @see com.sun.source.util.Trees#getOriginalType(javax.lang.model.type.ErrorType)
390     */
391    public TypeMirror getOriginalType(ErrorType errorType) {
392        return docTrees.getOriginalType(errorType);
393    }
394
395    /**
396     * Delegates to the docTrees passed to the constructor.
397     * 
398     * {@inheritDoc}
399     * @see com.sun.source.util.Trees#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, com.sun.source.tree.Tree, com.sun.source.tree.CompilationUnitTree)
400     */
401    public void printMessage(Kind kind, CharSequence msg, Tree t,
402            CompilationUnitTree root) {
403        docTrees.printMessage(kind, msg, t, root);
404    }
405
406    /**
407     * Delegates to the docTrees passed to the constructor.
408     * 
409     * {@inheritDoc}
410     * @see com.sun.source.util.Trees#getLub(com.sun.source.tree.CatchTree)
411     */
412    public TypeMirror getLub(CatchTree tree) {
413        return docTrees.getLub(tree);
414    }
415
416    /**
417     * Delegates to the docTrees passed to the constructor.
418     * 
419     * {@inheritDoc}
420     */
421    @Override
422    public TypeMirror getType(DocTreePath path) {
423        return docTrees.getType(path);
424    }
425
426    /**
427     * Delegates to the docTrees passed to the constructor.
428     * 
429     * {@inheritDoc}
430     */
431    @Override
432    public String getCharacters(EntityTree tree) {
433        return docTrees.getCharacters(tree);
434    }
435
436    /**
437     * Delegates to the docTrees passed to the constructor.
438     * 
439     * {@inheritDoc}
440     * @see java.lang.Object#toString()
441     */
442    public String toString() {
443        return docTrees.toString();
444    }
445
446}