diff --git a/.all-contributorsrc b/.all-contributorsrc index 95ebc05d6e..e26a244d2f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7865,6 +7865,24 @@ "contributions": [ "code" ] + }, + { + "login": "chenguangqi", + "name": "天热吃西瓜", + "avatar_url": "https://avatars.githubusercontent.com/u/6231010?v=4", + "profile": "http://chenguangqi.github.io/", + "contributions": [ + "bug" + ] + }, + { + "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..b6ccbdf647 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -350,770 +350,773 @@ 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

🐛 任贵杰
任贵杰

🐛 + 天热吃西瓜
天热吃西瓜

🐛 茅延安
茅延安

💻 diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 3a1b90322b..e64354df24 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -17,11 +17,16 @@ 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 +* html + * [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 -* html - * [5322](https://github.com/pmd/pmd/issues/5322): \[html] CPD throws exception on when HTML file is missing closing tag + * [#5329](https://github.com/pmd/pmd/issues/5329): \[java] Type inference issue with unknown method ref in call chain +* java-performance + * [#5314](https://github.com/pmd/pmd/issues/5314): \[java] InsufficientStringBufferDeclarationRule: Lack of handling for char type parameters ### 🚨 API Changes @@ -31,6 +36,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 %} 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..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,14 +14,19 @@ 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; import io.github.apexdevtools.apexparser.ApexLexer; +import io.github.apexdevtools.apexparser.CaseInsensitiveInputStream; @InternalApi final class ApexCommentBuilder { @@ -103,7 +108,15 @@ 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))); + 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<>(); 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 67c6706f29..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 @@ -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,36 @@ class ApexLexerTest { ApexParser.CompilationUnitContext compilationUnit = parser.compilationUnit(); assertNotNull(compilationUnit); } + + @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)))); + } + + 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(); + } + + private 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; + } + } } 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/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/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/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/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))); + } + } 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/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 + + 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[]