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 + [##"