Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java
41161 views
1
/*
2
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package jdk.javadoc.internal.tool;
27
28
import java.io.PrintStream;
29
import java.io.PrintWriter;
30
import java.lang.ref.Reference;
31
import java.lang.ref.SoftReference;
32
import java.util.EnumSet;
33
import java.util.LinkedHashMap;
34
import java.util.Locale;
35
import java.util.Map;
36
import java.util.ResourceBundle;
37
import java.util.Set;
38
39
import javax.lang.model.element.Element;
40
import javax.lang.model.element.Modifier;
41
import javax.lang.model.element.NestingKind;
42
import javax.tools.Diagnostic;
43
import javax.tools.Diagnostic.Kind;
44
import javax.tools.FileObject;
45
import javax.tools.ForwardingFileObject;
46
import javax.tools.JavaFileObject;
47
48
import jdk.javadoc.doclet.Reporter;
49
50
import com.sun.tools.javac.tree.EndPosTable;
51
import com.sun.tools.javac.util.Context.Factory;
52
import com.sun.tools.javac.util.DiagnosticSource;
53
import com.sun.source.tree.CompilationUnitTree;
54
import com.sun.source.util.DocSourcePositions;
55
import com.sun.source.util.DocTreePath;
56
import com.sun.source.util.TreePath;
57
import com.sun.tools.javac.tree.JCTree;
58
import com.sun.tools.javac.util.Context;
59
import com.sun.tools.javac.util.JCDiagnostic;
60
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
61
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
62
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
63
import com.sun.tools.javac.util.JavacMessages;
64
import com.sun.tools.javac.util.Log;
65
66
/**
67
* Class for reporting diagnostics and other messages.
68
*
69
* The class leverages the javac support for reporting diagnostics, for stylistic consistency
70
* of diagnostic messages and to avoid code duplication.
71
*
72
* The class is a subtype of javac's Log, and is primarily an adapter between
73
* javadoc method signatures and the underlying javac methods. Within this class,
74
* the methods call down to a core {@code report} method which hands off to
75
* a similar method in the superclass ({@code Log.report}, which takes care
76
* of reporting the diagnostic (unless it has been suppressed), displaying
77
* the source line and a caret to indicate the position of the issue (if appropriate),
78
* counting errors and warnings, and so on.
79
*
80
* In general, the underlying javac layer is more powerful, whereas the javadoc methods are
81
* constrained by the public {@link jdk.javadoc.doclet.Doclet} API.
82
*
83
* In the underlying javac layer, the following abstractions are used:
84
* <ul>
85
* <li>{@code DiagnosticType} -- error, warning, note, etc.
86
* <li>{@code DiagnosticSource} -- a file object and a cache of its content
87
* <li>{@code DiagnosticPosition} -- a tuple of values (start, pos, end) for the position of a diagnostic
88
* <li>{@code DiagnosticFlag} -- additional flags related to the diagnostic
89
* </ul>
90
*
91
* The javadoc layer is defined by the methods on {@code Doclet.Reporter}, and by
92
* assorted methods defined in this class for use by the javadoc tool.
93
* The primary data types are:
94
* <ul>
95
* <li>{@code Diagnostic.Kind} -- maps to {@code DiagnosticType} and {@code Set<DiagnosticFlag>}
96
* <li>{@code Element} -- maps to {@code DiagnosticSource} and {@code DiagnosticPosition}
97
* <li>{@code DocTreePath} -- maps to {@code DiagnosticSource} and {@code DiagnosticPosition}
98
* </ul>
99
*
100
* The reporting methods in the javac layer primarily take pre-localized (key, args) pairs,
101
* while the methods in the javadoc layer, especially the {@code Reporter} interface, take
102
* localized strings. To accommodate this, "wrapper" resources are used, whose value is {@code {0}},
103
* to pass the localized string down to javac. A side-effect is that clients using a
104
* {@code DiagnosticListener} with a {@code DocumentationTask} cannot access the original resource
105
* key for the localized message.
106
* Given the limitations of the API, it is not possible to do any better.
107
* The javac Annotation Processing API has the same problem.
108
*
109
* There is a slight disparity between javac's use of streams and javadoc's use of streams.
110
* javac reports <b>all</b> diagnostics to the "error" stream, and provides a separate
111
* "output" stream for expected output, such as command-line help or the output from options
112
* like {@code -Xprint}. javadoc API, and {@code Reporter} in particular, does not specify
113
* the use of streams, and provides no support for identifying or specifying streams. JDK-8267204.
114
* The current implementation/workaround is to write errors and warnings to the "error"
115
* stream and notes to the "output" stream.
116
*
117
*
118
* <p><b>This is NOT part of any supported API.
119
* If you write code that depends on this, you do so at your own risk.
120
* This code and its internal interfaces are subject to change or
121
* deletion without notice.</b>
122
*
123
* @see java.util.ResourceBundle
124
* @see java.text.MessageFormat
125
*/
126
public class Messager extends Log implements Reporter {
127
/** The overall context for the documentation run. */
128
private final Context context;
129
130
/** The tool environment, providing access to the tool's utility classes and tables. */
131
private ToolEnvironment toolEnv;
132
133
/** The utility class to access the positions of items in doc comments. */
134
private DocSourcePositions sourcePositions;
135
136
/**
137
* A memory-sensitive cache of recently used {@code DiagnosticSource} objects.
138
*/
139
private final LinkedHashMap<JavaFileObject, SoftReference<DiagnosticSource>> diagSourceCache;
140
141
/** Get the current messager, which is also the compiler log. */
142
public static Messager instance0(Context context) {
143
Log instance = context.get(logKey);
144
if (!(instance instanceof Messager m))
145
throw new InternalError("no messager instance!");
146
return m;
147
}
148
149
public static void preRegister(Context context,
150
final String programName) {
151
context.put(logKey, (Factory<Log>)c -> new Messager(c, programName));
152
}
153
154
public static void preRegister(Context context, final String programName,
155
final PrintWriter outWriter, final PrintWriter errWriter) {
156
context.put(logKey, (Factory<Log>)c -> new Messager(c, programName, outWriter, errWriter));
157
}
158
159
final String programName;
160
161
private Locale locale;
162
private final JavacMessages messages;
163
private final JCDiagnostic.Factory javadocDiags;
164
165
private static PrintWriter createPrintWriter(PrintStream ps, boolean autoflush) {
166
return new PrintWriter(ps, autoflush) {
167
// avoid closing system streams
168
@Override
169
public void close() {
170
super.flush();
171
}
172
};
173
}
174
175
/**
176
* Constructor
177
* @param programName Name of the program (for error messages).
178
*/
179
public Messager(Context context, String programName) {
180
// use the current values of System.out, System.err, in case they have been redirected
181
this(context, programName,
182
createPrintWriter(System.out, false),
183
createPrintWriter(System.err, true));
184
}
185
186
/**
187
* Constructor
188
* @param programName Name of the program (for error messages).
189
* @param outWriter Stream for notices etc.
190
* @param errWriter Stream for errors and warnings
191
*/
192
public Messager(Context context, String programName, PrintWriter outWriter, PrintWriter errWriter) {
193
super(context, outWriter, errWriter);
194
messages = JavacMessages.instance(context);
195
messages.add(locale -> ResourceBundle.getBundle("jdk.javadoc.internal.tool.resources.javadoc",
196
locale));
197
javadocDiags = new JCDiagnostic.Factory(messages, "javadoc");
198
this.programName = programName;
199
this.context = context;
200
locale = Locale.getDefault();
201
202
diagSourceCache = new LinkedHashMap<>() {
203
private static final int MAX_ENTRIES = 5;
204
205
@Override
206
protected boolean removeEldestEntry(Map.Entry<JavaFileObject, SoftReference<DiagnosticSource>> eldest) {
207
return size() > MAX_ENTRIES;
208
}
209
};
210
}
211
212
@Override // Reporter
213
public PrintWriter getStandardWriter() {
214
return getWriter(Log.WriterKind.STDOUT);
215
}
216
217
@Override // Reporter
218
public PrintWriter getDiagnosticWriter() {
219
return getWriter(Log.WriterKind.STDERR);
220
}
221
222
public void setLocale(Locale locale) {
223
this.locale = locale;
224
}
225
226
/**
227
* Returns the localized string from the tool's resource bundles.
228
*
229
* @param key the resource key
230
* @param args arguments for the resource
231
*/
232
String getText(String key, Object... args) {
233
return messages.getLocalizedString(locale, key, args);
234
}
235
236
@Override // Reporter
237
public void print(Kind kind, String message) {
238
report(kind, null, null, message);
239
}
240
241
@Override // Reporter
242
public void print(Diagnostic.Kind kind, DocTreePath path, String message) {
243
DiagnosticType dt = getDiagnosticType(kind);
244
Set<DiagnosticFlag> flags = getDiagnosticFlags(kind);
245
DiagnosticSource ds = getDiagnosticSource(path);
246
DiagnosticPosition dp = getDiagnosticPosition(path);
247
report(dt, flags, ds, dp, message);
248
}
249
250
@Override // Reporter
251
public void print(Kind kind, Element element, String message) {
252
DiagnosticType dt = getDiagnosticType(kind);
253
Set<DiagnosticFlag> flags = getDiagnosticFlags(kind);
254
DiagnosticSource ds = getDiagnosticSource(element);
255
DiagnosticPosition dp = getDiagnosticPosition(element);
256
report(dt, flags, ds, dp, message);
257
}
258
259
@Override // Reporter
260
public void print(Kind kind, FileObject file, int start, int pos, int end, String message) throws IllegalArgumentException {
261
DiagnosticType dt = getDiagnosticType(kind);
262
Set<DiagnosticFlag> flags = getDiagnosticFlags(kind);
263
// Although not required to do so, it is the case that any file object returned from the
264
// javac impl of JavaFileManager will return an object that implements JavaFileObject.
265
// See PathFileObject, which provides the primary impls of (Java)FileObject.
266
JavaFileObject fo = file instanceof JavaFileObject _fo ? _fo : new WrappingJavaFileObject(file);
267
DiagnosticSource ds = new DiagnosticSource(fo, this);
268
DiagnosticPosition dp = createDiagnosticPosition(null, start, pos, end);
269
report(dt, flags, ds, dp, message);
270
}
271
272
private class WrappingJavaFileObject
273
extends ForwardingFileObject<FileObject> implements JavaFileObject {
274
275
WrappingJavaFileObject(FileObject fo) {
276
super(fo);
277
assert !(fo instanceof JavaFileObject);
278
}
279
280
@Override
281
public Kind getKind() {
282
String name = fileObject.getName();
283
return name.endsWith(Kind.HTML.extension)
284
? JavaFileObject.Kind.HTML
285
: JavaFileObject.Kind.OTHER;
286
}
287
288
@Override
289
public boolean isNameCompatible(String simpleName, Kind kind) {
290
return false;
291
}
292
293
@Override
294
public NestingKind getNestingKind() {
295
return null;
296
}
297
298
@Override
299
public Modifier getAccessLevel() {
300
return null;
301
}
302
}
303
304
/**
305
* Prints an error message.
306
*
307
* @param message the message
308
*/
309
public void printError(String message) {
310
report(DiagnosticType.ERROR,null, null, message);
311
}
312
313
/**
314
* Prints an error message for a given documentation tree node.
315
*
316
* @param path the path for the documentation tree node
317
* @param message the message
318
*/
319
public void printError(DocTreePath path, String message) {
320
DiagnosticSource ds = getDiagnosticSource(path);
321
DiagnosticPosition dp = getDiagnosticPosition(path);
322
report(DiagnosticType.ERROR, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
323
}
324
325
/**
326
* Prints an error message for a given element.
327
*
328
* @param element the element
329
* @param message the message
330
*/
331
public void printError(Element element, String message) {
332
DiagnosticSource ds = getDiagnosticSource(element);
333
DiagnosticPosition dp = getDiagnosticPosition(element);
334
report(DiagnosticType.ERROR, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
335
}
336
337
/**
338
* Prints an error message.
339
*
340
* @param key the resource key for the message
341
* @param args the arguments for the message
342
*/
343
public void printErrorUsingKey(String key, Object... args) {
344
printError(getText(key, args));
345
}
346
347
/**
348
* Prints a warning message.
349
*
350
* @param message the message
351
*/
352
public void printWarning(String message) {
353
report(DiagnosticType.WARNING, null, null, message);
354
}
355
356
/**
357
* Prints a warning message for a given documentation tree node.
358
*
359
* @param path the path for the documentation tree node
360
* @param message the message
361
*/
362
public void printWarning(DocTreePath path, String message) {
363
DiagnosticSource ds = getDiagnosticSource(path);
364
DiagnosticPosition dp = getDiagnosticPosition(path);
365
report(DiagnosticType.WARNING, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
366
}
367
368
/**
369
* Prints a warning message for a given element.
370
*
371
* @param element the element
372
* @param message the message
373
*/
374
public void printWarning(Element element, String message) {
375
DiagnosticSource ds = getDiagnosticSource(element);
376
DiagnosticPosition dp = getDiagnosticPosition(element);
377
report(DiagnosticType.WARNING, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
378
}
379
380
/**
381
* Prints a warning message.
382
*
383
* @param key the resource key for the message
384
* @param args the arguments for the message
385
*/
386
public void printWarningUsingKey(String key, Object... args) {
387
printWarning(getText(key, args));
388
}
389
390
/**
391
* Prints a warning message for an element.
392
*
393
* @param element the element
394
* @param key the resource key for the message
395
* @param args the arguments for the message
396
*/
397
public void printWarningUsingKey(Element element, String key, Object... args) {
398
printWarning(element, getText(key, args));
399
}
400
401
/**
402
* Prints a "notice" message to the standard writer.
403
*
404
* @param key the resource key for the message
405
* @param args the arguments for the message
406
*/
407
public void noticeUsingKey(String key, Object... args) {
408
printRawLines(getStandardWriter(), getText(key, args));
409
}
410
411
/**
412
* Prints a "notice" message to the standard writer.
413
*
414
* @param message the message
415
*/
416
public void notice(String message) {
417
printRawLines(getStandardWriter(), message);
418
}
419
420
/**
421
* Returns true if errors have been recorded.
422
*/
423
public boolean hasErrors() {
424
return nerrors != 0;
425
}
426
427
/**
428
* Returns true if warnings have been recorded.
429
*/
430
public boolean hasWarnings() {
431
return nwarnings != 0;
432
}
433
434
/**
435
* Prints the error and warning counts, if any, to the diagnostic writer.
436
*/
437
public void printErrorWarningCounts() {
438
printCount(nerrors, "main.error", "main.errors");
439
printCount(nwarnings, "main.warning", "main.warnings");
440
}
441
442
private void printCount(int count, String singleKey, String pluralKey) {
443
if (count > 0) {
444
String message = getText(count > 1 ? pluralKey : singleKey, count);
445
if (diagListener != null) {
446
report(DiagnosticType.NOTE, null, null, message);
447
} else {
448
printRawLines(getDiagnosticWriter(), message);
449
}
450
}
451
}
452
453
/**
454
* Reports a diagnostic message.
455
*
456
* @param kind the kind of diagnostic
457
* @param ds the diagnostic source
458
* @param dp the diagnostic position
459
* @param message the message
460
*/
461
private void report(Diagnostic.Kind kind, DiagnosticSource ds, DiagnosticPosition dp, String message) {
462
report(getDiagnosticType(kind), getDiagnosticFlags(kind), ds, dp, message);
463
}
464
465
/**
466
* Reports a diagnostic message.
467
*
468
* @param dt the diagnostic type
469
* @param ds the diagnostic source
470
* @param dp the diagnostic position
471
* @param message the message
472
*/
473
private void report(DiagnosticType dt, DiagnosticSource ds, DiagnosticPosition dp, String message) {
474
report(dt, EnumSet.noneOf(DiagnosticFlag.class), ds, dp, message);
475
}
476
477
/**
478
* Reports a diagnostic message, with diagnostic flags.
479
* For javadoc, the only flag that is used is {@code MANDATORY_WARNING}, and only
480
* because in principle the public API supports it via {@code Kind.MANDATORY_WARNING}.
481
* javadoc itself does generate mandatory warnings.
482
*
483
* This is the primary low-level wrapper around the underlying {@code Log.report}.
484
* Because we already have a localized message, we use wrapper resources (just {@code {0}})
485
* to wrap the string. The current behavior is one wrapper per diagnostic type.
486
* We could improve this by subtyping {@code DiagnosticInfo} to modify the resource key used.
487
*
488
* {@code Log} reports all diagnostics to the corresponding writer, which defaults
489
* to the "error" stream, when using the two-stream constructor. That doesn't work
490
* for javadoc, which has historically written notes to the "output" stream, because
491
* the public API used by doclets does not provide for more detailed control.
492
* Therefore, for now, javadoc continues to use the (deprecated) three-stream
493
* constructor, with the {@code NOTE} stream set to the "output" stream.
494
*
495
* {@code Log} reports all notes with a "Note:" prefix. That's not good for the
496
* standard doclet, which uses notes to report the various "progress" messages,
497
* such as "Generating class ...". They can be written directly to the diagnostic
498
* writer, but that bypasses low-level checks about whether to suppress notes,
499
* and bypasses the diagnostic listener for API clients.
500
* Overall, it's an over-constrained problem with no obvious good solution.
501
*
502
* Note: there is an intentional difference in behavior between the diagnostic source
503
* being set to {@code null} (no source intended) and {@code NO_SOURCE} (no source available).
504
*
505
* @param dt the diagnostic type
506
* @param ds the diagnostic source
507
* @param dp the diagnostic position
508
* @param message the message
509
*/
510
private void report(DiagnosticType dt, Set<DiagnosticFlag> flags, DiagnosticSource ds, DiagnosticPosition dp, String message) {
511
report(javadocDiags.create(dt, null, flags, ds, dp, "message", message));
512
}
513
514
/**
515
* Returns a diagnostic position for a documentation tree node.
516
*
517
* @param path the path for the documentation tree node
518
* @return the diagnostic position
519
*/
520
private DiagnosticPosition getDiagnosticPosition(DocTreePath path) {
521
DocSourcePositions posns = getSourcePositions();
522
CompilationUnitTree compUnit = path.getTreePath().getCompilationUnit();
523
int start = (int) posns.getStartPosition(compUnit, path.getDocComment(), path.getLeaf());
524
int end = (int) posns.getEndPosition(compUnit, path.getDocComment(), path.getLeaf());
525
return createDiagnosticPosition(null, start, start, end);
526
}
527
528
/**
529
* Returns a diagnostic position for an element, or {@code null} if the source
530
* file is not available.
531
*
532
* @param element the element
533
* @return the diagnostic position
534
*/
535
private DiagnosticPosition getDiagnosticPosition(Element element) {
536
ToolEnvironment toolEnv = getToolEnv();
537
DocSourcePositions posns = getSourcePositions();
538
TreePath tp = toolEnv.elementToTreePath.get(element);
539
if (tp == null) {
540
return null;
541
}
542
CompilationUnitTree compUnit = tp.getCompilationUnit();
543
JCTree tree = (JCTree) tp.getLeaf();
544
int start = (int) posns.getStartPosition(compUnit, tree);
545
int pos = tree.getPreferredPosition();
546
int end = (int) posns.getEndPosition(compUnit, tree);
547
return createDiagnosticPosition(tree, start, pos, end);
548
}
549
550
/**
551
* Creates a diagnostic position.
552
*
553
* @param tree the tree node, or null if no tree is applicable
554
* @param start the start position
555
* @param pos the "preferred" position: this is used to position the caret in messages
556
* @param end the end position
557
* @return the diagnostic position
558
*/
559
private DiagnosticPosition createDiagnosticPosition(JCTree tree, int start, int pos, int end) {
560
return new DiagnosticPosition() {
561
@Override
562
public JCTree getTree() {
563
return tree;
564
}
565
566
@Override
567
public int getStartPosition() {
568
return start;
569
}
570
571
@Override
572
public int getPreferredPosition() {
573
return pos;
574
}
575
576
@Override
577
public int getEndPosition(EndPosTable endPosTable) {
578
return end;
579
}
580
};
581
}
582
583
/**
584
* Returns the diagnostic type for a diagnostic kind.
585
*
586
* @param kind the diagnostic kind
587
* @return the diagnostic type
588
*/
589
private DiagnosticType getDiagnosticType(Diagnostic.Kind kind) {
590
return switch (kind) {
591
case ERROR -> DiagnosticType.ERROR;
592
case WARNING, MANDATORY_WARNING -> DiagnosticType.WARNING;
593
case NOTE -> DiagnosticType.NOTE;
594
case OTHER -> DiagnosticType.FRAGMENT;
595
};
596
}
597
598
/**
599
* Returns the diagnostic flags for a diagnostic kind.
600
* A diagnostic kind of {@code MANDATORY_WARNING} requires the {@code MANDATORY} flag.
601
*
602
* @param kind the diagnostic kind
603
* @return the flags
604
*/
605
private Set<DiagnosticFlag> getDiagnosticFlags(Diagnostic.Kind kind) {
606
return kind == Kind.MANDATORY_WARNING
607
? EnumSet.of(DiagnosticFlag.MANDATORY)
608
: EnumSet.noneOf(DiagnosticFlag.class);
609
}
610
611
/**
612
* Returns the diagnostic source for an documentation tree node.
613
*
614
* @param path the path for the documentation tree node
615
* @return the diagnostic source
616
*/
617
private DiagnosticSource getDiagnosticSource(DocTreePath path) {
618
return getDiagnosticSource(path.getTreePath().getCompilationUnit().getSourceFile());
619
}
620
621
/**
622
* Returns the diagnostic source for an element, or {@code NO_SOURCE} if the
623
* source file is not known (for example, if the element was read from a class file).
624
*
625
* @param element the element
626
* @return the diagnostic source
627
*/
628
private DiagnosticSource getDiagnosticSource(Element element) {
629
TreePath tp = getToolEnv().elementToTreePath.get(element);
630
return tp == null ? DiagnosticSource.NO_SOURCE
631
: getDiagnosticSource(tp.getCompilationUnit().getSourceFile());
632
}
633
634
/**
635
* Returns the diagnostic source for a file object.
636
*
637
* {@code DiagnosticSource} objects are moderately expensive because they maintain
638
* an internal copy of the content, to provide the line map.
639
* Therefore, we keep a small memory-sensitive cache of recently used objects.
640
*
641
* @param fo the file object
642
* @return the diagnostic source
643
*/
644
private DiagnosticSource getDiagnosticSource(JavaFileObject fo) {
645
Reference<DiagnosticSource> ref = diagSourceCache.get(fo);
646
DiagnosticSource ds = ref == null ? null : ref.get();
647
if (ds == null) {
648
ds = new DiagnosticSource(fo, this);
649
diagSourceCache.put(fo, new SoftReference<>(ds));
650
}
651
return ds;
652
}
653
654
/**
655
* Returns the object for computing source positions.
656
*
657
* The value is determined lazily because the tool environment is computed lazily.
658
*
659
* @return the object for computing source positions
660
*/
661
private DocSourcePositions getSourcePositions() {
662
if (sourcePositions == null) {
663
sourcePositions = getToolEnv().docTrees.getSourcePositions();
664
}
665
return sourcePositions;
666
}
667
668
/**
669
* Returns the tool environment.
670
*
671
* The value is determined lazily, because creating it eagerly disrupts
672
* the overall initialization of objects in the context.
673
*
674
* @return the tool environment
675
*/
676
private ToolEnvironment getToolEnv() {
677
if (toolEnv == null) {
678
toolEnv = ToolEnvironment.instance(context);
679
}
680
return toolEnv;
681
}
682
}
683
684