diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index 7f1b36f96e..e4e445af38 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -19,6 +19,12 @@ This is a {{ site.pmd.release_type }} release.
### New and noteworthy
+#### New Rules
+
+* The new Apex rule {% rule "apex/errorprone/OverrideBothEqualsAndHashcode" %} brings the well known Java rule
+ to Apex. In Apex the same principle applies: `equals` and `hashCode` should always be overridden
+ together to ensure collection classes such as Maps and Sets work as expected.
+
### Fixed Issues
* core
@@ -26,12 +32,17 @@ This is a {{ site.pmd.release_type }} release.
* [#2994](https://github.com/pmd/pmd/pull/2994): \[core] Fix code climate severity strings
* java-bestpractices
* [#575](https://github.com/pmd/pmd/issues/575): \[java] LiteralsFirstInComparisons should consider constant fields
+* java-codestyle
+ * [#2960](https://github.com/pmd/pmd/issues/2960): \[java] Thread issue in MethodNamingConventionsRule
### API Changes
### External Contributions
+* [#2666](https://github.com/pmd/pmd/pull/2666): \[swift] Manage swift5 string literals - [kenji21](https://github.com/kenji21)
+* [#2959](https://github.com/pmd/pmd/pull/2959): \[apex] New Rule: override equals and hashcode rule - [recdevs](https://github.com/recdevs)
* [#2964](https://github.com/pmd/pmd/pull/2964): \[cs] Update C# grammar for additional C# 7 and C# 8 features - [Maikel Steneker](https://github.com/maikelsteneker)
+* [#2965](https://github.com/pmd/pmd/pull/2965): \[cs] Improvements for ignore sequences of literals functionality - [Maikel Steneker](https://github.com/maikelsteneker)
* [#2983](https://github.com/pmd/pmd/pull/2983): \[java] LiteralsFirstInComparisons should consider constant fields - [Ozan Gulle](https://github.com/ozangulle)
* [#2994](https://github.com/pmd/pmd/pull/2994): \[core] Fix code climate severity strings - [Vincent Maurin](https://github.com/vmaurin)
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/errorprone/OverrideBothEqualsAndHashcodeRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/errorprone/OverrideBothEqualsAndHashcodeRule.java
new file mode 100644
index 0000000000..29d90ad523
--- /dev/null
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/errorprone/OverrideBothEqualsAndHashcodeRule.java
@@ -0,0 +1,68 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.apex.rule.errorprone;
+
+import net.sourceforge.pmd.lang.apex.ast.ASTMethod;
+import net.sourceforge.pmd.lang.apex.ast.ASTParameter;
+import net.sourceforge.pmd.lang.apex.ast.ASTUserClass;
+import net.sourceforge.pmd.lang.apex.ast.ApexNode;
+import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
+
+public class OverrideBothEqualsAndHashcodeRule extends AbstractApexRule {
+
+ public OverrideBothEqualsAndHashcodeRule() {
+ addRuleChainVisit(ASTUserClass.class);
+ }
+
+ @Override
+ public Object visit(ASTUserClass node, Object data) {
+ ApexNode> equalsNode = null;
+ ApexNode> hashNode = null;
+ for (ASTMethod method : node.findChildrenOfType(ASTMethod.class)) {
+ if (equalsNode == null && isEquals(method)) {
+ equalsNode = method;
+ }
+ if (hashNode == null && isHashCode(method)) {
+ hashNode = method;
+ }
+ if (hashNode != null && equalsNode != null) {
+ break;
+ }
+ }
+
+ if (equalsNode != null && hashNode == null) {
+ addViolation(data, equalsNode);
+ } else if (hashNode != null && equalsNode == null) {
+ addViolation(data, hashNode);
+ }
+
+ return data;
+ }
+
+ private boolean isEquals(ASTMethod node) {
+ int numParams = 0;
+ String paramType = null;
+ for (int ix = 0; ix < node.getNumChildren(); ix++) {
+ ApexNode> sn = node.getChild(ix);
+ if (sn instanceof ASTParameter) {
+ numParams++;
+ paramType = ((ASTParameter) sn).getType();
+ }
+ }
+ return numParams == 1 && "equals".equalsIgnoreCase(node.getImage()) && "Object".equalsIgnoreCase(paramType);
+ }
+
+ private boolean isHashCode(ASTMethod node) {
+ int numParams = 0;
+ for (int ix = 0; ix < node.getNumChildren(); ix++) {
+ ApexNode> sn = node.getChild(ix);
+ if (sn instanceof ASTParameter) {
+ numParams++;
+ }
+ }
+
+ return numParams == 0 && "hashCode".equalsIgnoreCase(node.getImage());
+ }
+}
diff --git a/pmd-apex/src/main/resources/category/apex/errorprone.xml b/pmd-apex/src/main/resources/category/apex/errorprone.xml
index d0933dbb80..5b8152560f 100644
--- a/pmd-apex/src/main/resources/category/apex/errorprone.xml
+++ b/pmd-apex/src/main/resources/category/apex/errorprone.xml
@@ -110,6 +110,30 @@ public without sharing class Foo {
+
+
+ Apex supported non existent annotations for legacy reasons.
+ In the future, use of such non-existent annotations could result in broken apex code that will not compile.
+ This will prevent users of garbage annotations from being able to use legitimate annotations added to Apex in the future.
+ A full list of supported annotations can be found at https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation.htm
+
+ 3
+
+
+
+
+
-
+ since="6.31.0"
+ message="Ensure you override both equals() and hashCode()"
+ class="net.sourceforge.pmd.lang.apex.rule.errorprone.OverrideBothEqualsAndHashcodeRule"
+ externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_errorprone.html#overridebothequalsandhashcode">
- Apex supported non existent annotations for legacy reasons.
- In the future, use of such non-existent annotations could result in broken apex code that will not compile.
- This will prevent users of garbage annotations from being able to use legitimate annotations added to Apex in the future.
- A full list of supported annotations can be found at https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation.htm
+Override both `public Boolean equals(Object obj)`, and `public Integer hashCode()`, or override neither.
+Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly
+delegating to your superclass.
+
+This is especially important when [Using Custom Types in Map Keys and Sets](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections_maps_keys_userdefined.htm).
3
-
diff --git a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml
index 1b5e312091..46cc093370 100644
--- a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml
+++ b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml
@@ -202,5 +202,6 @@
3
+
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/OverrideBothEqualsAndHashcodeTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/OverrideBothEqualsAndHashcodeTest.java
new file mode 100644
index 0000000000..0b334a5f9f
--- /dev/null
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/errorprone/OverrideBothEqualsAndHashcodeTest.java
@@ -0,0 +1,11 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.apex.rule.errorprone;
+
+import net.sourceforge.pmd.testframework.PmdRuleTst;
+
+public class OverrideBothEqualsAndHashcodeTest extends PmdRuleTst {
+ // no additional unit tests
+}
diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/OverrideBothEqualsAndHashcode.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/OverrideBothEqualsAndHashcode.xml
new file mode 100644
index 0000000000..d321c92777
--- /dev/null
+++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/errorprone/xml/OverrideBothEqualsAndHashcode.xml
@@ -0,0 +1,166 @@
+
+
+
+
+ hash code only
+ 1
+
+
+
+
+ nested hash code only
+ 1
+
+
+
+
+ equals only
+ 1
+
+
+
+
+ nested equals only, checking case insensitiveness
+ 1
+
+
+
+
+ overrides both
+ 0
+
+
+
+
+ nested overrides both
+ 0
+
+
+
+
+ overrides neither
+ 0
+
+
+
+
+ equals sig uses String, not Object
+ 1
+
+
+
+
+ interface
+ 0
+
+
+
+
+ implements equals but with 2 args, hashCode overloaded as well
+ 0
+
+
+
+
+ overloaded hashCode
+ 0
+
+
+
+
+ overloaded both
+ 0
+
+
+
+
+ overloaded hashCode, should fail on equals
+ 1
+
+
+
+
+ implements hashCode but with args
+ 0
+ a) {
+ return 0;
+ }
+}
+ ]]>
+
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/6310.xml b/pmd-core/src/main/resources/rulesets/releases/6310.xml
new file mode 100644
index 0000000000..eaf61d2469
--- /dev/null
+++ b/pmd-core/src/main/resources/rulesets/releases/6310.xml
@@ -0,0 +1,13 @@
+
+
+
+
+This ruleset contains links to rules that are new in PMD v6.31.0
+
+
+
+
+
diff --git a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java
index 7c0e895378..f956201793 100644
--- a/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java
+++ b/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java
@@ -64,7 +64,7 @@ public class CsTokenizer extends AntlrTokenizer {
private final boolean ignoreLiteralSequences;
private boolean discardingUsings = false;
private boolean discardingNL = false;
- private boolean discardingLiterals = false;
+ private AntlrToken discardingLiteralsUntil = null;
private boolean discardCurrent = false;
CsTokenFilter(final AntlrTokenManager tokenManager, boolean ignoreUsings, boolean ignoreLiteralSequences) {
@@ -162,19 +162,24 @@ public class CsTokenizer extends AntlrTokenizer {
private void skipLiteralSequences(final AntlrToken currentToken, final Iterable remainingTokens) {
if (ignoreLiteralSequences) {
final int type = currentToken.getKind();
- if (type == CSharpLexer.OPEN_BRACE && isSequenceOfLiterals(remainingTokens)) {
- discardingLiterals = true;
- } else if (type == CSharpLexer.CLOSE_BRACE && discardingLiterals) {
- discardingLiterals = false;
- discardCurrent = true;
+ if (isDiscardingLiterals()) {
+ if (currentToken == discardingLiteralsUntil) { // NOPMD - intentional check for reference equality
+ discardingLiteralsUntil = null;
+ discardCurrent = true;
+ }
+ } else if (type == CSharpLexer.OPEN_BRACE) {
+ final AntlrToken finalToken = findEndOfSequenceOfLiterals(remainingTokens);
+ discardingLiteralsUntil = finalToken;
}
}
}
- private boolean isSequenceOfLiterals(final Iterable remainingTokens) {
+ private AntlrToken findEndOfSequenceOfLiterals(final Iterable remainingTokens) {
boolean seenLiteral = false;
+ int braceCount = 0;
for (final AntlrToken token : remainingTokens) {
switch (token.getKind()) {
+ case CSharpLexer.BIN_INTEGER_LITERAL:
case CSharpLexer.CHARACTER_LITERAL:
case CSharpLexer.HEX_INTEGER_LITERAL:
case CSharpLexer.INTEGER_LITERAL:
@@ -183,20 +188,33 @@ public class CsTokenizer extends AntlrTokenizer {
break; // can be skipped; continue to the next token
case CSharpLexer.COMMA:
break; // can be skipped; continue to the next token
+ case CSharpLexer.OPEN_BRACE:
+ braceCount++;
+ break; // curly braces are allowed, as long as they're balanced
case CSharpLexer.CLOSE_BRACE:
- // end of the list; skip all contents
- return seenLiteral;
+ braceCount--;
+ if (braceCount < 0) {
+ // end of the list; skip all contents
+ return seenLiteral ? token : null;
+ } else {
+ // curly braces are not yet balanced; continue to the next token
+ break;
+ }
default:
// some other token than the expected ones; this is not a sequence of literals
- return false;
+ return null;
}
}
- return false;
+ return null;
+ }
+
+ public boolean isDiscardingLiterals() {
+ return discardingLiteralsUntil != null;
}
@Override
protected boolean isLanguageSpecificDiscarding() {
- return discardingUsings || discardingNL || discardingLiterals || discardCurrent;
+ return discardingUsings || discardingNL || isDiscardingLiterals() || discardCurrent;
}
}
}
diff --git a/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.cs b/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.cs
index a3ceee1dca..6ebda7d3ff 100644
--- a/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.cs
+++ b/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.cs
@@ -3,6 +3,22 @@ using System.Collections;
using System.Collections.Generic;
public class LongLists {
List l = new List {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ };
+ byte[,] a = {1,2,3,4,5};
+ byte[,] b = {{1,2},{3,4},{5,6}};
+ int[,] c = {
+ 157, // decimal literal
+ 0377, // octal literal
+ 36_000_000, // literal with digit separators
+ 0x3fff, // hexadecimal literal
+ 0X3FFF, // same hexadecimal literal
+ 328u, // unsigned value
+ 0x7FFFFFL, // long value
+ 0776745ul, // unsigned long value
+ 18.46, // float
+ 18.46e0, // double with exponent
+ 18.46e1, // double with exponent
+ 0b000001, // binary literal
};
}
diff --git a/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.txt b/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.txt
index f5024fc29c..8cd2c19447 100644
--- a/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.txt
+++ b/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers.txt
@@ -36,309 +36,402 @@ L5
[>] 33 34
[{] 35 36
L6
- [0] 6 7
- [,] 7 8
- [0] 8 9
- [,] 9 10
- [0] 10 11
- [,] 11 12
- [0] 12 13
- [,] 13 14
- [0] 14 15
- [,] 15 16
- [0] 16 17
- [,] 17 18
- [0] 18 19
- [,] 19 20
- [0] 20 21
- [,] 21 22
- [0] 22 23
- [,] 23 24
- [0] 24 25
- [,] 25 26
- [0] 26 27
- [,] 27 28
- [0] 28 29
- [,] 29 30
- [0] 30 31
- [,] 31 32
- [0] 32 33
- [,] 33 34
- [0] 34 35
- [,] 35 36
- [0] 36 37
- [,] 37 38
- [0] 38 39
- [,] 39 40
- [0] 40 41
- [,] 41 42
- [0] 42 43
- [,] 43 44
- [0] 44 45
- [,] 45 46
- [0] 46 47
- [,] 47 48
- [0] 48 49
- [,] 49 50
- [0] 50 51
- [,] 51 52
- [0] 52 53
- [,] 53 54
- [0] 54 55
- [,] 55 56
- [0] 56 57
- [,] 57 58
- [0] 58 59
- [,] 59 60
- [0] 60 61
- [,] 61 62
- [0] 62 63
- [,] 63 64
- [0] 64 65
- [,] 65 66
- [0] 66 67
- [,] 67 68
- [0] 68 69
- [,] 69 70
- [0] 70 71
- [,] 71 72
- [0] 72 73
- [,] 73 74
- [0] 74 75
- [,] 75 76
- [0] 76 77
- [,] 77 78
- [0] 78 79
- [,] 79 80
- [0] 80 81
- [,] 81 82
- [0] 82 83
- [,] 83 84
- [0] 84 85
- [,] 85 86
- [0] 86 87
- [,] 87 88
- [0] 88 89
- [,] 89 90
- [0] 90 91
- [,] 91 92
- [0] 92 93
- [,] 93 94
- [0] 94 95
- [,] 95 96
- [0] 96 97
- [,] 97 98
- [0] 98 99
- [,] 99 100
- [0] 100 101
- [,] 101 102
- [0] 102 103
- [,] 103 104
- [0] 104 105
- [,] 105 106
- [0] 106 107
- [,] 107 108
- [0] 108 109
- [,] 109 110
- [0] 110 111
- [,] 111 112
- [0] 112 113
- [,] 113 114
- [0] 114 115
- [,] 115 116
- [0] 116 117
- [,] 117 118
- [0] 118 119
- [,] 119 120
- [0] 120 121
- [,] 121 122
- [0] 122 123
- [,] 123 124
- [0] 124 125
- [,] 125 126
- [0] 126 127
- [,] 127 128
- [0] 128 129
- [,] 129 130
- [0] 130 131
- [,] 131 132
- [0] 132 133
- [,] 133 134
- [0] 134 135
- [,] 135 136
- [0] 136 137
- [,] 137 138
- [0] 138 139
- [,] 139 140
- [0] 140 141
- [,] 141 142
- [0] 142 143
- [,] 143 144
- [0] 144 145
- [,] 145 146
- [0] 146 147
- [,] 147 148
- [0] 148 149
- [,] 149 150
- [0] 150 151
- [,] 151 152
- [0] 152 153
- [,] 153 154
- [0] 154 155
- [,] 155 156
- [0] 156 157
- [,] 157 158
- [0] 158 159
- [,] 159 160
- [0] 160 161
- [,] 161 162
- [0] 162 163
- [,] 163 164
- [0] 164 165
- [,] 165 166
- [0] 166 167
- [,] 167 168
- [0] 168 169
- [,] 169 170
- [0] 170 171
- [,] 171 172
- [0] 172 173
- [,] 173 174
- [0] 174 175
- [,] 175 176
- [0] 176 177
- [,] 177 178
- [0] 178 179
- [,] 179 180
- [0] 180 181
- [,] 181 182
- [0] 182 183
- [,] 183 184
- [0] 184 185
- [,] 185 186
- [0] 186 187
- [,] 187 188
- [0] 188 189
- [,] 189 190
- [0] 190 191
- [,] 191 192
- [0] 192 193
- [,] 193 194
- [0] 194 195
- [,] 195 196
- [0] 196 197
- [,] 197 198
- [0] 198 199
- [,] 199 200
- [0] 200 201
- [,] 201 202
- [0] 202 203
- [,] 203 204
- [0] 204 205
- [,] 205 206
- [0] 206 207
- [,] 207 208
- [0] 208 209
- [,] 209 210
- [0] 210 211
- [,] 211 212
- [0] 212 213
- [,] 213 214
- [0] 214 215
- [,] 215 216
- [0] 216 217
- [,] 217 218
- [0] 218 219
- [,] 219 220
- [0] 220 221
- [,] 221 222
- [0] 222 223
- [,] 223 224
- [0] 224 225
- [,] 225 226
- [0] 226 227
- [,] 227 228
- [0] 228 229
- [,] 229 230
- [0] 230 231
- [,] 231 232
- [0] 232 233
- [,] 233 234
- [0] 234 235
- [,] 235 236
- [0] 236 237
- [,] 237 238
- [0] 238 239
- [,] 239 240
- [0] 240 241
- [,] 241 242
- [0] 242 243
- [,] 243 244
- [0] 244 245
- [,] 245 246
- [0] 246 247
- [,] 247 248
- [0] 248 249
- [,] 249 250
- [0] 250 251
- [,] 251 252
- [0] 252 253
- [,] 253 254
- [0] 254 255
- [,] 255 256
- [0] 256 257
- [,] 257 258
- [0] 258 259
- [,] 259 260
- [0] 260 261
- [,] 261 262
- [0] 262 263
- [,] 263 264
- [0] 264 265
- [,] 265 266
- [0] 266 267
- [,] 267 268
- [0] 268 269
- [,] 269 270
- [0] 270 271
- [,] 271 272
- [0] 272 273
- [,] 273 274
- [0] 274 275
- [,] 275 276
- [0] 276 277
- [,] 277 278
- [0] 278 279
- [,] 279 280
- [0] 280 281
- [,] 281 282
- [0] 282 283
- [,] 283 284
- [0] 284 285
- [,] 285 286
- [0] 286 287
- [,] 287 288
- [0] 288 289
- [,] 289 290
- [0] 290 291
- [,] 291 292
- [0] 292 293
- [,] 293 294
- [0] 294 295
- [,] 295 296
- [0] 296 297
- [,] 297 298
- [0] 298 299
- [,] 299 300
- [0] 300 301
- [,] 301 302
- [0] 302 303
- [,] 303 304
- [0] 304 305
- [,] 305 306
+ [0] 7 8
+ [,] 8 9
+ [0] 9 10
+ [,] 10 11
+ [0] 11 12
+ [,] 12 13
+ [0] 13 14
+ [,] 14 15
+ [0] 15 16
+ [,] 16 17
+ [0] 17 18
+ [,] 18 19
+ [0] 19 20
+ [,] 20 21
+ [0] 21 22
+ [,] 22 23
+ [0] 23 24
+ [,] 24 25
+ [0] 25 26
+ [,] 26 27
+ [0] 27 28
+ [,] 28 29
+ [0] 29 30
+ [,] 30 31
+ [0] 31 32
+ [,] 32 33
+ [0] 33 34
+ [,] 34 35
+ [0] 35 36
+ [,] 36 37
+ [0] 37 38
+ [,] 38 39
+ [0] 39 40
+ [,] 40 41
+ [0] 41 42
+ [,] 42 43
+ [0] 43 44
+ [,] 44 45
+ [0] 45 46
+ [,] 46 47
+ [0] 47 48
+ [,] 48 49
+ [0] 49 50
+ [,] 50 51
+ [0] 51 52
+ [,] 52 53
+ [0] 53 54
+ [,] 54 55
+ [0] 55 56
+ [,] 56 57
+ [0] 57 58
+ [,] 58 59
+ [0] 59 60
+ [,] 60 61
+ [0] 61 62
+ [,] 62 63
+ [0] 63 64
+ [,] 64 65
+ [0] 65 66
+ [,] 66 67
+ [0] 67 68
+ [,] 68 69
+ [0] 69 70
+ [,] 70 71
+ [0] 71 72
+ [,] 72 73
+ [0] 73 74
+ [,] 74 75
+ [0] 75 76
+ [,] 76 77
+ [0] 77 78
+ [,] 78 79
+ [0] 79 80
+ [,] 80 81
+ [0] 81 82
+ [,] 82 83
+ [0] 83 84
+ [,] 84 85
+ [0] 85 86
+ [,] 86 87
+ [0] 87 88
+ [,] 88 89
+ [0] 89 90
+ [,] 90 91
+ [0] 91 92
+ [,] 92 93
+ [0] 93 94
+ [,] 94 95
+ [0] 95 96
+ [,] 96 97
+ [0] 97 98
+ [,] 98 99
+ [0] 99 100
+ [,] 100 101
+ [0] 101 102
+ [,] 102 103
+ [0] 103 104
+ [,] 104 105
+ [0] 105 106
+ [,] 106 107
+ [0] 107 108
+ [,] 108 109
+ [0] 109 110
+ [,] 110 111
+ [0] 111 112
+ [,] 112 113
+ [0] 113 114
+ [,] 114 115
+ [0] 115 116
+ [,] 116 117
+ [0] 117 118
+ [,] 118 119
+ [0] 119 120
+ [,] 120 121
+ [0] 121 122
+ [,] 122 123
+ [0] 123 124
+ [,] 124 125
+ [0] 125 126
+ [,] 126 127
+ [0] 127 128
+ [,] 128 129
+ [0] 129 130
+ [,] 130 131
+ [0] 131 132
+ [,] 132 133
+ [0] 133 134
+ [,] 134 135
+ [0] 135 136
+ [,] 136 137
+ [0] 137 138
+ [,] 138 139
+ [0] 139 140
+ [,] 140 141
+ [0] 141 142
+ [,] 142 143
+ [0] 143 144
+ [,] 144 145
+ [0] 145 146
+ [,] 146 147
+ [0] 147 148
+ [,] 148 149
+ [0] 149 150
+ [,] 150 151
+ [0] 151 152
+ [,] 152 153
+ [0] 153 154
+ [,] 154 155
+ [0] 155 156
+ [,] 156 157
+ [0] 157 158
+ [,] 158 159
+ [0] 159 160
+ [,] 160 161
+ [0] 161 162
+ [,] 162 163
+ [0] 163 164
+ [,] 164 165
+ [0] 165 166
+ [,] 166 167
+ [0] 167 168
+ [,] 168 169
+ [0] 169 170
+ [,] 170 171
+ [0] 171 172
+ [,] 172 173
+ [0] 173 174
+ [,] 174 175
+ [0] 175 176
+ [,] 176 177
+ [0] 177 178
+ [,] 178 179
+ [0] 179 180
+ [,] 180 181
+ [0] 181 182
+ [,] 182 183
+ [0] 183 184
+ [,] 184 185
+ [0] 185 186
+ [,] 186 187
+ [0] 187 188
+ [,] 188 189
+ [0] 189 190
+ [,] 190 191
+ [0] 191 192
+ [,] 192 193
+ [0] 193 194
+ [,] 194 195
+ [0] 195 196
+ [,] 196 197
+ [0] 197 198
+ [,] 198 199
+ [0] 199 200
+ [,] 200 201
+ [0] 201 202
+ [,] 202 203
+ [0] 203 204
+ [,] 204 205
+ [0] 205 206
+ [,] 206 207
+ [0] 207 208
+ [,] 208 209
+ [0] 209 210
+ [,] 210 211
+ [0] 211 212
+ [,] 212 213
+ [0] 213 214
+ [,] 214 215
+ [0] 215 216
+ [,] 216 217
+ [0] 217 218
+ [,] 218 219
+ [0] 219 220
+ [,] 220 221
+ [0] 221 222
+ [,] 222 223
+ [0] 223 224
+ [,] 224 225
+ [0] 225 226
+ [,] 226 227
+ [0] 227 228
+ [,] 228 229
+ [0] 229 230
+ [,] 230 231
+ [0] 231 232
+ [,] 232 233
+ [0] 233 234
+ [,] 234 235
+ [0] 235 236
+ [,] 236 237
+ [0] 237 238
+ [,] 238 239
+ [0] 239 240
+ [,] 240 241
+ [0] 241 242
+ [,] 242 243
+ [0] 243 244
+ [,] 244 245
+ [0] 245 246
+ [,] 246 247
+ [0] 247 248
+ [,] 248 249
+ [0] 249 250
+ [,] 250 251
+ [0] 251 252
+ [,] 252 253
+ [0] 253 254
+ [,] 254 255
+ [0] 255 256
+ [,] 256 257
+ [0] 257 258
+ [,] 258 259
+ [0] 259 260
+ [,] 260 261
+ [0] 261 262
+ [,] 262 263
+ [0] 263 264
+ [,] 264 265
+ [0] 265 266
+ [,] 266 267
+ [0] 267 268
+ [,] 268 269
+ [0] 269 270
+ [,] 270 271
+ [0] 271 272
+ [,] 272 273
+ [0] 273 274
+ [,] 274 275
+ [0] 275 276
+ [,] 276 277
+ [0] 277 278
+ [,] 278 279
+ [0] 279 280
+ [,] 280 281
+ [0] 281 282
+ [,] 282 283
+ [0] 283 284
+ [,] 284 285
+ [0] 285 286
+ [,] 286 287
+ [0] 287 288
+ [,] 288 289
+ [0] 289 290
+ [,] 290 291
+ [0] 291 292
+ [,] 292 293
+ [0] 293 294
+ [,] 294 295
+ [0] 295 296
+ [,] 296 297
+ [0] 297 298
+ [,] 298 299
+ [0] 299 300
+ [,] 300 301
+ [0] 301 302
+ [,] 302 303
+ [0] 303 304
+ [,] 304 305
+ [0] 305 306
+ [,] 306 307
L7
[}] 5 6
[;] 6 7
L8
+ [byte] 5 9
+ [\[] 9 10
+ [,] 10 11
+ [\]] 11 12
+ [a] 13 14
+ [=] 15 16
+ [{] 17 18
+ [1] 18 19
+ [,] 19 20
+ [2] 20 21
+ [,] 21 22
+ [3] 22 23
+ [,] 23 24
+ [4] 24 25
+ [,] 25 26
+ [5] 26 27
+ [}] 27 28
+ [;] 28 29
+L9
+ [byte] 5 9
+ [\[] 9 10
+ [,] 10 11
+ [\]] 11 12
+ [b] 13 14
+ [=] 15 16
+ [{] 17 18
+ [{] 18 19
+ [1] 19 20
+ [,] 20 21
+ [2] 21 22
+ [}] 22 23
+ [,] 23 24
+ [{] 24 25
+ [3] 25 26
+ [,] 26 27
+ [4] 27 28
+ [}] 28 29
+ [,] 29 30
+ [{] 30 31
+ [5] 31 32
+ [,] 32 33
+ [6] 33 34
+ [}] 34 35
+ [}] 35 36
+ [;] 36 37
+L10
+ [int] 5 8
+ [\[] 8 9
+ [,] 9 10
+ [\]] 10 11
+ [c] 12 13
+ [=] 14 15
+ [{] 16 17
+L11
+ [157] 7 10
+ [,] 10 11
+L12
+ [0377] 7 11
+ [,] 11 12
+L13
+ [36_000_000] 7 17
+ [,] 17 18
+L14
+ [0x3fff] 7 13
+ [,] 13 14
+L15
+ [0X3FFF] 7 13
+ [,] 13 14
+L16
+ [328u] 7 11
+ [,] 11 12
+L17
+ [0x7FFFFFL] 7 16
+ [,] 16 17
+L18
+ [0776745ul] 7 16
+ [,] 16 17
+L19
+ [18.46] 7 12
+ [,] 12 13
+L20
+ [18.46e0] 7 14
+ [,] 14 15
+L21
+ [18.46e1] 7 14
+ [,] 14 15
+L22
+ [0b000001] 7 15
+ [,] 15 16
+L23
+ [}] 5 6
+ [;] 6 7
+L24
[}] 1 2
EOF
diff --git a/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers_ignored.txt b/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers_ignored.txt
index 811acd84ec..a65dde2a89 100644
--- a/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers_ignored.txt
+++ b/pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/listOfNumbers_ignored.txt
@@ -37,5 +37,30 @@ L5
L7
[;] 6 7
L8
+ [byte] 5 9
+ [\[] 9 10
+ [,] 10 11
+ [\]] 11 12
+ [a] 13 14
+ [=] 15 16
+ [;] 28 29
+L9
+ [byte] 5 9
+ [\[] 9 10
+ [,] 10 11
+ [\]] 11 12
+ [b] 13 14
+ [=] 15 16
+ [;] 36 37
+L10
+ [int] 5 8
+ [\[] 8 9
+ [,] 9 10
+ [\]] 10 11
+ [c] 12 13
+ [=] 14 15
+L23
+ [;] 6 7
+L24
[}] 1 2
EOF
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java
index b25e691c11..088508b93c 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java
@@ -17,7 +17,7 @@ import net.sourceforge.pmd.properties.PropertyDescriptor;
public class MethodNamingConventionsRule extends AbstractNamingConventionRule {
- private static final Map DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>();
+ private final Map descriptorToDisplayName = new HashMap<>();
private final PropertyDescriptor instanceRegex = defaultProp("", "instance").build();
private final PropertyDescriptor staticRegex = defaultProp("static").build();
@@ -78,7 +78,7 @@ public class MethodNamingConventionsRule extends AbstractNamingConventionRule descriptor) {
- return DESCRIPTOR_TO_DISPLAY_NAME.get(descriptor.name());
+ return descriptorToDisplayName.get(descriptor.name());
}
}
diff --git a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4 b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4
index 45699d16d3..3a8e374ff6 100644
--- a/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4
+++ b/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4
@@ -1038,7 +1038,7 @@ ImplicitParameterName : '$' DecimalLiteral ; // TODO: don't allow '_' here
// GRAMMAR OF A LITERAL
booleanLiteral: BooleanLiteral ;
-literal : numericLiteral | MultiStringLiteral | SingleStringLiteral | BooleanLiteral | NilLiteral ;
+literal : numericLiteral | MultiStringLiteral | SingleStringLiteral | BooleanLiteral | NilLiteral | RawMultiStringLiteral | RawSingleStringLiteral ;
// GRAMMAR OF AN INTEGER LITERAL
@@ -1093,11 +1093,16 @@ TRIPLEDQUOTES : '"""' ;
MultiStringLiteral : TRIPLEDQUOTES '\n' .*? '\n' TRIPLEDQUOTES ;
fragment MultiQuotedText : MultiQuotedTextItem+ ;
-fragment MultiQuotedTextItem : MultiInterpolatedString
- | ~[\\\u000A\u000D]
- ;
+fragment MultiQuotedTextItem : MultiInterpolatedString | ~[\\\u000A\u000D] ;
fragment MultiInterpolatedString: '\\(' (MultiQuotedTextItem | SingleStringLiteral)* ')';
+// swift 5 extended delimiter, eg ##"abc"##
+RawSingleStringLiteral : '#"' RawSingleQuotedTextItem* '"#' | '#' RawSingleStringLiteral '#';
+fragment RawSingleQuotedTextItem : ~[\u000A\u000D] ;
+
+RawMultiStringLiteral : '#"""' RawMultiQuotedTextItem* '"""#' | '#' RawMultiStringLiteral '#';
+fragment RawMultiQuotedTextItem : . ;
+
// StringLiteral : '"' QuotedText? '"' ;
SingleStringLiteral : '"' QuotedText? '"' ;
fragment SingleDoubleQuote : '"' | ~["] ;
diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.swift b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.swift
index 6e77f1dd29..85bd015309 100644
--- a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.swift
+++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.swift
@@ -38,3 +38,16 @@ var x = 2
print(x[keyPath: id]) // prints 2
x[keyPath: id] = 3
print(x[keyPath: id]) // prints 3
+
+// https://www.swiftbysundell.com/articles/string-literals-in-swift/
+let rawString = #"Press "Continue" to close this dialog."#
+extension URL {
+ func html(withTitle title: String) -> String {
+ return ##"\#(title)"##
+ }
+}
+
+let rawMultiString = ###"a\###"###
+let rawMultiString2 = ###"""a\###
+""hey""
+"""###
diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.txt b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.txt
index 5a8a5f541d..d2e8583af3 100644
--- a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.txt
+++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/cpd/testdata/Swift5.0.txt
@@ -197,4 +197,42 @@ L40
[id] 18 20
[\]] 20 21
[)] 21 22
+L43
+ [let] 1 4
+ [rawString] 5 14
+ [=] 15 16
+ [#"Press "Continue" to close this d[ 17 59
+L44
+ [extension] 1 10
+ [URL] 11 14
+ [{] 15 16
+L45
+ [func] 5 9
+ [html] 10 14
+ [(] 14 15
+ [withTitle] 15 24
+ [title] 25 30
+ [:] 30 31
+ [String] 32 38
+ [)] 38 39
+ [->] 40 42
+ [String] 43 49
+ [{] 50 51
+L46
+ [return] 9 15
+ [##"