Skip to content

Commit 448a65b

Browse files
committed
refactor: Fix or suppress codesmell recommendations
1 parent 698baf0 commit 448a65b

File tree

22 files changed

+234
-95
lines changed

22 files changed

+234
-95
lines changed

SuppressWarnings.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# JSON→URL: common uses of @SuppressWarnings
2+
3+
There are a number of places in the code where a `@SuppressWarnings`
4+
annotation is used. Rather than repeating the `WONTFIX` or `FALSE POSITIVE`
5+
justification for common use cases all over the code, this file serves as a
6+
reference.
7+
8+
## !API!
9+
Items marked with `!API!` would break the existing public API if the
10+
PMD/sonar recommendation was followed. They're good candidates for future
11+
improvement.
12+
13+
## Complexity
14+
15+
This is reported by PMD via
16+
[CyclomaticComplexity](https://pmd.github.io/pmd/pmd_rules_java_design.html#cyclomaticcomplexity)
17+
and
18+
[NPathComplexity](https://pmd.github.io/pmd/pmd_rules_java_design.html#npathcomplexity),
19+
and
20+
reported by sonarlint via
21+
[java:S3776](https://rules.sonarsource.com/c/RSPEC-3776).
22+
23+
While
24+
[complexity](https://en.wikipedia.org/wiki/Cyclomatic_complexity)
25+
is a thing one generally wants to avoid, in these cases the method's content is
26+
really a single, logical thought. The tool's recommendation is to reduce the
27+
complexity of the method, which usually means splitting the code into multiple
28+
methods. However, splitting it into multiple methods, in this case, won't
29+
allow them to be independently tested (a primary motivation), and it will likely
30+
make it harder to follow the logic due to the additional indirection.
31+
32+
```java
33+
@SuppressWarnings({
34+
// See SuppressWarnings.md#complexity
35+
"PMD.CyclomaticComplexity",
36+
"PMD.NPathComplexity",
37+
"java:S3776"
38+
})
39+
```
40+
41+
## Reassigning Loop Variables
42+
43+
Generally you want to avoid assigning to loop variables. However, sometimes it's
44+
necessary to make the code function properly, and alternative implementations
45+
are far less readable.
46+
47+
```java
48+
@SuppressWarnings({
49+
// See SuppressWarnings.md
50+
"PMD.AvoidReassigningLoopVariables", "java:S127"
51+
})
52+
```
53+
## Shadowing an instance variable with a local variable
54+
55+
It's often a bad idea to shadow an instance variable with a local variable.
56+
However, in some cases that's exactly what you want, when the local variable
57+
has the same semantic meaning as the instance variable, but it:
58+
59+
* serves as a cache (improves performance)
60+
* needs to have some logic applied before it can be used
61+
62+
```java
63+
@SuppressWarnings("java:S1117") // See SuppressWarnings.md
64+
```
65+
66+
## Shadowing a class/interface name
67+
68+
It's usually bad practice to shadow a class or interface name that you
69+
reference. However, the way the JSON→URL API is intended to be used, a
70+
user should never attempt to use both at the same time. Each derived class is
71+
an implementation of the parent class for its implementation target (e.g.
72+
json.org, JSR374, etc), and the user should only ever be using the derived
73+
class.
74+
75+
```java
76+
@SuppressWarnings("java:S2176") // See SuppressWarnings.md
77+
```
78+
79+
## Type parameter names
80+
81+
Names should follow a naming convention, and generics are no exception.
82+
JSON→URL does follow a convention, it's just not the default, and I
83+
couldn't find a PMD parameter that allows me to change the regex.
84+
85+
```java
86+
@SuppressWarnings({"PMD.GenericsNaming", "java:S119"}) // See SuppressWarnings.md
87+
```
88+

module/jsonurl-core/src/main/java/org/jsonurl/JsonUrlOptionable.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public interface JsonUrlOptionable {
3939
/**
4040
* Get the options from the given object, if possible.
4141
*/
42+
@SuppressWarnings("java:S1168") // See SuppressWarnings.md - !API!
4243
static Set<JsonUrlOption> getJsonUrlOptions(Object obj) {
4344
if (obj instanceof JsonUrlOptionable) {
4445
return ((JsonUrlOptionable)obj).options();

module/jsonurl-core/src/main/java/org/jsonurl/ParseException.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,15 @@ public int getColumn() {
110110
/**
111111
* Exception type description.
112112
*/
113+
@SuppressWarnings(
114+
// false positive; It's overridden by subclasses
115+
"java:S3400")
113116
protected String typeDescription() {
114117
return "parse error";
115118
}
116119

117120
@Override
121+
@SuppressWarnings("java:S1117") // See SuppressWarnings.md
118122
public String toString() {
119123
StringBuilder buf = new StringBuilder(64);
120124

module/jsonurl-core/src/main/java/org/jsonurl/stream/AbstractCharIterator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public abstract class AbstractCharIterator implements CharIterator {
8181
* exception is thrown.
8282
* @param name Resource {@link Resource#getName() name}
8383
*/
84-
public AbstractCharIterator(String name) {
84+
protected AbstractCharIterator(String name) {
8585
this(name, JsonUrlLimits.DEFAULT_MAX_PARSE_CHARS);
8686
}
8787

@@ -91,7 +91,7 @@ public AbstractCharIterator(String name) {
9191
* @param limit maximum number of parsed characters before a
9292
* {@link org.jsonurl.LimitException LimitException} is thrown.
9393
*/
94-
public AbstractCharIterator(String name, long limit) {
94+
protected AbstractCharIterator(String name, long limit) {
9595
this.name = name;
9696
this.limit = limit;
9797
}

module/jsonurl-core/src/main/java/org/jsonurl/stream/AbstractEventIterator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public abstract class AbstractEventIterator
8787
* Construct a new AbstractIterator.
8888
* @param text input text
8989
*/
90-
public AbstractEventIterator(
90+
protected AbstractEventIterator(
9191
CharIterator text,
9292
JsonUrlLimits limits,
9393
Set<JsonUrlOption> options) {
@@ -168,6 +168,7 @@ public static JsonUrlEvent getTrueFalseNull(CharSequence text) { // NOPMD
168168
*
169169
* @param type the type found during parse
170170
*/
171+
@SuppressWarnings("java:S1117") // See SuppressWarnings.md
171172
protected void checkResultType(ValueType type) {
172173
if (!doneTypeCheck) {
173174
doneTypeCheck = true;
@@ -191,6 +192,7 @@ protected void checkResultType(ValueType type) {
191192
*
192193
* @see #checkResultType(ValueType)
193194
*/
195+
@SuppressWarnings("java:S1117") // See SuppressWarnings.md
194196
protected void checkResultTypeIsComposite() {
195197
if (!doneTypeCheck) {
196198
doneTypeCheck = true;

module/jsonurl-core/src/main/java/org/jsonurl/stream/AbstractGrammar.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@ private enum State {
110110
*/
111111
private static final String INTERNAL_PARSE_ERROR = "internal parse error";
112112

113-
/*
114-
* empty string.
115-
*
116-
private static final String EMPTY_STRING = "";*/
117-
118113
/**
119114
* Parse state stack.
120115
*/
@@ -135,7 +130,6 @@ private enum State {
135130
* Buffered "next" event value.
136131
*/
137132
private JsonUrlEvent savedEventValue;
138-
//private Deque<JsonUrlEvent> savedEventStack = new LinkedList<>();
139133

140134
/**
141135
* Current parse/nesting depth.
@@ -153,7 +147,7 @@ private enum State {
153147
* @param limits a valid JsonUrlLimits or null
154148
* @param options valid JsonUrlOptions or null
155149
*/
156-
public AbstractGrammar(
150+
protected AbstractGrammar(
157151
CharIterator text,
158152
JsonUrlLimits limits,
159153
Set<JsonUrlOption> options) {

module/jsonurl-core/src/main/java/org/jsonurl/stream/JsonUrlGrammarAQF.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,12 @@ private void decodeBang(StringBuilder decodedText, boolean isFirst) {
138138
}
139139

140140
@Override
141-
@SuppressWarnings("PMD.CyclomaticComplexity")
141+
@SuppressWarnings({
142+
"PMD.CyclomaticComplexity",
143+
144+
// false positive
145+
"java:S135"
146+
})
142147
protected boolean readAndBufferLiteral() {
143148
final StringBuilder decodedText = this.decodedTextBuffer;
144149
decodedText.setLength(0);

module/jsonurl-core/src/main/java/org/jsonurl/text/JsonTextAppendable.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,8 @@
2929
* @author David MacCormack
3030
* @since 2020-11-01
3131
*/
32+
@SuppressWarnings(
33+
// false positive - it's used by subclasses
34+
"java:S2326")
3235
public interface JsonTextAppendable<A,R> extends JsonTextBuilder<R>, Appendable {
3336
}

module/jsonurl-core/src/main/java/org/jsonurl/text/JsonUrlTextAppender.java

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -396,26 +396,20 @@ private static <T extends Appendable> void appendCodePoint(
396396
/**
397397
* Test if the given text matches one of: true, false, null.
398398
*/
399-
@SuppressWarnings("PMD.CyclomaticComplexity")
399+
@SuppressWarnings({"java:S3776", "PMD.CyclomaticComplexity"})
400400
private static boolean isTrueFalseNull(CharSequence text, int start, int end) {
401401
switch (end - start) {
402402
case 4:
403403
switch (text.charAt(0)) {
404404
case 't':
405-
if (text.charAt(1) == 'r'
406-
&& text.charAt(2) == 'u'
407-
&& text.charAt(3) == 'e') {
408-
return true;
409-
}
410-
return false;
405+
return text.charAt(1) == 'r'
406+
&& text.charAt(2) == 'u'
407+
&& text.charAt(3) == 'e';
411408

412409
case 'n':
413-
if (text.charAt(1) == 'u'
414-
&& text.charAt(2) == 'l'
415-
&& text.charAt(3) == 'l') {
416-
return true;
417-
}
418-
return false;
410+
return text.charAt(1) == 'u'
411+
&& text.charAt(2) == 'l'
412+
&& text.charAt(3) == 'l';
419413

420414
default:
421415
return false;
@@ -424,14 +418,11 @@ private static boolean isTrueFalseNull(CharSequence text, int start, int end) {
424418
// fall through
425419

426420
case 5:
427-
if (text.charAt(0) == 'f'
428-
&& text.charAt(1) == 'a'
429-
&& text.charAt(2) == 'l'
430-
&& text.charAt(3) == 's'
431-
&& text.charAt(4) == 'e') {
432-
return true;
433-
}
434-
return false;
421+
return text.charAt(0) == 'f'
422+
&& text.charAt(1) == 'a'
423+
&& text.charAt(2) == 'l'
424+
&& text.charAt(3) == 's'
425+
&& text.charAt(4) == 'e';
435426

436427
default:
437428
return false;
@@ -467,7 +458,12 @@ private static boolean contains(
467458
* @param options a valid JsonUrlOptions or null
468459
* @return true if dest was modified
469460
*/
470-
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
461+
@SuppressWarnings({
462+
// See SuppressWarnings.md#complexity
463+
"PMD.CyclomaticComplexity",
464+
"PMD.NPathComplexity",
465+
"java:S3776"
466+
})
471467
private static <T extends Appendable> boolean appendLiteral(
472468
T dest,
473469
CharSequence text,

module/jsonurl-core/src/main/java/org/jsonurl/text/NumberBuilder.java

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,18 @@ public boolean parse(CharSequence text, Set<JsonUrlOption> options) {
468468
* @param stop an index
469469
* @return true if the CharSequence was successfully parsed
470470
*/
471-
public boolean parse(//NOPMD
471+
@SuppressWarnings({
472+
// See SuppressWarnings.md#complexity
473+
"PMD.CyclomaticComplexity",
474+
"PMD.NPathComplexity",
475+
"java:S3776"
476+
})
477+
public boolean parse(
472478
CharSequence text,
473479
int start,
474480
int stop,
475481
Set<JsonUrlOption> options) {
476-
int pos = this.start = start; //NOPMD
482+
int pos = this.start = start;
477483

478484
char c = text.charAt(start); //NOPMD
479485

@@ -612,7 +618,17 @@ public static boolean isNumber(
612618
* @param options a valid set of options or {@code null}
613619
* @return true if the CharSequence is a JSON&#x2192;URL number
614620
*/
615-
public static boolean isNumber(//NOPMD
621+
@SuppressWarnings({
622+
// See SuppressWarnings.md#complexity
623+
"PMD.CyclomaticComplexity",
624+
"PMD.NPathComplexity",
625+
626+
//
627+
// this is part of the public API, and I don't want to break it
628+
//
629+
"java:S1172"
630+
})
631+
public static boolean isNumber(
616632
CharSequence text,
617633
int start,
618634
int stop,
@@ -1104,9 +1120,15 @@ private static int parseInteger(
11041120
* @param stop stop index
11051121
* @return a long
11061122
*/
1123+
@SuppressWarnings({
1124+
"PMD.ShortVariable",
1125+
1126+
// doing so is semantically meaningful in this case
1127+
"PMD.AvoidReassigningParameters"
1128+
})
11071129
private static long parseLong(
11081130
CharSequence text,
1109-
int start, // NOPMD
1131+
int start,
11101132
int stop,
11111133
int defaultValue) {
11121134

@@ -1115,9 +1137,9 @@ private static long parseLong(
11151137
}
11161138

11171139
long ret = 0;
1118-
boolean isneg = false; // NOPMD
1140+
boolean isneg = false;
11191141

1120-
char c = text.charAt(start); // NOPMD
1142+
char c = text.charAt(start);
11211143

11221144
switch (c) {
11231145
case MINUS:

0 commit comments

Comments
 (0)