• 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

68.75
/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileId.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.document;
6

7
import java.io.File;
8
import java.net.URI;
9
import java.nio.file.Path;
10
import java.nio.file.Paths;
11
import java.util.Objects;
12

13
import org.checkerframework.checker.nullness.qual.Nullable;
14

15
import net.sourceforge.pmd.renderers.Renderer;
16
import net.sourceforge.pmd.reporting.RuleViolation;
17

18
/**
19
 * An identifier for a {@link TextFile}. This is not a path, but provides
20
 * several methods to be rendered into path-like strings in different formats
21
 * (for use mostly by {@link Renderer} instances). File IDs are used to
22
 * identify files e.g. in {@link RuleViolation}, {@link FileLocation}, {@link TextFile}.
23
 *
24
 * <p>Note that the addressed file may not be an actual file on a file system.
25
 * For instance, you can create file ids from strings ({@link #fromPathLikeString(String)}),
26
 * or use {@link #STDIN} to address standard input. The rendering methods
27
 * of this interface (like {@link #getAbsolutePath()}) do not have to return
28
 * actual paths for those exotic files, and operate on a best-effort basis.
29
 *
30
 * @author Clément Fournier
31
 */
32
public interface FileId extends Comparable<FileId> {
33

34
    /**
35
     * The name used for an unknown file. This is mostly only
36
     * relevant for unit tests.
37
     */
38
    FileId UNKNOWN = new FileId() {
1✔
39
        @Override
40
        public String getFileName() {
UNCOV
41
            return "(unknown)";
×
42
        }
43

44
        @Override
45
        public String getOriginalPath() {
46
            return "(unknown)";
1✔
47
        }
48

49
        @Override
50
        public String getAbsolutePath() {
51
            return getOriginalPath();
1✔
52
        }
53

54
        @Override
55
        public String getUriString() {
UNCOV
56
            return "file://" + getOriginalPath();
×
57
        }
58

59
        @Override
60
        public @Nullable FileId getParentFsPath() {
UNCOV
61
            return null;
×
62
        }
63

64
        @Override
65
        public String toString() {
UNCOV
66
            return "FileId(unknown)";
×
67
        }
68
    };
69

70
    /** The virtual file ID for standard input. */
71
    FileId STDIN = new FileId() {
1✔
72
        @Override
73
        public String getAbsolutePath() {
UNCOV
74
            return "stdin";
×
75
        }
76

77
        @Override
78
        public String getUriString() {
UNCOV
79
            return "stdin";
×
80
        }
81

82
        @Override
83
        public String getFileName() {
UNCOV
84
            return "stdin";
×
85
        }
86

87
        @Override
88
        public String getOriginalPath() {
UNCOV
89
            return "stdin";
×
90
        }
91

92
        @Override
93
        public @Nullable FileId getParentFsPath() {
UNCOV
94
            return null;
×
95
        }
96

97
        @Override
98
        public String toString() {
UNCOV
99
            return "FileId(STDIN)";
×
100
        }
101
    };
102

103

104
    /**
105
     * Return the simple file name, like {@link Path#getFileName()}.
106
     * This includes the extension.
107
     */
108
    String getFileName();
109

110
    /**
111
     * Return the path as it was input by the user. This may be a
112
     * relative or absolute path.
113
     */
114
    String getOriginalPath();
115

116
    /**
117
     * Return an absolute path to this file in its containing file system.
118
     * If the file is in a zip file, then this returns a path from the
119
     * zip root, and does not include the path of the zip itself.
120
     */
121
    String getAbsolutePath();
122

123
    /**
124
     * Return a string that looks like a URI pointing to this file.
125
     */
126
    String getUriString();
127

128
    /**
129
     * If this file is in a nested filesystem (eg a zip file), return
130
     * the file ID of the container in the outer file system. Return
131
     * null if this is in the root file system.
132
     */
133
    @Nullable FileId getParentFsPath();
134

135

136
    /**
137
     * Two file IDs are equal if they have the same {@link #getUriString()}.
138
     *
139
     * @param o Object
140
     */
141
    @Override
142
    boolean equals(Object o);
143

144

145
    @Override
146
    default int compareTo(FileId o) {
147
        return this.getAbsolutePath().compareTo(o.getAbsolutePath());
1✔
148
    }
149

150
    /**
151
     * This method is intentionally only meant for debugging, and its output
152
     * is unspecified. Code that needs a string representation should use one
153
     * of the named string conversion methods.
154
     */
155
    @Override
156
    String toString();
157

158
    /**
159
     * Return a path ID for the given string. The string is interpreted
160
     * as a file system path, so that {@link #getAbsolutePath()} and
161
     * {@link #getUriString()} may work.
162
     *
163
     * @param str A string. Should be a valid file system path for the platform (see
164
     *            {@link Paths#get(String, String...)}.
165
     *
166
     * @return A new file id
167
     */
168
    static FileId fromPathLikeString(String str) {
169
        Path absPath = Paths.get(str).toAbsolutePath();
1✔
170

171
        // this is null for the root path.
172
        @Nullable Path fileNamePath = absPath.getFileName();
1✔
173
        return new FileId() {
1✔
174
            final String fileName = fileNamePath == null ? "" : fileNamePath.toString();
1!
175
            final String absPathStr = absPath.toString();
1✔
176

177

178
            @Override
179
            public String getAbsolutePath() {
180
                return absPathStr;
1✔
181
            }
182

183

184
            @Override
185
            public String getUriString() {
186
                // pretend...
187
                return "file://" + str;
1✔
188
            }
189

190
            @Override
191
            public String getFileName() {
192
                return fileName;
1✔
193
            }
194

195
            @Override
196
            public String getOriginalPath() {
197
                return str;
1✔
198
            }
199

200
            @Override
201
            public boolean equals(Object obj) {
202
                return obj instanceof FileId
1!
203
                    && ((FileId) obj).getUriString().equals(this.getUriString());
1✔
204
            }
205

206
            @Override
207
            public int hashCode() {
208
                return getUriString().hashCode();
1✔
209
            }
210

211
            @Override
212
            public @Nullable FileId getParentFsPath() {
213
                return null;
1✔
214
            }
215

216
            @Override
217
            public String toString() {
218
                return "FileId(fromPathLike=" + str + ")";
1✔
219
            }
220
        };
221
    }
222

223
    /**
224
     * Return a new path id for the given path.
225
     *
226
     * @param path   The path
227
     * @param fsPath The file id of the containing file system, if it is some Zip file.
228
     *
229
     * @return A new file id.
230
     */
231
    static FileId fromPath(Path path, @Nullable FileId fsPath) {
232
        return new FileId() {
1✔
233
            // Compute these beforehand as that will fail if the path
234
            // is invalid (better now than later).
235
            // Also, not hitting the filesystem every time we want to
236
            // do a compareTo is good for performance.
237
            final String absPath = path.normalize().toAbsolutePath().toString();
1✔
238
            final String uriString = path.normalize().toUri().toString();
1✔
239
            final String fileName = path.getFileName().toString();
1✔
240
            final String origPath = path.toString();
1✔
241

242
            @Override
243
            public String getAbsolutePath() {
244
                return absPath;
1✔
245
            }
246

247
            @Override
248
            public String getUriString() {
249
                return uriString;
1✔
250
            }
251

252
            @Override
253
            public String getFileName() {
254
                return fileName;
1✔
255
            }
256

257
            @Override
258
            public String getOriginalPath() {
259
                return origPath;
1✔
260
            }
261

262
            @Override
263
            public @Nullable FileId getParentFsPath() {
264
                return fsPath;
1✔
265
            }
266

267
            @Override
268
            public boolean equals(Object obj) {
269
                return obj instanceof FileId
1!
270
                    && ((FileId) obj).getUriString().equals(this.getUriString());
1!
271
            }
272

273
            @Override
274
            public int hashCode() {
275
                return getUriString().hashCode();
1✔
276
            }
277

278
            @Override
279
            public String toString() {
UNCOV
280
                return "FileId(fromPath=" + path + ")";
×
281
            }
282
        };
283
    }
284

285
    /**
286
     * Return a file ID for the given path. This uses {@link #fromPath(Path, FileId)}
287
     * and defaults the second parameter to null.
288
     */
289
    static FileId fromPath(Path path) {
290
        return fromPath(path, null);
1✔
291
    }
292

293
    /**
294
     * Return a file ID whose methods behave the same as the first parameter,
295
     * and whose {@link #getParentFsPath()} returns the second parameter.
296
     *
297
     * @param self         A file id
298
     * @param parentFsPath Another file id for the parent.
299
     */
300

301
    static FileId asChildOf(FileId self, FileId parentFsPath) {
302
        if (Objects.equals(self.getParentFsPath(), parentFsPath)) {
1✔
303
            return self;
1✔
304
        }
305
        return new FileId() {
1✔
306
            @Override
307
            public @Nullable FileId getParentFsPath() {
308
                return parentFsPath;
1✔
309
            }
310

311
            @Override
312
            public String getUriString() {
313
                return self.getUriString();
1✔
314
            }
315

316
            @Override
317
            public String getFileName() {
318
                return self.getFileName();
1✔
319
            }
320

321
            @Override
322
            public String getOriginalPath() {
323
                return self.getOriginalPath();
1✔
324
            }
325

326
            @Override
327
            public String getAbsolutePath() {
328
                return self.getAbsolutePath();
1✔
329
            }
330

331
            @Override
332
            public boolean equals(Object obj) {
UNCOV
333
                return obj instanceof FileId
×
UNCOV
334
                    && getUriString().equals(((FileId) obj).getUriString());
×
335
            }
336

337
            @Override
338
            public int hashCode() {
UNCOV
339
                return getUriString().hashCode();
×
340
            }
341

342
            @Override
343
            public String toString() {
UNCOV
344
                return "FileId(" + self + ",asChildOf=" + parentFsPath + ")";
×
345
            }
346
        };
347
    }
348

349
    /**
350
     * Return a file ID which interprets the first parameter as an absolute path.
351
     * The path must be a valid path for this system ({@link Paths#get(String, String...)} should not fail).
352
     * The URI is rebuilt using the outer file ID if it is non-null.
353
     *
354
     * @param absPath Absolute path for the file
355
     * @param outer   File ID of the outer file system (Zip), if it exists
356
     *
357
     * @return A new file id
358
     */
359
    static FileId fromAbsolutePath(String absPath, @Nullable FileId outer) {
360
        Path fileName = Paths.get(absPath).getFileName();
1✔
361
        // we know this one uses platform specific thing (for display)
362
        String platformAbsPath = absPath.replace('/', File.separatorChar);
1✔
363
        // we know this one uses / (for URIs)
364
        String uriAbsPath = platformAbsPath.replace(File.separatorChar, '/');
1✔
365
        String uriStr = outer != null ? "jar:" + outer.getUriString() + "!" + uriAbsPath
1!
366
                                      : "file://" + uriAbsPath;
1✔
367
        // zip file
368
        return new FileId() {
1✔
369
            @Override
370
            public String getFileName() {
371
                return fileName.toString();
1✔
372
            }
373

374
            @Override
375
            public String getOriginalPath() {
376
                return absPath;
1✔
377
            }
378

379
            @Override
380
            public String getAbsolutePath() {
381
                return platformAbsPath;
1✔
382
            }
383

384
            @Override
385
            public String getUriString() {
386
                return uriStr;
1✔
387
            }
388

389
            @Override
390
            public @Nullable FileId getParentFsPath() {
391
                return outer;
1✔
392
            }
393

394
            @Override
395
            public boolean equals(Object obj) {
UNCOV
396
                return obj instanceof FileId && getUriString().equals(((FileId) obj).getUriString());
×
397
            }
398

399
            @Override
400
            public int hashCode() {
UNCOV
401
                return getUriString().hashCode();
×
402
            }
403

404
            @Override
405
            public String toString() {
UNCOV
406
                return "FileId(fromAbsolutePath=" + absPath + ",outer=" + outer + ")";
×
407
            }
408
        };
409
    }
410

411
    /**
412
     * Return a file ID for a URI.
413
     * The URI must have scheme {@code file} or {@code jar} and be a
414
     * valid URI (see {@link URI#create(String)}). If the scheme is {@code jar},
415
     * then the {@link #getParentFsPath()} is populated with the path of the jar.
416
     *
417
     * @param uriStr A uri string
418
     *
419
     * @return A new file id
420
     */
421
    static FileId fromURI(String uriStr) throws IllegalArgumentException {
422
        URI uri = URI.create(uriStr);
1✔
423
        String schemeSpecificPart = uri.getSchemeSpecificPart();
1✔
424
        if ("jar".equals(uri.getScheme())) {
1✔
425
            int split = schemeSpecificPart.lastIndexOf('!');
1✔
426
            if (split == -1) {
1!
UNCOV
427
                throw new IllegalArgumentException("expected a jar specific path");
×
428
            } else {
429
                String zipUri = schemeSpecificPart.substring(0, split);
1✔
430
                String localPath = schemeSpecificPart.substring(split + 1);
1✔
431
                FileId outer = fromURI(zipUri);
1✔
432

433
                return fromAbsolutePath(localPath, outer);
1✔
434
            }
435
        } else if ("file".equals(uri.getScheme())) {
1!
436
            Path path = Paths.get(uri);
1✔
437
            return fromPath(path);
1✔
438
        }
UNCOV
439
        throw new UnsupportedOperationException("Unknown scheme " + uriStr);
×
440
    }
441
}
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