From 61b1c372cd9e633c0a7ba86f39ab6e8fa2df95db Mon Sep 17 00:00:00 2001 From: Willem Hajenius Date: Mon, 21 Oct 2024 23:45:20 +0200 Subject: [PATCH 01/37] [apex] Must use case-insensitive input stream to avoid choking on Unicode escape sequences --- .../pmd/lang/apex/ast/ApexCommentBuilder.java | 4 ++- .../pmd/lang/apex/ast/ApexLexerTest.java | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java index a135ca4603..48d41f0faa 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java @@ -22,6 +22,7 @@ import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextRegion; import io.github.apexdevtools.apexparser.ApexLexer; +import io.github.apexdevtools.apexparser.CaseInsensitiveInputStream; @InternalApi final class ApexCommentBuilder { @@ -103,7 +104,8 @@ final class ApexCommentBuilder { } private static CommentInformation extractInformationFromComments(TextDocument sourceCode, String suppressMarker) { - ApexLexer lexer = new ApexLexer(CharStreams.fromString(sourceCode.getText().toString())); + String source = sourceCode.getText().toString(); + ApexLexer lexer = new ApexLexer(new CaseInsensitiveInputStream(CharStreams.fromString(source))); List allCommentTokens = new ArrayList<>(); Map suppressMap = new HashMap<>(); diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java index 67c6706f29..b075160370 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java @@ -8,14 +8,18 @@ package net.sourceforge.pmd.lang.apex.ast; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; import org.junit.jupiter.api.Test; import io.github.apexdevtools.apexparser.ApexLexer; import io.github.apexdevtools.apexparser.ApexParser; +import io.github.apexdevtools.apexparser.CaseInsensitiveInputStream; /** * This is an exploration test for {@link ApexLexer}. @@ -49,4 +53,35 @@ class ApexLexerTest { ApexParser.CompilationUnitContext compilationUnit = parser.compilationUnit(); assertNotNull(compilationUnit); } + + @Test + void testLexerUnicodeEscapes() { + String s = "'Fran\\u00E7ois'"; + assertEquals(2, getLexingErrors(CharStreams.fromString(s))); + assertEquals(0, getLexingErrors(new CaseInsensitiveInputStream(CharStreams.fromString(s)))); + } + + private int getLexingErrors(CharStream stream) { + ApexLexer lexer = new ApexLexer(stream); + ErrorListener errorListener = new ErrorListener(); + lexer.removeErrorListeners(); // Avoid distracting "token recognition error" stderr output + lexer.addErrorListener(errorListener); + CommonTokenStream tokens = new CommonTokenStream(lexer); + tokens.fill(); + return errorListener.getErrorCount(); + } + + static class ErrorListener extends BaseErrorListener { + private int errorCount = 0; + + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, + int charPositionInLine, String msg, RecognitionException e) { + ++errorCount; + } + + public int getErrorCount() { + return errorCount; + } + } } From 16eafc89c2cdf8c0a370ab98d979d41d5d799540 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 27 Oct 2024 16:24:05 +0100 Subject: [PATCH 02/37] [java] TooFewBranchesForSwitch - allow list of case constants Fixes #5287 --- docs/pages/release_notes.md | 2 + .../resources/category/java/performance.xml | 2 +- .../xml/TooFewBranchesForSwitch.xml | 42 +++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index bc1a36ec7a..68f3742003 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -15,6 +15,8 @@ This is a {{ site.pmd.release_type }} release. ### ๐Ÿš€ New and noteworthy ### ๐Ÿ› Fixed Issues +* java-performance + * [#5287](https://github.com/pmd/pmd/issues/5287): \[java] TooFewBranchesForSwitch false-positive with switch using list of case constants ### ๐Ÿšจ API Changes diff --git a/pmd-java/src/main/resources/category/java/performance.xml b/pmd-java/src/main/resources/category/java/performance.xml index a8e4c37142..8b2d4e20c5 100644 --- a/pmd-java/src/main/resources/category/java/performance.xml +++ b/pmd-java/src/main/resources/category/java/performance.xml @@ -629,7 +629,7 @@ Note: This rule was named TooFewBranchesForASwitchStatement before PMD 7.7.0. diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml index e603390ec6..2da0d99a82 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml @@ -136,6 +136,48 @@ public class SwitchWithRecordPattern { } } } +]]> + + + + #5287 [java] TooFewBranchesForSwitch false-positive with switch using list of case constants + 3 + 0 + 1; + default -> 0; + }; + } + + int checkSwitchStatement(SomeEnum someEnumValue) { + int result; + switch(someEnumValue) { + case A, B, C -> { result = 1; } + default -> { result = 0; } + } + return result; + } + + int checkSwitchExpressionGroup(SomeEnum someEnumValue) { + return switch(someEnumValue) { + case A, B, C: yield 1; + default: yield 0; + }; + } + + int checkSwitchStatementGroup(SomeEnum someEnumValue) { + int result; + switch(someEnumValue) { + case A, B, C: result = 1; break; + default: result = 0; break; + } + return result; + } +} ]]> From 36dfcf82112044442d083c15c778658a988fa949 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 03:08:41 +0000 Subject: [PATCH 03/37] Bump org.apache.maven.plugins:maven-clean-plugin from 3.3.2 to 3.4.0 Bumps [org.apache.maven.plugins:maven-clean-plugin](https://github.com/apache/maven-clean-plugin) from 3.3.2 to 3.4.0. - [Release notes](https://github.com/apache/maven-clean-plugin/releases) - [Commits](https://github.com/apache/maven-clean-plugin/compare/maven-clean-plugin-3.3.2...maven-clean-plugin-3.4.0) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-clean-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d09220f92b..915bd9c00e 100644 --- a/pom.xml +++ b/pom.xml @@ -202,7 +202,7 @@ org.apache.maven.plugins maven-clean-plugin - 3.3.2 + 3.4.0 From e15c05721eb1b202f41a8fa03db835becababff5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:23:58 +0100 Subject: [PATCH 04/37] Bump webrick from 1.8.2 to 1.9.0 in /docs in the all-gems group across 1 directory (#5308) Bump webrick in /docs in the all-gems group across 1 directory Bumps the all-gems group with 1 update in the /docs directory: [webrick](https://github.com/ruby/webrick). Updates `webrick` from 1.8.2 to 1.9.0 - [Release notes](https://github.com/ruby/webrick/releases) - [Commits](https://github.com/ruby/webrick/compare/v1.8.2...v1.9.0) --- updated-dependencies: - dependency-name: webrick dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-gems ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 85d32da6ff..c65178abcd 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -266,7 +266,7 @@ GEM concurrent-ruby (~> 1.0) unicode-display_width (1.8.0) uri (0.13.1) - webrick (1.8.2) + webrick (1.9.0) PLATFORMS x86_64-linux From a1996554d88d8a9109a44d31af9d62746f2e02ef Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 31 Oct 2024 17:04:19 +0100 Subject: [PATCH 05/37] [java] Add DeadlockTest for verifying #5293 - Improve logging for Parselock Refs #5293 --- .../java/symbols/internal/asm/ClassStub.java | 7 +- .../symbols/internal/asm/GenericSigBase.java | 8 +- .../java/symbols/internal/asm/ModuleStub.java | 2 +- .../java/symbols/internal/asm/ParseLock.java | 18 +++- .../pmd/lang/java/symbols/DeadlockTest.java | 86 +++++++++++++++++++ .../test/resources/simplelogger.properties | 5 ++ 6 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java create mode 100644 pmd-java/src/test/resources/simplelogger.properties diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java index 6a050ca5b3..c5337cf773 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java @@ -84,12 +84,7 @@ final class ClassStub implements JClassSymbol, AsmStub, AnnotationOwner { this.resolver = resolver; this.names = new Names(internalName); - this.parseLock = new ParseLock() { - // note to devs: to debug the parsing logic you might have - // to replace the implementation of toString temporarily, - // otherwise an IDE could call toString just to show the item - // in the debugger view (which could cause parsing of the class file). - + this.parseLock = new ParseLock("ClassStub:" + internalName) { @Override protected boolean doParse() throws IOException { try (InputStream instream = loader.getInputStream()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java index 6784468646..8ee5f39aaa 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java @@ -46,9 +46,9 @@ abstract class GenericSigBase { protected List typeParameters; private final ParseLock lock; - protected GenericSigBase(T ctx) { + protected GenericSigBase(T ctx, String parseLockName) { this.ctx = ctx; - this.lock = new ParseLock() { + this.lock = new ParseLock(parseLockName) { @Override protected boolean doParse() { GenericSigBase.this.doParse(); @@ -116,7 +116,7 @@ abstract class GenericSigBase { @Nullable String signature, // null if doesn't use generics in header @Nullable String superInternalName, // null if this is the Object class String[] interfaces) { - super(ctx); + super(ctx, "LazyClassSignature:" + ctx.getInternalName() + "[" + signature + "]"); this.signature = signature; this.rawItfs = CollectionUtil.map(interfaces, ctx.getResolver()::resolveFromInternalNameCannotFail); @@ -233,7 +233,7 @@ abstract class GenericSigBase { @Nullable String genericSig, @Nullable String[] exceptions, boolean skipFirstParam) { - super(ctx); + super(ctx, "LazyMethodType:" + (genericSig != null ? genericSig : descriptor)); this.signature = genericSig != null ? genericSig : descriptor; // generic signatures already omit the synthetic param this.skipFirstParam = skipFirstParam && genericSig == null; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ModuleStub.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ModuleStub.java index 3db93664d3..1c0b33b0d2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ModuleStub.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ModuleStub.java @@ -35,7 +35,7 @@ class ModuleStub implements JModuleSymbol, AsmStub, AnnotationOwner { this.resolver = resolver; this.moduleName = moduleName; - this.parseLock = new ParseLock() { + this.parseLock = new ParseLock("ModuleStub:" + moduleName) { @Override protected boolean doParse() throws IOException { try (InputStream instream = loader.getInputStream()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ParseLock.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ParseLock.java index a7bfada5ea..a0150e00fe 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ParseLock.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ParseLock.java @@ -17,15 +17,30 @@ abstract class ParseLock { private static final Logger LOG = LoggerFactory.getLogger(ParseLock.class); private volatile ParseStatus status = ParseStatus.NOT_PARSED; + private final String name; + + protected ParseLock(String name) { + this.name = name; + } public void ensureParsed() { getFinalStatus(); } + private void logParseLockTrace(String prefix) { + if (LOG.isTraceEnabled()) { + LOG.trace("{} {}: {}", Thread.currentThread().getName(), String.format("%-15s", prefix), this); + } + } + private ParseStatus getFinalStatus() { ParseStatus status = this.status; if (!status.isFinished) { + logParseLockTrace("waiting on"); + synchronized (this) { + logParseLockTrace("locked"); + status = this.status; if (status == ParseStatus.NOT_PARSED) { this.status = ParseStatus.BEING_PARSED; @@ -54,6 +69,7 @@ abstract class ParseLock { throw new IllegalStateException("Thread is reentering the parse lock"); } } + logParseLockTrace("released"); } return status; } @@ -85,7 +101,7 @@ abstract class ParseLock { @Override public String toString() { - return "ParseLock{status=" + status + '}'; + return "ParseLock{name=" + name + ",status=" + status + '}'; } private enum ParseStatus { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java new file mode 100644 index 0000000000..25e3de1948 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java @@ -0,0 +1,86 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.symbols; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +import net.sourceforge.pmd.lang.java.JavaParsingHelper; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; + +/** + * Tests to help analyze [java] Deadlock when executing PMD in multiple threads #5293. + * + * @see [java] Deadlock when executing PMD in multiple threads #5293 + */ +class DeadlockTest { + + abstract static class Outer implements GenericInterface, GenericClass> { + // must be a nested class, that is reusing the type param T of the outer class + abstract static class Inner { + Inner(Outer grid) { } + } + } + + static class GenericBaseClass { } + + interface GenericInterface { } + + abstract static class GenericClass extends GenericBaseClass> { } + + @Test + @Timeout(2) + void parseWithoutDeadlock() throws InterruptedException { + /* + Deadlock: + t1 -> locks parse for Outer.Inner and waits for parse lock for Outer + t2 -> locks parse for Outer, locks parse for GenericInterface and then waits for parse lock for Outer.Inner + + + In order to reproduce the deadlock reliably, add the following piece into ParseLock, just at the beginning + of the synchronized block (line 42): + + // t1 needs to wait after having the lock, so that t2 can go on and wait on the same lock + if (Thread.currentThread().getName().equals("t1") && this.toString().contains("LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer$Inner[ { + ASTCompilationUnit class1 = JavaParsingHelper.DEFAULT.parse( + "package net.sourceforge.pmd.lang.java.symbols;\n" + + "import net.sourceforge.pmd.lang.java.symbols.DeadlockTest.Outer;\n" + + " class Class1 {\n" + + " public static Outer.Inner newInner(Outer grid) {\n" + + " return null;\n" + + " }\n" + + " }\n" + ); + assertNotNull(class1); + }, "t1"); + + Thread t2 = new Thread(() -> { + ASTCompilationUnit class2 = JavaParsingHelper.DEFAULT.parse( + "package net.sourceforge.pmd.lang.java.symbols;\n" + + "import net.sourceforge.pmd.lang.java.symbols.DeadlockTest.Outer;\n" + + " class Class2 {\n" + + " protected Outer theOuter;\n" + + " }\n" + ); + assertNotNull(class2); + }, "t2"); + + t1.start(); + t2.start(); + + t1.join(); + t2.join(); + } +} diff --git a/pmd-java/src/test/resources/simplelogger.properties b/pmd-java/src/test/resources/simplelogger.properties new file mode 100644 index 0000000000..8a4eafe283 --- /dev/null +++ b/pmd-java/src/test/resources/simplelogger.properties @@ -0,0 +1,5 @@ +# +# BSD-style license; for more info see http://pmd.sourceforge.net/license.html +# + +#org.slf4j.simpleLogger.log.net.sourceforge.pmd.lang.java.symbols.internal.asm.ParseLock=trace From 1ee649442914de12f06de12f586cc647ad9a27a6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 4 Nov 2024 10:40:32 +0100 Subject: [PATCH 06/37] [java] Fix #5293: Parse number of type parameters eagerly When creating a LazyClassSignature or LazyMethodType, make sure to parse the number of type parameters eagerly, so that AstDisambiguationPass can get this number without triggering additional parsing. --- .../java/symbols/internal/asm/ClassStub.java | 4 +-- .../symbols/internal/asm/GenericSigBase.java | 20 ++++++++--- .../asm/GenericTypeParameterCounter.java | 36 +++++++++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericTypeParameterCounter.java diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java index c5337cf773..15ae7b0535 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/ClassStub.java @@ -310,9 +310,9 @@ final class ClassStub implements JClassSymbol, AsmStub, AnnotationOwner { } @Override - public boolean isGeneric() { + public int getTypeParameterCount() { parseLock.ensureParsed(); - return signature.isGeneric(); + return signature.getTypeParameterCount(); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java index 8ee5f39aaa..eabeb13c5a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericSigBase.java @@ -81,7 +81,11 @@ abstract class GenericSigBase { protected abstract boolean postCondition(); - protected abstract boolean isGeneric(); + protected abstract int getTypeParameterCount(); + + protected boolean isGeneric() { + return getTypeParameterCount() > 0; + } public void setTypeParams(List tvars) { assert this.typeParameters == null : "Type params were already parsed for " + this; @@ -105,6 +109,7 @@ abstract class GenericSigBase { private static final String OBJECT_BOUND = ":" + OBJECT_SIG; private final @Nullable String signature; + private final int typeParameterCount; private @Nullable JClassType superType; private List superItfs; @@ -118,6 +123,7 @@ abstract class GenericSigBase { String[] interfaces) { super(ctx, "LazyClassSignature:" + ctx.getInternalName() + "[" + signature + "]"); this.signature = signature; + this.typeParameterCount = GenericTypeParameterCounter.determineTypeParameterCount(this.signature); this.rawItfs = CollectionUtil.map(interfaces, ctx.getResolver()::resolveFromInternalNameCannotFail); this.rawSuper = ctx.getResolver().resolveFromInternalNameCannotFail(superInternalName); @@ -157,8 +163,9 @@ abstract class GenericSigBase { } @Override - protected boolean isGeneric() { - return signature != null && TypeParamsParser.hasTypeParams(signature); + protected int getTypeParameterCount() { + // note: no ensureParsed() needed, the type parameters are counted eagerly + return typeParameterCount; } @Override @@ -206,6 +213,7 @@ abstract class GenericSigBase { static class LazyMethodType extends GenericSigBase implements TypeAnnotationReceiver { private final @NonNull String signature; + private final int typeParameterCount; private @Nullable TypeAnnotationSet receiverAnnotations; private List parameterTypes; @@ -235,6 +243,7 @@ abstract class GenericSigBase { boolean skipFirstParam) { super(ctx, "LazyMethodType:" + (genericSig != null ? genericSig : descriptor)); this.signature = genericSig != null ? genericSig : descriptor; + this.typeParameterCount = GenericTypeParameterCounter.determineTypeParameterCount(genericSig); // generic signatures already omit the synthetic param this.skipFirstParam = skipFirstParam && genericSig == null; this.rawExceptions = exceptions; @@ -288,8 +297,9 @@ abstract class GenericSigBase { @Override - protected boolean isGeneric() { - return TypeParamsParser.hasTypeParams(signature); + protected int getTypeParameterCount() { + // note: no ensureParsed() needed, the type parameters are counted eagerly + return typeParameterCount; } void setParameterTypes(List params) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericTypeParameterCounter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericTypeParameterCounter.java new file mode 100644 index 0000000000..28f309c43b --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/GenericTypeParameterCounter.java @@ -0,0 +1,36 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.symbols.internal.asm; + +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; + +class GenericTypeParameterCounter extends SignatureVisitor { + private int count; + + GenericTypeParameterCounter() { + super(AsmSymbolResolver.ASM_API_V); + } + + @Override + public void visitFormalTypeParameter(String name) { + count++; + } + + public int getCount() { + return count; + } + + static int determineTypeParameterCount(String signature) { + if (signature == null) { + return 0; + } + + SignatureReader signatureReader = new SignatureReader(signature); + GenericTypeParameterCounter counter = new GenericTypeParameterCounter(); + signatureReader.accept(counter); + return counter.getCount(); + } +} From 733ac4bba04520af86097047c56bba1e9b8b5900 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Mon, 4 Nov 2024 11:21:25 +0100 Subject: [PATCH 07/37] [doc] Update release notes (#5293) --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 3c14674217..3e50f0fc86 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -17,6 +17,8 @@ This is a {{ site.pmd.release_type }} release. ### ๐Ÿ› Fixed Issues * ant * [#1860](https://github.com/pmd/pmd/issues/1860): \[ant] Reflective access warnings on java > 9 and java < 17 +* java + * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads ### ๐Ÿšจ API Changes From 9dcb697f13549dab1bce1dac0d4c9b7fa5cfe215 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 7 Nov 2024 12:38:11 +0100 Subject: [PATCH 08/37] Improve DeadlockTest --- .../pmd/lang/java/symbols/DeadlockTest.java | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java index 25e3de1948..15358be481 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/symbols/DeadlockTest.java @@ -4,12 +4,19 @@ package net.sourceforge.pmd.lang.java.symbols; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.ArrayList; +import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import net.sourceforge.pmd.lang.java.JavaParsingHelper; +import net.sourceforge.pmd.lang.java.ast.ASTClassType; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; /** @@ -38,7 +45,21 @@ class DeadlockTest { /* Deadlock: t1 -> locks parse for Outer.Inner and waits for parse lock for Outer + โ”œโ”€ t1 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer$Inner[Ljava/lang/Object;],status=NOT_PARSED} + โ””โ”€ t1 locked : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer$Inner[Ljava/lang/Object;],status=NOT_PARSED} + โ””โ”€ t1 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer[Ljava/lang/Object;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericInterface;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass;>;],status=BEING_PARSED} t2 -> locks parse for Outer, locks parse for GenericInterface and then waits for parse lock for Outer.Inner + โ”œโ”€ t2 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer[Ljava/lang/Object;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericInterface;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass;>;],status=NOT_PARSED} + โ””โ”€ t2 locked : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer[Ljava/lang/Object;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericInterface;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass;>;],status=NOT_PARSED} + โ”œโ”€ t2 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest[null],status=NOT_PARSED} + โ”œโ”€ t2 locked : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest[null],status=NOT_PARSED} + โ”œโ”€ t2 released : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest[null],status=FULL} + โ”œโ”€ t2 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer[Ljava/lang/Object;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericInterface;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass;>;],status=BEING_PARSED} + โ”œโ”€ t2 locked : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer[Ljava/lang/Object;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericInterface;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass;>;],status=BEING_PARSED} + โ”œโ”€ t2 released : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer[Ljava/lang/Object;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericInterface;Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass;>;],status=BEING_PARSED} + โ””โ”€ t2 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass[Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericBaseClass;>;],status=NOT_PARSED} + โ”œโ”€ t2 locked : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericClass[Lnet/sourceforge/pmd/lang/java/symbols/DeadlockTest$GenericBaseClass;>;],status=NOT_PARSED} + โ””โ”€ t2 waiting on : ParseLock{name=LazyClassSignature:net/sourceforge/pmd/lang/java/symbols/DeadlockTest$Outer$Inner[Ljava/lang/Object;],status=NOT_PARSED} In order to reproduce the deadlock reliably, add the following piece into ParseLock, just at the beginning @@ -51,20 +72,50 @@ class DeadlockTest { } catch (InterruptedException ignored) { } } + + And then, introduce a bug again. One way to make the test fail is: + Comment out the method "public int getTypeParameterCount()", so that it is inherited again. + Add the following method: + @Override + public boolean isGeneric() { + parseLock.ensureParsed(); + return signature.isGeneric(); + } */ + List exceptions = new ArrayList<>(); + Thread.UncaughtExceptionHandler exceptionHandler = (t, e) -> { + exceptions.add(e); + e.printStackTrace(); + }; + Thread t1 = new Thread(() -> { ASTCompilationUnit class1 = JavaParsingHelper.DEFAULT.parse( "package net.sourceforge.pmd.lang.java.symbols;\n" + "import net.sourceforge.pmd.lang.java.symbols.DeadlockTest.Outer;\n" + " class Class1 {\n" - + " public static Outer.Inner newInner(Outer grid) {\n" + + " public static Outer.Inner newInner(Outer grid) {\n" + " return null;\n" + " }\n" + " }\n" ); assertNotNull(class1); + + // Outer.Inner = return type of method "newInner" + List classTypes = class1.descendants(ASTClassType.class).toList(); + ASTClassType outerInner = classTypes.get(0); + assertGenericClassType(outerInner, "Inner", "X", "T"); + + // Outer = qualifier of Outer.Inner + ASTClassType outer = classTypes.get(1); + assertEquals("Outer", outer.getSimpleName()); + assertNull(outer.getTypeArguments()); + + // Outer = formal parameter type of method newInner + ASTClassType outerFormalParam = classTypes.get(3); + assertGenericClassType(outerFormalParam, "Outer", "X", "T"); }, "t1"); + t1.setUncaughtExceptionHandler(exceptionHandler); Thread t2 = new Thread(() -> { ASTCompilationUnit class2 = JavaParsingHelper.DEFAULT.parse( @@ -75,12 +126,32 @@ class DeadlockTest { + " }\n" ); assertNotNull(class2); + + // Outer = type of field "theOuter" + ASTClassType firstClassType = class2.descendants(ASTClassType.class).first(); + assertNotNull(firstClassType); + assertGenericClassType(firstClassType, "Outer", "M", "T"); }, "t2"); + t2.setUncaughtExceptionHandler(exceptionHandler); t1.start(); t2.start(); t1.join(); t2.join(); + + assertAll(exceptions.stream() + .map(e -> () -> { + throw e; + })); + } + + private static void assertGenericClassType(ASTClassType classType, String simpleName, String actualTypeParamName, String originalTypeParamName) { + assertEquals(simpleName, classType.getSimpleName()); + assertEquals(1, classType.getTypeArguments().size()); + assertEquals(actualTypeParamName, ((ASTClassType) classType.getTypeArguments().get(0)).getSimpleName()); + JTypeParameterOwnerSymbol symbol = (JTypeParameterOwnerSymbol) classType.getTypeMirror().getSymbol(); + assertEquals(1, symbol.getTypeParameterCount()); + assertEquals(originalTypeParamName, symbol.getTypeParameters().get(0).getName()); } } From ca208d22416dc2abec528208347fca1de34e3de9 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 7 Nov 2024 12:40:18 +0100 Subject: [PATCH 09/37] Bump maven-pmd-plugin from 3.24.0 to 3.26.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 915bd9c00e..dec91f16ef 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ 3.2.5 10.18.1 3.5.0 - 3.24.0 + 3.26.0 1.10.14 3.6.3 4.9.3 From ee7d6fed3e4795f4fcb8827d8fc6a6851bf191dc Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 7 Nov 2024 19:50:29 +0100 Subject: [PATCH 10/37] [java] TooFewBranchesForSwitch - add test case from comment on #5311 --- .../xml/TooFewBranchesForSwitch.xml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml index 2da0d99a82..4cbc9893c7 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/TooFewBranchesForSwitch.xml @@ -178,6 +178,26 @@ class Tester { return result; } } +]]> + + + + From #5311: Another example for list of case constants + 0 + "Hello"; + case E, F, G -> "World"; + }; + } + + enum Bar { + A, B, C, D, E, F, G + } +} ]]> From 07de5559bcb39ab3e4908735d16c4954f005596e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 03:35:46 +0000 Subject: [PATCH 11/37] Bump org.apache.commons:commons-compress from 1.26.0 to 1.27.1 Bumps org.apache.commons:commons-compress from 1.26.0 to 1.27.1. --- updated-dependencies: - dependency-name: org.apache.commons:commons-compress dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pmd-dist/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 7bfaf114e5..5a40e514e2 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -178,7 +178,7 @@ org.apache.commons commons-compress - 1.26.0 + 1.27.1 test From 529693c916ebca6226ae501c1ceaf53eb88f95ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 13 Nov 2024 22:27:51 +0100 Subject: [PATCH 12/37] [java] fix inference dependency issue Reported in #5324 I improved the verbose logging output a bit so some of the changes are not directly relevant. --- .../types/internal/infer/ExprCheckHelper.java | 18 +- .../lang/java/types/internal/infer/Infer.java | 13 +- .../internal/infer/InferenceContext.java | 87 +++++++- .../internal/infer/TypeInferenceLogger.java | 74 +++++-- .../types/internal/infer/VarWalkStrategy.java | 8 + .../lang/java/types/TypesTreeDumpTest.java | 5 + .../bestpractices/xml/UnusedPrivateMethod.xml | 43 ++++ .../NestedLambdasAndMethodCalls.java | 38 ++++ .../dumptests/NestedLambdasAndMethodCalls.txt | 194 ++++++++++++++++++ .../java/types/dumptests/UnnamedPatterns.txt | 6 +- 10 files changed, 448 insertions(+), 38 deletions(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.txt diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java index c5c20caec9..dc8955fcb0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java @@ -552,8 +552,15 @@ final class ExprCheckHelper { // finally, add bounds if (result != ts.NO_TYPE) { + Set inputIvars = infCtx.freeVarsIn(groundFun.getFormalParameters()); + // The free vars of the return type depend on the free vars of the parameters. + // This explicit dependency is there to prevent solving the variables in the + // return type before solving those of the parameters. That is because the variables + // mentioned in the return type may be further constrained by adding the return constraints + // below (in the listener), which is only triggered when the input ivars have been instantiated. + infCtx.addInstantiationDependencies(infCtx.freeVarsIn(groundFun.getReturnType()), inputIvars); infCtx.addInstantiationListener( - infCtx.freeVarsIn(groundFun.getFormalParameters()), + inputIvars, solvedCtx -> { if (mayMutateExpr()) { lambda.setInferredType(solvedCtx.ground(groundTargetType)); @@ -562,8 +569,15 @@ final class ExprCheckHelper { lambda.updateTypingContext(solvedGroundFun); } JTypeMirror groundResult = solvedCtx.ground(result); + // We need to build another checker that uses the solved context. + // This is because the free vars may have been adopted by a parent + // context, so the solvedCtx may be that parent context. The checks + // must use that context so that constraints and listeners are added + // to the parent context, since that one is responsible for solving + // the variables. + ExprCheckHelper newChecker = new ExprCheckHelper(solvedCtx, phase, this.checker, site, infer); for (ExprMirror expr : lambda.getResultExpressions()) { - if (!isCompatible(groundResult, expr)) { + if (!newChecker.isCompatible(groundResult, expr)) { return; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java index 02f16611d5..7982304210 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java @@ -602,17 +602,20 @@ public final class Infer { // see: https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.1 // as per https://docs.oracle.com/javase/specs/jls/se9/html/jls-18.html#jls-18.5.2 // we only test it can reduce, we don't commit inferred types at this stage - InferenceContext ctxCopy = infCtx.copy(); - LOG.applicabilityTest(ctxCopy, m); - ctxCopy.solve(/*onlyBoundedVars:*/isPreJava8()); - + InferenceContext ctxCopy = infCtx.shallowCopy(); + LOG.applicabilityTest(ctxCopy); + try { + ctxCopy.solve(/*onlyBoundedVars:*/isPreJava8()); + } finally { + LOG.finishApplicabilityTest(); + } // if unchecked conversion was needed, update the site for invocation pass if (ctxCopy.needsUncheckedConversion()) { site.setNeedsUncheckedConversion(); } // don't commit any types - return m; + return infCtx.mapToIVars(m); } } finally { // Note that even if solve succeeded, listeners checking deferred diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java index ba3a78640e..73b843439f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java @@ -13,11 +13,13 @@ import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.function.Supplier; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -38,6 +40,7 @@ import net.sourceforge.pmd.lang.java.types.internal.infer.IncorporationAction.Pr import net.sourceforge.pmd.lang.java.types.internal.infer.IncorporationAction.SubstituteInst; import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind; import net.sourceforge.pmd.lang.java.types.internal.infer.VarWalkStrategy.GraphWalk; +import net.sourceforge.pmd.util.CollectionUtil; /** * Context of a type inference process. This object maintains a set of @@ -51,6 +54,13 @@ final class InferenceContext { private static int ctxId = 0; private final Map> instantiationListeners = new HashMap<>(); + // explicit dependencies between variables for graph building + private final Map> instantiationConstraints = new HashMap<>(); + // This flag is set to true when the explicit dependencies are changed, + // or when this context adopted new ivars. This means we should interrupt + // resolution and recompute the dependency graph between ivars, because + // the new variables may have dependencies on existing variables, and vice versa. + private boolean graphWasChanged = false; private final Set freeVars = new LinkedHashSet<>(); private final Set inferenceVars = new LinkedHashSet<>(); @@ -127,18 +137,19 @@ final class InferenceContext { } } - public InferenceContext copy() { + /** + * Performs a shallow copy of this context, which would allow solving + * the variables without executing listeners. Instantiation listeners + * are not copied, and parent contexts are not copied. + */ + public InferenceContext shallowCopy() { final InferenceContext copy = new InferenceContext(ts, supertypeCheckCache, Collections.emptyList(), logger); copy.freeVars.addAll(this.freeVars); copy.inferenceVars.addAll(this.inferenceVars); copy.incorporationActions.addAll(this.incorporationActions); + copy.instantiationConstraints.putAll(this.instantiationConstraints); copy.mapping = mapping; // mapping is immutable, so we can share it safely - // recursively copy parentsโ€ฆ - if (this.parent != null) { - copy.parent = this.parent.copy(); - } - return copy; } @@ -310,10 +321,20 @@ final class InferenceContext { * Copy variable in this inference context to the given context */ void duplicateInto(final InferenceContext that) { + boolean changedGraph = !that.freeVars.containsAll(this.freeVars) + || !this.instantiationConstraints.isEmpty(); + that.graphWasChanged |= changedGraph; that.inferenceVars.addAll(this.inferenceVars); that.freeVars.addAll(this.freeVars); that.incorporationActions.addAll(this.incorporationActions); that.instantiationListeners.putAll(this.instantiationListeners); + CollectionUtil.mergeMaps( + that.instantiationConstraints, + this.instantiationConstraints, + (set1, set2) -> { + set1.addAll(set2); + return set1; + }); this.parent = that; @@ -324,6 +345,30 @@ final class InferenceContext { } + // The `from` ivars depend on the `dependencies` ivars for resolution. + void addInstantiationDependencies(Set from, Set dependencies) { + if (from.isEmpty()) { + return; + } + Set outputVars = new HashSet<>(dependencies); + outputVars.removeAll(from); + if (outputVars.isEmpty()) { + return; + } + for (InferenceVar inputVar : from) { + logger.ivarDependencyRegistered(this, inputVar, outputVars); + instantiationConstraints.merge(inputVar, outputVars, (o1, o2) -> { + o2 = new LinkedHashSet<>(o2); + o2.addAll(o1); + return o2; + }); + } + } + + Map> getInstantiationDependencies() { + return instantiationConstraints; + } + void addInstantiationListener(Set relevantTypes, InstantiationListener listener) { Set free = freeVarsIn(relevantTypes); if (free.isEmpty()) { @@ -448,7 +493,7 @@ final class InferenceContext { } boolean solve(boolean onlyBoundedVars) { - return solve(new GraphWalk(this, onlyBoundedVars)); + return solve(() -> new GraphWalk(this, onlyBoundedVars)); } /** @@ -459,6 +504,26 @@ final class InferenceContext { solve(new GraphWalk(var)); } + + private boolean solve(Supplier newWalker) { + VarWalkStrategy strategy = newWalker.get(); + while (strategy != null) { + if (solve(strategy)) { + break; + } + strategy = newWalker.get(); + } + return freeVars.isEmpty(); + } + + + /** + * This returns true if solving the VarWalkStrategy succeeded entirely. + * Resolution can be interrupted early to account for new ivars and dependencies, + * which may change the graph dependencies. In this case this method returns + * false, we recompute the graph with the new ivars and dependencies, and + * we try again to make progress. + */ private boolean solve(VarWalkStrategy walker) { incorporate(); @@ -470,6 +535,12 @@ final class InferenceContext { //repeat until all variables are solved outer: while (!intersect(freeVars, varsToSolve).isEmpty() && progress) { + if (graphWasChanged) { + graphWasChanged = false; + logger.contextDependenciesChanged(this); + return false; + } + progress = false; for (List wave : ReductionStep.WAVES) { if (solveBatchProgressed(varsToSolve, wave)) { @@ -481,7 +552,7 @@ final class InferenceContext { } } } - return freeVars.isEmpty(); + return true; } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java index 023e422a49..2c9cfff9ef 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java @@ -12,6 +12,7 @@ import java.util.ArrayDeque; import java.util.Deque; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -61,7 +62,10 @@ public interface TypeInferenceLogger { default void ctxInitialization(InferenceContext ctx, JMethodSig sig) { } - default void applicabilityTest(InferenceContext ctx, JMethodSig sig) { } + default void applicabilityTest(InferenceContext ctx) { } + + default void finishApplicabilityTest() { + } default void startArgsChecks() { } @@ -81,6 +85,8 @@ public interface TypeInferenceLogger { default void propagateAndAbort(InferenceContext context, InferenceContext parent) { } + default void contextDependenciesChanged(InferenceContext ctx) { } + // ivar events @@ -90,6 +96,8 @@ public interface TypeInferenceLogger { default void ivarInstantiated(InferenceContext ctx, InferenceVar var, JTypeMirror inst) { } + default void ivarDependencyRegistered(InferenceContext ctx, InferenceVar var, Set deps) { } + /** * Log that the instantiation of the method type m for the given @@ -136,9 +144,11 @@ public interface TypeInferenceLogger { protected final PrintStream out; - protected static final int LEVEL_INCREMENT = 4; - private int level; private String indent; + /** + * Four spaces. + */ + protected static final String BASE_INDENT = " "; protected static final String ANSI_RESET = "\u001B[0m"; protected static final String ANSI_BLUE = "\u001B[34m"; @@ -177,16 +187,24 @@ public interface TypeInferenceLogger { public SimpleLogger(PrintStream out) { this.out = out; - updateLevel(0); + this.indent = ""; } - protected int getLevel() { - return level; + protected void addIndentSegment(String segment) { + indent += segment; } - protected void updateLevel(int increment) { - level += increment; - indent = StringUtils.repeat(' ', level); + protected void removeIndentSegment(String segment) { + assert indent.endsWith(segment) : "mismatched end section!"; + indent = StringUtils.removeEnd(indent, segment); + } + + protected void setIndent(String indent) { + this.indent = indent; + } + + protected String getIndent() { + return indent; } protected void println(String str) { @@ -196,13 +214,13 @@ public interface TypeInferenceLogger { protected void endSection(String footer) { - updateLevel(-LEVEL_INCREMENT); + removeIndentSegment(BASE_INDENT); println(footer); } protected void startSection(String header) { println(header); - updateLevel(+LEVEL_INCREMENT); + addIndentSegment(BASE_INDENT); } @Override @@ -335,7 +353,7 @@ public interface TypeInferenceLogger { class VerboseLogger extends SimpleLogger { - private final Deque marks = new ArrayDeque<>(); + private final Deque marks = new ArrayDeque<>(); public VerboseLogger(PrintStream out) { super(out); @@ -343,16 +361,16 @@ public interface TypeInferenceLogger { } void mark() { - marks.push(getLevel()); + marks.push(getIndent()); } void rollback(String lastWords) { - int pop = marks.pop(); - updateLevel(pop - getLevel()); // back to normal + final String savedIndent = marks.pop(); + setIndent(savedIndent); // back to normal if (!lastWords.isEmpty()) { - updateLevel(+LEVEL_INCREMENT); + addIndentSegment(BASE_INDENT); println(lastWords); - updateLevel(-LEVEL_INCREMENT); + setIndent(savedIndent); } } @@ -369,8 +387,14 @@ public interface TypeInferenceLogger { } @Override - public void applicabilityTest(InferenceContext ctx, JMethodSig sig) { - println(String.format("Applicability testing with Context %-11d%s", ctx.getId(), ppHighlight(ctx.mapToIVars(sig)))); + public void applicabilityTest(InferenceContext ctx) { + println(String.format("Solving with context %d for applicability testing", ctx.getId())); + addIndentSegment("| "); + } + + @Override + public void finishApplicabilityTest() { + removeIndentSegment("| "); } @Override @@ -404,7 +428,7 @@ public interface TypeInferenceLogger { @Override public void startArg(int i, ExprMirror expr, JTypeMirror formalType) { - startSection("Checking arg " + i + " against " + formalType); + startSection("Checking arg " + i + " against " + colorIvars(formalType)); printExpr(expr); } @@ -452,6 +476,16 @@ public interface TypeInferenceLogger { println(addCtxInfo(ctx, "Ivar instantiated") + color(var + " := ", ANSI_BLUE) + colorIvars(inst)); } + @Override + public void ivarDependencyRegistered(InferenceContext ctx, InferenceVar var, Set deps) { + println(addCtxInfo(ctx, "Ivar dependency registered: ") + color(var + " -> ", ANSI_BLUE) + colorIvars(deps)); + } + + @Override + public void contextDependenciesChanged(InferenceContext ctx) { + println("Recomputing dependency graph (ctx " + ctx.getId() + ")"); + } + private @NonNull String addCtxInfo(InferenceContext ctx, String event) { return String.format("%-20s(ctx %d): ", event, ctx.getId()); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/VarWalkStrategy.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/VarWalkStrategy.java index 2177a1cf92..19774ca49e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/VarWalkStrategy.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/VarWalkStrategy.java @@ -90,6 +90,14 @@ interface VarWalkStrategy extends Iterator> { } } + ctx.getInstantiationDependencies().forEach((ivar, deps) -> { + Vertex vertex = graph.addLeaf(ivar); + for (InferenceVar dep : deps) { + Vertex target = graph.addLeaf(dep); + graph.addEdge(vertex, target); + } + }); + // Here, "ฮฑ depends on ฮฒ" is modelled by an edge ฮฑ -> ฮฒ // Merge strongly connected components into a "super node". diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java index f69b79479c..9b8baaeca6 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java @@ -50,6 +50,11 @@ class TypesTreeDumpTest extends BaseTreeDumpTest { doTest("UnnamedPatterns"); } + @Test + void testNestedLambdasAndMethodCalls() { + doTest("NestedLambdasAndMethodCalls"); + } + @Override protected @NonNull String normalize(@NonNull String str) { return super.normalize(str) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index e81d963fcb..2679f0a8c5 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2134,4 +2134,47 @@ public class ObtainViaTest { } ]]> + + UnusedPrivateMethod with method reference + 0 + > map = new Main().run(library); + System.out.println(map); + } + + private Map> run(Library library) { + return library + .books() + .stream() + .map(book -> book.lenders().stream().collect(Collectors.toMap(Lender::name, lender -> Map.of(book.title(), lender.status())))) + .reduce(this::reduceBooksAndLenderStatusByLender) + .orElse(null); + } + + private Map> reduceBooksAndLenderStatusByLender( + Map> previousMap, + Map> nextMap + ) { + previousMap.putAll(nextMap); + return previousMap; + } + } + + + record Lender(String name, String status) {} + record Book(String title, Collection lenders) {} + record Library(Collection books) {} + ]]> + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.java new file mode 100644 index 0000000000..33914e0a68 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.java @@ -0,0 +1,38 @@ +package org.example.unusedPrivateMethod; + +import static java.util.Collections.emptySet; + +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; + +public class NestedLambdasAndMethodCalls { + + public static void main(String[] args) { + Library library = new Library(emptySet()); + Map> map = new Main().run(library); + System.out.println(map); + } + + private Map> run(Library library) { + return library + .books() + .stream() + .map(book -> book.lenders().stream().collect(Collectors.toMap(Lender::name, lender -> Map.of(book.title(), lender.status())))) + .reduce(this::reduceBooksAndLenderStatusByLender) + .orElse(null); + } + + private Map> reduceBooksAndLenderStatusByLender( + Map> previousMap, + Map> nextMap + ) { + previousMap.putAll(nextMap); + return previousMap; + } +} + + +record Lender(String name, String status) {} +record Book(String title, Collection lenders) {} +record Library(Collection books) {} \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.txt new file mode 100644 index 0000000000..9099296ff8 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/NestedLambdasAndMethodCalls.txt @@ -0,0 +1,194 @@ ++- CompilationUnit[] + +- PackageDeclaration[] + | +- ModifierList[] + +- ImportDeclaration[] + +- ImportDeclaration[] + +- ImportDeclaration[] + +- ImportDeclaration[] + +- ClassDeclaration[@TypeMirror = "org.example.unusedPrivateMethod.NestedLambdasAndMethodCalls"] + | +- ModifierList[] + | +- ClassBody[] + | +- MethodDeclaration[@Name = "main"] + | | +- ModifierList[] + | | +- VoidType[@TypeMirror = "void"] + | | +- FormalParameters[] + | | | +- FormalParameter[@TypeMirror = "java.lang.String[]"] + | | | +- ModifierList[] + | | | +- ArrayType[@TypeMirror = "java.lang.String[]"] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | | +- ArrayDimensions[] + | | | | +- ArrayTypeDim[] + | | | +- VariableId[@Name = "args", @TypeMirror = "java.lang.String[]"] + | | +- Block[] + | | +- LocalVariableDeclaration[] + | | | +- ModifierList[] + | | | +- ClassType[@TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | | +- VariableDeclarator[] + | | | +- VariableId[@Name = "library", @TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | | +- ConstructorCall[@Failed = false, @Function = "org.example.unusedPrivateMethod.Library.new(java.util.Collection) -> org.example.unusedPrivateMethod.Library", @MethodName = "new", @TypeMirror = "org.example.unusedPrivateMethod.Library", @Unchecked = false, @VarargsCall = false] + | | | +- ClassType[@TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | | +- ArgumentList[] + | | | +- MethodCall[@Failed = false, @Function = "java.util.Collections. emptySet() -> java.util.Set", @MethodName = "emptySet", @TypeMirror = "java.util.Set", @Unchecked = false, @VarargsCall = false] + | | | +- ArgumentList[] + | | +- LocalVariableDeclaration[] + | | | +- ModifierList[] + | | | +- ClassType[@TypeMirror = "java.util.Map>"] + | | | | +- TypeArguments[] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | | +- ClassType[@TypeMirror = "java.util.Map"] + | | | | +- TypeArguments[] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- VariableDeclarator[] + | | | +- VariableId[@Name = "map", @TypeMirror = "java.util.Map>"] + | | | +- MethodCall[@Failed = true, @Function = "(*unknown*).(*unknown method*)() -> (*unknown*)", @MethodName = "run", @TypeMirror = "(*unknown*)", @Unchecked = false, @VarargsCall = false] + | | | +- ConstructorCall[@Failed = true, @Function = "(*unknown*).(*unknown method*)() -> (*unknown*)", @MethodName = "new", @TypeMirror = "*Main", @Unchecked = false, @VarargsCall = false] + | | | | +- ClassType[@TypeMirror = "*Main"] + | | | | +- ArgumentList[] + | | | +- ArgumentList[] + | | | +- VariableAccess[@Name = "library", @TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | +- ExpressionStatement[] + | | +- MethodCall[@Failed = false, @Function = "java.io.PrintStream.println(java.lang.Object) -> void", @MethodName = "println", @TypeMirror = "void", @Unchecked = false, @VarargsCall = false] + | | +- FieldAccess[@Name = "out", @TypeMirror = "java.io.PrintStream"] + | | | +- TypeExpression[@TypeMirror = "java.lang.System"] + | | | +- ClassType[@TypeMirror = "java.lang.System"] + | | +- ArgumentList[] + | | +- VariableAccess[@Name = "map", @TypeMirror = "java.util.Map>"] + | +- MethodDeclaration[@Name = "run"] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "java.util.Map>"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- ClassType[@TypeMirror = "java.util.Map"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | +- FormalParameters[] + | | | +- FormalParameter[@TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | | +- ModifierList[] + | | | +- ClassType[@TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | | +- VariableId[@Name = "library", @TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | +- Block[] + | | +- ReturnStatement[] + | | +- MethodCall[@Failed = false, @Function = "java.util.Optional>>.orElse(java.util.Map>) -> java.util.Map>", @MethodName = "orElse", @TypeMirror = "java.util.Map>", @Unchecked = false, @VarargsCall = false] + | | +- MethodCall[@Failed = false, @Function = "java.util.stream.Stream>>.reduce(java.util.function.BinaryOperator>>) -> java.util.Optional>>", @MethodName = "reduce", @TypeMirror = "java.util.Optional>>", @Unchecked = false, @VarargsCall = false] + | | | +- MethodCall[@Failed = false, @Function = "java.util.stream.Stream. map(java.util.function.Function>>) -> java.util.stream.Stream>>", @MethodName = "map", @TypeMirror = "java.util.stream.Stream>>", @Unchecked = false, @VarargsCall = false] + | | | | +- MethodCall[@Failed = false, @Function = "java.util.Collection.stream() -> java.util.stream.Stream", @MethodName = "stream", @TypeMirror = "java.util.stream.Stream", @Unchecked = false, @VarargsCall = false] + | | | | | +- MethodCall[@Failed = false, @Function = "org.example.unusedPrivateMethod.Library.books() -> java.util.Collection", @MethodName = "books", @TypeMirror = "java.util.Collection", @Unchecked = false, @VarargsCall = false] + | | | | | | +- VariableAccess[@Name = "library", @TypeMirror = "org.example.unusedPrivateMethod.Library"] + | | | | | | +- ArgumentList[] + | | | | | +- ArgumentList[] + | | | | +- ArgumentList[] + | | | | +- LambdaExpression[@TypeMirror = "java.util.function.Function>>"] + | | | | +- LambdaParameterList[] + | | | | | +- LambdaParameter[@TypeMirror = "org.example.unusedPrivateMethod.Book"] + | | | | | +- ModifierList[] + | | | | | +- VariableId[@Name = "book", @TypeMirror = "org.example.unusedPrivateMethod.Book"] + | | | | +- MethodCall[@Failed = false, @Function = "java.util.stream.Stream. collect(java.util.stream.Collector>>) -> java.util.Map>", @MethodName = "collect", @TypeMirror = "java.util.Map>", @Unchecked = false, @VarargsCall = false] + | | | | +- MethodCall[@Failed = false, @Function = "java.util.Collection.stream() -> java.util.stream.Stream", @MethodName = "stream", @TypeMirror = "java.util.stream.Stream", @Unchecked = false, @VarargsCall = false] + | | | | | +- MethodCall[@Failed = false, @Function = "org.example.unusedPrivateMethod.Book.lenders() -> java.util.Collection", @MethodName = "lenders", @TypeMirror = "java.util.Collection", @Unchecked = false, @VarargsCall = false] + | | | | | | +- VariableAccess[@Name = "book", @TypeMirror = "org.example.unusedPrivateMethod.Book"] + | | | | | | +- ArgumentList[] + | | | | | +- ArgumentList[] + | | | | +- ArgumentList[] + | | | | +- MethodCall[@Failed = false, @Function = "java.util.stream.Collectors. toMap(java.util.function.Function, java.util.function.Function>) -> java.util.stream.Collector>>", @MethodName = "toMap", @TypeMirror = "java.util.stream.Collector>>", @Unchecked = false, @VarargsCall = false] + | | | | +- TypeExpression[@TypeMirror = "java.util.stream.Collectors"] + | | | | | +- ClassType[@TypeMirror = "java.util.stream.Collectors"] + | | | | +- ArgumentList[] + | | | | +- MethodReference[@TypeMirror = "java.util.function.Function"] + | | | | | +- TypeExpression[@TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | | | | | +- ClassType[@TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | | | | +- LambdaExpression[@TypeMirror = "java.util.function.Function>"] + | | | | +- LambdaParameterList[] + | | | | | +- LambdaParameter[@TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | | | | | +- ModifierList[] + | | | | | +- VariableId[@Name = "lender", @TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | | | | +- MethodCall[@Failed = false, @Function = "java.util.Map. of(java.lang.String, java.lang.String) -> java.util.Map", @MethodName = "of", @TypeMirror = "java.util.Map", @Unchecked = false, @VarargsCall = false] + | | | | +- TypeExpression[@TypeMirror = "java.util.Map"] + | | | | | +- ClassType[@TypeMirror = "java.util.Map"] + | | | | +- ArgumentList[] + | | | | +- MethodCall[@Failed = false, @Function = "org.example.unusedPrivateMethod.Book.title() -> java.lang.String", @MethodName = "title", @TypeMirror = "java.lang.String", @Unchecked = false, @VarargsCall = false] + | | | | | +- VariableAccess[@Name = "book", @TypeMirror = "org.example.unusedPrivateMethod.Book"] + | | | | | +- ArgumentList[] + | | | | +- MethodCall[@Failed = false, @Function = "org.example.unusedPrivateMethod.Lender.status() -> java.lang.String", @MethodName = "status", @TypeMirror = "java.lang.String", @Unchecked = false, @VarargsCall = false] + | | | | +- VariableAccess[@Name = "lender", @TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | | | | +- ArgumentList[] + | | | +- ArgumentList[] + | | | +- MethodReference[@TypeMirror = "java.util.function.BinaryOperator>>"] + | | | +- ThisExpression[@TypeMirror = "org.example.unusedPrivateMethod.NestedLambdasAndMethodCalls"] + | | +- ArgumentList[] + | | +- NullLiteral[@TypeMirror = "null"] + | +- MethodDeclaration[@Name = "reduceBooksAndLenderStatusByLender"] + | +- ModifierList[] + | +- ClassType[@TypeMirror = "java.util.Map>"] + | | +- TypeArguments[] + | | +- ClassType[@TypeMirror = "java.lang.String"] + | | +- ClassType[@TypeMirror = "java.util.Map"] + | | +- TypeArguments[] + | | +- ClassType[@TypeMirror = "java.lang.String"] + | | +- ClassType[@TypeMirror = "java.lang.String"] + | +- FormalParameters[] + | | +- FormalParameter[@TypeMirror = "java.util.Map>"] + | | | +- ModifierList[] + | | | +- ClassType[@TypeMirror = "java.util.Map>"] + | | | | +- TypeArguments[] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | | +- ClassType[@TypeMirror = "java.util.Map"] + | | | | +- TypeArguments[] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- VariableId[@Name = "previousMap", @TypeMirror = "java.util.Map>"] + | | +- FormalParameter[@TypeMirror = "java.util.Map>"] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "java.util.Map>"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- ClassType[@TypeMirror = "java.util.Map"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | +- VariableId[@Name = "nextMap", @TypeMirror = "java.util.Map>"] + | +- Block[] + | +- ExpressionStatement[] + | | +- MethodCall[@Failed = false, @Function = "java.util.Map>.putAll(java.util.Map>) -> void", @MethodName = "putAll", @TypeMirror = "void", @Unchecked = false, @VarargsCall = false] + | | +- VariableAccess[@Name = "previousMap", @TypeMirror = "java.util.Map>"] + | | +- ArgumentList[] + | | +- VariableAccess[@Name = "nextMap", @TypeMirror = "java.util.Map>"] + | +- ReturnStatement[] + | +- VariableAccess[@Name = "previousMap", @TypeMirror = "java.util.Map>"] + +- RecordDeclaration[@TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | +- ModifierList[] + | +- RecordComponentList[] + | | +- RecordComponent[@TypeMirror = "java.lang.String"] + | | | +- ModifierList[] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- VariableId[@Name = "name", @TypeMirror = "java.lang.String"] + | | +- RecordComponent[@TypeMirror = "java.lang.String"] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "java.lang.String"] + | | +- VariableId[@Name = "status", @TypeMirror = "java.lang.String"] + | +- RecordBody[] + +- RecordDeclaration[@TypeMirror = "org.example.unusedPrivateMethod.Book"] + | +- ModifierList[] + | +- RecordComponentList[] + | | +- RecordComponent[@TypeMirror = "java.lang.String"] + | | | +- ModifierList[] + | | | +- ClassType[@TypeMirror = "java.lang.String"] + | | | +- VariableId[@Name = "title", @TypeMirror = "java.lang.String"] + | | +- RecordComponent[@TypeMirror = "java.util.Collection"] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "java.util.Collection"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "org.example.unusedPrivateMethod.Lender"] + | | +- VariableId[@Name = "lenders", @TypeMirror = "java.util.Collection"] + | +- RecordBody[] + +- RecordDeclaration[@TypeMirror = "org.example.unusedPrivateMethod.Library"] + +- ModifierList[] + +- RecordComponentList[] + | +- RecordComponent[@TypeMirror = "java.util.Collection"] + | +- ModifierList[] + | +- ClassType[@TypeMirror = "java.util.Collection"] + | | +- TypeArguments[] + | | +- ClassType[@TypeMirror = "org.example.unusedPrivateMethod.Book"] + | +- VariableId[@Name = "books", @TypeMirror = "java.util.Collection"] + +- RecordBody[] diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnnamedPatterns.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnnamedPatterns.txt index 25eb7dd0d7..e1fa78ded1 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnnamedPatterns.txt +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnnamedPatterns.txt @@ -583,7 +583,7 @@ | +- ArgumentList[] | +- StringLiteral[@TypeMirror = "java.lang.String"] +- ExpressionStatement[] - +- MethodCall[@Failed = false, @Function = "java.util.stream.Stream. collect(java.util.stream.Collector>) -> java.util.Map", @MethodName = "collect", @TypeMirror = "java.util.Map", @Unchecked = false, @VarargsCall = false] + +- MethodCall[@Failed = false, @Function = "java.util.stream.Stream. collect(java.util.stream.Collector>) -> java.util.Map", @MethodName = "collect", @TypeMirror = "java.util.Map", @Unchecked = false, @VarargsCall = false] +- MethodCall[@Failed = false, @Function = "java.util.Collection.stream() -> java.util.stream.Stream", @MethodName = "stream", @TypeMirror = "java.util.stream.Stream", @Unchecked = false, @VarargsCall = false] | +- MethodCall[@Failed = false, @Function = "java.util.List. of(java.lang.String, java.lang.String) -> java.util.List", @MethodName = "of", @TypeMirror = "java.util.List", @Unchecked = false, @VarargsCall = false] | | +- TypeExpression[@TypeMirror = "java.util.List"] @@ -593,14 +593,14 @@ | | +- StringLiteral[@TypeMirror = "java.lang.String"] | +- ArgumentList[] +- ArgumentList[] - +- MethodCall[@Failed = false, @Function = "java.util.stream.Collectors. toMap(java.util.function.Function, java.util.function.Function) -> java.util.stream.Collector>", @MethodName = "toMap", @TypeMirror = "java.util.stream.Collector>", @Unchecked = false, @VarargsCall = false] + +- MethodCall[@Failed = false, @Function = "java.util.stream.Collectors. toMap(java.util.function.Function, java.util.function.Function) -> java.util.stream.Collector>", @MethodName = "toMap", @TypeMirror = "java.util.stream.Collector>", @Unchecked = false, @VarargsCall = false] +- TypeExpression[@TypeMirror = "java.util.stream.Collectors"] | +- ClassType[@TypeMirror = "java.util.stream.Collectors"] +- ArgumentList[] +- MethodReference[@TypeMirror = "java.util.function.Function"] | +- TypeExpression[@TypeMirror = "java.lang.String"] | +- ClassType[@TypeMirror = "java.lang.String"] - +- LambdaExpression[@TypeMirror = "java.util.function.Function"] + +- LambdaExpression[@TypeMirror = "java.util.function.Function"] +- LambdaParameterList[] | +- LambdaParameter[@TypeMirror = "java.lang.String"] | +- ModifierList[] From ed5e862aa384301a9e3c99f037930342cb6d23c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:14:44 +0100 Subject: [PATCH 13/37] Bump rouge from 4.4.0 to 4.5.0 in the all-gems group across 1 directory (#5316) Bumps the all-gems group with 1 update in the / directory: [rouge](https://github.com/rouge-ruby/rouge). Updates `rouge` from 4.4.0 to 4.5.0 - [Release notes](https://github.com/rouge-ruby/rouge/releases) - [Changelog](https://github.com/rouge-ruby/rouge/blob/master/CHANGELOG.md) - [Commits](https://github.com/rouge-ruby/rouge/compare/v4.4.0...v4.5.0) --- updated-dependencies: - dependency-name: rouge dependency-type: direct:development update-type: version-update:semver-minor dependency-group: all-gems ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1f7805ea50..41dfc5878a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -75,7 +75,7 @@ GEM racc (1.8.1) rchardet (1.8.0) rexml (3.3.9) - rouge (4.4.0) + rouge (4.5.0) rufus-scheduler (3.9.2) fugit (~> 1.1, >= 1.11.1) safe_yaml (1.0.5) From e5a123698144993b6cf8808e6206fae3b4ff5d88 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 15:48:47 +0100 Subject: [PATCH 14/37] Update pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml --- .../lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 2679f0a8c5..2a743036a6 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2135,7 +2135,7 @@ public class ObtainViaTest { ]]> - UnusedPrivateMethod with method reference + #5324 UnusedPrivateMethod with method reference 0 Date: Thu, 14 Nov 2024 15:50:35 +0100 Subject: [PATCH 15/37] [doc] Update release notes (#5324) --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 3e50f0fc86..5fa3ac04b6 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,6 +19,7 @@ This is a {{ site.pmd.release_type }} release. * [#1860](https://github.com/pmd/pmd/issues/1860): \[ant] Reflective access warnings on java > 9 and java < 17 * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads + * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas ### ๐Ÿšจ API Changes From a79d3e6557381cdad139d1ab2ee5d7921f78a081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 14 Nov 2024 16:13:30 +0100 Subject: [PATCH 16/37] Add unit tests --- .../java/internal/JavaLanguageProperties.java | 2 +- .../internal/infer/InferenceContext.java | 1 + .../internal/infer/TypeInferenceLogger.java | 10 +- .../internal/infer/InferenceCtxUnitTests.java | 93 +++++++++++++++++++ 4 files changed, 103 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java index 7fafea029e..7590d48f6f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java @@ -22,7 +22,7 @@ public class JavaLanguageProperties extends JvmLanguagePropertyBundle { PropertyFactory.enumProperty("xTypeInferenceLogging", EnumUtils.getEnumMap(InferenceLoggingVerbosity.class)) .desc("Verbosity of the type inference logging") - .defaultValue(InferenceLoggingVerbosity.DISABLED) + .defaultValue(InferenceLoggingVerbosity.VERBOSE) .build(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java index 73b843439f..8cc251fa0e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceContext.java @@ -525,6 +525,7 @@ final class InferenceContext { * we try again to make progress. */ private boolean solve(VarWalkStrategy walker) { + graphWasChanged = false; incorporate(); while (walker.hasNext()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java index 2c9cfff9ef..cb7fe3e6d3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/TypeInferenceLogger.java @@ -22,6 +22,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.internal.JavaLanguageProperties; import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol; import net.sourceforge.pmd.lang.java.types.JMethodSig; import net.sourceforge.pmd.lang.java.types.JTypeMirror; @@ -34,6 +35,12 @@ import net.sourceforge.pmd.util.StringUtil; /** * A strategy to log the execution traces of {@link Infer}. + * The default does nothing, so the logger calls can be optimized out + * at runtime, while not having to check that logging is enabled at the + * call sites. + * + *

To enable logging for the CLI, use the language property ({@link JavaLanguageProperties}) + * {@code xTypeInferenceLogging}. From tests, see {@code JavaParsingHelper#logTypeInferenceVerbose()}. */ @SuppressWarnings("PMD.UncommentedEmptyMethodBody") public interface TypeInferenceLogger { @@ -64,8 +71,7 @@ public interface TypeInferenceLogger { default void applicabilityTest(InferenceContext ctx) { } - default void finishApplicabilityTest() { - } + default void finishApplicabilityTest() { } default void startArgsChecks() { } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceCtxUnitTests.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceCtxUnitTests.java index 5e33c6dd01..ba1d834261 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceCtxUnitTests.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/internal/infer/InferenceCtxUnitTests.java @@ -8,7 +8,10 @@ import static net.sourceforge.pmd.lang.java.types.TestUtilitiesForTypesKt.captur import static net.sourceforge.pmd.lang.java.types.internal.infer.BaseTypeInferenceUnitTest.Bound.eqBound; import static net.sourceforge.pmd.lang.java.types.internal.infer.BaseTypeInferenceUnitTest.Bound.lower; import static net.sourceforge.pmd.lang.java.types.internal.infer.BaseTypeInferenceUnitTest.Bound.upper; +import static net.sourceforge.pmd.util.CollectionUtil.setOf; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -19,11 +22,17 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import java.util.List; +import java.util.Set; + +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.java.types.JTypeMirror; import net.sourceforge.pmd.lang.java.types.TypeOps; import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind; +import net.sourceforge.pmd.lang.java.types.internal.infer.VarWalkStrategy.GraphWalk; +import net.sourceforge.pmd.util.IteratorUtil; /** * @@ -331,4 +340,88 @@ class InferenceCtxUnitTests extends BaseTypeInferenceUnitTest { assertThat(a, hasBoundsExactly(upper(ts.BOOLEAN.box()))); } + + private static @NotNull List> createBatchSetsFromGraph(InferenceContext ctx) { + GraphWalk graphWalk = new GraphWalk(ctx, false); + List> batches = IteratorUtil.toList(graphWalk); + return batches; + } + + @Test + void testGraphBuilding() { + InferenceContext ctx = emptyCtx(); + InferenceVar a = newIvar(ctx); + InferenceVar b = newIvar(ctx); + + List> batches = createBatchSetsFromGraph(ctx); + // no dependency: unordered + assertThat(batches, containsInAnyOrder(setOf(a), setOf(b))); + } + + @Test + void testGraphBuildingWithDependency() { + InferenceContext ctx = emptyCtx(); + InferenceVar a = newIvar(ctx); + InferenceVar b = newIvar(ctx); + + // a -> b + addSubtypeConstraint(ctx, a, ts.arrayType(b)); + + List> batches = createBatchSetsFromGraph(ctx); + + assertThat(batches, contains(setOf(b), setOf(a))); + } + + @Test + void testGraphBuildingWithDependency2() { + InferenceContext ctx = emptyCtx(); + InferenceVar a = newIvar(ctx); + InferenceVar b = newIvar(ctx); + + // a -> b + // b -> a (because of propagation) + addSubtypeConstraint(ctx, a, b); + + List> batches = createBatchSetsFromGraph(ctx); + + assertThat(batches, contains(setOf(b, a))); + } + + + + + @Test + void testGraphBuildingWithExtraDependency() { + InferenceContext ctx = emptyCtx(); + InferenceVar a = newIvar(ctx); + InferenceVar b = newIvar(ctx); + + // b -> a + ctx.addInstantiationDependencies(setOf(b), setOf(a)); + + List> batches = createBatchSetsFromGraph(ctx); + + assertThat(batches, contains(setOf(a), setOf(b))); + } + + @Test + void testGraphBuildingWithDependencyCycle() { + InferenceContext ctx = emptyCtx(); + InferenceVar a = newIvar(ctx); + InferenceVar b = newIvar(ctx); + InferenceVar c = newIvar(ctx); + + // a -> b, b -> a, + // a -> c, b -> c + a.addBound(BoundKind.UPPER, b); + a.addBound(BoundKind.EQ, listType(c)); + b.addBound(BoundKind.LOWER, a); + b.addBound(BoundKind.LOWER, listType(c)); + + + List> batches = createBatchSetsFromGraph(ctx); + + assertThat(batches, contains(setOf(c), setOf(b, a))); + } + } From 2df68ed16888ce9945dfc960d5b51c2547d4c833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 14 Nov 2024 16:32:09 +0100 Subject: [PATCH 17/37] Disable type inf logging by default --- .../pmd/lang/java/internal/JavaLanguageProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java index 7590d48f6f..7fafea029e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/internal/JavaLanguageProperties.java @@ -22,7 +22,7 @@ public class JavaLanguageProperties extends JvmLanguagePropertyBundle { PropertyFactory.enumProperty("xTypeInferenceLogging", EnumUtils.getEnumMap(InferenceLoggingVerbosity.class)) .desc("Verbosity of the type inference logging") - .defaultValue(InferenceLoggingVerbosity.VERBOSE) + .defaultValue(InferenceLoggingVerbosity.DISABLED) .build(); From 634a5252860d7e966109eef62ae3cb0973c6b491 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 17:07:37 +0100 Subject: [PATCH 18/37] [html] Test for a closing tag when determining node positions Fixes #5322 --- docs/pages/release_notes.md | 2 ++ .../pmd/lang/html/ast/LineNumbers.java | 11 ++++---- .../pmd/lang/html/cpd/HtmlCpdLexerTest.java | 9 +++++++ .../lang/html/cpd/testdata/InvalidHtml.html | 7 +++++ .../lang/html/cpd/testdata/InvalidHtml.txt | 22 +++++++++++++++ .../pmd/lang/html/cpd/testdata/MetaTag.html | 9 +++++++ .../pmd/lang/html/cpd/testdata/MetaTag.txt | 27 +++++++++++++++++++ 7 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.html create mode 100644 pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.txt create mode 100644 pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.html create mode 100644 pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.txt diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5fa3ac04b6..3a1b90322b 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -20,6 +20,8 @@ This is a {{ site.pmd.release_type }} release. * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas +* html + * [5322](https://github.com/pmd/pmd/issues/5322): \[html] CPD throws exception on when HTML file is missing closing tag ### ๐Ÿšจ API Changes diff --git a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java index 423b2772fb..5419b30e3a 100644 --- a/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java +++ b/pmd-html/src/main/java/net/sourceforge/pmd/lang/html/ast/LineNumbers.java @@ -50,15 +50,14 @@ class LineNumbers { nextIndex = determineLocation((AbstractHtmlNode) child, nextIndex); } - // autoclosing element, eg - boolean isAutoClose = n.getNumChildren() == 0 - && n instanceof ASTHtmlElement - // nextIndex is up to the closing > at this point - && htmlString.startsWith("/>", nextIndex - 2); + // explicitly closing element, eg. + boolean hasCloseElement = n instanceof ASTHtmlElement + // nextIndex is up to the closing tag at this point + && htmlString.startsWith("", nextIndex); if (n instanceof ASTHtmlDocument) { nextIndex = htmlString.length(); - } else if (n instanceof ASTHtmlElement && !isAutoClose) { + } else if (n instanceof ASTHtmlElement && hasCloseElement) { nextIndex += 2 + n.getXPathNodeName().length() + 1; // } else if (n instanceof ASTHtmlComment) { nextIndex += 4 + 3; // diff --git a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/cpd/HtmlCpdLexerTest.java b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/cpd/HtmlCpdLexerTest.java index 04db5c6152..088837d2ce 100644 --- a/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/cpd/HtmlCpdLexerTest.java +++ b/pmd-html/src/test/java/net/sourceforge/pmd/lang/html/cpd/HtmlCpdLexerTest.java @@ -21,4 +21,13 @@ class HtmlCpdLexerTest extends CpdTextComparisonTest { doTest("SimpleHtmlFile"); } + @Test + void invalidHtml() { + doTest("InvalidHtml"); + } + + @Test + void metaTag() { + doTest("MetaTag"); + } } diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.html b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.html new file mode 100644 index 0000000000..73acc68e1d --- /dev/null +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.html @@ -0,0 +1,7 @@ + + + + +

+ + diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.txt new file mode 100644 index 0000000000..2cc097ffd2 --- /dev/null +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/InvalidHtml.txt @@ -0,0 +1,22 @@ + [Image] or [Truncated image[ Bcol Ecol +L1 + [#document] 1 8 + [#doctype] 1 15 + [\n] 16 16 +L2 + [html] 1 7 + [\n] 17 17 +L3 + [body] 1 7 + [\n] 7 7 +L4 + [#comment] 1 36 + [\n] 37 37 +L5 + [div] 1 22 + [\n] 22 22 +L6 + [\n] 8 8 +L7 + [\n] 8 8 +EOF diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.html b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.html new file mode 100644 index 0000000000..d8a96810a8 --- /dev/null +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.txt b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.txt new file mode 100644 index 0000000000..0547e117b8 --- /dev/null +++ b/pmd-html/src/test/resources/net/sourceforge/pmd/lang/html/cpd/testdata/MetaTag.txt @@ -0,0 +1,27 @@ + [Image] or [Truncated image[ Bcol Ecol +L1 + [#document] 1 8 + [#doctype] 1 15 + [\n] 16 16 +L2 + [html] 1 7 + [\n] 17 17 +L3 + [head] 1 7 + [\n ] 7 4 +L4 + [#comment] 5 66 + [\n ] 67 4 +L5 + [meta] 5 27 + [\n] 27 27 +L6 + [\n] 8 8 +L7 + [body] 1 7 + [\n] 7 7 +L8 + [\n] 8 8 +L9 + [\n] 8 8 +EOF From 61eb116833573ce78ca3d1eb6bdf1fb1892f8685 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 17:39:07 +0100 Subject: [PATCH 19/37] [java] PreserveStackTrace - consider instance type patterns Fixes #5318 --- docs/pages/release_notes.md | 2 + .../bestpractices/PreserveStackTraceRule.java | 73 ++++++++++++------- .../bestpractices/xml/PreserveStackTrace.xml | 31 ++++++++ 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5fa3ac04b6..ea37011a0f 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -20,6 +20,8 @@ This is a {{ site.pmd.release_type }} release. * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas +* java-bestpractices + * [#5318](https://github.com/pmd/pmd/issues/5318): \[java] PreserveStackTraceRule: false-positive on Pattern Matching with instanceof ### ๐Ÿšจ API Changes diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java index 03d0d9faea..229e8a5da0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/PreserveStackTraceRule.java @@ -4,11 +4,10 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; +import java.util.Collections; import java.util.HashSet; import java.util.Set; -import org.checkerframework.checker.nullness.qual.NonNull; - import net.sourceforge.pmd.lang.ast.NodeStream; import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr; import net.sourceforge.pmd.lang.java.ast.ASTCastExpression; @@ -17,13 +16,17 @@ import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall; import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTInfixExpression; import net.sourceforge.pmd.lang.java.ast.ASTInitializer; import net.sourceforge.pmd.lang.java.ast.ASTList; import net.sourceforge.pmd.lang.java.ast.ASTMethodCall; +import net.sourceforge.pmd.lang.java.ast.ASTPatternExpression; import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTTypePattern; import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess; import net.sourceforge.pmd.lang.java.ast.ASTVariableId; +import net.sourceforge.pmd.lang.java.ast.BinaryOp; import net.sourceforge.pmd.lang.java.ast.InvocationNode; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.internal.JavaAstUtils; @@ -64,7 +67,7 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { for (ASTThrowStatement throwStatement : catchStmt.getBody().descendants(ASTThrowStatement.class)) { ASTExpression thrownExpr = throwStatement.getExpr(); - if (!exprConsumesException(exceptionParam, thrownExpr, true)) { + if (!exprConsumesException(Collections.singleton(exceptionParam), thrownExpr, true)) { asCtx(data).addViolation(thrownExpr, exceptionParam.getName()); } } @@ -72,25 +75,39 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { return null; } - private boolean exprConsumesException(ASTVariableId exceptionParam, ASTExpression expr, boolean mayBeSelf) { + private boolean exprConsumesException(Set exceptionParams, ASTExpression expr, boolean mayBeSelf) { if (expr instanceof ASTConstructorCall) { // new Exception(e) - return ctorConsumesException(exceptionParam, (ASTConstructorCall) expr); + return ctorConsumesException(exceptionParams, (ASTConstructorCall) expr); } else if (expr instanceof ASTMethodCall) { - return methodConsumesException(exceptionParam, (ASTMethodCall) expr); + return methodConsumesException(exceptionParams, (ASTMethodCall) expr); } else if (expr instanceof ASTCastExpression) { ASTExpression innermost = JavaAstUtils.peelCasts(expr); - return exprConsumesException(exceptionParam, innermost, mayBeSelf); + return exprConsumesException(exceptionParams, innermost, mayBeSelf); } else if (expr instanceof ASTConditionalExpression) { ASTConditionalExpression ternary = (ASTConditionalExpression) expr; - return exprConsumesException(exceptionParam, ternary.getThenBranch(), mayBeSelf) - && exprConsumesException(exceptionParam, ternary.getElseBranch(), mayBeSelf); + Set possibleExceptionParams = new HashSet<>(exceptionParams); + + // Peel out a type pattern variable in case this conditional is an instanceof pattern + NodeStream.of(ternary.getCondition()) + .filterIs(ASTInfixExpression.class) + .filterMatching(ASTInfixExpression::getOperator, BinaryOp.INSTANCEOF) + .map(ASTInfixExpression::getRightOperand) + .filterIs(ASTPatternExpression.class) + .map(ASTPatternExpression::getPattern) + .filterIs(ASTTypePattern.class) + .map(ASTTypePattern::getVarId) + .firstOpt() + .ifPresent(possibleExceptionParams::add); + + return exprConsumesException(possibleExceptionParams, ternary.getThenBranch(), mayBeSelf) + && exprConsumesException(possibleExceptionParams, ternary.getElseBranch(), mayBeSelf); } else if (expr instanceof ASTVariableAccess) { JVariableSymbol referencedSym = ((ASTVariableAccess) expr).getReferencedSym(); @@ -99,7 +116,7 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { } ASTVariableId decl = referencedSym.tryGetNode(); - if (decl == exceptionParam) { + if (exceptionParams.contains(decl)) { return mayBeSelf; } else if (decl == null || decl.isFormalParameter() || decl.isField()) { return false; @@ -113,16 +130,16 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { // if any of the initializer and usages consumes the variable, // answer true. - if (exprConsumesException(exceptionParam, decl.getInitializer(), mayBeSelf)) { + if (exprConsumesException(exceptionParams, decl.getInitializer(), mayBeSelf)) { return true; } for (ASTNamedReferenceExpr usage : decl.getLocalUsages()) { - if (assignmentRhsConsumesException(exceptionParam, decl, usage)) { + if (assignmentRhsConsumesException(exceptionParams, decl, usage)) { return true; } - if (JavaAstUtils.followingCallChain(usage).any(it -> consumesExceptionNonRecursive(exceptionParam, it))) { + if (JavaAstUtils.followingCallChain(usage).any(it -> consumesExceptionNonRecursive(exceptionParams, it))) { return true; } } @@ -134,7 +151,7 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { } } - private boolean assignmentRhsConsumesException(ASTVariableId exceptionParam, ASTVariableId lhsVariable, ASTNamedReferenceExpr usage) { + private boolean assignmentRhsConsumesException(Set exceptionParams, ASTVariableId lhsVariable, ASTNamedReferenceExpr usage) { if (usage.getIndexInParent() == 0) { ASTExpression assignmentRhs = JavaAstUtils.getOtherOperandIfInAssignmentExpr(usage); boolean rhsIsSelfReferential = @@ -142,25 +159,25 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { .descendantsOrSelf() .filterIs(ASTVariableAccess.class) .any(it -> JavaAstUtils.isReferenceToVar(it, lhsVariable.getSymbol())); - return !rhsIsSelfReferential && exprConsumesException(exceptionParam, assignmentRhs, true); + return !rhsIsSelfReferential && exprConsumesException(exceptionParams, assignmentRhs, true); } return false; } - private boolean ctorConsumesException(ASTVariableId exceptionParam, ASTConstructorCall ctorCall) { - return ctorCall.isAnonymousClass() && callsInitCauseInAnonInitializer(exceptionParam, ctorCall) - || anArgumentConsumesException(exceptionParam, ctorCall); + private boolean ctorConsumesException(Set exceptionParams, ASTConstructorCall ctorCall) { + return ctorCall.isAnonymousClass() && callsInitCauseInAnonInitializer(exceptionParams, ctorCall) + || anArgumentConsumesException(exceptionParams, ctorCall); } - private boolean consumesExceptionNonRecursive(ASTVariableId exceptionParam, ASTExpression expr) { + private boolean consumesExceptionNonRecursive(Set exceptionParam, ASTExpression expr) { if (expr instanceof ASTConstructorCall) { return ctorConsumesException(exceptionParam, (ASTConstructorCall) expr); } return expr instanceof InvocationNode && anArgumentConsumesException(exceptionParam, (InvocationNode) expr); } - private boolean methodConsumesException(ASTVariableId exceptionParam, ASTMethodCall call) { - if (anArgumentConsumesException(exceptionParam, call)) { + private boolean methodConsumesException(Set exceptionParams, ASTMethodCall call) { + if (anArgumentConsumesException(exceptionParams, call)) { return true; } ASTExpression qualifier = call.getQualifier(); @@ -168,24 +185,24 @@ public class PreserveStackTraceRule extends AbstractJavaRulechainRule { return false; } boolean mayBeSelf = ALLOWED_GETTERS.anyMatch(call); - return exprConsumesException(exceptionParam, qualifier, mayBeSelf); + return exprConsumesException(exceptionParams, qualifier, mayBeSelf); } - private boolean callsInitCauseInAnonInitializer(ASTVariableId exceptionParam, ASTConstructorCall ctorCall) { + private boolean callsInitCauseInAnonInitializer(Set exceptionParams, ASTConstructorCall ctorCall) { return NodeStream.of(ctorCall.getAnonymousClassDeclaration()) .flatMap(ASTTypeDeclaration::getDeclarations) .map(NodeStream.asInstanceOf(ASTFieldDeclaration.class, ASTInitializer.class)) .descendants().filterIs(ASTMethodCall.class) - .any(it -> isInitCauseWithTargetInArg(exceptionParam, it)); + .any(it -> isInitCauseWithTargetInArg(exceptionParams, it)); } - private boolean isInitCauseWithTargetInArg(ASTVariableId exceptionSym, JavaNode expr) { - return INIT_CAUSE.matchesCall(expr) && anArgumentConsumesException(exceptionSym, (ASTMethodCall) expr); + private boolean isInitCauseWithTargetInArg(Set exceptionParams, JavaNode expr) { + return INIT_CAUSE.matchesCall(expr) && anArgumentConsumesException(exceptionParams, (ASTMethodCall) expr); } - private boolean anArgumentConsumesException(@NonNull ASTVariableId exceptionParam, InvocationNode thrownExpr) { + private boolean anArgumentConsumesException(Set exceptionParams, InvocationNode thrownExpr) { for (ASTExpression arg : ASTList.orEmptyStream(thrownExpr.getArguments())) { - if (exprConsumesException(exceptionParam, arg, true)) { + if (exprConsumesException(exceptionParams, arg, true)) { return true; } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml index 5292c61d64..637b6dffa6 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/PreserveStackTrace.xml @@ -1168,4 +1168,35 @@ public class Foo { ]]> + + #5318 [java] PreserveStackTraceRule: false-positive on Pattern Matching with instanceof + 0 + formatExceptionHandler = e -> { e.printStackTrace(); }; +} +]]> + From bf388d7fd059aec33d38f6b2088470c04ea1aea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Thu, 14 Nov 2024 17:27:45 +0100 Subject: [PATCH 20/37] Propagate unknown type better when mref is unresolved --- .../types/internal/infer/ExprCheckHelper.java | 7 ++ .../java/types/internal/infer/ExprOps.java | 1 - .../lang/java/types/TypesTreeDumpTest.java | 5 ++ .../pmd/lang/java/types/AstTestUtil.kt | 1 + .../infer/UnresolvedTypesRecoveryTest.kt | 38 +++++++++ .../bestpractices/xml/UnusedPrivateMethod.xml | 41 ++++++++++ .../types/dumptests/UnresolvedThings.java | 16 ++++ .../java/types/dumptests/UnresolvedThings.txt | 80 +++++++++++++++++++ 8 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.java create mode 100644 pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.txt diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java index dc8955fcb0..f6521426e2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprCheckHelper.java @@ -335,6 +335,13 @@ final class ExprCheckHelper { checker.checkExprConstraint(infCtx, capture(r2), r); } completeMethodRefInference(mref, nonWildcard, fun, exactMethod, true); + } else if (TypeOps.isUnresolved(mref.getTypeToSearch())) { + // Then this is neither an exact nor inexact method ref, + // we just don't know what it is. + + // The return values of the mref are assimilated to an (*unknown*) type. + checker.checkExprConstraint(infCtx, ts.UNKNOWN, fun.getReturnType()); + completeMethodRefInference(mref, nonWildcard, fun, ts.UNRESOLVED_METHOD, false); } else { // Otherwise, the method reference is inexact, and: diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprOps.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprOps.java index 8ea1cee3da..a04c91c55f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprOps.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprOps.java @@ -227,7 +227,6 @@ final class ExprOps { } } else { JClassType enclosing = mref.getEnclosingType(); - accessible = mref.getTypeToSearch() .streamMethods(TypeOps.accessibleMethodFilter(mref.getMethodName(), enclosing.getSymbol())) .collect(OverloadSet.collectMostSpecific(enclosing)); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java index 9b8baaeca6..50d22c663d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/types/TypesTreeDumpTest.java @@ -55,6 +55,11 @@ class TypesTreeDumpTest extends BaseTreeDumpTest { doTest("NestedLambdasAndMethodCalls"); } + @Test + void testUnresolvedThings() { + doTest("UnresolvedThings"); + } + @Override protected @NonNull String normalize(@NonNull String str) { return super.normalize(str) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/AstTestUtil.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/AstTestUtil.kt index 1545c93f7e..e5c04d1ac5 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/AstTestUtil.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/AstTestUtil.kt @@ -21,6 +21,7 @@ fun JavaNode.declaredMethodSignatures(): List = methodDeclarations() fun JavaNode.methodCalls(): DescendantNodeStream = descendants(ASTMethodCall::class.java) fun JavaNode.firstMethodCall() = methodCalls().crossFindBoundaries().firstOrThrow() +fun JavaNode.firstMethodCall(name: String) = methodCalls().crossFindBoundaries().filter { it.methodName == name }.firstOrThrow() fun JavaNode.ctorCalls(): DescendantNodeStream = descendants(ASTConstructorCall::class.java) fun JavaNode.firstCtorCall() = ctorCalls().crossFindBoundaries().firstOrThrow() diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt index 24d7ec3c04..45c13cf569 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt @@ -664,4 +664,42 @@ class C { fooToInt.referencedMethod.symbol shouldBe toIntFun } } + + parserTest("Type inference should not resolve UNKNOWN bounded types to Object #5329") { + + val (acu, _) = parser.parseWithTypeInferenceSpy( + """ + import java.util.ArrayList; + import java.util.List; + import java.util.stream.Stream; + import java.util.stream.Collectors; + + class Foo { + public Item methodA(List loads) { + List items = new ArrayList<>(); + loads.stream() + // Here this collect call should have type + // Map<(*unknown*), List<*Item>> + // ie, key is unknown, not Object. + .collect(Collectors.groupingBy(Item::getValue)) + .forEach((a, b) -> items.add(buildItem(a, b))); + } + + private SummaryDto.ItemDto buildItem(BigDecimal a, List b) { + return SummaryDto.ItemDto.builder().build(); + } + } + """ + ) + + val collect = acu.firstMethodCall("collect") + val buildItem = acu.firstMethodCall("buildItem") + val (_, buildItemDecl) = acu.methodDeclarations().toList { it.symbol } + val (itemT) = acu.descendants(ASTClassType::class.java).toList { it.typeMirror } + + acu.withTypeDsl { + collect shouldHaveType java.util.Map::class[ts.UNKNOWN, java.util.List::class[itemT]] + buildItem.methodType.symbol shouldBe buildItemDecl + } + } }) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 2a743036a6..1a6dd1488d 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2177,4 +2177,45 @@ public class ObtainViaTest { record Library(Collection books) {} ]]> + + #5324 UnusedPrivateMethod with unresolved types + 0 + { + try { + return registerUser(email, firstName, lastName); + } catch (Exception e) { + throw new IllegalStateException("Failed to register user for " + email, e); + } + }); + // ... + return user; + } + + private User registerUser(String email, String firstName, String lastName) throws Exception { + // register user logic here... + } + } + ]]> + + + #5329 UnusedPrivateMethod with unresolved types + 0 + items = new ArrayList<>(); + loads.stream() + .collect(Collectors.groupingBy(Item::getValue)) + .forEach((a, b) -> items.add(buildItem(a, b))); + } + + private SummaryDto.ItemDto buildItem(BigDecimal a, List b) { + return SummaryDto.ItemDto.builder().build(); + } + } + ]]> + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.java new file mode 100644 index 0000000000..83eb9d62b4 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.java @@ -0,0 +1,16 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import java.util.stream.Collectors; +class Foo { + public User methodA(List loads) { + List items = new ArrayList<>(); + loads.stream() + .collect(Collectors.groupingBy(Item::getValue)) + .forEach((a, b) -> items.add(buildItem(a, b))); + } + + private SummaryDto.ItemDto buildItem(BigDecimal a, List b) { + return SummaryDto.ItemDto.builder().build(); + } +} \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.txt b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.txt new file mode 100644 index 0000000000..32f1f2643e --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/types/dumptests/UnresolvedThings.txt @@ -0,0 +1,80 @@ ++- CompilationUnit[] + +- ImportDeclaration[] + +- ImportDeclaration[] + +- ImportDeclaration[] + +- ImportDeclaration[] + +- ClassDeclaration[@TypeMirror = "Foo"] + +- ModifierList[] + +- ClassBody[] + +- MethodDeclaration[@Name = "methodA"] + | +- ModifierList[] + | +- ClassType[@TypeMirror = "*User"] + | +- FormalParameters[] + | | +- FormalParameter[@TypeMirror = "java.util.List<*Item>"] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "java.util.List<*Item>"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "*Item"] + | | +- VariableId[@Name = "loads", @TypeMirror = "java.util.List<*Item>"] + | +- Block[] + | +- LocalVariableDeclaration[] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "java.util.List<*SummaryDto.ItemDto>"] + | | | +- TypeArguments[] + | | | +- ClassType[@TypeMirror = "*SummaryDto.ItemDto"] + | | +- VariableDeclarator[] + | | +- VariableId[@Name = "items", @TypeMirror = "java.util.List<*SummaryDto.ItemDto>"] + | | +- ConstructorCall[@Failed = false, @Function = "java.util.ArrayList<*SummaryDto.ItemDto>.new() -> java.util.ArrayList<*SummaryDto.ItemDto>", @MethodName = "new", @TypeMirror = "java.util.ArrayList<*SummaryDto.ItemDto>", @Unchecked = false, @VarargsCall = false] + | | +- ClassType[@TypeMirror = "java.util.ArrayList"] + | | | +- TypeArguments[] + | | +- ArgumentList[] + | +- ExpressionStatement[] + | +- MethodCall[@Failed = false, @Function = "java.util.Map<(*unknown*), java.util.List<*Item>>.forEach(java.util.function.BiConsumer>) -> void", @MethodName = "forEach", @TypeMirror = "void", @Unchecked = false, @VarargsCall = false] + | +- MethodCall[@Failed = false, @Function = "java.util.stream.Stream<*Item>. collect(java.util.stream.Collector>>) -> java.util.Map<(*unknown*), java.util.List<*Item>>", @MethodName = "collect", @TypeMirror = "java.util.Map<(*unknown*), java.util.List<*Item>>", @Unchecked = false, @VarargsCall = false] + | | +- MethodCall[@Failed = false, @Function = "java.util.Collection<*Item>.stream() -> java.util.stream.Stream<*Item>", @MethodName = "stream", @TypeMirror = "java.util.stream.Stream<*Item>", @Unchecked = false, @VarargsCall = false] + | | | +- VariableAccess[@Name = "loads", @TypeMirror = "java.util.List<*Item>"] + | | | +- ArgumentList[] + | | +- ArgumentList[] + | | +- MethodCall[@Failed = false, @Function = "java.util.stream.Collectors. groupingBy(java.util.function.Function) -> java.util.stream.Collector<*Item, java.lang.Object, java.util.Map<(*unknown*), java.util.List<*Item>>>", @MethodName = "groupingBy", @TypeMirror = "java.util.stream.Collector<*Item, java.lang.Object, java.util.Map<(*unknown*), java.util.List<*Item>>>", @Unchecked = false, @VarargsCall = false] + | | +- TypeExpression[@TypeMirror = "java.util.stream.Collectors"] + | | | +- ClassType[@TypeMirror = "java.util.stream.Collectors"] + | | +- ArgumentList[] + | | +- MethodReference[@TypeMirror = "java.util.function.Function<*Item, (*unknown*)>"] + | | +- AmbiguousName[@TypeMirror = "(*unknown*)"] + | +- ArgumentList[] + | +- LambdaExpression[@TypeMirror = "java.util.function.BiConsumer<(*unknown*), java.util.List<*Item>>"] + | +- LambdaParameterList[] + | | +- LambdaParameter[@TypeMirror = "(*unknown*)"] + | | | +- ModifierList[] + | | | +- VariableId[@Name = "a", @TypeMirror = "(*unknown*)"] + | | +- LambdaParameter[@TypeMirror = "java.util.List<*Item>"] + | | +- ModifierList[] + | | +- VariableId[@Name = "b", @TypeMirror = "java.util.List<*Item>"] + | +- MethodCall[@Failed = false, @Function = "java.util.List<*SummaryDto.ItemDto>.add(*SummaryDto.ItemDto) -> boolean", @MethodName = "add", @TypeMirror = "boolean", @Unchecked = false, @VarargsCall = false] + | +- VariableAccess[@Name = "items", @TypeMirror = "java.util.List<*SummaryDto.ItemDto>"] + | +- ArgumentList[] + | +- MethodCall[@Failed = false, @Function = "Foo.buildItem(*BigDecimal, java.util.List<*Item>) -> *SummaryDto.ItemDto", @MethodName = "buildItem", @TypeMirror = "*SummaryDto.ItemDto", @Unchecked = false, @VarargsCall = false] + | +- ArgumentList[] + | +- VariableAccess[@Name = "a", @TypeMirror = "(*unknown*)"] + | +- VariableAccess[@Name = "b", @TypeMirror = "java.util.List<*Item>"] + +- MethodDeclaration[@Name = "buildItem"] + +- ModifierList[] + +- ClassType[@TypeMirror = "*SummaryDto.ItemDto"] + +- FormalParameters[] + | +- FormalParameter[@TypeMirror = "*BigDecimal"] + | | +- ModifierList[] + | | +- ClassType[@TypeMirror = "*BigDecimal"] + | | +- VariableId[@Name = "a", @TypeMirror = "*BigDecimal"] + | +- FormalParameter[@TypeMirror = "java.util.List<*Item>"] + | +- ModifierList[] + | +- ClassType[@TypeMirror = "java.util.List<*Item>"] + | | +- TypeArguments[] + | | +- ClassType[@TypeMirror = "*Item"] + | +- VariableId[@Name = "b", @TypeMirror = "java.util.List<*Item>"] + +- Block[] + +- ReturnStatement[] + +- MethodCall[@Failed = true, @Function = "(*unknown*).(*unknown method*)() -> (*unknown*)", @MethodName = "build", @TypeMirror = "(*unknown*)", @Unchecked = false, @VarargsCall = false] + +- MethodCall[@Failed = true, @Function = "(*unknown*).(*unknown method*)() -> (*unknown*)", @MethodName = "builder", @TypeMirror = "(*unknown*)", @Unchecked = false, @VarargsCall = false] + | +- AmbiguousName[@TypeMirror = "(*unknown*)"] + | +- ArgumentList[] + +- ArgumentList[] From bb729e02f4a6f472fb732688024cf941f2c32908 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 17:39:32 +0100 Subject: [PATCH 21/37] Add @VitaliiIevtushenko as a contributor --- .all-contributorsrc | 9 + docs/pages/pmd/projectdocs/credits.md | 238 +++++++++++++------------- 2 files changed, 129 insertions(+), 118 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 95ebc05d6e..171741bf0b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7865,6 +7865,15 @@ "contributions": [ "code" ] + }, + { + "login": "VitaliiIevtushenko", + "name": "Vitalii Yevtushenko", + "avatar_url": "https://avatars.githubusercontent.com/u/11145125?v=4", + "profile": "https://github.com/VitaliiIevtushenko", + "contributions": [ + "bug" + ] } ], "contributorsPerLine": 7, diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 9497ea7378..6f7d9255aa 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -350,769 +350,771 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d JJengility
JJengility

๐Ÿ› Jake Hemmerle
Jake Hemmerle

๐Ÿ› + Jakub Dupak
Jakub Dupak

๐Ÿ’ป James Harrison
James Harrison

๐Ÿ› ๐Ÿ’ป Jamie Bisotti
Jamie Bisotti

๐Ÿ› Jan
Jan

๐Ÿ› Jan Aertgeerts
Jan Aertgeerts

๐Ÿ’ป ๐Ÿ› - Jan Brรผmmer
Jan Brรผmmer

๐Ÿ› + Jan Brรผmmer
Jan Brรผmmer

๐Ÿ› Jan Tล™รญska
Jan Tล™รญska

๐Ÿ› Jan-Lukas Else
Jan-Lukas Else

๐Ÿ› Jason Qiu
Jason Qiu

๐Ÿ’ป ๐Ÿ“– Jason Williams
Jason Williams

๐Ÿ› Javier Spagnoletti
Javier Spagnoletti

๐Ÿ› Jean-Paul Mayer
Jean-Paul Mayer

๐Ÿ› - Jean-Simon Larochelle
Jean-Simon Larochelle

๐Ÿ› + Jean-Simon Larochelle
Jean-Simon Larochelle

๐Ÿ› Jeff Bartolotta
Jeff Bartolotta

๐Ÿ’ป ๐Ÿ› Jeff Hube
Jeff Hube

๐Ÿ’ป ๐Ÿ› Jeff Jensen
Jeff Jensen

๐Ÿ› Jeff May
Jeff May

๐Ÿ› Jens Gerdes
Jens Gerdes

๐Ÿ› Jeroen Borgers
Jeroen Borgers

๐Ÿ› ๐Ÿ’ป ๐Ÿ“ข - Jeroen Meijer
Jeroen Meijer

๐Ÿ› + Jeroen Meijer
Jeroen Meijer

๐Ÿ› Jeroen van Wilgenburg
Jeroen van Wilgenburg

๐Ÿ“– Jerome Russ
Jerome Russ

๐Ÿ› JerritEic
JerritEic

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› Jiri Pejchal
Jiri Pejchal

๐Ÿ› Jithin Sunny
Jithin Sunny

๐Ÿ› Jiล™รญ ล korpil
Jiล™รญ ล korpil

๐Ÿ› - Joao Machado
Joao Machado

๐Ÿ› + Joao Machado
Joao Machado

๐Ÿ› Jochen Krauss
Jochen Krauss

๐Ÿ› Johan Hammar
Johan Hammar

๐Ÿ› John Karp
John Karp

๐Ÿ› John Zhang
John Zhang

๐Ÿ› John-Teng
John-Teng

๐Ÿ’ป ๐Ÿ› Jon Moroney
Jon Moroney

๐Ÿ’ป ๐Ÿ› - Jonas Geiregat
Jonas Geiregat

๐Ÿ› + Jonas Geiregat
Jonas Geiregat

๐Ÿ› Jonas KeรŸler
Jonas KeรŸler

๐Ÿ› Jonathan Wiesel
Jonathan Wiesel

๐Ÿ’ป ๐Ÿ› Jordan
Jordan

๐Ÿ› Jordi Llach
Jordi Llach

๐Ÿ› Jorge Solรณrzano
Jorge Solรณrzano

๐Ÿ› JorneVL
JorneVL

๐Ÿ› - Jose Palafox
Jose Palafox

๐Ÿ› + Jose Palafox
Jose Palafox

๐Ÿ› Jose Stovall
Jose Stovall

๐Ÿ› Joseph
Joseph

๐Ÿ’ป Joseph Heenan
Joseph Heenan

๐Ÿ› Josh Feingold
Josh Feingold

๐Ÿ’ป ๐Ÿ› Josh Holthaus
Josh Holthaus

๐Ÿ› Joshua S Arquilevich
Joshua S Arquilevich

๐Ÿ› - Joรฃo Dinis Ferreira
Joรฃo Dinis Ferreira

๐Ÿ“– + Joรฃo Dinis Ferreira
Joรฃo Dinis Ferreira

๐Ÿ“– Joรฃo Ferreira
Joรฃo Ferreira

๐Ÿ’ป ๐Ÿ› Joรฃo Pedro Schmitt
Joรฃo Pedro Schmitt

๐Ÿ› Juan Martรญn Sotuyo Dodero
Juan Martรญn Sotuyo Dodero

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› ๐Ÿšง Juan Pablo Civile
Juan Pablo Civile

๐Ÿ› Julian Voronetsky
Julian Voronetsky

๐Ÿ› Julien
Julien

๐Ÿ› - Julius
Julius

๐Ÿ› + Julius
Julius

๐Ÿ› JustPRV
JustPRV

๐Ÿ› Justin Stroud
Justin Stroud

๐Ÿ’ป Jรถrn Huxhorn
Jรถrn Huxhorn

๐Ÿ› KThompso
KThompso

๐Ÿ› Kai Amundsen
Kai Amundsen

๐Ÿ› Karel Vervaeke
Karel Vervaeke

๐Ÿ› - Karl-Andero Mere
Karl-Andero Mere

๐Ÿ› + Karl-Andero Mere
Karl-Andero Mere

๐Ÿ› Karl-Philipp Richter
Karl-Philipp Richter

๐Ÿ› Karsten Silz
Karsten Silz

๐Ÿ› Kazuma Watanabe
Kazuma Watanabe

๐Ÿ› Kev
Kev

๐Ÿ› Keve Mรผller
Keve Mรผller

๐Ÿ› Kevin Guerra
Kevin Guerra

๐Ÿ’ป - Kevin Jones
Kevin Jones

๐Ÿ› ๐Ÿ’ป + Kevin Jones
Kevin Jones

๐Ÿ› ๐Ÿ’ป Kevin Poorman
Kevin Poorman

๐Ÿ› Kevin Wayne
Kevin Wayne

๐Ÿ› Kieran Black
Kieran Black

๐Ÿ› Kirill Zubov
Kirill Zubov

๐Ÿ› Kirk Clemens
Kirk Clemens

๐Ÿ’ป ๐Ÿ› Klaus Hartl
Klaus Hartl

๐Ÿ› - Koen Van Looveren
Koen Van Looveren

๐Ÿ› + Koen Van Looveren
Koen Van Looveren

๐Ÿ› Kris Scheibe
Kris Scheibe

๐Ÿ’ป ๐Ÿ› Krystian Dabrowski
Krystian Dabrowski

๐Ÿ› ๐Ÿ’ป Kunal Thanki
Kunal Thanki

๐Ÿ› LaLucid
LaLucid

๐Ÿ’ป Larry Diamond
Larry Diamond

๐Ÿ’ป ๐Ÿ› Lars Knickrehm
Lars Knickrehm

๐Ÿ› - Laurent Bovet
Laurent Bovet

๐Ÿ› ๐Ÿ’ป + Laurent Bovet
Laurent Bovet

๐Ÿ› ๐Ÿ’ป Leo Gutierrez
Leo Gutierrez

๐Ÿ› LiGaOg
LiGaOg

๐Ÿ’ป Liam Sharp
Liam Sharp

๐Ÿ› Lintsi
Lintsi

๐Ÿ› Linus Fernandes
Linus Fernandes

๐Ÿ› Lixon Lookose
Lixon Lookose

๐Ÿ› - Logesh
Logesh

๐Ÿ› + Logesh
Logesh

๐Ÿ› Lorenzo Gabriele
Lorenzo Gabriele

๐Ÿ› Loรฏc Ledoyen
Loรฏc Ledoyen

๐Ÿ› Lucas
Lucas

๐Ÿ› Lucas Silva
Lucas Silva

๐Ÿ› Lucas Soncini
Lucas Soncini

๐Ÿ’ป ๐Ÿ› Luis Alcantar
Luis Alcantar

๐Ÿ’ป - Lukas Grรคf
Lukas Grรคf

๐Ÿ’ป + Lukas Grรคf
Lukas Grรคf

๐Ÿ’ป Lukasz Slonina
Lukasz Slonina

๐Ÿ› Lukebray
Lukebray

๐Ÿ› Lynn
Lynn

๐Ÿ’ป ๐Ÿ› Lyor Goldstein
Lyor Goldstein

๐Ÿ› MCMicS
MCMicS

๐Ÿ› Macarse
Macarse

๐Ÿ› - Machine account for PMD
Machine account for PMD

๐Ÿ’ป + Machine account for PMD
Machine account for PMD

๐Ÿ’ป Maciek Siemczyk
Maciek Siemczyk

๐Ÿ› Maikel Steneker
Maikel Steneker

๐Ÿ’ป ๐Ÿ› Maksim Moiseikin
Maksim Moiseikin

๐Ÿ› Manfred Koch
Manfred Koch

๐Ÿ› Manuel Moya Ferrer
Manuel Moya Ferrer

๐Ÿ’ป ๐Ÿ› Manuel Ryan
Manuel Ryan

๐Ÿ› - Marat Vyshegorodtsev
Marat Vyshegorodtsev

๐Ÿ› + Marat Vyshegorodtsev
Marat Vyshegorodtsev

๐Ÿ› Marcel Hรคrle
Marcel Hรคrle

๐Ÿ› Marcello Fialho
Marcello Fialho

๐Ÿ› Marcin Dฤ…browski
Marcin Dฤ…browski

๐Ÿ’ป Marcin Rataj
Marcin Rataj

๐Ÿ› Marcono1234
Marcono1234

๐Ÿ› Mark Adamcin
Mark Adamcin

๐Ÿ› - Mark Hall
Mark Hall

๐Ÿ’ป ๐Ÿ› + Mark Hall
Mark Hall

๐Ÿ’ป ๐Ÿ› Mark Kolich
Mark Kolich

๐Ÿ› Mark Pritchard
Mark Pritchard

๐Ÿ› Markus Rathgeb
Markus Rathgeb

๐Ÿ› Marquis Wang
Marquis Wang

๐Ÿ› MartGit
MartGit

๐Ÿ› Martin Feldsztejn
Martin Feldsztejn

๐Ÿ› - Martin Lehmann
Martin Lehmann

๐Ÿ› + Martin Lehmann
Martin Lehmann

๐Ÿ› Martin Spamer
Martin Spamer

๐Ÿ› Martin Tarjรกnyi
Martin Tarjรกnyi

๐Ÿ› MatFl
MatFl

๐Ÿ› Mateusz Stefanski
Mateusz Stefanski

๐Ÿ› Mathieu Gouin
Mathieu Gouin

๐Ÿ› MatiasComercio
MatiasComercio

๐Ÿ’ป ๐Ÿ› - Matt Benson
Matt Benson

๐Ÿ› + Matt Benson
Matt Benson

๐Ÿ› Matt De Poorter
Matt De Poorter

๐Ÿ› Matt Hargett
Matt Hargett

๐Ÿ’ป ๐Ÿ’ต Matt Harrah
Matt Harrah

๐Ÿ› Matt Nelson
Matt Nelson

๐Ÿ› Matthew Amos
Matthew Amos

๐Ÿ› Matthew Duggan
Matthew Duggan

๐Ÿ› - Matthew Hall
Matthew Hall

๐Ÿ› + Matthew Hall
Matthew Hall

๐Ÿ› Matthew Rossner
Matthew Rossner

๐Ÿ› Matรญas Fraga
Matรญas Fraga

๐Ÿ’ป ๐Ÿ› Maxime Robert
Maxime Robert

๐Ÿ’ป ๐Ÿ› MetaBF
MetaBF

๐Ÿ› Metin Dagcilar
Metin Dagcilar

๐Ÿ› Michael
Michael

๐Ÿ› - Michael Bell
Michael Bell

๐Ÿ› + Michael Bell
Michael Bell

๐Ÿ› Michael Bernstein
Michael Bernstein

๐Ÿ› Michael Clay
Michael Clay

๐Ÿ› Michael Dombrowski
Michael Dombrowski

๐Ÿ› Michael Hausegger
Michael Hausegger

๐Ÿ› Michael Hoefer
Michael Hoefer

๐Ÿ› Michael Kolesnikov
Michael Kolesnikov

๐Ÿ› - Michael Mรถbius
Michael Mรถbius

๐Ÿ› + Michael Mรถbius
Michael Mรถbius

๐Ÿ› Michael N. Lipp
Michael N. Lipp

๐Ÿ› Michael Pellegrini
Michael Pellegrini

๐Ÿ› Michal Kordas
Michal Kordas

๐Ÿ› Michaล‚ Borek
Michaล‚ Borek

๐Ÿ› Michaล‚ Kuliล„ski
Michaล‚ Kuliล„ski

๐Ÿ› Miguel Nรบรฑez Dรญaz-Montes
Miguel Nรบรฑez Dรญaz-Montes

๐Ÿ› - Mihai Ionut
Mihai Ionut

๐Ÿ› + Mihai Ionut
Mihai Ionut

๐Ÿ› Mikhail Kuchma
Mikhail Kuchma

๐Ÿ› Mirek Hankus
Mirek Hankus

๐Ÿ› Mitch Spano
Mitch Spano

๐Ÿ› Mladjan Gadzic
Mladjan Gadzic

๐Ÿ› MrAngry52
MrAngry52

๐Ÿ› Muminur Choudhury
Muminur Choudhury

๐Ÿ› - Mykhailo Palahuta
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ› + Mykhailo Palahuta
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ› Nagendra Kumar Singh
Nagendra Kumar Singh

๐Ÿ› Nahuel Barrios
Nahuel Barrios

๐Ÿ› Nakul Sharma
Nakul Sharma

๐Ÿ› Nathan Braun
Nathan Braun

๐Ÿ› Nathan Reynolds
Nathan Reynolds

๐Ÿ› Nathan Reynolds
Nathan Reynolds

๐Ÿ› - Nathanaรซl
Nathanaรซl

๐Ÿ› + Nathanaรซl
Nathanaรซl

๐Ÿ› Naveen
Naveen

๐Ÿ’ป Nazdravi
Nazdravi

๐Ÿ› Neha-Dhonde
Neha-Dhonde

๐Ÿ› Nicholas Doyle
Nicholas Doyle

๐Ÿ› Nick Butcher
Nick Butcher

๐Ÿ› Nico Gallinal
Nico Gallinal

๐Ÿ› - Nicola Dal Maso
Nicola Dal Maso

๐Ÿ› + Nicola Dal Maso
Nicola Dal Maso

๐Ÿ› Nicolas Filotto
Nicolas Filotto

๐Ÿ’ป Nicolas Vervelle
Nicolas Vervelle

๐Ÿ› Nicolas Vuillamy
Nicolas Vuillamy

๐Ÿ“– Nikita Chursin
Nikita Chursin

๐Ÿ› Niklas Baudy
Niklas Baudy

๐Ÿ› Nikolas Havrikov
Nikolas Havrikov

๐Ÿ› - Nilesh Virkar
Nilesh Virkar

๐Ÿ› + Nilesh Virkar
Nilesh Virkar

๐Ÿ› Nimit Patel
Nimit Patel

๐Ÿ› Niranjan Harpale
Niranjan Harpale

๐Ÿ› Nirvik Patel
Nirvik Patel

๐Ÿ’ป Noah Sussman
Noah Sussman

๐Ÿ› Noah0120
Noah0120

๐Ÿ› Noam Tamim
Noam Tamim

๐Ÿ› - Noel Grandin
Noel Grandin

๐Ÿ› + Noel Grandin
Noel Grandin

๐Ÿ› Olaf Haalstra
Olaf Haalstra

๐Ÿ› Oleg Andreych
Oleg Andreych

๐Ÿ’ป ๐Ÿ› Oleg Pavlenko
Oleg Pavlenko

๐Ÿ› Oleksii Dykov
Oleksii Dykov

๐Ÿ’ป ๐Ÿ› Oliver Eikemeier
Oliver Eikemeier

๐Ÿ› Oliver Siegmar
Oliver Siegmar

๐Ÿ’ต - Olivier Parent
Olivier Parent

๐Ÿ’ป ๐Ÿ› + Olivier Parent
Olivier Parent

๐Ÿ’ป ๐Ÿ› Ollie Abbey
Ollie Abbey

๐Ÿ’ป ๐Ÿ› Ondrej Kratochvil
Ondrej Kratochvil

๐Ÿ› OverDrone
OverDrone

๐Ÿ› Ozan Gulle
Ozan Gulle

๐Ÿ’ป ๐Ÿ› PUNEET JAIN
PUNEET JAIN

๐Ÿ› Parbati Bose
Parbati Bose

๐Ÿ› - Paul Berg
Paul Berg

๐Ÿ› + Paul Berg
Paul Berg

๐Ÿ› Paul Guyot
Paul Guyot

๐Ÿ’ป Pavel Bludov
Pavel Bludov

๐Ÿ› Pavel Miฤka
Pavel Miฤka

๐Ÿ› Pedro Nuno Santos
Pedro Nuno Santos

๐Ÿ› Pedro Rijo
Pedro Rijo

๐Ÿ› Pelisse Romain
Pelisse Romain

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› - Per Abich
Per Abich

๐Ÿ’ป + Per Abich
Per Abich

๐Ÿ’ป Pete Davids
Pete Davids

๐Ÿ› Peter Bruin
Peter Bruin

๐Ÿ› Peter Chittum
Peter Chittum

๐Ÿ’ป ๐Ÿ› Peter Cudmore
Peter Cudmore

๐Ÿ› Peter Kasson
Peter Kasson

๐Ÿ› Peter Kofler
Peter Kofler

๐Ÿ› - Peter Paul Bakker
Peter Paul Bakker

๐Ÿ’ป + Peter Paul Bakker
Peter Paul Bakker

๐Ÿ’ป Peter Rader
Peter Rader

๐Ÿ› Pham Hai Trung
Pham Hai Trung

๐Ÿ› Philip Graf
Philip Graf

๐Ÿ’ป ๐Ÿ› Philip Hachey
Philip Hachey

๐Ÿ› Philippe Ozil
Philippe Ozil

๐Ÿ› Phinehas Artemix
Phinehas Artemix

๐Ÿ› - Phokham Nonava
Phokham Nonava

๐Ÿ› + Phokham Nonava
Phokham Nonava

๐Ÿ› Pim van der Loos
Pim van der Loos

๐Ÿ’ป โš ๏ธ Piotr Szymaล„ski
Piotr Szymaล„ski

๐Ÿ› Piotrek ลปygieล‚o
Piotrek ลปygieล‚o

๐Ÿ’ป ๐Ÿ› ๐Ÿ“– Pranay Jaiswal
Pranay Jaiswal

๐Ÿ› Prasad Kamath
Prasad Kamath

๐Ÿ› Prasanna
Prasanna

๐Ÿ› - Presh-AR
Presh-AR

๐Ÿ› + Presh-AR
Presh-AR

๐Ÿ› Puneet1726
Puneet1726

๐Ÿ› RBRi
RBRi

๐Ÿ› Rafael Cortรชs
Rafael Cortรชs

๐Ÿ› RaheemShaik999
RaheemShaik999

๐Ÿ› RajeshR
RajeshR

๐Ÿ’ป ๐Ÿ› Ramachandra Mohan
Ramachandra Mohan

๐Ÿ› - Ramel0921
Ramel0921

๐Ÿ› + Ramel0921
Ramel0921

๐Ÿ› Raquel Pau
Raquel Pau

๐Ÿ› Ravikiran Janardhana
Ravikiran Janardhana

๐Ÿ› Reda Benhemmouche
Reda Benhemmouche

๐Ÿ› Reinhard Schiedermeier
Reinhard Schiedermeier

๐Ÿ› Renato Oliveira
Renato Oliveira

๐Ÿ’ป ๐Ÿ› Rich DiCroce
Rich DiCroce

๐Ÿ› - Richard Corfield
Richard Corfield

๐Ÿ’ป + Richard Corfield
Richard Corfield

๐Ÿ’ป Richard Corfield
Richard Corfield

๐Ÿ› ๐Ÿ’ป Riot R1cket
Riot R1cket

๐Ÿ› Rishabh Jain
Rishabh Jain

๐Ÿ› RishabhDeep Singh
RishabhDeep Singh

๐Ÿ› Rob Baillie
Rob Baillie

๐Ÿ› Robbie Martinus
Robbie Martinus

๐Ÿ’ป ๐Ÿ› - Robert Henry
Robert Henry

๐Ÿ› + Robert Henry
Robert Henry

๐Ÿ› Robert Mihaly
Robert Mihaly

๐Ÿ› Robert Painsi
Robert Painsi

๐Ÿ› Robert Russell
Robert Russell

๐Ÿ› Robert Sรถsemann
Robert Sรถsemann

๐Ÿ’ป ๐Ÿ“– ๐Ÿ“ข ๐Ÿ› Robert Whitebit
Robert Whitebit

๐Ÿ› Robin Richtsfeld
Robin Richtsfeld

๐Ÿ› - Robin Stocker
Robin Stocker

๐Ÿ’ป ๐Ÿ› + Robin Stocker
Robin Stocker

๐Ÿ’ป ๐Ÿ› Robin Wils
Robin Wils

๐Ÿ› RochusOest
RochusOest

๐Ÿ› Rodolfo Noviski
Rodolfo Noviski

๐Ÿ› Rodrigo Casara
Rodrigo Casara

๐Ÿ› Rodrigo Fernandes
Rodrigo Fernandes

๐Ÿ› Roman Salvador
Roman Salvador

๐Ÿ’ป ๐Ÿ› - Ronald Blaschke
Ronald Blaschke

๐Ÿ› + Ronald Blaschke
Ronald Blaschke

๐Ÿ› Rรณbert Papp
Rรณbert Papp

๐Ÿ› Saikat Sengupta
Saikat Sengupta

๐Ÿ› Saksham Handu
Saksham Handu

๐Ÿ› Saladoc
Saladoc

๐Ÿ› Salesforce Bob Lightning
Salesforce Bob Lightning

๐Ÿ› Sam Carlberg
Sam Carlberg

๐Ÿ› - Sascha Riemer
Sascha Riemer

๐Ÿ› + Sascha Riemer
Sascha Riemer

๐Ÿ› Sashko
Sashko

๐Ÿ’ป Satoshi Kubo
Satoshi Kubo

๐Ÿ› Scott Kennedy
Scott Kennedy

๐Ÿ› Scott Wells
Scott Wells

๐Ÿ› ๐Ÿ’ป Scrates1
Scrates1

๐Ÿ› ๐Ÿ’ป Scrsloota
Scrsloota

๐Ÿ’ป - Sebastian Bรถgl
Sebastian Bรถgl

๐Ÿ› + Sebastian Bรถgl
Sebastian Bรถgl

๐Ÿ› Sebastian Davids
Sebastian Davids

๐Ÿ› Sebastian Schuberth
Sebastian Schuberth

๐Ÿ› Sebastian Schwarz
Sebastian Schwarz

๐Ÿ› Seren
Seren

๐Ÿ› ๐Ÿ’ป Sergey Gorbaty
Sergey Gorbaty

๐Ÿ› Sergey Kozlov
Sergey Kozlov

๐Ÿ› - Sergey Yanzin
Sergey Yanzin

๐Ÿ’ป ๐Ÿ› + Sergey Yanzin
Sergey Yanzin

๐Ÿ’ป ๐Ÿ› Seth Wilcox
Seth Wilcox

๐Ÿ’ป Shai Bennathan
Shai Bennathan

๐Ÿ› ๐Ÿ’ป Shubham
Shubham

๐Ÿ’ป ๐Ÿ› Simon Abykov
Simon Abykov

๐Ÿ’ป ๐Ÿ› Simon Xiao
Simon Xiao

๐Ÿ› Srinivasan Venkatachalam
Srinivasan Venkatachalam

๐Ÿ› - Stanislav Gromov
Stanislav Gromov

๐Ÿ› + Stanislav Gromov
Stanislav Gromov

๐Ÿ› Stanislav Myachenkov
Stanislav Myachenkov

๐Ÿ’ป Stefan Birkner
Stefan Birkner

๐Ÿ› Stefan Bohn
Stefan Bohn

๐Ÿ› Stefan Endrullis
Stefan Endrullis

๐Ÿ› Stefan Klรถss-Schuster
Stefan Klรถss-Schuster

๐Ÿ› Stefan Wolf
Stefan Wolf

๐Ÿ› - Stephan H. Wissel
Stephan H. Wissel

๐Ÿ› + Stephan H. Wissel
Stephan H. Wissel

๐Ÿ› Stephen
Stephen

๐Ÿ› Stephen Carter
Stephen Carter

๐Ÿ› Stephen Friedrich
Stephen Friedrich

๐Ÿ› Steve Babula
Steve Babula

๐Ÿ’ป Steven Stearns
Steven Stearns

๐Ÿ› ๐Ÿ’ป Stexxe
Stexxe

๐Ÿ› - Stian Lรฅgstad
Stian Lรฅgstad

๐Ÿ› + Stian Lรฅgstad
Stian Lรฅgstad

๐Ÿ› StuartClayton5
StuartClayton5

๐Ÿ› Supun Arunoda
Supun Arunoda

๐Ÿ› Suren Abrahamyan
Suren Abrahamyan

๐Ÿ› Suvashri
Suvashri

๐Ÿ“– SwatiBGupta1110
SwatiBGupta1110

๐Ÿ› SyedThoufich
SyedThoufich

๐Ÿ› - Szymon Sasin
Szymon Sasin

๐Ÿ› + Szymon Sasin
Szymon Sasin

๐Ÿ› T-chuangxin
T-chuangxin

๐Ÿ› TERAI Atsuhiro
TERAI Atsuhiro

๐Ÿ› TIOBE Software
TIOBE Software

๐Ÿ’ป ๐Ÿ› Tarush Singh
Tarush Singh

๐Ÿ’ป Taylor Smock
Taylor Smock

๐Ÿ› Techeira Damiรกn
Techeira Damiรกn

๐Ÿ’ป ๐Ÿ› - Ted Husted
Ted Husted

๐Ÿ› + Ted Husted
Ted Husted

๐Ÿ› TehBakker
TehBakker

๐Ÿ› The Gitter Badger
The Gitter Badger

๐Ÿ› Theodoor
Theodoor

๐Ÿ› Thiago Henrique Hรผpner
Thiago Henrique Hรผpner

๐Ÿ› Thibault Meyer
Thibault Meyer

๐Ÿ› Thomas Gรผttler
Thomas Gรผttler

๐Ÿ› - Thomas Jones-Low
Thomas Jones-Low

๐Ÿ› + Thomas Jones-Low
Thomas Jones-Low

๐Ÿ› Thomas Smith
Thomas Smith

๐Ÿ’ป ๐Ÿ› ThrawnCA
ThrawnCA

๐Ÿ› Thu Vo
Thu Vo

๐Ÿ› Thunderforge
Thunderforge

๐Ÿ’ป ๐Ÿ› Tim van der Lippe
Tim van der Lippe

๐Ÿ› Tobias Weimer
Tobias Weimer

๐Ÿ’ป ๐Ÿ› - Tom Copeland
Tom Copeland

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– + Tom Copeland
Tom Copeland

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– Tom Daly
Tom Daly

๐Ÿ› Tomas
Tomas

๐Ÿ› Tomer Figenblat
Tomer Figenblat

๐Ÿ› Tomi De Lucca
Tomi De Lucca

๐Ÿ’ป ๐Ÿ› Tony
Tony

๐Ÿ“– Torsten Kleiber
Torsten Kleiber

๐Ÿ› - TrackerSB
TrackerSB

๐Ÿ› + TrackerSB
TrackerSB

๐Ÿ› Tyson Stewart
Tyson Stewart

๐Ÿ› Ullrich Hafner
Ullrich Hafner

๐Ÿ› Utku Cuhadaroglu
Utku Cuhadaroglu

๐Ÿ’ป ๐Ÿ› Valentin Brandl
Valentin Brandl

๐Ÿ› Valeria
Valeria

๐Ÿ› Valery Yatsynovich
Valery Yatsynovich

๐Ÿ“– - Vasily Anisimov
Vasily Anisimov

๐Ÿ› + Vasily Anisimov
Vasily Anisimov

๐Ÿ› Vedant Chokshi
Vedant Chokshi

๐Ÿ› Vibhor Goyal
Vibhor Goyal

๐Ÿ› Vickenty Fesunov
Vickenty Fesunov

๐Ÿ› Victor Noรซl
Victor Noรซl

๐Ÿ› Vincent Galloy
Vincent Galloy

๐Ÿ’ป Vincent HUYNH
Vincent HUYNH

๐Ÿ› - Vincent Maurin
Vincent Maurin

๐Ÿ› + Vincent Maurin
Vincent Maurin

๐Ÿ› Vincent Privat
Vincent Privat

๐Ÿ› Vishhwas
Vishhwas

๐Ÿ› Vishv_Android
Vishv_Android

๐Ÿ› + Vitalii Yevtushenko
Vitalii Yevtushenko

๐Ÿ› Vitaly
Vitaly

๐Ÿ› Vitaly Polonetsky
Vitaly Polonetsky

๐Ÿ› - Vojtech Polivka
Vojtech Polivka

๐Ÿ› - Vsevolod Zholobov
Vsevolod Zholobov

๐Ÿ› + Vojtech Polivka
Vojtech Polivka

๐Ÿ› + Vsevolod Zholobov
Vsevolod Zholobov

๐Ÿ› Vyom Yadav
Vyom Yadav

๐Ÿ’ป Wang Shidong
Wang Shidong

๐Ÿ› Waqas Ahmed
Waqas Ahmed

๐Ÿ› Wayne J. Earl
Wayne J. Earl

๐Ÿ› Wchenghui
Wchenghui

๐Ÿ› - Wener
Wener

๐Ÿ’ป - Will Winder
Will Winder

๐Ÿ› + Wener
Wener

๐Ÿ’ป + Will Winder
Will Winder

๐Ÿ› William Brockhus
William Brockhus

๐Ÿ’ป ๐Ÿ› Wilson Kurniawan
Wilson Kurniawan

๐Ÿ› Wim Deblauwe
Wim Deblauwe

๐Ÿ› Woongsik Choi
Woongsik Choi

๐Ÿ› XenoAmess
XenoAmess

๐Ÿ’ป ๐Ÿ› - Yang
Yang

๐Ÿ’ป - YaroslavTER
YaroslavTER

๐Ÿ› + Yang
Yang

๐Ÿ’ป + YaroslavTER
YaroslavTER

๐Ÿ› Yasar Shaikh
Yasar Shaikh

๐Ÿ’ป Young Chan
Young Chan

๐Ÿ’ป ๐Ÿ› YuJin Kim
YuJin Kim

๐Ÿ› Yuri Dolzhenko
Yuri Dolzhenko

๐Ÿ› Yurii Dubinka
Yurii Dubinka

๐Ÿ› - Zoltan Farkas
Zoltan Farkas

๐Ÿ› - Zustin
Zustin

๐Ÿ› + Zoltan Farkas
Zoltan Farkas

๐Ÿ› + Zustin
Zustin

๐Ÿ› aaronhurst-google
aaronhurst-google

๐Ÿ› ๐Ÿ’ป alexmodis
alexmodis

๐Ÿ› andreoss
andreoss

๐Ÿ› andrey81inmd
andrey81inmd

๐Ÿ’ป ๐Ÿ› anicoara
anicoara

๐Ÿ› - arunprasathav
arunprasathav

๐Ÿ› - asiercamara
asiercamara

๐Ÿ› + arunprasathav
arunprasathav

๐Ÿ› + asiercamara
asiercamara

๐Ÿ› astillich-igniti
astillich-igniti

๐Ÿ’ป avesolovksyy
avesolovksyy

๐Ÿ› avishvat
avishvat

๐Ÿ› avivmu
avivmu

๐Ÿ› axelbarfod1
axelbarfod1

๐Ÿ› - b-3-n
b-3-n

๐Ÿ› - balbhadra9
balbhadra9

๐Ÿ› + b-3-n
b-3-n

๐Ÿ› + balbhadra9
balbhadra9

๐Ÿ› base23de
base23de

๐Ÿ› bergander
bergander

๐Ÿ› ๐Ÿ’ป berkam
berkam

๐Ÿ’ป ๐Ÿ› breizh31
breizh31

๐Ÿ› caesarkim
caesarkim

๐Ÿ› - carolyujing
carolyujing

๐Ÿ› - cbfiddle
cbfiddle

๐Ÿ› + carolyujing
carolyujing

๐Ÿ› + cbfiddle
cbfiddle

๐Ÿ› cesares-basilico
cesares-basilico

๐Ÿ› chrite
chrite

๐Ÿ› ciufudean
ciufudean

๐Ÿ“– cobratbq
cobratbq

๐Ÿ› coladict
coladict

๐Ÿ› - cosmoJFH
cosmoJFH

๐Ÿ› - cristalp
cristalp

๐Ÿ› + cosmoJFH
cosmoJFH

๐Ÿ› + cristalp
cristalp

๐Ÿ› crunsk
crunsk

๐Ÿ› cwholmes
cwholmes

๐Ÿ› cyberjj999
cyberjj999

๐Ÿ› cyw3
cyw3

๐Ÿ› ๐Ÿ“– d1ss0nanz
d1ss0nanz

๐Ÿ› - dague1
dague1

๐Ÿ“– - dalizi007
dalizi007

๐Ÿ’ป + dague1
dague1

๐Ÿ“– + dalizi007
dalizi007

๐Ÿ’ป danbrycefairsailcom
danbrycefairsailcom

๐Ÿ› dariansanity
dariansanity

๐Ÿ› darrenmiliband
darrenmiliband

๐Ÿ› davidburstrom
davidburstrom

๐Ÿ› dbirkman-paloalto
dbirkman-paloalto

๐Ÿ› - deepak-patra
deepak-patra

๐Ÿ› - dependabot[bot]
dependabot[bot]

๐Ÿ’ป ๐Ÿ› + deepak-patra
deepak-patra

๐Ÿ› + dependabot[bot]
dependabot[bot]

๐Ÿ’ป ๐Ÿ› dinesh150
dinesh150

๐Ÿ› diziaq
diziaq

๐Ÿ› dreaminpast123
dreaminpast123

๐Ÿ› duanyanan
duanyanan

๐Ÿ› dutt-sanjay
dutt-sanjay

๐Ÿ› - duursma
duursma

๐Ÿ’ป - dylanleung
dylanleung

๐Ÿ› + duursma
duursma

๐Ÿ’ป + dylanleung
dylanleung

๐Ÿ› dzeigler
dzeigler

๐Ÿ› eant60
eant60

๐Ÿ› ekkirala
ekkirala

๐Ÿ› emersonmoura
emersonmoura

๐Ÿ› emouty
emouty

๐Ÿ’ป ๐Ÿ› - eugenepugach
eugenepugach

๐Ÿ› - fairy
fairy

๐Ÿ› + eugenepugach
eugenepugach

๐Ÿ› + fairy
fairy

๐Ÿ› filiprafalowicz
filiprafalowicz

๐Ÿ’ป flxbl-io
flxbl-io

๐Ÿ’ต foxmason
foxmason

๐Ÿ› frankegabor
frankegabor

๐Ÿ› frankl
frankl

๐Ÿ› - freafrea
freafrea

๐Ÿ› - fsapatin
fsapatin

๐Ÿ› + freafrea
freafrea

๐Ÿ› + fsapatin
fsapatin

๐Ÿ› gearsethenry
gearsethenry

๐Ÿ› gracia19
gracia19

๐Ÿ› gudzpoz
gudzpoz

๐Ÿ› guo fei
guo fei

๐Ÿ› gurmsc5
gurmsc5

๐Ÿ› - gwilymatgearset
gwilymatgearset

๐Ÿ’ป ๐Ÿ› - haigsn
haigsn

๐Ÿ› + gwilymatgearset
gwilymatgearset

๐Ÿ’ป ๐Ÿ› + haigsn
haigsn

๐Ÿ› hemanshu070
hemanshu070

๐Ÿ› henrik242
henrik242

๐Ÿ› hongpuwu
hongpuwu

๐Ÿ› hvbtup
hvbtup

๐Ÿ’ป ๐Ÿ› igniti GmbH
igniti GmbH

๐Ÿ› - ilovezfs
ilovezfs

๐Ÿ› - imax-erik
imax-erik

๐Ÿ› + ilovezfs
ilovezfs

๐Ÿ› + imax-erik
imax-erik

๐Ÿ› itaigilo
itaigilo

๐Ÿ› jakivey32
jakivey32

๐Ÿ› jbennett2091
jbennett2091

๐Ÿ› jcamerin
jcamerin

๐Ÿ› jkeener1
jkeener1

๐Ÿ› - jmetertea
jmetertea

๐Ÿ› - johnra2
johnra2

๐Ÿ’ป + jmetertea
jmetertea

๐Ÿ› + johnra2
johnra2

๐Ÿ’ป johnzhao9
johnzhao9

๐Ÿ› josemanuelrolon
josemanuelrolon

๐Ÿ’ป ๐Ÿ› kabroxiko
kabroxiko

๐Ÿ’ป ๐Ÿ› karthikaiyasamy
karthikaiyasamy

๐Ÿ“– karwer
karwer

๐Ÿ› - kaulonline
kaulonline

๐Ÿ› - kdaemonv
kdaemonv

๐Ÿ› + kaulonline
kaulonline

๐Ÿ› + kdaemonv
kdaemonv

๐Ÿ› kdebski85
kdebski85

๐Ÿ› ๐Ÿ’ป kenji21
kenji21

๐Ÿ’ป ๐Ÿ› kfranic
kfranic

๐Ÿ› khalidkh
khalidkh

๐Ÿ› koalalam
koalalam

๐Ÿ› - krzyk
krzyk

๐Ÿ› - lasselindqvist
lasselindqvist

๐Ÿ› + krzyk
krzyk

๐Ÿ› + lasselindqvist
lasselindqvist

๐Ÿ› lgemeinhardt
lgemeinhardt

๐Ÿ› lihuaib
lihuaib

๐Ÿ› liqingjun123
liqingjun123

๐Ÿ› lonelyma1021
lonelyma1021

๐Ÿ› lpeddy
lpeddy

๐Ÿ› - lujiefsi
lujiefsi

๐Ÿ’ป - lukelukes
lukelukes

๐Ÿ’ป + lujiefsi
lujiefsi

๐Ÿ’ป + lukelukes
lukelukes

๐Ÿ’ป lyriccoder
lyriccoder

๐Ÿ› marcelmore
marcelmore

๐Ÿ› matchbox
matchbox

๐Ÿ› matthiaskraaz
matthiaskraaz

๐Ÿ› meandonlyme
meandonlyme

๐Ÿ› - mikesive
mikesive

๐Ÿ› - milossesic
milossesic

๐Ÿ› + mikesive
mikesive

๐Ÿ› + milossesic
milossesic

๐Ÿ› mluckam
mluckam

๐Ÿ’ป ๐Ÿ› mohan-chinnappan-n
mohan-chinnappan-n

๐Ÿ’ป mriddell95
mriddell95

๐Ÿ› mrlzh
mrlzh

๐Ÿ› msloan
msloan

๐Ÿ› - mucharlaravalika
mucharlaravalika

๐Ÿ› - mvenneman
mvenneman

๐Ÿ› + mucharlaravalika
mucharlaravalika

๐Ÿ› + mvenneman
mvenneman

๐Ÿ› nareshl119
nareshl119

๐Ÿ› nicolas-harraudeau-sonarsource
nicolas-harraudeau-sonarsource

๐Ÿ› noerremark
noerremark

๐Ÿ› novsirion
novsirion

๐Ÿ› nwcm
nwcm

๐Ÿ“– ๐Ÿ› ๐Ÿ’ป - oggboy
oggboy

๐Ÿ› - oinume
oinume

๐Ÿ› + oggboy
oggboy

๐Ÿ› + oinume
oinume

๐Ÿ› orimarko
orimarko

๐Ÿ’ป ๐Ÿ› pablogomez2197
pablogomez2197

๐Ÿ› pacvz
pacvz

๐Ÿ’ป pallavi agarwal
pallavi agarwal

๐Ÿ› parksungrin
parksungrin

๐Ÿ› - patpatpat123
patpatpat123

๐Ÿ› - patriksevallius
patriksevallius

๐Ÿ› + patpatpat123
patpatpat123

๐Ÿ› + patriksevallius
patriksevallius

๐Ÿ› pbrajesh1
pbrajesh1

๐Ÿ› phoenix384
phoenix384

๐Ÿ› piotrszymanski-sc
piotrszymanski-sc

๐Ÿ’ป plan3d
plan3d

๐Ÿ› poojasix
poojasix

๐Ÿ› - prabhushrikant
prabhushrikant

๐Ÿ› - pujitha8783
pujitha8783

๐Ÿ› + prabhushrikant
prabhushrikant

๐Ÿ› + pujitha8783
pujitha8783

๐Ÿ› r-r-a-j
r-r-a-j

๐Ÿ› raghujayjunk
raghujayjunk

๐Ÿ› rajeshveera
rajeshveera

๐Ÿ› rajeswarreddy88
rajeswarreddy88

๐Ÿ› recdevs
recdevs

๐Ÿ› - reudismam
reudismam

๐Ÿ’ป ๐Ÿ› - rijkt
rijkt

๐Ÿ› + reudismam
reudismam

๐Ÿ’ป ๐Ÿ› + rijkt
rijkt

๐Ÿ› rillig-tk
rillig-tk

๐Ÿ› rmohan20
rmohan20

๐Ÿ’ป ๐Ÿ› rnveach
rnveach

๐Ÿ› rxmicro
rxmicro

๐Ÿ› ryan-gustafson
ryan-gustafson

๐Ÿ’ป ๐Ÿ› - sabi0
sabi0

๐Ÿ› - scais
scais

๐Ÿ› + sabi0
sabi0

๐Ÿ› + scais
scais

๐Ÿ› schosin
schosin

๐Ÿ› screamingfrog
screamingfrog

๐Ÿ’ต sebbASF
sebbASF

๐Ÿ› sergeygorbaty
sergeygorbaty

๐Ÿ’ป shilko2013
shilko2013

๐Ÿ› - shiomiyan
shiomiyan

๐Ÿ“– - simeonKondr
simeonKondr

๐Ÿ› + shiomiyan
shiomiyan

๐Ÿ“– + simeonKondr
simeonKondr

๐Ÿ› snajberk
snajberk

๐Ÿ› sniperrifle2004
sniperrifle2004

๐Ÿ› snuyanzin
snuyanzin

๐Ÿ› ๐Ÿ’ป soloturn
soloturn

๐Ÿ› soyodream
soyodream

๐Ÿ› - sratz
sratz

๐Ÿ› - stonio
stonio

๐Ÿ› + sratz
sratz

๐Ÿ› + stonio
stonio

๐Ÿ› sturton
sturton

๐Ÿ’ป ๐Ÿ› sudharmohan
sudharmohan

๐Ÿ› suruchidawar
suruchidawar

๐Ÿ› svenfinitiv
svenfinitiv

๐Ÿ› szymanp23
szymanp23

๐Ÿ› ๐Ÿ’ป - tashiscool
tashiscool

๐Ÿ› - test-git-hook
test-git-hook

๐Ÿ› + tashiscool
tashiscool

๐Ÿ› + test-git-hook
test-git-hook

๐Ÿ› testation21
testation21

๐Ÿ’ป ๐Ÿ› thanosa
thanosa

๐Ÿ› tiandiyixian
tiandiyixian

๐Ÿ› tobwoerk
tobwoerk

๐Ÿ› tprouvot
tprouvot

๐Ÿ› ๐Ÿ’ป - trentchilders
trentchilders

๐Ÿ› - triandicAnt
triandicAnt

๐Ÿ› + trentchilders
trentchilders

๐Ÿ› + triandicAnt
triandicAnt

๐Ÿ› trishul14
trishul14

๐Ÿ› tsui
tsui

๐Ÿ› wangzitom12306
wangzitom12306

๐Ÿ› winhkey
winhkey

๐Ÿ› witherspore
witherspore

๐Ÿ› - wjljack
wjljack

๐Ÿ› - wuchiuwong
wuchiuwong

๐Ÿ› + wjljack
wjljack

๐Ÿ› + wuchiuwong
wuchiuwong

๐Ÿ› xingsong
xingsong

๐Ÿ› xioayuge
xioayuge

๐Ÿ› xnYi9wRezm
xnYi9wRezm

๐Ÿ’ป ๐Ÿ› xuanuy
xuanuy

๐Ÿ› xyf0921
xyf0921

๐Ÿ› - yalechen-cyw3
yalechen-cyw3

๐Ÿ› - yasuharu-sato
yasuharu-sato

๐Ÿ› + yalechen-cyw3
yalechen-cyw3

๐Ÿ› + yasuharu-sato
yasuharu-sato

๐Ÿ› zenglian
zenglian

๐Ÿ› zgrzyt93
zgrzyt93

๐Ÿ’ป ๐Ÿ› zh3ng
zh3ng

๐Ÿ› zt_soft
zt_soft

๐Ÿ› ztt79
ztt79

๐Ÿ› - zzzzfeng
zzzzfeng

๐Ÿ› - รrpรกd Magosรกnyi
รrpรกd Magosรกnyi

๐Ÿ› + zzzzfeng
zzzzfeng

๐Ÿ› + รrpรกd Magosรกnyi
รrpรกd Magosรกnyi

๐Ÿ› ไปป่ดตๆฐ
ไปป่ดตๆฐ

๐Ÿ› ่Œ…ๅปถๅฎ‰
่Œ…ๅปถๅฎ‰

๐Ÿ’ป From 3fdbf7d6cbaaa78f2edc2f48922beeb5c2e4a9ce Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 17:48:08 +0100 Subject: [PATCH 22/37] [java] InsufficientStringBufferDeclaration: Fix CCE for Character Fixes #5314 --- docs/pages/release_notes.md | 2 ++ ...sufficientStringBufferDeclarationRule.java | 8 +++++++- .../InsufficientStringBufferDeclaration.xml | 19 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5fa3ac04b6..3893f1a820 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -20,6 +20,8 @@ This is a {{ site.pmd.release_type }} release. * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas +* java-performance + * [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters ### ๐Ÿšจ API Changes diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java index a6fabf91a2..5acd063c15 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/InsufficientStringBufferDeclarationRule.java @@ -240,6 +240,12 @@ public class InsufficientStringBufferDeclarationRule extends AbstractJavaRulecha private int calculateExpression(ASTExpression expression) { Object value = expression.getConstValue(); - return value == null ? State.UNKNOWN_CAPACITY : (Integer) value; + if (value == null) { + return State.UNKNOWN_CAPACITY; + } + if (value instanceof Character) { + return (Character) value; + } + return (Integer) value; } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InsufficientStringBufferDeclaration.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InsufficientStringBufferDeclaration.xml index ec267fcfcc..bd5d364eb1 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InsufficientStringBufferDeclaration.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InsufficientStringBufferDeclaration.xml @@ -1419,4 +1419,23 @@ public class LiteralExpression { } ]]> + + + #5314 [java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters + 0 + + From 01b8ca765bc16a57bac3bb8a14f2c13839ae2dd7 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 17:48:26 +0100 Subject: [PATCH 23/37] Add @chenguangqi as a contributor --- .all-contributorsrc | 9 ++ docs/pages/pmd/projectdocs/credits.md | 172 +++++++++++++------------- 2 files changed, 96 insertions(+), 85 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 95ebc05d6e..1d4a930f38 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7865,6 +7865,15 @@ "contributions": [ "code" ] + }, + { + "login": "chenguangqi", + "name": "ๅคฉ็ƒญๅƒ่ฅฟ็“œ", + "avatar_url": "https://avatars.githubusercontent.com/u/6231010?v=4", + "profile": "http://chenguangqi.github.io/", + "contributions": [ + "bug" + ] } ], "contributorsPerLine": 7, diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 9497ea7378..7b6a55aec6 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -350,770 +350,772 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d JJengility
JJengility

๐Ÿ› Jake Hemmerle
Jake Hemmerle

๐Ÿ› + Jakub Dupak
Jakub Dupak

๐Ÿ’ป James Harrison
James Harrison

๐Ÿ› ๐Ÿ’ป Jamie Bisotti
Jamie Bisotti

๐Ÿ› Jan
Jan

๐Ÿ› Jan Aertgeerts
Jan Aertgeerts

๐Ÿ’ป ๐Ÿ› - Jan Brรผmmer
Jan Brรผmmer

๐Ÿ› + Jan Brรผmmer
Jan Brรผmmer

๐Ÿ› Jan Tล™รญska
Jan Tล™รญska

๐Ÿ› Jan-Lukas Else
Jan-Lukas Else

๐Ÿ› Jason Qiu
Jason Qiu

๐Ÿ’ป ๐Ÿ“– Jason Williams
Jason Williams

๐Ÿ› Javier Spagnoletti
Javier Spagnoletti

๐Ÿ› Jean-Paul Mayer
Jean-Paul Mayer

๐Ÿ› - Jean-Simon Larochelle
Jean-Simon Larochelle

๐Ÿ› + Jean-Simon Larochelle
Jean-Simon Larochelle

๐Ÿ› Jeff Bartolotta
Jeff Bartolotta

๐Ÿ’ป ๐Ÿ› Jeff Hube
Jeff Hube

๐Ÿ’ป ๐Ÿ› Jeff Jensen
Jeff Jensen

๐Ÿ› Jeff May
Jeff May

๐Ÿ› Jens Gerdes
Jens Gerdes

๐Ÿ› Jeroen Borgers
Jeroen Borgers

๐Ÿ› ๐Ÿ’ป ๐Ÿ“ข - Jeroen Meijer
Jeroen Meijer

๐Ÿ› + Jeroen Meijer
Jeroen Meijer

๐Ÿ› Jeroen van Wilgenburg
Jeroen van Wilgenburg

๐Ÿ“– Jerome Russ
Jerome Russ

๐Ÿ› JerritEic
JerritEic

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› Jiri Pejchal
Jiri Pejchal

๐Ÿ› Jithin Sunny
Jithin Sunny

๐Ÿ› Jiล™รญ ล korpil
Jiล™รญ ล korpil

๐Ÿ› - Joao Machado
Joao Machado

๐Ÿ› + Joao Machado
Joao Machado

๐Ÿ› Jochen Krauss
Jochen Krauss

๐Ÿ› Johan Hammar
Johan Hammar

๐Ÿ› John Karp
John Karp

๐Ÿ› John Zhang
John Zhang

๐Ÿ› John-Teng
John-Teng

๐Ÿ’ป ๐Ÿ› Jon Moroney
Jon Moroney

๐Ÿ’ป ๐Ÿ› - Jonas Geiregat
Jonas Geiregat

๐Ÿ› + Jonas Geiregat
Jonas Geiregat

๐Ÿ› Jonas KeรŸler
Jonas KeรŸler

๐Ÿ› Jonathan Wiesel
Jonathan Wiesel

๐Ÿ’ป ๐Ÿ› Jordan
Jordan

๐Ÿ› Jordi Llach
Jordi Llach

๐Ÿ› Jorge Solรณrzano
Jorge Solรณrzano

๐Ÿ› JorneVL
JorneVL

๐Ÿ› - Jose Palafox
Jose Palafox

๐Ÿ› + Jose Palafox
Jose Palafox

๐Ÿ› Jose Stovall
Jose Stovall

๐Ÿ› Joseph
Joseph

๐Ÿ’ป Joseph Heenan
Joseph Heenan

๐Ÿ› Josh Feingold
Josh Feingold

๐Ÿ’ป ๐Ÿ› Josh Holthaus
Josh Holthaus

๐Ÿ› Joshua S Arquilevich
Joshua S Arquilevich

๐Ÿ› - Joรฃo Dinis Ferreira
Joรฃo Dinis Ferreira

๐Ÿ“– + Joรฃo Dinis Ferreira
Joรฃo Dinis Ferreira

๐Ÿ“– Joรฃo Ferreira
Joรฃo Ferreira

๐Ÿ’ป ๐Ÿ› Joรฃo Pedro Schmitt
Joรฃo Pedro Schmitt

๐Ÿ› Juan Martรญn Sotuyo Dodero
Juan Martรญn Sotuyo Dodero

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› ๐Ÿšง Juan Pablo Civile
Juan Pablo Civile

๐Ÿ› Julian Voronetsky
Julian Voronetsky

๐Ÿ› Julien
Julien

๐Ÿ› - Julius
Julius

๐Ÿ› + Julius
Julius

๐Ÿ› JustPRV
JustPRV

๐Ÿ› Justin Stroud
Justin Stroud

๐Ÿ’ป Jรถrn Huxhorn
Jรถrn Huxhorn

๐Ÿ› KThompso
KThompso

๐Ÿ› Kai Amundsen
Kai Amundsen

๐Ÿ› Karel Vervaeke
Karel Vervaeke

๐Ÿ› - Karl-Andero Mere
Karl-Andero Mere

๐Ÿ› + Karl-Andero Mere
Karl-Andero Mere

๐Ÿ› Karl-Philipp Richter
Karl-Philipp Richter

๐Ÿ› Karsten Silz
Karsten Silz

๐Ÿ› Kazuma Watanabe
Kazuma Watanabe

๐Ÿ› Kev
Kev

๐Ÿ› Keve Mรผller
Keve Mรผller

๐Ÿ› Kevin Guerra
Kevin Guerra

๐Ÿ’ป - Kevin Jones
Kevin Jones

๐Ÿ› ๐Ÿ’ป + Kevin Jones
Kevin Jones

๐Ÿ› ๐Ÿ’ป Kevin Poorman
Kevin Poorman

๐Ÿ› Kevin Wayne
Kevin Wayne

๐Ÿ› Kieran Black
Kieran Black

๐Ÿ› Kirill Zubov
Kirill Zubov

๐Ÿ› Kirk Clemens
Kirk Clemens

๐Ÿ’ป ๐Ÿ› Klaus Hartl
Klaus Hartl

๐Ÿ› - Koen Van Looveren
Koen Van Looveren

๐Ÿ› + Koen Van Looveren
Koen Van Looveren

๐Ÿ› Kris Scheibe
Kris Scheibe

๐Ÿ’ป ๐Ÿ› Krystian Dabrowski
Krystian Dabrowski

๐Ÿ› ๐Ÿ’ป Kunal Thanki
Kunal Thanki

๐Ÿ› LaLucid
LaLucid

๐Ÿ’ป Larry Diamond
Larry Diamond

๐Ÿ’ป ๐Ÿ› Lars Knickrehm
Lars Knickrehm

๐Ÿ› - Laurent Bovet
Laurent Bovet

๐Ÿ› ๐Ÿ’ป + Laurent Bovet
Laurent Bovet

๐Ÿ› ๐Ÿ’ป Leo Gutierrez
Leo Gutierrez

๐Ÿ› LiGaOg
LiGaOg

๐Ÿ’ป Liam Sharp
Liam Sharp

๐Ÿ› Lintsi
Lintsi

๐Ÿ› Linus Fernandes
Linus Fernandes

๐Ÿ› Lixon Lookose
Lixon Lookose

๐Ÿ› - Logesh
Logesh

๐Ÿ› + Logesh
Logesh

๐Ÿ› Lorenzo Gabriele
Lorenzo Gabriele

๐Ÿ› Loรฏc Ledoyen
Loรฏc Ledoyen

๐Ÿ› Lucas
Lucas

๐Ÿ› Lucas Silva
Lucas Silva

๐Ÿ› Lucas Soncini
Lucas Soncini

๐Ÿ’ป ๐Ÿ› Luis Alcantar
Luis Alcantar

๐Ÿ’ป - Lukas Grรคf
Lukas Grรคf

๐Ÿ’ป + Lukas Grรคf
Lukas Grรคf

๐Ÿ’ป Lukasz Slonina
Lukasz Slonina

๐Ÿ› Lukebray
Lukebray

๐Ÿ› Lynn
Lynn

๐Ÿ’ป ๐Ÿ› Lyor Goldstein
Lyor Goldstein

๐Ÿ› MCMicS
MCMicS

๐Ÿ› Macarse
Macarse

๐Ÿ› - Machine account for PMD
Machine account for PMD

๐Ÿ’ป + Machine account for PMD
Machine account for PMD

๐Ÿ’ป Maciek Siemczyk
Maciek Siemczyk

๐Ÿ› Maikel Steneker
Maikel Steneker

๐Ÿ’ป ๐Ÿ› Maksim Moiseikin
Maksim Moiseikin

๐Ÿ› Manfred Koch
Manfred Koch

๐Ÿ› Manuel Moya Ferrer
Manuel Moya Ferrer

๐Ÿ’ป ๐Ÿ› Manuel Ryan
Manuel Ryan

๐Ÿ› - Marat Vyshegorodtsev
Marat Vyshegorodtsev

๐Ÿ› + Marat Vyshegorodtsev
Marat Vyshegorodtsev

๐Ÿ› Marcel Hรคrle
Marcel Hรคrle

๐Ÿ› Marcello Fialho
Marcello Fialho

๐Ÿ› Marcin Dฤ…browski
Marcin Dฤ…browski

๐Ÿ’ป Marcin Rataj
Marcin Rataj

๐Ÿ› Marcono1234
Marcono1234

๐Ÿ› Mark Adamcin
Mark Adamcin

๐Ÿ› - Mark Hall
Mark Hall

๐Ÿ’ป ๐Ÿ› + Mark Hall
Mark Hall

๐Ÿ’ป ๐Ÿ› Mark Kolich
Mark Kolich

๐Ÿ› Mark Pritchard
Mark Pritchard

๐Ÿ› Markus Rathgeb
Markus Rathgeb

๐Ÿ› Marquis Wang
Marquis Wang

๐Ÿ› MartGit
MartGit

๐Ÿ› Martin Feldsztejn
Martin Feldsztejn

๐Ÿ› - Martin Lehmann
Martin Lehmann

๐Ÿ› + Martin Lehmann
Martin Lehmann

๐Ÿ› Martin Spamer
Martin Spamer

๐Ÿ› Martin Tarjรกnyi
Martin Tarjรกnyi

๐Ÿ› MatFl
MatFl

๐Ÿ› Mateusz Stefanski
Mateusz Stefanski

๐Ÿ› Mathieu Gouin
Mathieu Gouin

๐Ÿ› MatiasComercio
MatiasComercio

๐Ÿ’ป ๐Ÿ› - Matt Benson
Matt Benson

๐Ÿ› + Matt Benson
Matt Benson

๐Ÿ› Matt De Poorter
Matt De Poorter

๐Ÿ› Matt Hargett
Matt Hargett

๐Ÿ’ป ๐Ÿ’ต Matt Harrah
Matt Harrah

๐Ÿ› Matt Nelson
Matt Nelson

๐Ÿ› Matthew Amos
Matthew Amos

๐Ÿ› Matthew Duggan
Matthew Duggan

๐Ÿ› - Matthew Hall
Matthew Hall

๐Ÿ› + Matthew Hall
Matthew Hall

๐Ÿ› Matthew Rossner
Matthew Rossner

๐Ÿ› Matรญas Fraga
Matรญas Fraga

๐Ÿ’ป ๐Ÿ› Maxime Robert
Maxime Robert

๐Ÿ’ป ๐Ÿ› MetaBF
MetaBF

๐Ÿ› Metin Dagcilar
Metin Dagcilar

๐Ÿ› Michael
Michael

๐Ÿ› - Michael Bell
Michael Bell

๐Ÿ› + Michael Bell
Michael Bell

๐Ÿ› Michael Bernstein
Michael Bernstein

๐Ÿ› Michael Clay
Michael Clay

๐Ÿ› Michael Dombrowski
Michael Dombrowski

๐Ÿ› Michael Hausegger
Michael Hausegger

๐Ÿ› Michael Hoefer
Michael Hoefer

๐Ÿ› Michael Kolesnikov
Michael Kolesnikov

๐Ÿ› - Michael Mรถbius
Michael Mรถbius

๐Ÿ› + Michael Mรถbius
Michael Mรถbius

๐Ÿ› Michael N. Lipp
Michael N. Lipp

๐Ÿ› Michael Pellegrini
Michael Pellegrini

๐Ÿ› Michal Kordas
Michal Kordas

๐Ÿ› Michaล‚ Borek
Michaล‚ Borek

๐Ÿ› Michaล‚ Kuliล„ski
Michaล‚ Kuliล„ski

๐Ÿ› Miguel Nรบรฑez Dรญaz-Montes
Miguel Nรบรฑez Dรญaz-Montes

๐Ÿ› - Mihai Ionut
Mihai Ionut

๐Ÿ› + Mihai Ionut
Mihai Ionut

๐Ÿ› Mikhail Kuchma
Mikhail Kuchma

๐Ÿ› Mirek Hankus
Mirek Hankus

๐Ÿ› Mitch Spano
Mitch Spano

๐Ÿ› Mladjan Gadzic
Mladjan Gadzic

๐Ÿ› MrAngry52
MrAngry52

๐Ÿ› Muminur Choudhury
Muminur Choudhury

๐Ÿ› - Mykhailo Palahuta
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ› + Mykhailo Palahuta
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ› Nagendra Kumar Singh
Nagendra Kumar Singh

๐Ÿ› Nahuel Barrios
Nahuel Barrios

๐Ÿ› Nakul Sharma
Nakul Sharma

๐Ÿ› Nathan Braun
Nathan Braun

๐Ÿ› Nathan Reynolds
Nathan Reynolds

๐Ÿ› Nathan Reynolds
Nathan Reynolds

๐Ÿ› - Nathanaรซl
Nathanaรซl

๐Ÿ› + Nathanaรซl
Nathanaรซl

๐Ÿ› Naveen
Naveen

๐Ÿ’ป Nazdravi
Nazdravi

๐Ÿ› Neha-Dhonde
Neha-Dhonde

๐Ÿ› Nicholas Doyle
Nicholas Doyle

๐Ÿ› Nick Butcher
Nick Butcher

๐Ÿ› Nico Gallinal
Nico Gallinal

๐Ÿ› - Nicola Dal Maso
Nicola Dal Maso

๐Ÿ› + Nicola Dal Maso
Nicola Dal Maso

๐Ÿ› Nicolas Filotto
Nicolas Filotto

๐Ÿ’ป Nicolas Vervelle
Nicolas Vervelle

๐Ÿ› Nicolas Vuillamy
Nicolas Vuillamy

๐Ÿ“– Nikita Chursin
Nikita Chursin

๐Ÿ› Niklas Baudy
Niklas Baudy

๐Ÿ› Nikolas Havrikov
Nikolas Havrikov

๐Ÿ› - Nilesh Virkar
Nilesh Virkar

๐Ÿ› + Nilesh Virkar
Nilesh Virkar

๐Ÿ› Nimit Patel
Nimit Patel

๐Ÿ› Niranjan Harpale
Niranjan Harpale

๐Ÿ› Nirvik Patel
Nirvik Patel

๐Ÿ’ป Noah Sussman
Noah Sussman

๐Ÿ› Noah0120
Noah0120

๐Ÿ› Noam Tamim
Noam Tamim

๐Ÿ› - Noel Grandin
Noel Grandin

๐Ÿ› + Noel Grandin
Noel Grandin

๐Ÿ› Olaf Haalstra
Olaf Haalstra

๐Ÿ› Oleg Andreych
Oleg Andreych

๐Ÿ’ป ๐Ÿ› Oleg Pavlenko
Oleg Pavlenko

๐Ÿ› Oleksii Dykov
Oleksii Dykov

๐Ÿ’ป ๐Ÿ› Oliver Eikemeier
Oliver Eikemeier

๐Ÿ› Oliver Siegmar
Oliver Siegmar

๐Ÿ’ต - Olivier Parent
Olivier Parent

๐Ÿ’ป ๐Ÿ› + Olivier Parent
Olivier Parent

๐Ÿ’ป ๐Ÿ› Ollie Abbey
Ollie Abbey

๐Ÿ’ป ๐Ÿ› Ondrej Kratochvil
Ondrej Kratochvil

๐Ÿ› OverDrone
OverDrone

๐Ÿ› Ozan Gulle
Ozan Gulle

๐Ÿ’ป ๐Ÿ› PUNEET JAIN
PUNEET JAIN

๐Ÿ› Parbati Bose
Parbati Bose

๐Ÿ› - Paul Berg
Paul Berg

๐Ÿ› + Paul Berg
Paul Berg

๐Ÿ› Paul Guyot
Paul Guyot

๐Ÿ’ป Pavel Bludov
Pavel Bludov

๐Ÿ› Pavel Miฤka
Pavel Miฤka

๐Ÿ› Pedro Nuno Santos
Pedro Nuno Santos

๐Ÿ› Pedro Rijo
Pedro Rijo

๐Ÿ› Pelisse Romain
Pelisse Romain

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› - Per Abich
Per Abich

๐Ÿ’ป + Per Abich
Per Abich

๐Ÿ’ป Pete Davids
Pete Davids

๐Ÿ› Peter Bruin
Peter Bruin

๐Ÿ› Peter Chittum
Peter Chittum

๐Ÿ’ป ๐Ÿ› Peter Cudmore
Peter Cudmore

๐Ÿ› Peter Kasson
Peter Kasson

๐Ÿ› Peter Kofler
Peter Kofler

๐Ÿ› - Peter Paul Bakker
Peter Paul Bakker

๐Ÿ’ป + Peter Paul Bakker
Peter Paul Bakker

๐Ÿ’ป Peter Rader
Peter Rader

๐Ÿ› Pham Hai Trung
Pham Hai Trung

๐Ÿ› Philip Graf
Philip Graf

๐Ÿ’ป ๐Ÿ› Philip Hachey
Philip Hachey

๐Ÿ› Philippe Ozil
Philippe Ozil

๐Ÿ› Phinehas Artemix
Phinehas Artemix

๐Ÿ› - Phokham Nonava
Phokham Nonava

๐Ÿ› + Phokham Nonava
Phokham Nonava

๐Ÿ› Pim van der Loos
Pim van der Loos

๐Ÿ’ป โš ๏ธ Piotr Szymaล„ski
Piotr Szymaล„ski

๐Ÿ› Piotrek ลปygieล‚o
Piotrek ลปygieล‚o

๐Ÿ’ป ๐Ÿ› ๐Ÿ“– Pranay Jaiswal
Pranay Jaiswal

๐Ÿ› Prasad Kamath
Prasad Kamath

๐Ÿ› Prasanna
Prasanna

๐Ÿ› - Presh-AR
Presh-AR

๐Ÿ› + Presh-AR
Presh-AR

๐Ÿ› Puneet1726
Puneet1726

๐Ÿ› RBRi
RBRi

๐Ÿ› Rafael Cortรชs
Rafael Cortรชs

๐Ÿ› RaheemShaik999
RaheemShaik999

๐Ÿ› RajeshR
RajeshR

๐Ÿ’ป ๐Ÿ› Ramachandra Mohan
Ramachandra Mohan

๐Ÿ› - Ramel0921
Ramel0921

๐Ÿ› + Ramel0921
Ramel0921

๐Ÿ› Raquel Pau
Raquel Pau

๐Ÿ› Ravikiran Janardhana
Ravikiran Janardhana

๐Ÿ› Reda Benhemmouche
Reda Benhemmouche

๐Ÿ› Reinhard Schiedermeier
Reinhard Schiedermeier

๐Ÿ› Renato Oliveira
Renato Oliveira

๐Ÿ’ป ๐Ÿ› Rich DiCroce
Rich DiCroce

๐Ÿ› - Richard Corfield
Richard Corfield

๐Ÿ’ป + Richard Corfield
Richard Corfield

๐Ÿ’ป Richard Corfield
Richard Corfield

๐Ÿ› ๐Ÿ’ป Riot R1cket
Riot R1cket

๐Ÿ› Rishabh Jain
Rishabh Jain

๐Ÿ› RishabhDeep Singh
RishabhDeep Singh

๐Ÿ› Rob Baillie
Rob Baillie

๐Ÿ› Robbie Martinus
Robbie Martinus

๐Ÿ’ป ๐Ÿ› - Robert Henry
Robert Henry

๐Ÿ› + Robert Henry
Robert Henry

๐Ÿ› Robert Mihaly
Robert Mihaly

๐Ÿ› Robert Painsi
Robert Painsi

๐Ÿ› Robert Russell
Robert Russell

๐Ÿ› Robert Sรถsemann
Robert Sรถsemann

๐Ÿ’ป ๐Ÿ“– ๐Ÿ“ข ๐Ÿ› Robert Whitebit
Robert Whitebit

๐Ÿ› Robin Richtsfeld
Robin Richtsfeld

๐Ÿ› - Robin Stocker
Robin Stocker

๐Ÿ’ป ๐Ÿ› + Robin Stocker
Robin Stocker

๐Ÿ’ป ๐Ÿ› Robin Wils
Robin Wils

๐Ÿ› RochusOest
RochusOest

๐Ÿ› Rodolfo Noviski
Rodolfo Noviski

๐Ÿ› Rodrigo Casara
Rodrigo Casara

๐Ÿ› Rodrigo Fernandes
Rodrigo Fernandes

๐Ÿ› Roman Salvador
Roman Salvador

๐Ÿ’ป ๐Ÿ› - Ronald Blaschke
Ronald Blaschke

๐Ÿ› + Ronald Blaschke
Ronald Blaschke

๐Ÿ› Rรณbert Papp
Rรณbert Papp

๐Ÿ› Saikat Sengupta
Saikat Sengupta

๐Ÿ› Saksham Handu
Saksham Handu

๐Ÿ› Saladoc
Saladoc

๐Ÿ› Salesforce Bob Lightning
Salesforce Bob Lightning

๐Ÿ› Sam Carlberg
Sam Carlberg

๐Ÿ› - Sascha Riemer
Sascha Riemer

๐Ÿ› + Sascha Riemer
Sascha Riemer

๐Ÿ› Sashko
Sashko

๐Ÿ’ป Satoshi Kubo
Satoshi Kubo

๐Ÿ› Scott Kennedy
Scott Kennedy

๐Ÿ› Scott Wells
Scott Wells

๐Ÿ› ๐Ÿ’ป Scrates1
Scrates1

๐Ÿ› ๐Ÿ’ป Scrsloota
Scrsloota

๐Ÿ’ป - Sebastian Bรถgl
Sebastian Bรถgl

๐Ÿ› + Sebastian Bรถgl
Sebastian Bรถgl

๐Ÿ› Sebastian Davids
Sebastian Davids

๐Ÿ› Sebastian Schuberth
Sebastian Schuberth

๐Ÿ› Sebastian Schwarz
Sebastian Schwarz

๐Ÿ› Seren
Seren

๐Ÿ› ๐Ÿ’ป Sergey Gorbaty
Sergey Gorbaty

๐Ÿ› Sergey Kozlov
Sergey Kozlov

๐Ÿ› - Sergey Yanzin
Sergey Yanzin

๐Ÿ’ป ๐Ÿ› + Sergey Yanzin
Sergey Yanzin

๐Ÿ’ป ๐Ÿ› Seth Wilcox
Seth Wilcox

๐Ÿ’ป Shai Bennathan
Shai Bennathan

๐Ÿ› ๐Ÿ’ป Shubham
Shubham

๐Ÿ’ป ๐Ÿ› Simon Abykov
Simon Abykov

๐Ÿ’ป ๐Ÿ› Simon Xiao
Simon Xiao

๐Ÿ› Srinivasan Venkatachalam
Srinivasan Venkatachalam

๐Ÿ› - Stanislav Gromov
Stanislav Gromov

๐Ÿ› + Stanislav Gromov
Stanislav Gromov

๐Ÿ› Stanislav Myachenkov
Stanislav Myachenkov

๐Ÿ’ป Stefan Birkner
Stefan Birkner

๐Ÿ› Stefan Bohn
Stefan Bohn

๐Ÿ› Stefan Endrullis
Stefan Endrullis

๐Ÿ› Stefan Klรถss-Schuster
Stefan Klรถss-Schuster

๐Ÿ› Stefan Wolf
Stefan Wolf

๐Ÿ› - Stephan H. Wissel
Stephan H. Wissel

๐Ÿ› + Stephan H. Wissel
Stephan H. Wissel

๐Ÿ› Stephen
Stephen

๐Ÿ› Stephen Carter
Stephen Carter

๐Ÿ› Stephen Friedrich
Stephen Friedrich

๐Ÿ› Steve Babula
Steve Babula

๐Ÿ’ป Steven Stearns
Steven Stearns

๐Ÿ› ๐Ÿ’ป Stexxe
Stexxe

๐Ÿ› - Stian Lรฅgstad
Stian Lรฅgstad

๐Ÿ› + Stian Lรฅgstad
Stian Lรฅgstad

๐Ÿ› StuartClayton5
StuartClayton5

๐Ÿ› Supun Arunoda
Supun Arunoda

๐Ÿ› Suren Abrahamyan
Suren Abrahamyan

๐Ÿ› Suvashri
Suvashri

๐Ÿ“– SwatiBGupta1110
SwatiBGupta1110

๐Ÿ› SyedThoufich
SyedThoufich

๐Ÿ› - Szymon Sasin
Szymon Sasin

๐Ÿ› + Szymon Sasin
Szymon Sasin

๐Ÿ› T-chuangxin
T-chuangxin

๐Ÿ› TERAI Atsuhiro
TERAI Atsuhiro

๐Ÿ› TIOBE Software
TIOBE Software

๐Ÿ’ป ๐Ÿ› Tarush Singh
Tarush Singh

๐Ÿ’ป Taylor Smock
Taylor Smock

๐Ÿ› Techeira Damiรกn
Techeira Damiรกn

๐Ÿ’ป ๐Ÿ› - Ted Husted
Ted Husted

๐Ÿ› + Ted Husted
Ted Husted

๐Ÿ› TehBakker
TehBakker

๐Ÿ› The Gitter Badger
The Gitter Badger

๐Ÿ› Theodoor
Theodoor

๐Ÿ› Thiago Henrique Hรผpner
Thiago Henrique Hรผpner

๐Ÿ› Thibault Meyer
Thibault Meyer

๐Ÿ› Thomas Gรผttler
Thomas Gรผttler

๐Ÿ› - Thomas Jones-Low
Thomas Jones-Low

๐Ÿ› + Thomas Jones-Low
Thomas Jones-Low

๐Ÿ› Thomas Smith
Thomas Smith

๐Ÿ’ป ๐Ÿ› ThrawnCA
ThrawnCA

๐Ÿ› Thu Vo
Thu Vo

๐Ÿ› Thunderforge
Thunderforge

๐Ÿ’ป ๐Ÿ› Tim van der Lippe
Tim van der Lippe

๐Ÿ› Tobias Weimer
Tobias Weimer

๐Ÿ’ป ๐Ÿ› - Tom Copeland
Tom Copeland

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– + Tom Copeland
Tom Copeland

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– Tom Daly
Tom Daly

๐Ÿ› Tomas
Tomas

๐Ÿ› Tomer Figenblat
Tomer Figenblat

๐Ÿ› Tomi De Lucca
Tomi De Lucca

๐Ÿ’ป ๐Ÿ› Tony
Tony

๐Ÿ“– Torsten Kleiber
Torsten Kleiber

๐Ÿ› - TrackerSB
TrackerSB

๐Ÿ› + TrackerSB
TrackerSB

๐Ÿ› Tyson Stewart
Tyson Stewart

๐Ÿ› Ullrich Hafner
Ullrich Hafner

๐Ÿ› Utku Cuhadaroglu
Utku Cuhadaroglu

๐Ÿ’ป ๐Ÿ› Valentin Brandl
Valentin Brandl

๐Ÿ› Valeria
Valeria

๐Ÿ› Valery Yatsynovich
Valery Yatsynovich

๐Ÿ“– - Vasily Anisimov
Vasily Anisimov

๐Ÿ› + Vasily Anisimov
Vasily Anisimov

๐Ÿ› Vedant Chokshi
Vedant Chokshi

๐Ÿ› Vibhor Goyal
Vibhor Goyal

๐Ÿ› Vickenty Fesunov
Vickenty Fesunov

๐Ÿ› Victor Noรซl
Victor Noรซl

๐Ÿ› Vincent Galloy
Vincent Galloy

๐Ÿ’ป Vincent HUYNH
Vincent HUYNH

๐Ÿ› - Vincent Maurin
Vincent Maurin

๐Ÿ› + Vincent Maurin
Vincent Maurin

๐Ÿ› Vincent Privat
Vincent Privat

๐Ÿ› Vishhwas
Vishhwas

๐Ÿ› Vishv_Android
Vishv_Android

๐Ÿ› Vitaly
Vitaly

๐Ÿ› Vitaly Polonetsky
Vitaly Polonetsky

๐Ÿ› Vojtech Polivka
Vojtech Polivka

๐Ÿ› - Vsevolod Zholobov
Vsevolod Zholobov

๐Ÿ› + Vsevolod Zholobov
Vsevolod Zholobov

๐Ÿ› Vyom Yadav
Vyom Yadav

๐Ÿ’ป Wang Shidong
Wang Shidong

๐Ÿ› Waqas Ahmed
Waqas Ahmed

๐Ÿ› Wayne J. Earl
Wayne J. Earl

๐Ÿ› Wchenghui
Wchenghui

๐Ÿ› Wener
Wener

๐Ÿ’ป - Will Winder
Will Winder

๐Ÿ› + Will Winder
Will Winder

๐Ÿ› William Brockhus
William Brockhus

๐Ÿ’ป ๐Ÿ› Wilson Kurniawan
Wilson Kurniawan

๐Ÿ› Wim Deblauwe
Wim Deblauwe

๐Ÿ› Woongsik Choi
Woongsik Choi

๐Ÿ› XenoAmess
XenoAmess

๐Ÿ’ป ๐Ÿ› Yang
Yang

๐Ÿ’ป - YaroslavTER
YaroslavTER

๐Ÿ› + YaroslavTER
YaroslavTER

๐Ÿ› Yasar Shaikh
Yasar Shaikh

๐Ÿ’ป Young Chan
Young Chan

๐Ÿ’ป ๐Ÿ› YuJin Kim
YuJin Kim

๐Ÿ› Yuri Dolzhenko
Yuri Dolzhenko

๐Ÿ› Yurii Dubinka
Yurii Dubinka

๐Ÿ› Zoltan Farkas
Zoltan Farkas

๐Ÿ› - Zustin
Zustin

๐Ÿ› + Zustin
Zustin

๐Ÿ› aaronhurst-google
aaronhurst-google

๐Ÿ› ๐Ÿ’ป alexmodis
alexmodis

๐Ÿ› andreoss
andreoss

๐Ÿ› andrey81inmd
andrey81inmd

๐Ÿ’ป ๐Ÿ› anicoara
anicoara

๐Ÿ› arunprasathav
arunprasathav

๐Ÿ› - asiercamara
asiercamara

๐Ÿ› + asiercamara
asiercamara

๐Ÿ› astillich-igniti
astillich-igniti

๐Ÿ’ป avesolovksyy
avesolovksyy

๐Ÿ› avishvat
avishvat

๐Ÿ› avivmu
avivmu

๐Ÿ› axelbarfod1
axelbarfod1

๐Ÿ› b-3-n
b-3-n

๐Ÿ› - balbhadra9
balbhadra9

๐Ÿ› + balbhadra9
balbhadra9

๐Ÿ› base23de
base23de

๐Ÿ› bergander
bergander

๐Ÿ› ๐Ÿ’ป berkam
berkam

๐Ÿ’ป ๐Ÿ› breizh31
breizh31

๐Ÿ› caesarkim
caesarkim

๐Ÿ› carolyujing
carolyujing

๐Ÿ› - cbfiddle
cbfiddle

๐Ÿ› + cbfiddle
cbfiddle

๐Ÿ› cesares-basilico
cesares-basilico

๐Ÿ› chrite
chrite

๐Ÿ› ciufudean
ciufudean

๐Ÿ“– cobratbq
cobratbq

๐Ÿ› coladict
coladict

๐Ÿ› cosmoJFH
cosmoJFH

๐Ÿ› - cristalp
cristalp

๐Ÿ› + cristalp
cristalp

๐Ÿ› crunsk
crunsk

๐Ÿ› cwholmes
cwholmes

๐Ÿ› cyberjj999
cyberjj999

๐Ÿ› cyw3
cyw3

๐Ÿ› ๐Ÿ“– d1ss0nanz
d1ss0nanz

๐Ÿ› dague1
dague1

๐Ÿ“– - dalizi007
dalizi007

๐Ÿ’ป + dalizi007
dalizi007

๐Ÿ’ป danbrycefairsailcom
danbrycefairsailcom

๐Ÿ› dariansanity
dariansanity

๐Ÿ› darrenmiliband
darrenmiliband

๐Ÿ› davidburstrom
davidburstrom

๐Ÿ› dbirkman-paloalto
dbirkman-paloalto

๐Ÿ› deepak-patra
deepak-patra

๐Ÿ› - dependabot[bot]
dependabot[bot]

๐Ÿ’ป ๐Ÿ› + dependabot[bot]
dependabot[bot]

๐Ÿ’ป ๐Ÿ› dinesh150
dinesh150

๐Ÿ› diziaq
diziaq

๐Ÿ› dreaminpast123
dreaminpast123

๐Ÿ› duanyanan
duanyanan

๐Ÿ› dutt-sanjay
dutt-sanjay

๐Ÿ› duursma
duursma

๐Ÿ’ป - dylanleung
dylanleung

๐Ÿ› + dylanleung
dylanleung

๐Ÿ› dzeigler
dzeigler

๐Ÿ› eant60
eant60

๐Ÿ› ekkirala
ekkirala

๐Ÿ› emersonmoura
emersonmoura

๐Ÿ› emouty
emouty

๐Ÿ’ป ๐Ÿ› eugenepugach
eugenepugach

๐Ÿ› - fairy
fairy

๐Ÿ› + fairy
fairy

๐Ÿ› filiprafalowicz
filiprafalowicz

๐Ÿ’ป flxbl-io
flxbl-io

๐Ÿ’ต foxmason
foxmason

๐Ÿ› frankegabor
frankegabor

๐Ÿ› frankl
frankl

๐Ÿ› freafrea
freafrea

๐Ÿ› - fsapatin
fsapatin

๐Ÿ› + fsapatin
fsapatin

๐Ÿ› gearsethenry
gearsethenry

๐Ÿ› gracia19
gracia19

๐Ÿ› gudzpoz
gudzpoz

๐Ÿ› guo fei
guo fei

๐Ÿ› gurmsc5
gurmsc5

๐Ÿ› gwilymatgearset
gwilymatgearset

๐Ÿ’ป ๐Ÿ› - haigsn
haigsn

๐Ÿ› + haigsn
haigsn

๐Ÿ› hemanshu070
hemanshu070

๐Ÿ› henrik242
henrik242

๐Ÿ› hongpuwu
hongpuwu

๐Ÿ› hvbtup
hvbtup

๐Ÿ’ป ๐Ÿ› igniti GmbH
igniti GmbH

๐Ÿ› ilovezfs
ilovezfs

๐Ÿ› - imax-erik
imax-erik

๐Ÿ› + imax-erik
imax-erik

๐Ÿ› itaigilo
itaigilo

๐Ÿ› jakivey32
jakivey32

๐Ÿ› jbennett2091
jbennett2091

๐Ÿ› jcamerin
jcamerin

๐Ÿ› jkeener1
jkeener1

๐Ÿ› jmetertea
jmetertea

๐Ÿ› - johnra2
johnra2

๐Ÿ’ป + johnra2
johnra2

๐Ÿ’ป johnzhao9
johnzhao9

๐Ÿ› josemanuelrolon
josemanuelrolon

๐Ÿ’ป ๐Ÿ› kabroxiko
kabroxiko

๐Ÿ’ป ๐Ÿ› karthikaiyasamy
karthikaiyasamy

๐Ÿ“– karwer
karwer

๐Ÿ› kaulonline
kaulonline

๐Ÿ› - kdaemonv
kdaemonv

๐Ÿ› + kdaemonv
kdaemonv

๐Ÿ› kdebski85
kdebski85

๐Ÿ› ๐Ÿ’ป kenji21
kenji21

๐Ÿ’ป ๐Ÿ› kfranic
kfranic

๐Ÿ› khalidkh
khalidkh

๐Ÿ› koalalam
koalalam

๐Ÿ› krzyk
krzyk

๐Ÿ› - lasselindqvist
lasselindqvist

๐Ÿ› + lasselindqvist
lasselindqvist

๐Ÿ› lgemeinhardt
lgemeinhardt

๐Ÿ› lihuaib
lihuaib

๐Ÿ› liqingjun123
liqingjun123

๐Ÿ› lonelyma1021
lonelyma1021

๐Ÿ› lpeddy
lpeddy

๐Ÿ› lujiefsi
lujiefsi

๐Ÿ’ป - lukelukes
lukelukes

๐Ÿ’ป + lukelukes
lukelukes

๐Ÿ’ป lyriccoder
lyriccoder

๐Ÿ› marcelmore
marcelmore

๐Ÿ› matchbox
matchbox

๐Ÿ› matthiaskraaz
matthiaskraaz

๐Ÿ› meandonlyme
meandonlyme

๐Ÿ› mikesive
mikesive

๐Ÿ› - milossesic
milossesic

๐Ÿ› + milossesic
milossesic

๐Ÿ› mluckam
mluckam

๐Ÿ’ป ๐Ÿ› mohan-chinnappan-n
mohan-chinnappan-n

๐Ÿ’ป mriddell95
mriddell95

๐Ÿ› mrlzh
mrlzh

๐Ÿ› msloan
msloan

๐Ÿ› mucharlaravalika
mucharlaravalika

๐Ÿ› - mvenneman
mvenneman

๐Ÿ› + mvenneman
mvenneman

๐Ÿ› nareshl119
nareshl119

๐Ÿ› nicolas-harraudeau-sonarsource
nicolas-harraudeau-sonarsource

๐Ÿ› noerremark
noerremark

๐Ÿ› novsirion
novsirion

๐Ÿ› nwcm
nwcm

๐Ÿ“– ๐Ÿ› ๐Ÿ’ป oggboy
oggboy

๐Ÿ› - oinume
oinume

๐Ÿ› + oinume
oinume

๐Ÿ› orimarko
orimarko

๐Ÿ’ป ๐Ÿ› pablogomez2197
pablogomez2197

๐Ÿ› pacvz
pacvz

๐Ÿ’ป pallavi agarwal
pallavi agarwal

๐Ÿ› parksungrin
parksungrin

๐Ÿ› patpatpat123
patpatpat123

๐Ÿ› - patriksevallius
patriksevallius

๐Ÿ› + patriksevallius
patriksevallius

๐Ÿ› pbrajesh1
pbrajesh1

๐Ÿ› phoenix384
phoenix384

๐Ÿ› piotrszymanski-sc
piotrszymanski-sc

๐Ÿ’ป plan3d
plan3d

๐Ÿ› poojasix
poojasix

๐Ÿ› prabhushrikant
prabhushrikant

๐Ÿ› - pujitha8783
pujitha8783

๐Ÿ› + pujitha8783
pujitha8783

๐Ÿ› r-r-a-j
r-r-a-j

๐Ÿ› raghujayjunk
raghujayjunk

๐Ÿ› rajeshveera
rajeshveera

๐Ÿ› rajeswarreddy88
rajeswarreddy88

๐Ÿ› recdevs
recdevs

๐Ÿ› reudismam
reudismam

๐Ÿ’ป ๐Ÿ› - rijkt
rijkt

๐Ÿ› + rijkt
rijkt

๐Ÿ› rillig-tk
rillig-tk

๐Ÿ› rmohan20
rmohan20

๐Ÿ’ป ๐Ÿ› rnveach
rnveach

๐Ÿ› rxmicro
rxmicro

๐Ÿ› ryan-gustafson
ryan-gustafson

๐Ÿ’ป ๐Ÿ› sabi0
sabi0

๐Ÿ› - scais
scais

๐Ÿ› + scais
scais

๐Ÿ› schosin
schosin

๐Ÿ› screamingfrog
screamingfrog

๐Ÿ’ต sebbASF
sebbASF

๐Ÿ› sergeygorbaty
sergeygorbaty

๐Ÿ’ป shilko2013
shilko2013

๐Ÿ› shiomiyan
shiomiyan

๐Ÿ“– - simeonKondr
simeonKondr

๐Ÿ› + simeonKondr
simeonKondr

๐Ÿ› snajberk
snajberk

๐Ÿ› sniperrifle2004
sniperrifle2004

๐Ÿ› snuyanzin
snuyanzin

๐Ÿ› ๐Ÿ’ป soloturn
soloturn

๐Ÿ› soyodream
soyodream

๐Ÿ› sratz
sratz

๐Ÿ› - stonio
stonio

๐Ÿ› + stonio
stonio

๐Ÿ› sturton
sturton

๐Ÿ’ป ๐Ÿ› sudharmohan
sudharmohan

๐Ÿ› suruchidawar
suruchidawar

๐Ÿ› svenfinitiv
svenfinitiv

๐Ÿ› szymanp23
szymanp23

๐Ÿ› ๐Ÿ’ป tashiscool
tashiscool

๐Ÿ› - test-git-hook
test-git-hook

๐Ÿ› + test-git-hook
test-git-hook

๐Ÿ› testation21
testation21

๐Ÿ’ป ๐Ÿ› thanosa
thanosa

๐Ÿ› tiandiyixian
tiandiyixian

๐Ÿ› tobwoerk
tobwoerk

๐Ÿ› tprouvot
tprouvot

๐Ÿ› ๐Ÿ’ป trentchilders
trentchilders

๐Ÿ› - triandicAnt
triandicAnt

๐Ÿ› + triandicAnt
triandicAnt

๐Ÿ› trishul14
trishul14

๐Ÿ› tsui
tsui

๐Ÿ› wangzitom12306
wangzitom12306

๐Ÿ› winhkey
winhkey

๐Ÿ› witherspore
witherspore

๐Ÿ› wjljack
wjljack

๐Ÿ› - wuchiuwong
wuchiuwong

๐Ÿ› + wuchiuwong
wuchiuwong

๐Ÿ› xingsong
xingsong

๐Ÿ› xioayuge
xioayuge

๐Ÿ› xnYi9wRezm
xnYi9wRezm

๐Ÿ’ป ๐Ÿ› xuanuy
xuanuy

๐Ÿ› xyf0921
xyf0921

๐Ÿ› yalechen-cyw3
yalechen-cyw3

๐Ÿ› - yasuharu-sato
yasuharu-sato

๐Ÿ› + yasuharu-sato
yasuharu-sato

๐Ÿ› zenglian
zenglian

๐Ÿ› zgrzyt93
zgrzyt93

๐Ÿ’ป ๐Ÿ› zh3ng
zh3ng

๐Ÿ› zt_soft
zt_soft

๐Ÿ› ztt79
ztt79

๐Ÿ› zzzzfeng
zzzzfeng

๐Ÿ› - รrpรกd Magosรกnyi
รrpรกd Magosรกnyi

๐Ÿ› + รrpรกd Magosรกnyi
รrpรกd Magosรกnyi

๐Ÿ› ไปป่ดตๆฐ
ไปป่ดตๆฐ

๐Ÿ› + ๅคฉ็ƒญๅƒ่ฅฟ็“œ
ๅคฉ็ƒญๅƒ่ฅฟ็“œ

๐Ÿ› ่Œ…ๅปถๅฎ‰
่Œ…ๅปถๅฎ‰

๐Ÿ’ป From 991bc2c41d92de4f9b18cfe67d63870fb9428a2e Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 18:12:13 +0100 Subject: [PATCH 24/37] [apex] Report LexException when extracting comments --- .../pmd/lang/apex/ast/ApexCommentBuilder.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java index 48d41f0faa..7cc9e23f8d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentBuilder.java @@ -14,10 +14,14 @@ import java.util.List; import java.util.Map; import java.util.RandomAccess; +import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.Token; import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.LexException; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextRegion; @@ -106,6 +110,13 @@ final class ApexCommentBuilder { private static CommentInformation extractInformationFromComments(TextDocument sourceCode, String suppressMarker) { String source = sourceCode.getText().toString(); ApexLexer lexer = new ApexLexer(new CaseInsensitiveInputStream(CharStreams.fromString(source))); + lexer.removeErrorListeners(); + lexer.addErrorListener(new BaseErrorListener() { + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { + throw new LexException(line, charPositionInLine, sourceCode.getFileId(), msg, e); + } + }); List allCommentTokens = new ArrayList<>(); Map suppressMap = new HashMap<>(); From 509452577def03f1ae357722204424d0ff53591d Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 18:16:06 +0100 Subject: [PATCH 25/37] [apex] Add test case for #5333 --- .../sourceforge/pmd/lang/apex/ast/ApexCommentTest.java | 8 ++++++++ .../net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentTest.java index 728cce6253..6e847170bf 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexCommentTest.java @@ -66,4 +66,12 @@ class ApexCommentTest extends ApexParserTestBase { ASTFormalComment comment = file.descendants(ASTUserClass.class).children(ASTFormalComment.class).first(); assertEquals(FORMAL_COMMENT_CONTENT, comment.getImage()); } + + @Test + void fileWithUnicodeEscapes() { + ASTApexFile file = apex.parse(FORMAL_COMMENT_CONTENT + "\n" + + "class MyClass { String s = 'Fran\\u00E7ois'; }"); + ASTFormalComment comment = file.descendants(ASTUserClass.class).children(ASTFormalComment.class).first(); + assertEquals(FORMAL_COMMENT_CONTENT, comment.getImage()); + } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java index b075160370..22104ac401 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexLexerTest.java @@ -57,6 +57,7 @@ class ApexLexerTest { @Test void testLexerUnicodeEscapes() { String s = "'Fran\\u00E7ois'"; + // note: with apex-parser 4.3.1, no errors are reported anymore assertEquals(2, getLexingErrors(CharStreams.fromString(s))); assertEquals(0, getLexingErrors(new CaseInsensitiveInputStream(CharStreams.fromString(s)))); } @@ -71,7 +72,7 @@ class ApexLexerTest { return errorListener.getErrorCount(); } - static class ErrorListener extends BaseErrorListener { + private static class ErrorListener extends BaseErrorListener { private int errorCount = 0; @Override From 093683bc592e968ae629f7087655575efd394c92 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 18:17:49 +0100 Subject: [PATCH 26/37] [doc] Update release notes (#5284, #5333) --- docs/pages/release_notes.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5fa3ac04b6..4a522f9532 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -17,6 +17,8 @@ This is a {{ site.pmd.release_type }} release. ### ๐Ÿ› Fixed Issues * ant * [#1860](https://github.com/pmd/pmd/issues/1860): \[ant] Reflective access warnings on java > 9 and java < 17 +* apex + * [#5333](https://github.com/pmd/pmd/issues/5333): \[apex] Token recognition errors for string containing unicode escape sequence * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas @@ -29,6 +31,7 @@ This is a {{ site.pmd.release_type }} release. instead (note different package `ast` instead of `antlr4`). ### โœจ External Contributions +* [#5284](https://github.com/pmd/pmd/pull/5284): \[apex] Use case-insensitive input stream to avoid choking on Unicode escape sequences - [Willem A. Hajenius](https://github.com/wahajenius) (@wahajenius) {% endtocmaker %} From e1d4f27e198beba891a3b4d20e112956229c6e4a Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 18:18:06 +0100 Subject: [PATCH 27/37] Add @wahajenius as a contributor --- .all-contributorsrc | 9 + docs/pages/pmd/projectdocs/credits.md | 234 +++++++++++++------------- 2 files changed, 127 insertions(+), 116 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 95ebc05d6e..3ccf2e8784 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7865,6 +7865,15 @@ "contributions": [ "code" ] + }, + { + "login": "wahajenius", + "name": "Willem A. Hajenius", + "avatar_url": "https://avatars.githubusercontent.com/u/7836322?v=4", + "profile": "https://github.com/wahajenius", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 9497ea7378..8bedbc0f63 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -350,769 +350,771 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d JJengility
JJengility

๐Ÿ› Jake Hemmerle
Jake Hemmerle

๐Ÿ› + Jakub Dupak
Jakub Dupak

๐Ÿ’ป James Harrison
James Harrison

๐Ÿ› ๐Ÿ’ป Jamie Bisotti
Jamie Bisotti

๐Ÿ› Jan
Jan

๐Ÿ› Jan Aertgeerts
Jan Aertgeerts

๐Ÿ’ป ๐Ÿ› - Jan Brรผmmer
Jan Brรผmmer

๐Ÿ› + Jan Brรผmmer
Jan Brรผmmer

๐Ÿ› Jan Tล™รญska
Jan Tล™รญska

๐Ÿ› Jan-Lukas Else
Jan-Lukas Else

๐Ÿ› Jason Qiu
Jason Qiu

๐Ÿ’ป ๐Ÿ“– Jason Williams
Jason Williams

๐Ÿ› Javier Spagnoletti
Javier Spagnoletti

๐Ÿ› Jean-Paul Mayer
Jean-Paul Mayer

๐Ÿ› - Jean-Simon Larochelle
Jean-Simon Larochelle

๐Ÿ› + Jean-Simon Larochelle
Jean-Simon Larochelle

๐Ÿ› Jeff Bartolotta
Jeff Bartolotta

๐Ÿ’ป ๐Ÿ› Jeff Hube
Jeff Hube

๐Ÿ’ป ๐Ÿ› Jeff Jensen
Jeff Jensen

๐Ÿ› Jeff May
Jeff May

๐Ÿ› Jens Gerdes
Jens Gerdes

๐Ÿ› Jeroen Borgers
Jeroen Borgers

๐Ÿ› ๐Ÿ’ป ๐Ÿ“ข - Jeroen Meijer
Jeroen Meijer

๐Ÿ› + Jeroen Meijer
Jeroen Meijer

๐Ÿ› Jeroen van Wilgenburg
Jeroen van Wilgenburg

๐Ÿ“– Jerome Russ
Jerome Russ

๐Ÿ› JerritEic
JerritEic

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› Jiri Pejchal
Jiri Pejchal

๐Ÿ› Jithin Sunny
Jithin Sunny

๐Ÿ› Jiล™รญ ล korpil
Jiล™รญ ล korpil

๐Ÿ› - Joao Machado
Joao Machado

๐Ÿ› + Joao Machado
Joao Machado

๐Ÿ› Jochen Krauss
Jochen Krauss

๐Ÿ› Johan Hammar
Johan Hammar

๐Ÿ› John Karp
John Karp

๐Ÿ› John Zhang
John Zhang

๐Ÿ› John-Teng
John-Teng

๐Ÿ’ป ๐Ÿ› Jon Moroney
Jon Moroney

๐Ÿ’ป ๐Ÿ› - Jonas Geiregat
Jonas Geiregat

๐Ÿ› + Jonas Geiregat
Jonas Geiregat

๐Ÿ› Jonas KeรŸler
Jonas KeรŸler

๐Ÿ› Jonathan Wiesel
Jonathan Wiesel

๐Ÿ’ป ๐Ÿ› Jordan
Jordan

๐Ÿ› Jordi Llach
Jordi Llach

๐Ÿ› Jorge Solรณrzano
Jorge Solรณrzano

๐Ÿ› JorneVL
JorneVL

๐Ÿ› - Jose Palafox
Jose Palafox

๐Ÿ› + Jose Palafox
Jose Palafox

๐Ÿ› Jose Stovall
Jose Stovall

๐Ÿ› Joseph
Joseph

๐Ÿ’ป Joseph Heenan
Joseph Heenan

๐Ÿ› Josh Feingold
Josh Feingold

๐Ÿ’ป ๐Ÿ› Josh Holthaus
Josh Holthaus

๐Ÿ› Joshua S Arquilevich
Joshua S Arquilevich

๐Ÿ› - Joรฃo Dinis Ferreira
Joรฃo Dinis Ferreira

๐Ÿ“– + Joรฃo Dinis Ferreira
Joรฃo Dinis Ferreira

๐Ÿ“– Joรฃo Ferreira
Joรฃo Ferreira

๐Ÿ’ป ๐Ÿ› Joรฃo Pedro Schmitt
Joรฃo Pedro Schmitt

๐Ÿ› Juan Martรญn Sotuyo Dodero
Juan Martรญn Sotuyo Dodero

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› ๐Ÿšง Juan Pablo Civile
Juan Pablo Civile

๐Ÿ› Julian Voronetsky
Julian Voronetsky

๐Ÿ› Julien
Julien

๐Ÿ› - Julius
Julius

๐Ÿ› + Julius
Julius

๐Ÿ› JustPRV
JustPRV

๐Ÿ› Justin Stroud
Justin Stroud

๐Ÿ’ป Jรถrn Huxhorn
Jรถrn Huxhorn

๐Ÿ› KThompso
KThompso

๐Ÿ› Kai Amundsen
Kai Amundsen

๐Ÿ› Karel Vervaeke
Karel Vervaeke

๐Ÿ› - Karl-Andero Mere
Karl-Andero Mere

๐Ÿ› + Karl-Andero Mere
Karl-Andero Mere

๐Ÿ› Karl-Philipp Richter
Karl-Philipp Richter

๐Ÿ› Karsten Silz
Karsten Silz

๐Ÿ› Kazuma Watanabe
Kazuma Watanabe

๐Ÿ› Kev
Kev

๐Ÿ› Keve Mรผller
Keve Mรผller

๐Ÿ› Kevin Guerra
Kevin Guerra

๐Ÿ’ป - Kevin Jones
Kevin Jones

๐Ÿ› ๐Ÿ’ป + Kevin Jones
Kevin Jones

๐Ÿ› ๐Ÿ’ป Kevin Poorman
Kevin Poorman

๐Ÿ› Kevin Wayne
Kevin Wayne

๐Ÿ› Kieran Black
Kieran Black

๐Ÿ› Kirill Zubov
Kirill Zubov

๐Ÿ› Kirk Clemens
Kirk Clemens

๐Ÿ’ป ๐Ÿ› Klaus Hartl
Klaus Hartl

๐Ÿ› - Koen Van Looveren
Koen Van Looveren

๐Ÿ› + Koen Van Looveren
Koen Van Looveren

๐Ÿ› Kris Scheibe
Kris Scheibe

๐Ÿ’ป ๐Ÿ› Krystian Dabrowski
Krystian Dabrowski

๐Ÿ› ๐Ÿ’ป Kunal Thanki
Kunal Thanki

๐Ÿ› LaLucid
LaLucid

๐Ÿ’ป Larry Diamond
Larry Diamond

๐Ÿ’ป ๐Ÿ› Lars Knickrehm
Lars Knickrehm

๐Ÿ› - Laurent Bovet
Laurent Bovet

๐Ÿ› ๐Ÿ’ป + Laurent Bovet
Laurent Bovet

๐Ÿ› ๐Ÿ’ป Leo Gutierrez
Leo Gutierrez

๐Ÿ› LiGaOg
LiGaOg

๐Ÿ’ป Liam Sharp
Liam Sharp

๐Ÿ› Lintsi
Lintsi

๐Ÿ› Linus Fernandes
Linus Fernandes

๐Ÿ› Lixon Lookose
Lixon Lookose

๐Ÿ› - Logesh
Logesh

๐Ÿ› + Logesh
Logesh

๐Ÿ› Lorenzo Gabriele
Lorenzo Gabriele

๐Ÿ› Loรฏc Ledoyen
Loรฏc Ledoyen

๐Ÿ› Lucas
Lucas

๐Ÿ› Lucas Silva
Lucas Silva

๐Ÿ› Lucas Soncini
Lucas Soncini

๐Ÿ’ป ๐Ÿ› Luis Alcantar
Luis Alcantar

๐Ÿ’ป - Lukas Grรคf
Lukas Grรคf

๐Ÿ’ป + Lukas Grรคf
Lukas Grรคf

๐Ÿ’ป Lukasz Slonina
Lukasz Slonina

๐Ÿ› Lukebray
Lukebray

๐Ÿ› Lynn
Lynn

๐Ÿ’ป ๐Ÿ› Lyor Goldstein
Lyor Goldstein

๐Ÿ› MCMicS
MCMicS

๐Ÿ› Macarse
Macarse

๐Ÿ› - Machine account for PMD
Machine account for PMD

๐Ÿ’ป + Machine account for PMD
Machine account for PMD

๐Ÿ’ป Maciek Siemczyk
Maciek Siemczyk

๐Ÿ› Maikel Steneker
Maikel Steneker

๐Ÿ’ป ๐Ÿ› Maksim Moiseikin
Maksim Moiseikin

๐Ÿ› Manfred Koch
Manfred Koch

๐Ÿ› Manuel Moya Ferrer
Manuel Moya Ferrer

๐Ÿ’ป ๐Ÿ› Manuel Ryan
Manuel Ryan

๐Ÿ› - Marat Vyshegorodtsev
Marat Vyshegorodtsev

๐Ÿ› + Marat Vyshegorodtsev
Marat Vyshegorodtsev

๐Ÿ› Marcel Hรคrle
Marcel Hรคrle

๐Ÿ› Marcello Fialho
Marcello Fialho

๐Ÿ› Marcin Dฤ…browski
Marcin Dฤ…browski

๐Ÿ’ป Marcin Rataj
Marcin Rataj

๐Ÿ› Marcono1234
Marcono1234

๐Ÿ› Mark Adamcin
Mark Adamcin

๐Ÿ› - Mark Hall
Mark Hall

๐Ÿ’ป ๐Ÿ› + Mark Hall
Mark Hall

๐Ÿ’ป ๐Ÿ› Mark Kolich
Mark Kolich

๐Ÿ› Mark Pritchard
Mark Pritchard

๐Ÿ› Markus Rathgeb
Markus Rathgeb

๐Ÿ› Marquis Wang
Marquis Wang

๐Ÿ› MartGit
MartGit

๐Ÿ› Martin Feldsztejn
Martin Feldsztejn

๐Ÿ› - Martin Lehmann
Martin Lehmann

๐Ÿ› + Martin Lehmann
Martin Lehmann

๐Ÿ› Martin Spamer
Martin Spamer

๐Ÿ› Martin Tarjรกnyi
Martin Tarjรกnyi

๐Ÿ› MatFl
MatFl

๐Ÿ› Mateusz Stefanski
Mateusz Stefanski

๐Ÿ› Mathieu Gouin
Mathieu Gouin

๐Ÿ› MatiasComercio
MatiasComercio

๐Ÿ’ป ๐Ÿ› - Matt Benson
Matt Benson

๐Ÿ› + Matt Benson
Matt Benson

๐Ÿ› Matt De Poorter
Matt De Poorter

๐Ÿ› Matt Hargett
Matt Hargett

๐Ÿ’ป ๐Ÿ’ต Matt Harrah
Matt Harrah

๐Ÿ› Matt Nelson
Matt Nelson

๐Ÿ› Matthew Amos
Matthew Amos

๐Ÿ› Matthew Duggan
Matthew Duggan

๐Ÿ› - Matthew Hall
Matthew Hall

๐Ÿ› + Matthew Hall
Matthew Hall

๐Ÿ› Matthew Rossner
Matthew Rossner

๐Ÿ› Matรญas Fraga
Matรญas Fraga

๐Ÿ’ป ๐Ÿ› Maxime Robert
Maxime Robert

๐Ÿ’ป ๐Ÿ› MetaBF
MetaBF

๐Ÿ› Metin Dagcilar
Metin Dagcilar

๐Ÿ› Michael
Michael

๐Ÿ› - Michael Bell
Michael Bell

๐Ÿ› + Michael Bell
Michael Bell

๐Ÿ› Michael Bernstein
Michael Bernstein

๐Ÿ› Michael Clay
Michael Clay

๐Ÿ› Michael Dombrowski
Michael Dombrowski

๐Ÿ› Michael Hausegger
Michael Hausegger

๐Ÿ› Michael Hoefer
Michael Hoefer

๐Ÿ› Michael Kolesnikov
Michael Kolesnikov

๐Ÿ› - Michael Mรถbius
Michael Mรถbius

๐Ÿ› + Michael Mรถbius
Michael Mรถbius

๐Ÿ› Michael N. Lipp
Michael N. Lipp

๐Ÿ› Michael Pellegrini
Michael Pellegrini

๐Ÿ› Michal Kordas
Michal Kordas

๐Ÿ› Michaล‚ Borek
Michaล‚ Borek

๐Ÿ› Michaล‚ Kuliล„ski
Michaล‚ Kuliล„ski

๐Ÿ› Miguel Nรบรฑez Dรญaz-Montes
Miguel Nรบรฑez Dรญaz-Montes

๐Ÿ› - Mihai Ionut
Mihai Ionut

๐Ÿ› + Mihai Ionut
Mihai Ionut

๐Ÿ› Mikhail Kuchma
Mikhail Kuchma

๐Ÿ› Mirek Hankus
Mirek Hankus

๐Ÿ› Mitch Spano
Mitch Spano

๐Ÿ› Mladjan Gadzic
Mladjan Gadzic

๐Ÿ› MrAngry52
MrAngry52

๐Ÿ› Muminur Choudhury
Muminur Choudhury

๐Ÿ› - Mykhailo Palahuta
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ› + Mykhailo Palahuta
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ› Nagendra Kumar Singh
Nagendra Kumar Singh

๐Ÿ› Nahuel Barrios
Nahuel Barrios

๐Ÿ› Nakul Sharma
Nakul Sharma

๐Ÿ› Nathan Braun
Nathan Braun

๐Ÿ› Nathan Reynolds
Nathan Reynolds

๐Ÿ› Nathan Reynolds
Nathan Reynolds

๐Ÿ› - Nathanaรซl
Nathanaรซl

๐Ÿ› + Nathanaรซl
Nathanaรซl

๐Ÿ› Naveen
Naveen

๐Ÿ’ป Nazdravi
Nazdravi

๐Ÿ› Neha-Dhonde
Neha-Dhonde

๐Ÿ› Nicholas Doyle
Nicholas Doyle

๐Ÿ› Nick Butcher
Nick Butcher

๐Ÿ› Nico Gallinal
Nico Gallinal

๐Ÿ› - Nicola Dal Maso
Nicola Dal Maso

๐Ÿ› + Nicola Dal Maso
Nicola Dal Maso

๐Ÿ› Nicolas Filotto
Nicolas Filotto

๐Ÿ’ป Nicolas Vervelle
Nicolas Vervelle

๐Ÿ› Nicolas Vuillamy
Nicolas Vuillamy

๐Ÿ“– Nikita Chursin
Nikita Chursin

๐Ÿ› Niklas Baudy
Niklas Baudy

๐Ÿ› Nikolas Havrikov
Nikolas Havrikov

๐Ÿ› - Nilesh Virkar
Nilesh Virkar

๐Ÿ› + Nilesh Virkar
Nilesh Virkar

๐Ÿ› Nimit Patel
Nimit Patel

๐Ÿ› Niranjan Harpale
Niranjan Harpale

๐Ÿ› Nirvik Patel
Nirvik Patel

๐Ÿ’ป Noah Sussman
Noah Sussman

๐Ÿ› Noah0120
Noah0120

๐Ÿ› Noam Tamim
Noam Tamim

๐Ÿ› - Noel Grandin
Noel Grandin

๐Ÿ› + Noel Grandin
Noel Grandin

๐Ÿ› Olaf Haalstra
Olaf Haalstra

๐Ÿ› Oleg Andreych
Oleg Andreych

๐Ÿ’ป ๐Ÿ› Oleg Pavlenko
Oleg Pavlenko

๐Ÿ› Oleksii Dykov
Oleksii Dykov

๐Ÿ’ป ๐Ÿ› Oliver Eikemeier
Oliver Eikemeier

๐Ÿ› Oliver Siegmar
Oliver Siegmar

๐Ÿ’ต - Olivier Parent
Olivier Parent

๐Ÿ’ป ๐Ÿ› + Olivier Parent
Olivier Parent

๐Ÿ’ป ๐Ÿ› Ollie Abbey
Ollie Abbey

๐Ÿ’ป ๐Ÿ› Ondrej Kratochvil
Ondrej Kratochvil

๐Ÿ› OverDrone
OverDrone

๐Ÿ› Ozan Gulle
Ozan Gulle

๐Ÿ’ป ๐Ÿ› PUNEET JAIN
PUNEET JAIN

๐Ÿ› Parbati Bose
Parbati Bose

๐Ÿ› - Paul Berg
Paul Berg

๐Ÿ› + Paul Berg
Paul Berg

๐Ÿ› Paul Guyot
Paul Guyot

๐Ÿ’ป Pavel Bludov
Pavel Bludov

๐Ÿ› Pavel Miฤka
Pavel Miฤka

๐Ÿ› Pedro Nuno Santos
Pedro Nuno Santos

๐Ÿ› Pedro Rijo
Pedro Rijo

๐Ÿ› Pelisse Romain
Pelisse Romain

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› - Per Abich
Per Abich

๐Ÿ’ป + Per Abich
Per Abich

๐Ÿ’ป Pete Davids
Pete Davids

๐Ÿ› Peter Bruin
Peter Bruin

๐Ÿ› Peter Chittum
Peter Chittum

๐Ÿ’ป ๐Ÿ› Peter Cudmore
Peter Cudmore

๐Ÿ› Peter Kasson
Peter Kasson

๐Ÿ› Peter Kofler
Peter Kofler

๐Ÿ› - Peter Paul Bakker
Peter Paul Bakker

๐Ÿ’ป + Peter Paul Bakker
Peter Paul Bakker

๐Ÿ’ป Peter Rader
Peter Rader

๐Ÿ› Pham Hai Trung
Pham Hai Trung

๐Ÿ› Philip Graf
Philip Graf

๐Ÿ’ป ๐Ÿ› Philip Hachey
Philip Hachey

๐Ÿ› Philippe Ozil
Philippe Ozil

๐Ÿ› Phinehas Artemix
Phinehas Artemix

๐Ÿ› - Phokham Nonava
Phokham Nonava

๐Ÿ› + Phokham Nonava
Phokham Nonava

๐Ÿ› Pim van der Loos
Pim van der Loos

๐Ÿ’ป โš ๏ธ Piotr Szymaล„ski
Piotr Szymaล„ski

๐Ÿ› Piotrek ลปygieล‚o
Piotrek ลปygieล‚o

๐Ÿ’ป ๐Ÿ› ๐Ÿ“– Pranay Jaiswal
Pranay Jaiswal

๐Ÿ› Prasad Kamath
Prasad Kamath

๐Ÿ› Prasanna
Prasanna

๐Ÿ› - Presh-AR
Presh-AR

๐Ÿ› + Presh-AR
Presh-AR

๐Ÿ› Puneet1726
Puneet1726

๐Ÿ› RBRi
RBRi

๐Ÿ› Rafael Cortรชs
Rafael Cortรชs

๐Ÿ› RaheemShaik999
RaheemShaik999

๐Ÿ› RajeshR
RajeshR

๐Ÿ’ป ๐Ÿ› Ramachandra Mohan
Ramachandra Mohan

๐Ÿ› - Ramel0921
Ramel0921

๐Ÿ› + Ramel0921
Ramel0921

๐Ÿ› Raquel Pau
Raquel Pau

๐Ÿ› Ravikiran Janardhana
Ravikiran Janardhana

๐Ÿ› Reda Benhemmouche
Reda Benhemmouche

๐Ÿ› Reinhard Schiedermeier
Reinhard Schiedermeier

๐Ÿ› Renato Oliveira
Renato Oliveira

๐Ÿ’ป ๐Ÿ› Rich DiCroce
Rich DiCroce

๐Ÿ› - Richard Corfield
Richard Corfield

๐Ÿ’ป + Richard Corfield
Richard Corfield

๐Ÿ’ป Richard Corfield
Richard Corfield

๐Ÿ› ๐Ÿ’ป Riot R1cket
Riot R1cket

๐Ÿ› Rishabh Jain
Rishabh Jain

๐Ÿ› RishabhDeep Singh
RishabhDeep Singh

๐Ÿ› Rob Baillie
Rob Baillie

๐Ÿ› Robbie Martinus
Robbie Martinus

๐Ÿ’ป ๐Ÿ› - Robert Henry
Robert Henry

๐Ÿ› + Robert Henry
Robert Henry

๐Ÿ› Robert Mihaly
Robert Mihaly

๐Ÿ› Robert Painsi
Robert Painsi

๐Ÿ› Robert Russell
Robert Russell

๐Ÿ› Robert Sรถsemann
Robert Sรถsemann

๐Ÿ’ป ๐Ÿ“– ๐Ÿ“ข ๐Ÿ› Robert Whitebit
Robert Whitebit

๐Ÿ› Robin Richtsfeld
Robin Richtsfeld

๐Ÿ› - Robin Stocker
Robin Stocker

๐Ÿ’ป ๐Ÿ› + Robin Stocker
Robin Stocker

๐Ÿ’ป ๐Ÿ› Robin Wils
Robin Wils

๐Ÿ› RochusOest
RochusOest

๐Ÿ› Rodolfo Noviski
Rodolfo Noviski

๐Ÿ› Rodrigo Casara
Rodrigo Casara

๐Ÿ› Rodrigo Fernandes
Rodrigo Fernandes

๐Ÿ› Roman Salvador
Roman Salvador

๐Ÿ’ป ๐Ÿ› - Ronald Blaschke
Ronald Blaschke

๐Ÿ› + Ronald Blaschke
Ronald Blaschke

๐Ÿ› Rรณbert Papp
Rรณbert Papp

๐Ÿ› Saikat Sengupta
Saikat Sengupta

๐Ÿ› Saksham Handu
Saksham Handu

๐Ÿ› Saladoc
Saladoc

๐Ÿ› Salesforce Bob Lightning
Salesforce Bob Lightning

๐Ÿ› Sam Carlberg
Sam Carlberg

๐Ÿ› - Sascha Riemer
Sascha Riemer

๐Ÿ› + Sascha Riemer
Sascha Riemer

๐Ÿ› Sashko
Sashko

๐Ÿ’ป Satoshi Kubo
Satoshi Kubo

๐Ÿ› Scott Kennedy
Scott Kennedy

๐Ÿ› Scott Wells
Scott Wells

๐Ÿ› ๐Ÿ’ป Scrates1
Scrates1

๐Ÿ› ๐Ÿ’ป Scrsloota
Scrsloota

๐Ÿ’ป - Sebastian Bรถgl
Sebastian Bรถgl

๐Ÿ› + Sebastian Bรถgl
Sebastian Bรถgl

๐Ÿ› Sebastian Davids
Sebastian Davids

๐Ÿ› Sebastian Schuberth
Sebastian Schuberth

๐Ÿ› Sebastian Schwarz
Sebastian Schwarz

๐Ÿ› Seren
Seren

๐Ÿ› ๐Ÿ’ป Sergey Gorbaty
Sergey Gorbaty

๐Ÿ› Sergey Kozlov
Sergey Kozlov

๐Ÿ› - Sergey Yanzin
Sergey Yanzin

๐Ÿ’ป ๐Ÿ› + Sergey Yanzin
Sergey Yanzin

๐Ÿ’ป ๐Ÿ› Seth Wilcox
Seth Wilcox

๐Ÿ’ป Shai Bennathan
Shai Bennathan

๐Ÿ› ๐Ÿ’ป Shubham
Shubham

๐Ÿ’ป ๐Ÿ› Simon Abykov
Simon Abykov

๐Ÿ’ป ๐Ÿ› Simon Xiao
Simon Xiao

๐Ÿ› Srinivasan Venkatachalam
Srinivasan Venkatachalam

๐Ÿ› - Stanislav Gromov
Stanislav Gromov

๐Ÿ› + Stanislav Gromov
Stanislav Gromov

๐Ÿ› Stanislav Myachenkov
Stanislav Myachenkov

๐Ÿ’ป Stefan Birkner
Stefan Birkner

๐Ÿ› Stefan Bohn
Stefan Bohn

๐Ÿ› Stefan Endrullis
Stefan Endrullis

๐Ÿ› Stefan Klรถss-Schuster
Stefan Klรถss-Schuster

๐Ÿ› Stefan Wolf
Stefan Wolf

๐Ÿ› - Stephan H. Wissel
Stephan H. Wissel

๐Ÿ› + Stephan H. Wissel
Stephan H. Wissel

๐Ÿ› Stephen
Stephen

๐Ÿ› Stephen Carter
Stephen Carter

๐Ÿ› Stephen Friedrich
Stephen Friedrich

๐Ÿ› Steve Babula
Steve Babula

๐Ÿ’ป Steven Stearns
Steven Stearns

๐Ÿ› ๐Ÿ’ป Stexxe
Stexxe

๐Ÿ› - Stian Lรฅgstad
Stian Lรฅgstad

๐Ÿ› + Stian Lรฅgstad
Stian Lรฅgstad

๐Ÿ› StuartClayton5
StuartClayton5

๐Ÿ› Supun Arunoda
Supun Arunoda

๐Ÿ› Suren Abrahamyan
Suren Abrahamyan

๐Ÿ› Suvashri
Suvashri

๐Ÿ“– SwatiBGupta1110
SwatiBGupta1110

๐Ÿ› SyedThoufich
SyedThoufich

๐Ÿ› - Szymon Sasin
Szymon Sasin

๐Ÿ› + Szymon Sasin
Szymon Sasin

๐Ÿ› T-chuangxin
T-chuangxin

๐Ÿ› TERAI Atsuhiro
TERAI Atsuhiro

๐Ÿ› TIOBE Software
TIOBE Software

๐Ÿ’ป ๐Ÿ› Tarush Singh
Tarush Singh

๐Ÿ’ป Taylor Smock
Taylor Smock

๐Ÿ› Techeira Damiรกn
Techeira Damiรกn

๐Ÿ’ป ๐Ÿ› - Ted Husted
Ted Husted

๐Ÿ› + Ted Husted
Ted Husted

๐Ÿ› TehBakker
TehBakker

๐Ÿ› The Gitter Badger
The Gitter Badger

๐Ÿ› Theodoor
Theodoor

๐Ÿ› Thiago Henrique Hรผpner
Thiago Henrique Hรผpner

๐Ÿ› Thibault Meyer
Thibault Meyer

๐Ÿ› Thomas Gรผttler
Thomas Gรผttler

๐Ÿ› - Thomas Jones-Low
Thomas Jones-Low

๐Ÿ› + Thomas Jones-Low
Thomas Jones-Low

๐Ÿ› Thomas Smith
Thomas Smith

๐Ÿ’ป ๐Ÿ› ThrawnCA
ThrawnCA

๐Ÿ› Thu Vo
Thu Vo

๐Ÿ› Thunderforge
Thunderforge

๐Ÿ’ป ๐Ÿ› Tim van der Lippe
Tim van der Lippe

๐Ÿ› Tobias Weimer
Tobias Weimer

๐Ÿ’ป ๐Ÿ› - Tom Copeland
Tom Copeland

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– + Tom Copeland
Tom Copeland

๐Ÿ› ๐Ÿ’ป ๐Ÿ“– Tom Daly
Tom Daly

๐Ÿ› Tomas
Tomas

๐Ÿ› Tomer Figenblat
Tomer Figenblat

๐Ÿ› Tomi De Lucca
Tomi De Lucca

๐Ÿ’ป ๐Ÿ› Tony
Tony

๐Ÿ“– Torsten Kleiber
Torsten Kleiber

๐Ÿ› - TrackerSB
TrackerSB

๐Ÿ› + TrackerSB
TrackerSB

๐Ÿ› Tyson Stewart
Tyson Stewart

๐Ÿ› Ullrich Hafner
Ullrich Hafner

๐Ÿ› Utku Cuhadaroglu
Utku Cuhadaroglu

๐Ÿ’ป ๐Ÿ› Valentin Brandl
Valentin Brandl

๐Ÿ› Valeria
Valeria

๐Ÿ› Valery Yatsynovich
Valery Yatsynovich

๐Ÿ“– - Vasily Anisimov
Vasily Anisimov

๐Ÿ› + Vasily Anisimov
Vasily Anisimov

๐Ÿ› Vedant Chokshi
Vedant Chokshi

๐Ÿ› Vibhor Goyal
Vibhor Goyal

๐Ÿ› Vickenty Fesunov
Vickenty Fesunov

๐Ÿ› Victor Noรซl
Victor Noรซl

๐Ÿ› Vincent Galloy
Vincent Galloy

๐Ÿ’ป Vincent HUYNH
Vincent HUYNH

๐Ÿ› - Vincent Maurin
Vincent Maurin

๐Ÿ› + Vincent Maurin
Vincent Maurin

๐Ÿ› Vincent Privat
Vincent Privat

๐Ÿ› Vishhwas
Vishhwas

๐Ÿ› Vishv_Android
Vishv_Android

๐Ÿ› Vitaly
Vitaly

๐Ÿ› Vitaly Polonetsky
Vitaly Polonetsky

๐Ÿ› Vojtech Polivka
Vojtech Polivka

๐Ÿ› - Vsevolod Zholobov
Vsevolod Zholobov

๐Ÿ› + Vsevolod Zholobov
Vsevolod Zholobov

๐Ÿ› Vyom Yadav
Vyom Yadav

๐Ÿ’ป Wang Shidong
Wang Shidong

๐Ÿ› Waqas Ahmed
Waqas Ahmed

๐Ÿ› Wayne J. Earl
Wayne J. Earl

๐Ÿ› Wchenghui
Wchenghui

๐Ÿ› Wener
Wener

๐Ÿ’ป - Will Winder
Will Winder

๐Ÿ› + Will Winder
Will Winder

๐Ÿ› + Willem A. Hajenius
Willem A. Hajenius

๐Ÿ’ป William Brockhus
William Brockhus

๐Ÿ’ป ๐Ÿ› Wilson Kurniawan
Wilson Kurniawan

๐Ÿ› Wim Deblauwe
Wim Deblauwe

๐Ÿ› Woongsik Choi
Woongsik Choi

๐Ÿ› XenoAmess
XenoAmess

๐Ÿ’ป ๐Ÿ› - Yang
Yang

๐Ÿ’ป - YaroslavTER
YaroslavTER

๐Ÿ› + Yang
Yang

๐Ÿ’ป + YaroslavTER
YaroslavTER

๐Ÿ› Yasar Shaikh
Yasar Shaikh

๐Ÿ’ป Young Chan
Young Chan

๐Ÿ’ป ๐Ÿ› YuJin Kim
YuJin Kim

๐Ÿ› Yuri Dolzhenko
Yuri Dolzhenko

๐Ÿ› Yurii Dubinka
Yurii Dubinka

๐Ÿ› - Zoltan Farkas
Zoltan Farkas

๐Ÿ› - Zustin
Zustin

๐Ÿ› + Zoltan Farkas
Zoltan Farkas

๐Ÿ› + Zustin
Zustin

๐Ÿ› aaronhurst-google
aaronhurst-google

๐Ÿ› ๐Ÿ’ป alexmodis
alexmodis

๐Ÿ› andreoss
andreoss

๐Ÿ› andrey81inmd
andrey81inmd

๐Ÿ’ป ๐Ÿ› anicoara
anicoara

๐Ÿ› - arunprasathav
arunprasathav

๐Ÿ› - asiercamara
asiercamara

๐Ÿ› + arunprasathav
arunprasathav

๐Ÿ› + asiercamara
asiercamara

๐Ÿ› astillich-igniti
astillich-igniti

๐Ÿ’ป avesolovksyy
avesolovksyy

๐Ÿ› avishvat
avishvat

๐Ÿ› avivmu
avivmu

๐Ÿ› axelbarfod1
axelbarfod1

๐Ÿ› - b-3-n
b-3-n

๐Ÿ› - balbhadra9
balbhadra9

๐Ÿ› + b-3-n
b-3-n

๐Ÿ› + balbhadra9
balbhadra9

๐Ÿ› base23de
base23de

๐Ÿ› bergander
bergander

๐Ÿ› ๐Ÿ’ป berkam
berkam

๐Ÿ’ป ๐Ÿ› breizh31
breizh31

๐Ÿ› caesarkim
caesarkim

๐Ÿ› - carolyujing
carolyujing

๐Ÿ› - cbfiddle
cbfiddle

๐Ÿ› + carolyujing
carolyujing

๐Ÿ› + cbfiddle
cbfiddle

๐Ÿ› cesares-basilico
cesares-basilico

๐Ÿ› chrite
chrite

๐Ÿ› ciufudean
ciufudean

๐Ÿ“– cobratbq
cobratbq

๐Ÿ› coladict
coladict

๐Ÿ› - cosmoJFH
cosmoJFH

๐Ÿ› - cristalp
cristalp

๐Ÿ› + cosmoJFH
cosmoJFH

๐Ÿ› + cristalp
cristalp

๐Ÿ› crunsk
crunsk

๐Ÿ› cwholmes
cwholmes

๐Ÿ› cyberjj999
cyberjj999

๐Ÿ› cyw3
cyw3

๐Ÿ› ๐Ÿ“– d1ss0nanz
d1ss0nanz

๐Ÿ› - dague1
dague1

๐Ÿ“– - dalizi007
dalizi007

๐Ÿ’ป + dague1
dague1

๐Ÿ“– + dalizi007
dalizi007

๐Ÿ’ป danbrycefairsailcom
danbrycefairsailcom

๐Ÿ› dariansanity
dariansanity

๐Ÿ› darrenmiliband
darrenmiliband

๐Ÿ› davidburstrom
davidburstrom

๐Ÿ› dbirkman-paloalto
dbirkman-paloalto

๐Ÿ› - deepak-patra
deepak-patra

๐Ÿ› - dependabot[bot]
dependabot[bot]

๐Ÿ’ป ๐Ÿ› + deepak-patra
deepak-patra

๐Ÿ› + dependabot[bot]
dependabot[bot]

๐Ÿ’ป ๐Ÿ› dinesh150
dinesh150

๐Ÿ› diziaq
diziaq

๐Ÿ› dreaminpast123
dreaminpast123

๐Ÿ› duanyanan
duanyanan

๐Ÿ› dutt-sanjay
dutt-sanjay

๐Ÿ› - duursma
duursma

๐Ÿ’ป - dylanleung
dylanleung

๐Ÿ› + duursma
duursma

๐Ÿ’ป + dylanleung
dylanleung

๐Ÿ› dzeigler
dzeigler

๐Ÿ› eant60
eant60

๐Ÿ› ekkirala
ekkirala

๐Ÿ› emersonmoura
emersonmoura

๐Ÿ› emouty
emouty

๐Ÿ’ป ๐Ÿ› - eugenepugach
eugenepugach

๐Ÿ› - fairy
fairy

๐Ÿ› + eugenepugach
eugenepugach

๐Ÿ› + fairy
fairy

๐Ÿ› filiprafalowicz
filiprafalowicz

๐Ÿ’ป flxbl-io
flxbl-io

๐Ÿ’ต foxmason
foxmason

๐Ÿ› frankegabor
frankegabor

๐Ÿ› frankl
frankl

๐Ÿ› - freafrea
freafrea

๐Ÿ› - fsapatin
fsapatin

๐Ÿ› + freafrea
freafrea

๐Ÿ› + fsapatin
fsapatin

๐Ÿ› gearsethenry
gearsethenry

๐Ÿ› gracia19
gracia19

๐Ÿ› gudzpoz
gudzpoz

๐Ÿ› guo fei
guo fei

๐Ÿ› gurmsc5
gurmsc5

๐Ÿ› - gwilymatgearset
gwilymatgearset

๐Ÿ’ป ๐Ÿ› - haigsn
haigsn

๐Ÿ› + gwilymatgearset
gwilymatgearset

๐Ÿ’ป ๐Ÿ› + haigsn
haigsn

๐Ÿ› hemanshu070
hemanshu070

๐Ÿ› henrik242
henrik242

๐Ÿ› hongpuwu
hongpuwu

๐Ÿ› hvbtup
hvbtup

๐Ÿ’ป ๐Ÿ› igniti GmbH
igniti GmbH

๐Ÿ› - ilovezfs
ilovezfs

๐Ÿ› - imax-erik
imax-erik

๐Ÿ› + ilovezfs
ilovezfs

๐Ÿ› + imax-erik
imax-erik

๐Ÿ› itaigilo
itaigilo

๐Ÿ› jakivey32
jakivey32

๐Ÿ› jbennett2091
jbennett2091

๐Ÿ› jcamerin
jcamerin

๐Ÿ› jkeener1
jkeener1

๐Ÿ› - jmetertea
jmetertea

๐Ÿ› - johnra2
johnra2

๐Ÿ’ป + jmetertea
jmetertea

๐Ÿ› + johnra2
johnra2

๐Ÿ’ป johnzhao9
johnzhao9

๐Ÿ› josemanuelrolon
josemanuelrolon

๐Ÿ’ป ๐Ÿ› kabroxiko
kabroxiko

๐Ÿ’ป ๐Ÿ› karthikaiyasamy
karthikaiyasamy

๐Ÿ“– karwer
karwer

๐Ÿ› - kaulonline
kaulonline

๐Ÿ› - kdaemonv
kdaemonv

๐Ÿ› + kaulonline
kaulonline

๐Ÿ› + kdaemonv
kdaemonv

๐Ÿ› kdebski85
kdebski85

๐Ÿ› ๐Ÿ’ป kenji21
kenji21

๐Ÿ’ป ๐Ÿ› kfranic
kfranic

๐Ÿ› khalidkh
khalidkh

๐Ÿ› koalalam
koalalam

๐Ÿ› - krzyk
krzyk

๐Ÿ› - lasselindqvist
lasselindqvist

๐Ÿ› + krzyk
krzyk

๐Ÿ› + lasselindqvist
lasselindqvist

๐Ÿ› lgemeinhardt
lgemeinhardt

๐Ÿ› lihuaib
lihuaib

๐Ÿ› liqingjun123
liqingjun123

๐Ÿ› lonelyma1021
lonelyma1021

๐Ÿ› lpeddy
lpeddy

๐Ÿ› - lujiefsi
lujiefsi

๐Ÿ’ป - lukelukes
lukelukes

๐Ÿ’ป + lujiefsi
lujiefsi

๐Ÿ’ป + lukelukes
lukelukes

๐Ÿ’ป lyriccoder
lyriccoder

๐Ÿ› marcelmore
marcelmore

๐Ÿ› matchbox
matchbox

๐Ÿ› matthiaskraaz
matthiaskraaz

๐Ÿ› meandonlyme
meandonlyme

๐Ÿ› - mikesive
mikesive

๐Ÿ› - milossesic
milossesic

๐Ÿ› + mikesive
mikesive

๐Ÿ› + milossesic
milossesic

๐Ÿ› mluckam
mluckam

๐Ÿ’ป ๐Ÿ› mohan-chinnappan-n
mohan-chinnappan-n

๐Ÿ’ป mriddell95
mriddell95

๐Ÿ› mrlzh
mrlzh

๐Ÿ› msloan
msloan

๐Ÿ› - mucharlaravalika
mucharlaravalika

๐Ÿ› - mvenneman
mvenneman

๐Ÿ› + mucharlaravalika
mucharlaravalika

๐Ÿ› + mvenneman
mvenneman

๐Ÿ› nareshl119
nareshl119

๐Ÿ› nicolas-harraudeau-sonarsource
nicolas-harraudeau-sonarsource

๐Ÿ› noerremark
noerremark

๐Ÿ› novsirion
novsirion

๐Ÿ› nwcm
nwcm

๐Ÿ“– ๐Ÿ› ๐Ÿ’ป - oggboy
oggboy

๐Ÿ› - oinume
oinume

๐Ÿ› + oggboy
oggboy

๐Ÿ› + oinume
oinume

๐Ÿ› orimarko
orimarko

๐Ÿ’ป ๐Ÿ› pablogomez2197
pablogomez2197

๐Ÿ› pacvz
pacvz

๐Ÿ’ป pallavi agarwal
pallavi agarwal

๐Ÿ› parksungrin
parksungrin

๐Ÿ› - patpatpat123
patpatpat123

๐Ÿ› - patriksevallius
patriksevallius

๐Ÿ› + patpatpat123
patpatpat123

๐Ÿ› + patriksevallius
patriksevallius

๐Ÿ› pbrajesh1
pbrajesh1

๐Ÿ› phoenix384
phoenix384

๐Ÿ› piotrszymanski-sc
piotrszymanski-sc

๐Ÿ’ป plan3d
plan3d

๐Ÿ› poojasix
poojasix

๐Ÿ› - prabhushrikant
prabhushrikant

๐Ÿ› - pujitha8783
pujitha8783

๐Ÿ› + prabhushrikant
prabhushrikant

๐Ÿ› + pujitha8783
pujitha8783

๐Ÿ› r-r-a-j
r-r-a-j

๐Ÿ› raghujayjunk
raghujayjunk

๐Ÿ› rajeshveera
rajeshveera

๐Ÿ› rajeswarreddy88
rajeswarreddy88

๐Ÿ› recdevs
recdevs

๐Ÿ› - reudismam
reudismam

๐Ÿ’ป ๐Ÿ› - rijkt
rijkt

๐Ÿ› + reudismam
reudismam

๐Ÿ’ป ๐Ÿ› + rijkt
rijkt

๐Ÿ› rillig-tk
rillig-tk

๐Ÿ› rmohan20
rmohan20

๐Ÿ’ป ๐Ÿ› rnveach
rnveach

๐Ÿ› rxmicro
rxmicro

๐Ÿ› ryan-gustafson
ryan-gustafson

๐Ÿ’ป ๐Ÿ› - sabi0
sabi0

๐Ÿ› - scais
scais

๐Ÿ› + sabi0
sabi0

๐Ÿ› + scais
scais

๐Ÿ› schosin
schosin

๐Ÿ› screamingfrog
screamingfrog

๐Ÿ’ต sebbASF
sebbASF

๐Ÿ› sergeygorbaty
sergeygorbaty

๐Ÿ’ป shilko2013
shilko2013

๐Ÿ› - shiomiyan
shiomiyan

๐Ÿ“– - simeonKondr
simeonKondr

๐Ÿ› + shiomiyan
shiomiyan

๐Ÿ“– + simeonKondr
simeonKondr

๐Ÿ› snajberk
snajberk

๐Ÿ› sniperrifle2004
sniperrifle2004

๐Ÿ› snuyanzin
snuyanzin

๐Ÿ› ๐Ÿ’ป soloturn
soloturn

๐Ÿ› soyodream
soyodream

๐Ÿ› - sratz
sratz

๐Ÿ› - stonio
stonio

๐Ÿ› + sratz
sratz

๐Ÿ› + stonio
stonio

๐Ÿ› sturton
sturton

๐Ÿ’ป ๐Ÿ› sudharmohan
sudharmohan

๐Ÿ› suruchidawar
suruchidawar

๐Ÿ› svenfinitiv
svenfinitiv

๐Ÿ› szymanp23
szymanp23

๐Ÿ› ๐Ÿ’ป - tashiscool
tashiscool

๐Ÿ› - test-git-hook
test-git-hook

๐Ÿ› + tashiscool
tashiscool

๐Ÿ› + test-git-hook
test-git-hook

๐Ÿ› testation21
testation21

๐Ÿ’ป ๐Ÿ› thanosa
thanosa

๐Ÿ› tiandiyixian
tiandiyixian

๐Ÿ› tobwoerk
tobwoerk

๐Ÿ› tprouvot
tprouvot

๐Ÿ› ๐Ÿ’ป - trentchilders
trentchilders

๐Ÿ› - triandicAnt
triandicAnt

๐Ÿ› + trentchilders
trentchilders

๐Ÿ› + triandicAnt
triandicAnt

๐Ÿ› trishul14
trishul14

๐Ÿ› tsui
tsui

๐Ÿ› wangzitom12306
wangzitom12306

๐Ÿ› winhkey
winhkey

๐Ÿ› witherspore
witherspore

๐Ÿ› - wjljack
wjljack

๐Ÿ› - wuchiuwong
wuchiuwong

๐Ÿ› + wjljack
wjljack

๐Ÿ› + wuchiuwong
wuchiuwong

๐Ÿ› xingsong
xingsong

๐Ÿ› xioayuge
xioayuge

๐Ÿ› xnYi9wRezm
xnYi9wRezm

๐Ÿ’ป ๐Ÿ› xuanuy
xuanuy

๐Ÿ› xyf0921
xyf0921

๐Ÿ› - yalechen-cyw3
yalechen-cyw3

๐Ÿ› - yasuharu-sato
yasuharu-sato

๐Ÿ› + yalechen-cyw3
yalechen-cyw3

๐Ÿ› + yasuharu-sato
yasuharu-sato

๐Ÿ› zenglian
zenglian

๐Ÿ› zgrzyt93
zgrzyt93

๐Ÿ’ป ๐Ÿ› zh3ng
zh3ng

๐Ÿ› zt_soft
zt_soft

๐Ÿ› ztt79
ztt79

๐Ÿ› - zzzzfeng
zzzzfeng

๐Ÿ› - รrpรกd Magosรกnyi
รrpรกd Magosรกnyi

๐Ÿ› + zzzzfeng
zzzzfeng

๐Ÿ› + รrpรกd Magosรกnyi
รrpรกd Magosรกnyi

๐Ÿ› ไปป่ดตๆฐ
ไปป่ดตๆฐ

๐Ÿ› ่Œ…ๅปถๅฎ‰
่Œ…ๅปถๅฎ‰

๐Ÿ’ป From 32f55e22e3df43e3442b8077752d404b2f18eea2 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Thu, 14 Nov 2024 19:18:11 +0100 Subject: [PATCH 28/37] [doc] Update release notes (#5329, #5330) --- docs/pages/release_notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 5fa3ac04b6..44f31cb3cc 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -20,6 +20,7 @@ This is a {{ site.pmd.release_type }} release. * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas + * [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain ### ๐Ÿšจ API Changes From 5931b6601cc14d245c01cedf7f24eed045a6d31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Nov 2024 15:23:52 +0100 Subject: [PATCH 29/37] [java] Fix #5097 - problem with unchecked conversion --- .../pmd/lang/java/types/TypeOps.java | 6 ++++ .../pmd/lang/java/types/SubtypingTest.kt | 9 +++-- .../infer/UnresolvedTypesRecoveryTest.kt | 35 +++++++++++++++++++ .../bestpractices/xml/UnusedPrivateMethod.xml | 32 +++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java index a6ac882819..7f976967d8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java @@ -717,6 +717,12 @@ public final class TypeOps { // no unchecked warning. return allArgsAreUnboundedWildcards(sargs) ? Convertibility.UNCHECKED_NO_WARNING : Convertibility.UNCHECKED_WARNING; + } else if (sargs.isEmpty()) { + // C <: |C| + // JLS 4.10.2 + // unchecked conversion converts a raw type to a generic type + // subtyping converts a generic type to its raw type + return Convertibility.SUBTYPING; } if (targs.size() != sargs.size()) { diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/SubtypingTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/SubtypingTest.kt index 03cfcddb4a..d3b3ba18c6 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/SubtypingTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/SubtypingTest.kt @@ -13,14 +13,14 @@ import io.kotest.property.Exhaustive import io.kotest.property.checkAll import io.kotest.property.exhaustive.ints import io.kotest.property.forAll -import net.sourceforge.pmd.lang.test.ast.shouldBeA import net.sourceforge.pmd.lang.java.ast.ParserTestCtx import net.sourceforge.pmd.lang.java.symbols.internal.UnresolvedClassStore import net.sourceforge.pmd.lang.java.symbols.internal.asm.createUnresolvedAsmSymbol -import net.sourceforge.pmd.lang.java.types.TypeConversion.* -import net.sourceforge.pmd.lang.java.types.TypeOps.Convertibility.* +import net.sourceforge.pmd.lang.java.types.TypeConversion.capture +import net.sourceforge.pmd.lang.java.types.TypeOps.Convertibility.UNCHECKED_NO_WARNING import net.sourceforge.pmd.lang.java.types.testdata.ComparableList import net.sourceforge.pmd.lang.java.types.testdata.SomeEnum +import net.sourceforge.pmd.lang.test.ast.shouldBeA import kotlin.test.assertTrue /** @@ -187,6 +187,9 @@ class SubtypingTest : FunSpec({ Class shouldBeUncheckedSubtypeOf `Class{String}` ts.STRING shouldBeSubtypeOf `Comparable{Wildcard}` + + val unresolvedT = ts.createUnresolvedAsmSymbol("foo") + unresolvedT[`?`] shouldBeSubtypeOf ts.rawType(unresolvedT) } test("Test wildcard subtyping") { diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt index 45c13cf569..82fdf359cd 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt @@ -702,4 +702,39 @@ class C { buildItem.methodType.symbol shouldBe buildItemDecl } } + + parserTest("Unresolved type should also allow unchecked conversion") { + // The problem here is that ConstraintViolation is not convertible to ConstraintViolation, + // because ConstraintViolation is not on the classpath. + + val (acu, _) = parser.parseWithTypeInferenceSpy( + """ + import java.util.Set; + class Foo { + private void foo(ConstraintViolation constraintViolation) { + constraintViolation.toString(); + } + + public void foos(Set> constraintViolations) { + constraintViolations.forEach(this::foo); + } + + } + """ + ) + +// val (foreach) = acu.methodCalls().toList() + val constraintViolationT = acu.descendants(ASTClassType::class.java) + .filter { it.simpleName == "ConstraintViolation" } + .firstOrThrow().typeMirror.symbol as JClassSymbol + val (fooDecl) = acu.methodDeclarations().toList { it.symbol } + val (mref) = acu.descendants(ASTMethodReference::class.java).toList() + + acu.withTypeDsl { + mref.referencedMethod.symbol shouldBe fooDecl + + mref shouldHaveType java.util.function.Consumer::class[constraintViolationT[`?`]] + + } + } }) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 1a6dd1488d..87f89cd75b 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2218,4 +2218,36 @@ public class ObtainViaTest { } ]]> + + #5097 UnusedPrivateMethod with unresolved target for method reference + 0 + > listOfLists) { + listOfLists.forEach(this::doWork); + } + + //BUT this does??? + //UnusedPrivateMethod - this as a false positive - but what is different? + private void addValidationError(ConstraintViolation constraintViolation) { + constraintViolation.toString(); + } + + public void addValidationErrors(Set> constraintViolations) { + constraintViolations.forEach(this::addValidationError); + } + + } + ]]> + From a72ac5845b20f26552327d090ffd468a498298c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Nov 2024 16:14:09 +0100 Subject: [PATCH 30/37] Add test for #5113 --- .../bestpractices/xml/UnusedPrivateMethod.xml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 1a6dd1488d..ae0fc5e242 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2218,4 +2218,24 @@ public class ObtainViaTest { } ]]> + + + UnusedPrivateMethod #5113 + 0 + foo(int param) { + var optional = param == 0 ? Optional.of(true) : Optional.of(false); + return optional.flatMap(this::dummy); + } + + private Optional dummy(boolean foo) { + return Optional.of(foo); + } + } + ]]> + + From b264fa14e15f8db96b6bee4ffc0f2e91444f6d16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Fri, 15 Nov 2024 16:28:08 +0100 Subject: [PATCH 31/37] Fix #5083 - mref without target type but with exact method has compile time decl --- .../lang/java/types/internal/infer/Infer.java | 15 +++-- .../internal/infer/MethodRefInferenceTest.kt | 41 ++++++++++++- .../infer/UnresolvedTypesRecoveryTest.kt | 6 +- .../bestpractices/xml/UnusedPrivateMethod.xml | 59 +++++++++++++++++++ 4 files changed, 111 insertions(+), 10 deletions(-) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java index 7982304210..e51ef905f2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/Infer.java @@ -36,7 +36,6 @@ import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.CtorInvocat import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.FunctionalExprMirror; import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror; import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror.MethodCtDecl; -import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.LambdaExprMirror; import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.MethodRefMirror; import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.PolyExprMirror; import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind; @@ -145,13 +144,19 @@ public final class Infer { LOG.logResolutionFail(rfe.getFailure()); // here we set expected if not null, the lambda will have the target type expr.setInferredType(expected == null ? ts.UNKNOWN : expected); + expr.setFunctionalMethod(ts.UNRESOLVED_METHOD); if (expr instanceof MethodRefMirror) { MethodRefMirror mref = (MethodRefMirror) expr; - mref.setFunctionalMethod(ts.UNRESOLVED_METHOD); + if (!TypeOps.isUnresolved(mref.getTypeToSearch())) { + JMethodSig exactMethod = ExprOps.getExactMethod(mref); + if (exactMethod != null) { + // as a fallback, if the method reference is exact, + // we populate the compile time decl anyway. + mref.setCompileTimeDecl(exactMethod); + return; + } + } mref.setCompileTimeDecl(ts.UNRESOLVED_METHOD); - } else { - LambdaExprMirror lambda = (LambdaExprMirror) expr; - lambda.setFunctionalMethod(ts.UNRESOLVED_METHOD); } } } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/MethodRefInferenceTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/MethodRefInferenceTest.kt index e928dda72b..ef10cf77df 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/MethodRefInferenceTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/MethodRefInferenceTest.kt @@ -5,12 +5,12 @@ package net.sourceforge.pmd.lang.java.types.internal.infer import io.kotest.matchers.shouldBe +import net.sourceforge.pmd.lang.java.ast.* +import net.sourceforge.pmd.lang.java.types.* import net.sourceforge.pmd.lang.test.ast.component6 import net.sourceforge.pmd.lang.test.ast.component7 import net.sourceforge.pmd.lang.test.ast.shouldBe import net.sourceforge.pmd.lang.test.ast.shouldMatchN -import net.sourceforge.pmd.lang.java.ast.* -import net.sourceforge.pmd.lang.java.types.* import java.util.* import java.util.function.* import java.util.stream.Collector @@ -331,12 +331,13 @@ class MethodRefInferenceTest : ProcessorTestSpec({ val t_Archive = acu.firstTypeSignature() val mref = acu.descendants(ASTMethodReference::class.java).firstOrThrow() + val (getName) = acu.declaredMethodSignatures().toList() val call = acu.firstMethodCall() spy.shouldHaveMissingCtDecl(call) acu.withTypeDsl { - mref.referencedMethod shouldBe ts.UNRESOLVED_METHOD + mref.referencedMethod shouldBe getName mref shouldHaveType ts.UNKNOWN call.methodType shouldBe ts.UNRESOLVED_METHOD call.overloadSelectionInfo.apply { @@ -1093,4 +1094,38 @@ class Scratch { mref shouldHaveType t_Additioner } } + + parserTest("Method ref without target type still populates CTDecl if exact") { + val (acu, spy) = parser.parseWithTypeInferenceSpy( + """ + class GenerationType { + static { + foo(GenerationType::isAndroidType); + } + { + foo(this::instance); + } + + private boolean instance(String data) {} + private static boolean isAndroidType(String data) { + return "android".equals(data); + } + } + """.trimIndent() + ) + + val (instance, static) = acu.declaredMethodSignatures() + + val mrefs = acu.descendants(ASTMethodReference::class.java).toList() + val (staticMref, instanceMref) = mrefs + + spy.shouldBeOk { + mrefs.forEach { + it shouldHaveType ts.UNKNOWN + it.functionalMethod shouldBe ts.UNRESOLVED_METHOD + } + instanceMref.referencedMethod shouldBe instance + staticMref.referencedMethod shouldBe static + } + } }) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt index 45c13cf569..7a8b14a2af 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/UnresolvedTypesRecoveryTest.kt @@ -530,6 +530,7 @@ class C { val (mref) = acu.descendants(ASTMethodReference::class.java).toList() val (lambdaCall, mrefCall) = acu.descendants(ASTMethodCall::class.java).toList() + val (fooDecl) = acu.declaredMethodSignatures().toList() spy.shouldHaveNoApplicableMethods(lambdaCall) spy.shouldHaveNoApplicableMethods(mrefCall) @@ -540,7 +541,7 @@ class C { mref shouldHaveType ts.UNKNOWN mref.functionalMethod shouldBe ts.UNRESOLVED_METHOD - mref.referencedMethod shouldBe ts.UNRESOLVED_METHOD + mref.referencedMethod shouldBe fooDecl // still populated because unambiguous } } @@ -562,6 +563,7 @@ class C { val (lambda) = acu.descendants(ASTLambdaExpression::class.java).toList() val (mref) = acu.descendants(ASTMethodReference::class.java).toList() + val (fooDecl) = acu.declaredMethodSignatures().toList() spy.shouldHaveNoLambdaCtx(lambda) spy.shouldHaveNoLambdaCtx(mref) @@ -572,7 +574,7 @@ class C { mref shouldHaveType ts.UNKNOWN mref.functionalMethod shouldBe ts.UNRESOLVED_METHOD - mref.referencedMethod shouldBe ts.UNRESOLVED_METHOD + mref.referencedMethod shouldBe fooDecl // still populated because unambiguous } } diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index ae0fc5e242..5f38fdcf2e 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2237,5 +2237,64 @@ public class ObtainViaTest { } ]]> + + UnusedPrivateMethod #5083 - method reference without target type + 0 + predicate; + + private static boolean isAppleType(String data) { + return "apple".equals(data); + } + + private static boolean isRokuType(String data) { + return "roku".equals(data); + } + + private static boolean isSamsungType(String data) { + return "samsung".equals(data); + } + + private static boolean isAmazonType(String data) { + return "amazon".equals(data); + } + + private static boolean isAndroidType(String data) { + return "android".equals(data); + } + } + ]]> + + + + UnusedPrivateMethod #5083 - method reference without target type (2) + 0 + + From aad8e93a2f71ed5daa53c892e24eb63ea06a8418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 15 Nov 2024 16:13:44 -0300 Subject: [PATCH 32/37] Add test case ensuring we don't incur in FNs --- .../bestpractices/xml/UnusedPrivateMethod.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 5f38fdcf2e..12b92436d9 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2297,4 +2297,20 @@ public class ObtainViaTest { ]]> + + UnusedPrivateMethod #5083 - method reference without target type (3) + 2 + s) { + s.forEach(this::foo); // Not being able to resolve UnresolvedType and AnotherUnresolvedType means we can't tell which foo is being used hereโ€ฆ + } +} + ]]> + + From a6746fcffaf28ce5e477134618c845ac2b48f491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 15 Nov 2024 16:14:53 -0300 Subject: [PATCH 33/37] Update changelog, refs #5083 --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index e64354df24..c1d07eb028 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -25,6 +25,8 @@ This is a {{ site.pmd.release_type }} release. * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas * [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain +* java-bestpractices + * [#5083](https://github.com/pmd/pmd/issues/5083): \[java] UnusedPrivateMethod false positive when method reference has no target type * java-performance * [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters From b6f45ed6187bebdefc4a51f058d6655d5cfdffc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 15 Nov 2024 17:54:35 -0300 Subject: [PATCH 34/37] Ensure types don't match --- .../lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 12b92436d9..329eaaf54b 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2306,7 +2306,7 @@ import java.util.Set; public class Foo { private void foo(AnotherUnresolvedType baz) {} private void foo(UnresolvedType baz) {} - public void bar(Set s) { + public void bar(Set s) { s.forEach(this::foo); // Not being able to resolve UnresolvedType and AnotherUnresolvedType means we can't tell which foo is being used hereโ€ฆ } } From 15cab177d237d838fcc4da6a7ca8a0617c43a74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 15 Nov 2024 18:30:03 -0300 Subject: [PATCH 35/37] Remove added test --- .../bestpractices/xml/UnusedPrivateMethod.xml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 329eaaf54b..548b16a161 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -2296,21 +2296,4 @@ public class ObtainViaTest { } ]]> - - - UnusedPrivateMethod #5083 - method reference without target type (3) - 2 - s) { - s.forEach(this::foo); // Not being able to resolve UnresolvedType and AnotherUnresolvedType means we can't tell which foo is being used hereโ€ฆ - } -} - ]]> - - From ee1ab976bc41fe307397975eddfa63056e33d314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Sotuyo=20Dodero?= Date: Fri, 15 Nov 2024 18:39:39 -0300 Subject: [PATCH 36/37] update changelog, refs #5097 --- docs/pages/release_notes.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index e64354df24..60fdbc6a45 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -25,6 +25,8 @@ This is a {{ site.pmd.release_type }} release. * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas * [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain +* java-bestpractices + * [#5097](https://github.com/pmd/pmd/issues/5097): \[java] UnusedPrivateMethod FP with raw type missing from the classpath * java-performance * [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters From a5925eb5ea6dc2ed4b980d1d0a2276977b1ae184 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 17 Nov 2024 15:24:49 +0100 Subject: [PATCH 37/37] [doc] Fix typo in release notes --- docs/pages/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 4469d3528b..496f8a26cb 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -20,7 +20,7 @@ This is a {{ site.pmd.release_type }} release. * apex * [#5333](https://github.com/pmd/pmd/issues/5333): \[apex] Token recognition errors for string containing unicode escape sequence * html - * [5322](https://github.com/pmd/pmd/issues/5322): \[html] CPD throws exception on when HTML file is missing closing tag + * [#5322](https://github.com/pmd/pmd/issues/5322): \[html] CPD throws exception on when HTML file is missing closing tag * java * [#5293](https://github.com/pmd/pmd/issues/5293): \[java] Deadlock when executing PMD in multiple threads * [#5324](https://github.com/pmd/pmd/issues/5324): \[java] Issue with type inference of nested lambdas