• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 4515

27 Mar 2025 12:01PM UTC coverage: 77.853% (+0.06%) from 77.796%
4515

push

github

adangel
Fix #5590: [java] LiteralsFirstInComparisons with constant field (#5595)

Merge pull request #5595 from oowekyala:issue5590-literal-comparison

17580 of 23536 branches covered (74.69%)

Branch coverage included in aggregate %.

106 of 110 new or added lines in 11 files covered. (96.36%)

62 existing lines in 5 files now uncovered.

38483 of 48475 relevant lines covered (79.39%)

0.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.15
/pmd-core/src/main/java/net/sourceforge/pmd/renderers/Renderer.java
1
/**
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.renderers;
6

7
import java.io.IOException;
8
import java.io.Writer;
9

10
import org.checkerframework.checker.nullness.qual.Nullable;
11

12
import net.sourceforge.pmd.benchmark.TimeTracker;
13
import net.sourceforge.pmd.benchmark.TimedOperation;
14
import net.sourceforge.pmd.benchmark.TimedOperationCategory;
15
import net.sourceforge.pmd.lang.document.TextFile;
16
import net.sourceforge.pmd.properties.PropertyDescriptor;
17
import net.sourceforge.pmd.properties.PropertySource;
18
import net.sourceforge.pmd.reporting.CloseHookFileListener;
19
import net.sourceforge.pmd.reporting.FileAnalysisListener;
20
import net.sourceforge.pmd.reporting.FileNameRenderer;
21
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
22
import net.sourceforge.pmd.reporting.ListenerInitializer;
23
import net.sourceforge.pmd.reporting.Report;
24
import net.sourceforge.pmd.reporting.Report.ConfigurationError;
25
import net.sourceforge.pmd.reporting.Report.GlobalReportBuilderListener;
26
import net.sourceforge.pmd.reporting.Report.ReportBuilderListener;
27

28
/**
29
 * This is an interface for rendering a Report. When a Renderer is being
30
 * invoked, the sequence of method calls is something like the following:
31
 * <ol>
32
 * <li>Renderer construction/initialization</li>
33
 * <li>{@link Renderer#setShowSuppressedViolations(boolean)}</li>
34
 * <li>{@link Renderer#setWriter(Writer)}</li>
35
 * <li>{@link Renderer#start()}</li>
36
 * <li>{@link Renderer#startFileAnalysis(TextFile)} for each source file
37
 * processed</li>
38
 * <li>{@link Renderer#renderFileReport(Report)} for each Report instance</li>
39
 * <li>{@link Renderer#end()}</li>
40
 * </ol>
41
 * <p>
42
 * An implementation of the Renderer interface is expected to have a default
43
 * constructor. Properties should be defined using the
44
 * {@link #definePropertyDescriptor(PropertyDescriptor)}
45
 * method. After the instance is created, the property values are set. This
46
 * means, you won't have access to property values in your constructor.
47
 */
48
// TODO Are implementations expected to be thread-safe?
49
public interface Renderer extends PropertySource {
50

51
    /**
52
     * Get the name of the Renderer.
53
     *
54
     * @return The name of the Renderer.
55
     */
56
    @Override
57
    String getName();
58

59
    /**
60
     * Set the name of the Renderer.
61
     *
62
     * @param name
63
     *            The name of the Renderer.
64
     */
65
    void setName(String name);
66

67
    /**
68
     * Get the description of the Renderer.
69
     *
70
     * @return The description of the Renderer.
71
     */
72
    String getDescription();
73

74
    /**
75
     * Return the default filename extension to use.
76
     *
77
     * @return String
78
     */
79
    String defaultFileExtension();
80

81
    /**
82
     * Set the description of the Renderer.
83
     *
84
     * @param description
85
     *            The description of the Renderer.
86
     */
87
    void setDescription(String description);
88

89
    /**
90
     * Get the indicator for whether to show suppressed violations.
91
     *
92
     * @return <code>true</code> if suppressed violations should show,
93
     *         <code>false</code> otherwise.
94
     */
95
    boolean isShowSuppressedViolations();
96

97
    /**
98
     * Set the indicator for whether to show suppressed violations.
99
     *
100
     * @param showSuppressedViolations
101
     *            Whether to show suppressed violations.
102
     */
103
    void setShowSuppressedViolations(boolean showSuppressedViolations);
104

105
    /**
106
     * Get the Writer for the Renderer.
107
     *
108
     * @return The Writer.
109
     */
110
    Writer getWriter();
111

112
    /**
113
     * Set the {@link FileNameRenderer} used to render file paths to the report.
114
     * Note that this renderer does not have to use the parameter to output paths.
115
     * Some report formats require a specific format for paths (eg a URI), and are
116
     * allowed to circumvent the provided strategy.
117
     *
118
     * @param fileNameRenderer a non-null file name renderer
119
     */
120
    void setFileNameRenderer(FileNameRenderer fileNameRenderer);
121

122
    /**
123
     * Set the Writer for the Renderer.
124
     *
125
     * @param writer The Writer.
126
     */
127
    void setWriter(Writer writer);
128

129
    /**
130
     * This method is called before any source files are processed. The Renderer
131
     * will have been fully initialized by the time this method is called, so
132
     * the Writer and other state will be available.
133
     *
134
     * @throws IOException
135
     */
136
    void start() throws IOException;
137

138
    /**
139
     * This method is called each time a source file is processed. It is called
140
     * after {@link Renderer#start()}, but before
141
     * {@link Renderer#renderFileReport(Report)} and {@link Renderer#end()}.
142
     *
143
     * This method may be invoked by different threads which are processing
144
     * files independently. Therefore, any non-trivial implementation of this
145
     * method needs to be thread-safe.
146
     *
147
     * @param dataSource
148
     *            The source file.
149
     */
150
    void startFileAnalysis(TextFile dataSource);
151

152
    /**
153
     * Render the given file Report. There may be multiple Report instances
154
     * which need to be rendered if produced by different threads. It is called
155
     * after {@link Renderer#start()} and
156
     * {@link Renderer#startFileAnalysis(TextFile)}, but before
157
     * {@link Renderer#end()}.
158
     *
159
     * @param report
160
     *            A file Report.
161
     * @throws IOException
162
     *
163
     * @see Report
164
     */
165
    void renderFileReport(Report report) throws IOException;
166

167
    /**
168
     * This method is at the very end of the Rendering process, after
169
     * {@link Renderer#renderFileReport(Report)}.
170
     */
171
    void end() throws IOException;
172

173
    void flush() throws IOException;
174

175
    /**
176
     * Sets the filename where the report should be written to. If no filename is provided,
177
     * the renderer should write to stdout.
178
     *
179
     * <p>Implementations must initialize the writer of the renderer.
180
     *
181
     * <p>See {@link AbstractRenderer#setReportFile(String)} for the default impl.
182
     *
183
     * @param reportFilename the filename (optional).
184
     */
185
    void setReportFile(String reportFilename);
186

187

188

189
    /**
190
     * Returns a new analysis listener, that handles violations by rendering
191
     * them in an implementation-defined way.
192
     */
193
    // TODO the default implementation matches the current behavior,
194
    //  ie violations are batched by file and forwarded to the renderer
195
    //  when the file is done. Many renderers could directly handle
196
    //  violations as they come though.
197
    default GlobalAnalysisListener newListener() throws IOException {
198
        try (TimedOperation ignored = TimeTracker.startOperation(TimedOperationCategory.REPORTING)) {
1✔
199
            this.start();
1✔
200
        }
201

202
        return new GlobalAnalysisListener() {
1✔
203

204
            // guard for the close routine
205
            final Object reportMergeLock = new Object();
1✔
206

207
            final GlobalReportBuilderListener configErrorReport = new GlobalReportBuilderListener();
1✔
208

209
            @Override
210
            public void onConfigError(ConfigurationError error) {
211
                configErrorReport.onConfigError(error);
1✔
212
            }
1✔
213

214
            @Override
215
            public ListenerInitializer initializer() {
216
                return new ListenerInitializer() {
1✔
217
                    @Override
218
                    public void setFileNameRenderer(FileNameRenderer fileNameRenderer) {
219
                        Renderer.this.setFileNameRenderer(fileNameRenderer);
1✔
220
                    }
1✔
221
                };
222
            }
223

224
            @Override
225
            public FileAnalysisListener startFileAnalysis(TextFile file) {
226
                Renderer renderer = Renderer.this;
1✔
227

228
                renderer.startFileAnalysis(file); // this routine is thread-safe by contract
1✔
229
                return new CloseHookFileListener<ReportBuilderListener>(new ReportBuilderListener()) {
1✔
230

231
                    @Override
232
                    protected void doClose(ReportBuilderListener reportBuilder, @Nullable Exception ignoredEx) throws Exception {
233
                        reportBuilder.close();
1✔
234
                        synchronized (reportMergeLock) {
1✔
235
                            // TODO renderFileReport should be thread-safe instead
236
                            try (TimedOperation ignored = TimeTracker.startOperation(TimedOperationCategory.REPORTING)) {
1✔
237
                                renderer.renderFileReport(reportBuilder.getResult());
1✔
238
                            }
239
                        }
1✔
240
                    }
1✔
241

242
                    @Override
243
                    public String toString() {
UNCOV
244
                        return "FileRendererListener[" + Renderer.this + "]";
×
245
                    }
246
                };
247
            }
248

249
            @Override
250
            public void close() throws Exception {
251
                configErrorReport.close();
1✔
252
                Renderer.this.renderFileReport(configErrorReport.getResult());
1✔
253
                try (TimedOperation ignored = TimeTracker.startOperation(TimedOperationCategory.REPORTING)) {
1✔
254
                    end();
1✔
255
                    flush();
1✔
256
                }
257
            }
1✔
258
        };
259
    }
260
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc