diff --git a/.travis/build-deploy.sh b/.travis/build-deploy.sh index 8d26b44b08..ece8029a7b 100755 --- a/.travis/build-deploy.sh +++ b/.travis/build-deploy.sh @@ -60,9 +60,14 @@ elif travis_isPullRequest; then log_info "This is a pull-request build" ./mvnw verify $MVN_BUILD_FLAGS ( - set +e - log_info "Running danger" - bundle exec danger --verbose + set +e + # Create a corresponding remote branch locally + if ! git show-ref --verify --quiet refs/heads/${TRAVIS_BRANCH}; then + git fetch --no-tags origin +refs/heads/${TRAVIS_BRANCH}:refs/remotes/origin/${TRAVIS_BRANCH} + git branch ${TRAVIS_BRANCH} origin/${TRAVIS_BRANCH} + fi + log_info "Running danger" + bundle exec danger --verbose ) elif travis_isPush; then diff --git a/.travis/install-openjdk.sh b/.travis/install-openjdk.sh index 017b50d488..3204cf0b95 100644 --- a/.travis/install-openjdk.sh +++ b/.travis/install-openjdk.sh @@ -1,21 +1,18 @@ # -# Original sources: -# Linux: https://github.com/AdoptOpenJDK/openjdk11-upstream-binaries/releases/jdk-11.0.3%2B7/ -# https://github.com/AdoptOpenJDK/openjdk11-upstream-binaries/releases/download/jdk-11.0.3%2B7/OpenJDK11U-x64_linux_11.0.3_7.tar.gz -# MacOSX: https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/jdk-11.0.3%2B7/ -# https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.3%2B7/OpenJDK11U-jdk_x64_mac_hotspot_11.0.3_7.tar.gz +# AdoptOpenJDK Builds from: +# https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/tag/jdk-11.0.4%2B11 # - if [[ "$OSTYPE" == "darwin"* ]]; then - OPENJDK_ARCHIVE=OpenJDK11U-jdk_x64_mac_hotspot_11.0.3_7.tar.gz + DOWNLOAD_URL=https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.4%2B11/OpenJDK11U-jdk_x64_mac_hotspot_11.0.4_11.tar.gz COMPONENTS_TO_STRIP=3 # e.g. jdk-11.0.3+7/Contents/Home/bin/java else - OPENJDK_ARCHIVE=OpenJDK11U-x64_linux_11.0.3_7.tar.gz + DOWNLOAD_URL=https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.4%2B11/OpenJDK11U-jdk_x64_linux_hotspot_11.0.4_11.tar.gz COMPONENTS_TO_STRIP=1 # e.g. openjdk-11.0.3+7/bin/java fi -DOWNLOAD_URL=https://pmd-code.org/${OPENJDK_ARCHIVE} +OPENJDK_ARCHIVE=$(basename $DOWNLOAD_URL) + LOCAL_DIR=${HOME}/.cache/openjdk TARGET_DIR=${HOME}/openjdk11 diff --git a/README.md b/README.md index b2ff396ea5..4ffb7c745d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ unnecessary object creation, and so forth. It supports Java, JavaScript, Salesfo XML, XSL. Additionally it includes **CPD**, the copy-paste-detector. CPD finds duplicated code in -C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Matlab, +C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex, Scala, Swift and Visualforce. ## Source and Documentation diff --git a/docs/_config.yml b/docs/_config.yml index df529ab2e4..ff47ffbc19 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,9 +1,9 @@ repository: pmd/pmd pmd: - version: 6.15.0 - previous_version: 6.14.0 - date: ??-May-2019 + version: 6.18.0 + previous_version: 6.17.0 + date: ??-August-2019 release_type: minor # release types: major, minor, bugfix diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 0841643c75..2249c13118 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -67,6 +67,9 @@ entries: - title: Writing XPath rules url: /pmd_userdocs_extending_writing_xpath_rules.html output: web, pdf + - title: Rule designer reference + url: /pmd_userdocs_extending_designer_reference.html + output: web, pdf - title: Defining rule properties url: /pmd_userdocs_extending_defining_properties.html output: web, pdf @@ -253,6 +256,21 @@ entries: - title: Security output: web, pdf url: /pmd_rules_vf_security.html + - title: null + output: web, pdf + subfolders: + - title: Swift Rules + output: web, pdf + subfolderitems: + - title: Index + output: web, pdf + url: /pmd_rules_swift.html + - title: Best Practices + output: web, pdf + url: /pmd_rules_swift_bestpractices.html + - title: Error Prone + output: web, pdf + url: /pmd_rules_swift_errorprone.html - title: null output: web, pdf subfolders: diff --git a/docs/_plugins/details_block.rb b/docs/_plugins/details_block.rb new file mode 100644 index 0000000000..db2a87050a --- /dev/null +++ b/docs/_plugins/details_block.rb @@ -0,0 +1,22 @@ +# Mimics an HTML
element +# Courtesy of https://github.com/towbi (https://gist.github.com/towbi/a67fda47e075d2b7fa4764bb42605063) +class DetailsTag < Liquid::Block + + def initialize(tag_name, markup, tokens) + super + @caption = markup + end + + def render(context) + site = context.registers[:site] + converter = site.find_converter_instance(::Jekyll::Converters::Markdown) + # below Jekyll 3.x use this: + # converter = site.getConverterImpl(::Jekyll::Converters::Markdown) + caption = converter.convert(@caption).gsub(/<\/?p[^>]*>/, '').chomp + body = converter.convert(super(context)) + "
#{caption}#{body}
" + end + +end + +Liquid::Template.register_tag('details', DetailsTag) diff --git a/docs/css/pmd-customstyles.css b/docs/css/pmd-customstyles.css index e9de59c713..2738de8db1 100644 --- a/docs/css/pmd-customstyles.css +++ b/docs/css/pmd-customstyles.css @@ -19,4 +19,36 @@ top: 50px; /* height of the nav bar */ bottom: 0px; width: 100%; -} \ No newline at end of file +} + +details { + border-radius: 3px; + background: #EEE; + margin-left: 10px; +} + +details p { + padding: 5px 10px 5px; + background: white; +} + +details summary { + font-size: 11pt; + vertical-align: top; + background: #d2d2d2; + color: black; + border-radius: 3px; + padding: 5px 10px; + outline: none; + cursor: pointer; + display: list-item; +} + +details summary::after { + content: "..."; +} + +details[open] summary { + background-color: #347DBE; + color: white; +} diff --git a/docs/images/designer/bottom-ui.png b/docs/images/designer/bottom-ui.png new file mode 100644 index 0000000000..64015fb7e8 Binary files /dev/null and b/docs/images/designer/bottom-ui.png differ diff --git a/docs/images/designer/demo.gif b/docs/images/designer/demo.gif new file mode 100644 index 0000000000..405712d484 Binary files /dev/null and b/docs/images/designer/demo.gif differ diff --git a/docs/images/designer/designer-top.png b/docs/images/designer/designer-top.png new file mode 100644 index 0000000000..45942a0ed4 Binary files /dev/null and b/docs/images/designer/designer-top.png differ diff --git a/docs/images/designer/designer.png b/docs/images/designer/designer.png new file mode 100644 index 0000000000..1068d6ce28 Binary files /dev/null and b/docs/images/designer/designer.png differ diff --git a/docs/images/designer/empty-tests.png b/docs/images/designer/empty-tests.png new file mode 100644 index 0000000000..6c71392b84 Binary files /dev/null and b/docs/images/designer/empty-tests.png differ diff --git a/docs/images/designer/export-example.gif b/docs/images/designer/export-example.gif new file mode 100644 index 0000000000..92af52fda9 Binary files /dev/null and b/docs/images/designer/export-example.gif differ diff --git a/docs/images/designer/hover-selection.gif b/docs/images/designer/hover-selection.gif new file mode 100644 index 0000000000..09bdc6bb7d Binary files /dev/null and b/docs/images/designer/hover-selection.gif differ diff --git a/docs/images/designer/parents-bar.gif b/docs/images/designer/parents-bar.gif new file mode 100644 index 0000000000..9a266db4b1 Binary files /dev/null and b/docs/images/designer/parents-bar.gif differ diff --git a/docs/images/designer/property-defs.png b/docs/images/designer/property-defs.png new file mode 100644 index 0000000000..54e3091976 Binary files /dev/null and b/docs/images/designer/property-defs.png differ diff --git a/docs/images/designer/property-edit.png b/docs/images/designer/property-edit.png new file mode 100644 index 0000000000..5470ad206f Binary files /dev/null and b/docs/images/designer/property-edit.png differ diff --git a/docs/images/designer/tests/add-violation.gif b/docs/images/designer/tests/add-violation.gif new file mode 100644 index 0000000000..c2b71ba494 Binary files /dev/null and b/docs/images/designer/tests/add-violation.gif differ diff --git a/docs/images/designer/tests/all-green.png b/docs/images/designer/tests/all-green.png new file mode 100644 index 0000000000..51264bf9ae Binary files /dev/null and b/docs/images/designer/tests/all-green.png differ diff --git a/docs/images/designer/tests/export.gif b/docs/images/designer/tests/export.gif new file mode 100644 index 0000000000..b2d36c89db Binary files /dev/null and b/docs/images/designer/tests/export.gif differ diff --git a/docs/images/designer/tests/failing.png b/docs/images/designer/tests/failing.png new file mode 100644 index 0000000000..96f8f14842 Binary files /dev/null and b/docs/images/designer/tests/failing.png differ diff --git a/docs/images/designer/tests/import.gif b/docs/images/designer/tests/import.gif new file mode 100644 index 0000000000..4aac308cce Binary files /dev/null and b/docs/images/designer/tests/import.gif differ diff --git a/docs/images/designer/tests/load.gif b/docs/images/designer/tests/load.gif new file mode 100644 index 0000000000..79b56a62bf Binary files /dev/null and b/docs/images/designer/tests/load.gif differ diff --git a/docs/images/designer/tests/property.gif b/docs/images/designer/tests/property.gif new file mode 100644 index 0000000000..0178084e6a Binary files /dev/null and b/docs/images/designer/tests/property.gif differ diff --git a/docs/images/designer/tests/toolbar.png b/docs/images/designer/tests/toolbar.png new file mode 100644 index 0000000000..8728ce7730 Binary files /dev/null and b/docs/images/designer/tests/toolbar.png differ diff --git a/docs/images/designer/usages.gif b/docs/images/designer/usages.gif new file mode 100644 index 0000000000..d637f46f14 Binary files /dev/null and b/docs/images/designer/usages.gif differ diff --git a/docs/pages/7_0_0_release_notes.md b/docs/pages/7_0_0_release_notes.md index c4c68d4bdc..b044ecaa4d 100644 --- a/docs/pages/7_0_0_release_notes.md +++ b/docs/pages/7_0_0_release_notes.md @@ -19,6 +19,27 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Full Antlr support + +Languages backed by an Antlr grammar are now fully supported. This means, it's now possible not only to use Antlr grammars for CPD, +but we can actually build full-fledged PMD rules for them as well. Both the traditional Java visitor rules, and the simpler +XPath rules are available to users. + +We expect this to enable both our dev team and external contributors to largely extend PMD usage for more languages. + +#### Swift support + +Given the full Antlr support, PMD now fully supports Swift. We are pleased to announce we are shipping a number of rules starting with PMD 7. + +* {% rule "swift/errorprone/ForceCast" %} (`swift-errorprone`) flags all force casts, making sure you are defensively considering all types. + Having the application crash shouldn't be an option. +* {% rule "swift/errorprone/ForceTry" %} (`swift-errorprone`) flags all force tries, making sure you are defensively handling exceptions. + Having the application crash shouldn't be an option. +* {% rule "swift/bestpractices/ProhibitedInterfaceBuilder" %} (`swift-bestpractices`) flags any usage of interface builder. Interface builder + files are prone to merge conflicts, and are impossible to code review, so larger teams usually try to avoid it or reduce it's usage. +* {% rule "swift/bestpractices/UnavailableFunction" %} (`swift-bestpractices`) flags any function throwing a `fatalError` not marked as + `@available(*, unavailable)` to ensure no calls are actually performed in the codebase. + ### Fixed Issues ### API Changes @@ -34,7 +55,11 @@ This is a {{ site.pmd.release_type }} release. ### External Contributions -* [#1658](https://github.com/pmd/pmd/pull/1658/): \[core] Node support for Antlr-based languages +* [#1658](https://github.com/pmd/pmd/pull/1658): \[core] Node support for Antlr-based languages - [Matías Fraga](https://github.com/matifraga) +* [#1698](https://github.com/pmd/pmd/pull/1698): \[core] [swift] Antlr Base Parser adapter and Swift Implementation - [Lucas Soncini](https://github.com/lsoncini) +* [#1774](https://github.com/pmd/pmd/pull/1774): \[core] Antlr visitor rules - [Lucas Soncini](https://github.com/lsoncini) +* [#1877](https://github.com/pmd/pmd/pull/1877): \[swift] Feature/swift rules - [Matias Fraga](https://github.com/matifraga) +* [#1882](https://github.com/pmd/pmd/pull/1882): \[swift] UnavailableFunction Swift rule - [Tomás de Lucca](https://github.com/tomidelucca) {% endtocmaker %} diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index 2586d1d946..a979294adf 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -73,6 +73,52 @@ the breaking API changes will be performed in 7.0.0. an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0, we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %} +#### 6.17.0 + +No changes. + +#### 6.16.0 + +##### Deprecated APIs + +> Reminder: Please don't use members marked with the annotation {% jdoc core::annotation.InternalApi %}, as they will likely be removed, hidden, or otherwise intentionally broken with 7.0.0. + + +###### In ASTs + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the Java AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and marked {% jdoc core::annotation.InternalApi %}. Nodes should only be obtained from the parser, which for rules, means that never need to instantiate node themselves. Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. Version 7.0.0 will bring a new set of abstractions that will be public API, but the base classes are and will stay internal. You should not couple your code to them. + * In the meantime you should use interfaces like {% jdoc java::lang.java.ast.JavaNode %} or {% jdoc core::lang.ast.Node %}, or the other published interfaces in this package, to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. We will make those setters package private with 7.0.0. + +Please look at {% jdoc_package java::lang.java.ast %} to find out the full list +of deprecations. + + +#### 6.15.0 + +##### Deprecated APIs + +###### For removal + +* The `DumpFacades` in all languages, that could be used to transform a AST into a textual representation, + will be removed with PMD 7. The rule designer is a better way to inspect nodes. + * {% jdoc !q!apex::lang.apex.ast.DumpFacade %} + * {% jdoc !q!java::lang.java.ast.DumpFacade %} + * {% jdoc !q!javascript::lang.ecmascript.ast.DumpFacade %} + * {% jdoc !q!jsp::lang.jsp.ast.DumpFacade %} + * {% jdoc !q!plsql::lang.plsql.ast.DumpFacade %} + * {% jdoc !q!visualforce::lang.vf.ast.DumpFacade %} + * {% jdoc !q!vm::lang.vm.ast.AbstractVmNode#dump(String, boolean, Writer) %} + * {% jdoc !q!xml::lang.xml.ast.DumpFacade %} +* The method {% jdoc !c!core::lang.LanguageVersionHandler#getDumpFacade(Writer, String, boolean) %} will be + removed as well. It is deprecated, along with all its implementations in the subclasses of {% jdoc core::lang.LanguageVersionHandler %}. + #### 6.14.0 No changes. diff --git a/docs/pages/pmd/projectdocs/trivia/news.md b/docs/pages/pmd/projectdocs/trivia/news.md index 5c7b3c0e6e..b9a2112c1b 100644 --- a/docs/pages/pmd/projectdocs/trivia/news.md +++ b/docs/pages/pmd/projectdocs/trivia/news.md @@ -6,6 +6,24 @@ author: Tom Copeland ## Sites/Articles about PMD + +### Salesforce / Apex Language Module + +* June 2019 - [Pluralsight](https://www.pluralsight.com/authors/don-robins) Course about leveraging PMD usage for Salesforce by [Robert Sösemann](https://github.com/rsoesemann) (Apex Language Module Contributor) [Play by Play: Automated Code Analysis in Salesforce - a Tools Deep-Dive](https://www.pluralsight.com/courses/play-by-play-automated-code-analysis-in-salesforce) + +* June 2018 - [Salesforce Way Podcast](https://salesforceway.com/podcast/podcast/) with [Robert Sösemann](https://github.com/rsoesemann) [Static Code Analysis with PMD for Apex](https://salesforceway.com/podcast/podcast/static-code-analysis-with-pmd-for-apex/) + +* January 2018 - [Webinar: How to contribute Apex rules to PMD with Robert Sösemann](https://www.youtube.com/watch?v=7_Ex9WWS_3Q) + +* August 2017 - Webinar about how to use PMD with The Welkin Suite Salesforce IDE - Author [Robert Sösemann](https://github.com/rsoesemann) - [Improving your Apex Code Quality with PMD in The Welkin Suite](https://www.youtube.com/watch?v=Ypyiy5b6huc) + +* November 2016 - Recording of [Robert Sösemann](https://github.com/rsoesemann)'s Session at Salesforce Dreamforce Conference about enforcing Clean Code in the Salesforce world using PMD and other tools [Clean Apex Code with Automatic Code Metrics](https://www.youtube.com/watch?v=bW7m6y6bEug) + + +### PMD in general and other Language Modules + +* May 2019 - [Code quality assurance with PMD – An extensible static code analyser for Java and other languages](https://www.datarespons.com/code-quality-assurance-with-pmd/) + * February 2012 - Romain Pelisse's lightning talk at FOSDEM 2012 about "PMD5: What can it do for you?". [Video recording is available](http://video.fosdem.org/2012/lightningtalks/PMD5.webm). @@ -27,7 +45,7 @@ author: Tom Copeland PMD/CPD analyses of Azureus and Columba. * April 2006 - John Ferguson Smart's article "PMD Squashes Code Bugs" on - [DevX](http://www.devx.com/Java/Article/31286) discusses PMD and the Eclipse plugin. Lots of screenshots! + [DevX](https://web.archive.org/web/20140214143838/http://www.devx.com/Java/Article/31286) discusses PMD and the Eclipse plugin. Lots of screenshots! * November 2005 - Mike Clark's article "Staying Out of Code Debt" on [StickyMinds](http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=ART&ObjectId=9860&tth=DYN&tt=siteemail&iDyn=2) @@ -45,7 +63,7 @@ author: Tom Copeland [Doctor Dobb's Journal](http://www.drdobbs.com/benefits-of-the-build/184415286) mentions PMD as a way to automate code reviews -* February 2005 - [Java Is Well-Suited for Open-Source Projects](http://www.eweek.com/c/a/Application-Development/Java-Is-WellSuited-for-OpenSource-Projects/) - +* February 2005 - [Java Is Well-Suited for Open-Source Projects](https://webcache.googleusercontent.com/search?q=cache:aEL-9Ncx2RgJ:https://www.eweek.com/development/java-is-well-suited-for-open-source-projects) - Peter Coffee's eWeek article on open source, Java, and PMD * January 2005 - [Zap bugs with PMD](http://www.ibm.com/developerworks/java/library/j-pmd/) - Elliotte Rusty diff --git a/docs/pages/pmd/rules/apex.md b/docs/pages/pmd/rules/apex.md index dec0347f36..d885409882 100644 --- a/docs/pages/pmd/rules/apex.md +++ b/docs/pages/pmd/rules/apex.md @@ -22,13 +22,17 @@ folder: pmd/rules {% include callout.html content="Rules which enforce a specific coding style." %} -* [ClassNamingConventions](pmd_rules_apex_codestyle.html#classnamingconventions): Class names should always begin with an upper case character. +* [ClassNamingConventions](pmd_rules_apex_codestyle.html#classnamingconventions): Configurable naming conventions for type declarations. This rule reports type declarat... +* [FieldNamingConventions](pmd_rules_apex_codestyle.html#fieldnamingconventions): Configurable naming conventions for field declarations. This rule reports variable declarations ... * [ForLoopsMustUseBraces](pmd_rules_apex_codestyle.html#forloopsmustusebraces): Avoid using 'for' statements without using surrounding braces. If the code formatting orindentati... +* [FormalParameterNamingConventions](pmd_rules_apex_codestyle.html#formalparameternamingconventions): Configurable naming conventions for formal parameters of methods. This rule reports fo... * [IfElseStmtsMustUseBraces](pmd_rules_apex_codestyle.html#ifelsestmtsmustusebraces): Avoid using if..else statements without using surrounding braces. If the code formattingor indent... * [IfStmtsMustUseBraces](pmd_rules_apex_codestyle.html#ifstmtsmustusebraces): Avoid using if statements without using braces to surround the code block. If the codeformatting ... -* [MethodNamingConventions](pmd_rules_apex_codestyle.html#methodnamingconventions): Method names should always begin with a lower case character, and should not contain underscores. +* [LocalVariableNamingConventions](pmd_rules_apex_codestyle.html#localvariablenamingconventions): Configurable naming conventions for local variable declarations. This rule reports var... +* [MethodNamingConventions](pmd_rules_apex_codestyle.html#methodnamingconventions): Configurable naming conventions for method declarations. This rule reports method decl... * [OneDeclarationPerLine](pmd_rules_apex_codestyle.html#onedeclarationperline): Apex allows the use of several variables declaration of the same type on one line. However, itcan... -* [VariableNamingConventions](pmd_rules_apex_codestyle.html#variablenamingconventions): A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... +* [PropertyNamingConventions](pmd_rules_apex_codestyle.html#propertynamingconventions): Configurable naming conventions for property declarations. This rule reports property ... +* [VariableNamingConventions](pmd_rules_apex_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_apex_codestyle.html#whileloopsmustusebraces): Avoid using 'while' statements without using braces to surround the code block. If the codeformat... ## Design @@ -116,7 +120,7 @@ folder: pmd/rules [AvoidDeeplyNestedIfStmts](pmd_rules_apex_design.html#avoiddeeplynestedifstmts), [ExcessiveClassLength](pmd_rules_apex_design.html#excessiveclasslength), [ExcessiveParameterList](pmd_rules_apex_design.html#excessiveparameterlist), [ExcessivePublicCount](pmd_rules_apex_design.html#excessivepubliccount), [NcssConstructorCount](pmd_rules_apex_design.html#ncssconstructorcount), [NcssMethodCount](pmd_rules_apex_design.html#ncssmethodcount), [NcssTypeCount](pmd_rules_apex_design.html#ncsstypecount), [StdCyclomaticComplexity](pmd_rules_apex_design.html#stdcyclomaticcomplexity), [TooManyFields](pmd_rules_apex_design.html#toomanyfields) -* Default ruleset used by the CodeClimate Engine for Salesforce.com Apex (`rulesets/apex/ruleset.xml`): +* Default ruleset for Salesforce.com Apex (`rulesets/apex/ruleset.xml`): Deprecated This ruleset is for backwards compatibility. @@ -154,7 +158,7 @@ folder: pmd/rules It contains the following rules: - [ApexBadCrypto](pmd_rules_apex_security.html#apexbadcrypto), [ApexCRUDViolation](pmd_rules_apex_security.html#apexcrudviolation), [ApexCSRF](pmd_rules_apex_security.html#apexcsrf), [ApexDangerousMethods](pmd_rules_apex_security.html#apexdangerousmethods), [ApexDoc](pmd_rules_apex_documentation.html#apexdoc), [ApexInsecureEndpoint](pmd_rules_apex_security.html#apexinsecureendpoint), [ApexOpenRedirect](pmd_rules_apex_security.html#apexopenredirect), [ApexSharingViolations](pmd_rules_apex_security.html#apexsharingviolations), [ApexSOQLInjection](pmd_rules_apex_security.html#apexsoqlinjection), [ApexSuggestUsingNamedCred](pmd_rules_apex_security.html#apexsuggestusingnamedcred), [ApexUnitTestClassShouldHaveAsserts](pmd_rules_apex_bestpractices.html#apexunittestclassshouldhaveasserts), [ApexUnitTestShouldNotUseSeeAllDataTrue](pmd_rules_apex_bestpractices.html#apexunittestshouldnotuseseealldatatrue), [ApexXSSFromEscapeFalse](pmd_rules_apex_security.html#apexxssfromescapefalse), [ApexXSSFromURLParam](pmd_rules_apex_security.html#apexxssfromurlparam), [AvoidDeeplyNestedIfStmts](pmd_rules_apex_design.html#avoiddeeplynestedifstmts), [AvoidDirectAccessTriggerMap](pmd_rules_apex_errorprone.html#avoiddirectaccesstriggermap), [AvoidDmlStatementsInLoops](pmd_rules_apex_performance.html#avoiddmlstatementsinloops), [AvoidGlobalModifier](pmd_rules_apex_bestpractices.html#avoidglobalmodifier), [AvoidHardcodingId](pmd_rules_apex_errorprone.html#avoidhardcodingid), [AvoidLogicInTrigger](pmd_rules_apex_bestpractices.html#avoidlogicintrigger), [AvoidNonExistentAnnotations](pmd_rules_apex_errorprone.html#avoidnonexistentannotations), [AvoidSoqlInLoops](pmd_rules_apex_performance.html#avoidsoqlinloops), [AvoidSoslInLoops](pmd_rules_apex_performance.html#avoidsoslinloops), [ClassNamingConventions](pmd_rules_apex_codestyle.html#classnamingconventions), [CyclomaticComplexity](pmd_rules_apex_design.html#cyclomaticcomplexity), [EmptyCatchBlock](pmd_rules_apex_errorprone.html#emptycatchblock), [EmptyIfStmt](pmd_rules_apex_errorprone.html#emptyifstmt), [EmptyStatementBlock](pmd_rules_apex_errorprone.html#emptystatementblock), [EmptyTryOrFinallyBlock](pmd_rules_apex_errorprone.html#emptytryorfinallyblock), [EmptyWhileStmt](pmd_rules_apex_errorprone.html#emptywhilestmt), [ExcessiveClassLength](pmd_rules_apex_design.html#excessiveclasslength), [ExcessiveParameterList](pmd_rules_apex_design.html#excessiveparameterlist), [ExcessivePublicCount](pmd_rules_apex_design.html#excessivepubliccount), [ForLoopsMustUseBraces](pmd_rules_apex_codestyle.html#forloopsmustusebraces), [IfElseStmtsMustUseBraces](pmd_rules_apex_codestyle.html#ifelsestmtsmustusebraces), [IfStmtsMustUseBraces](pmd_rules_apex_codestyle.html#ifstmtsmustusebraces), [MethodNamingConventions](pmd_rules_apex_codestyle.html#methodnamingconventions), [MethodWithSameNameAsEnclosingClass](pmd_rules_apex_errorprone.html#methodwithsamenameasenclosingclass), [NcssConstructorCount](pmd_rules_apex_design.html#ncssconstructorcount), [NcssMethodCount](pmd_rules_apex_design.html#ncssmethodcount), [NcssTypeCount](pmd_rules_apex_design.html#ncsstypecount), [OneDeclarationPerLine](pmd_rules_apex_codestyle.html#onedeclarationperline), [StdCyclomaticComplexity](pmd_rules_apex_design.html#stdcyclomaticcomplexity), [TooManyFields](pmd_rules_apex_design.html#toomanyfields), [VariableNamingConventions](pmd_rules_apex_codestyle.html#variablenamingconventions), [WhileLoopsMustUseBraces](pmd_rules_apex_codestyle.html#whileloopsmustusebraces) + [ApexBadCrypto](pmd_rules_apex_security.html#apexbadcrypto), [ApexCRUDViolation](pmd_rules_apex_security.html#apexcrudviolation), [ApexCSRF](pmd_rules_apex_security.html#apexcsrf), [ApexDangerousMethods](pmd_rules_apex_security.html#apexdangerousmethods), [ApexDoc](pmd_rules_apex_documentation.html#apexdoc), [ApexInsecureEndpoint](pmd_rules_apex_security.html#apexinsecureendpoint), [ApexOpenRedirect](pmd_rules_apex_security.html#apexopenredirect), [ApexSharingViolations](pmd_rules_apex_security.html#apexsharingviolations), [ApexSOQLInjection](pmd_rules_apex_security.html#apexsoqlinjection), [ApexSuggestUsingNamedCred](pmd_rules_apex_security.html#apexsuggestusingnamedcred), [ApexUnitTestClassShouldHaveAsserts](pmd_rules_apex_bestpractices.html#apexunittestclassshouldhaveasserts), [ApexUnitTestShouldNotUseSeeAllDataTrue](pmd_rules_apex_bestpractices.html#apexunittestshouldnotuseseealldatatrue), [ApexXSSFromEscapeFalse](pmd_rules_apex_security.html#apexxssfromescapefalse), [ApexXSSFromURLParam](pmd_rules_apex_security.html#apexxssfromurlparam), [AvoidDeeplyNestedIfStmts](pmd_rules_apex_design.html#avoiddeeplynestedifstmts), [AvoidDirectAccessTriggerMap](pmd_rules_apex_errorprone.html#avoiddirectaccesstriggermap), [AvoidDmlStatementsInLoops](pmd_rules_apex_performance.html#avoiddmlstatementsinloops), [AvoidGlobalModifier](pmd_rules_apex_bestpractices.html#avoidglobalmodifier), [AvoidHardcodingId](pmd_rules_apex_errorprone.html#avoidhardcodingid), [AvoidLogicInTrigger](pmd_rules_apex_bestpractices.html#avoidlogicintrigger), [AvoidNonExistentAnnotations](pmd_rules_apex_errorprone.html#avoidnonexistentannotations), [AvoidSoqlInLoops](pmd_rules_apex_performance.html#avoidsoqlinloops), [AvoidSoslInLoops](pmd_rules_apex_performance.html#avoidsoslinloops), [ClassNamingConventions](pmd_rules_apex_codestyle.html#classnamingconventions), [CyclomaticComplexity](pmd_rules_apex_design.html#cyclomaticcomplexity), [EmptyCatchBlock](pmd_rules_apex_errorprone.html#emptycatchblock), [EmptyIfStmt](pmd_rules_apex_errorprone.html#emptyifstmt), [EmptyStatementBlock](pmd_rules_apex_errorprone.html#emptystatementblock), [EmptyTryOrFinallyBlock](pmd_rules_apex_errorprone.html#emptytryorfinallyblock), [EmptyWhileStmt](pmd_rules_apex_errorprone.html#emptywhilestmt), [ExcessiveClassLength](pmd_rules_apex_design.html#excessiveclasslength), [ExcessiveParameterList](pmd_rules_apex_design.html#excessiveparameterlist), [ExcessivePublicCount](pmd_rules_apex_design.html#excessivepubliccount), [FieldNamingConventions](pmd_rules_apex_codestyle.html#fieldnamingconventions), [ForLoopsMustUseBraces](pmd_rules_apex_codestyle.html#forloopsmustusebraces), [FormalParameterNamingConventions](pmd_rules_apex_codestyle.html#formalparameternamingconventions), [IfElseStmtsMustUseBraces](pmd_rules_apex_codestyle.html#ifelsestmtsmustusebraces), [IfStmtsMustUseBraces](pmd_rules_apex_codestyle.html#ifstmtsmustusebraces), [LocalVariableNamingConventions](pmd_rules_apex_codestyle.html#localvariablenamingconventions), [MethodNamingConventions](pmd_rules_apex_codestyle.html#methodnamingconventions), [MethodWithSameNameAsEnclosingClass](pmd_rules_apex_errorprone.html#methodwithsamenameasenclosingclass), [NcssConstructorCount](pmd_rules_apex_design.html#ncssconstructorcount), [NcssMethodCount](pmd_rules_apex_design.html#ncssmethodcount), [NcssTypeCount](pmd_rules_apex_design.html#ncsstypecount), [OneDeclarationPerLine](pmd_rules_apex_codestyle.html#onedeclarationperline), [PropertyNamingConventions](pmd_rules_apex_codestyle.html#propertynamingconventions), [StdCyclomaticComplexity](pmd_rules_apex_design.html#stdcyclomaticcomplexity), [TooManyFields](pmd_rules_apex_design.html#toomanyfields), [WhileLoopsMustUseBraces](pmd_rules_apex_codestyle.html#whileloopsmustusebraces) * Security (`rulesets/apex/security.xml`): diff --git a/docs/pages/pmd/rules/apex/bestpractices.md b/docs/pages/pmd/rules/apex/bestpractices.md index 4acf3f478d..7fdf465d45 100644 --- a/docs/pages/pmd/rules/apex/bestpractices.md +++ b/docs/pages/pmd/rules/apex/bestpractices.md @@ -24,7 +24,7 @@ improves the readability of test output. **Example(s):** ``` java -@isTest +{%raw%}@isTest public class Foo { @isTest static void methodATest() { @@ -33,18 +33,10 @@ public class Foo { System.assert(o.isClosed); // not good System.assert(o.isClosed, 'Opportunity is not closed.'); // good } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Bug Risk|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -63,7 +55,7 @@ with messages provide the developer a clearer idea of what the test does. **Example(s):** ``` java -@isTest +{%raw%}@isTest public class Foo { public static testMethod void testSomething() { Account a = null; @@ -71,18 +63,10 @@ public class Foo { // System.assertNotEquals(a, null, 'account not found'); a.toString(); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Bug Risk|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -101,7 +85,7 @@ As testMethod keyword is deprecated, Salesforce advices to use @isTest annotatio **Example(s):** ``` java -@isTest +{%raw%}@isTest private class ATest { @isTest static void methodATest() { @@ -116,18 +100,10 @@ private class ATest { } private void fetchData() { } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Bug Risk|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -145,7 +121,7 @@ Apex unit tests should not use @isTest(seeAllData=true) because it opens up the **Example(s):** ``` java -@isTest(seeAllData = true) +{%raw%}@isTest(seeAllData = true) public class Foo { public static testMethod void testSomething() { Account a = null; @@ -153,18 +129,10 @@ public class Foo { // System.assertNotEquals(a, null, 'account not found'); a.toString(); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Bug Risk|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -183,22 +151,14 @@ Many interfaces (e.g. Batch) required global modifiers in the past but don't req **Example(s):** ``` java -global class Unchangeable { +{%raw%}global class Unchangeable { global UndeletableType unchangable(UndeletableType param) { // ... } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -219,7 +179,7 @@ See more here: https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex **Example(s):** ``` java -trigger Accounts on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) { +{%raw%}trigger Accounts on Account (before insert, before update, before delete, after insert, after update, after delete, after undelete) { for(Account acc : Trigger.new) { if(Trigger.isInsert) { // ... @@ -231,18 +191,10 @@ trigger Accounts on Account (before insert, before update, before delete, after // ... } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|200|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` diff --git a/docs/pages/pmd/rules/apex/codestyle.md b/docs/pages/pmd/rules/apex/codestyle.md index 7f8f72b1a5..5e62cf6937 100644 --- a/docs/pages/pmd/rules/apex/codestyle.md +++ b/docs/pages/pmd/rules/apex/codestyle.md @@ -5,7 +5,7 @@ permalink: pmd_rules_apex_codestyle.html folder: pmd/rules/apex sidebaractiveurl: /pmd_rules_apex.html editmepath: ../pmd-apex/src/main/resources/category/apex/codestyle.xml -keywords: Code Style, ClassNamingConventions, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, ForLoopsMustUseBraces, MethodNamingConventions, OneDeclarationPerLine, VariableNamingConventions, WhileLoopsMustUseBraces +keywords: Code Style, ClassNamingConventions, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, FieldNamingConventions, ForLoopsMustUseBraces, FormalParameterNamingConventions, LocalVariableNamingConventions, MethodNamingConventions, OneDeclarationPerLine, PropertyNamingConventions, VariableNamingConventions, WhileLoopsMustUseBraces language: Apex --- @@ -15,29 +15,103 @@ language: Apex **Priority:** High (1) -Class names should always begin with an upper case character. +Configurable naming conventions for type declarations. This rule reports +type declarations which do not match the regex that applies to their +specific kind (e.g. enum or interface). Each regex can be configured through +properties. + +By default this rule uses the standard Apex naming convention (Pascal case). **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.ClassNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/ClassNamingConventionsRule.java) **Example(s):** ``` java -public class Foo {} +{%raw%}public class FooClass { } // This is in pascal case, so it's ok + +public class fooClass { } // This will be reported unless you change the regex{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|5|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| +|testClassPattern|\[A-Z\]\[a-zA-Z0-9\_\]\*|Regex which applies to test class names|no| +|abstractClassPattern|\[A-Z\]\[a-zA-Z0-9\_\]\*|Regex which applies to abstract class names|no| +|classPattern|\[A-Z\]\[a-zA-Z0-9\_\]\*|Regex which applies to class names|no| +|interfacePattern|\[A-Z\]\[a-zA-Z0-9\_\]\*|Regex which applies to interface names|no| +|enumPattern|\[A-Z\]\[a-zA-Z0-9\_\]\*|Regex which applies to enum names|no| **Use this rule with the default properties by just referencing it:** ``` xml ``` +**Use this rule and customize it:** +``` xml + + + + + + + + + +``` + +## FieldNamingConventions + +**Since:** PMD 6.15.0 + +**Priority:** High (1) + +Configurable naming conventions for field declarations. This rule reports variable declarations +which do not match the regex that applies to their specific kind ---e.g. constants (static final), +static field, final field. Each regex can be configured through properties. + +By default this rule uses the standard Apex naming convention (Camel case). + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.FieldNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsRule.java) + +**Example(s):** + +``` java +{%raw%}public class Foo { + Integer instanceField; // This is in camel case, so it's ok + + Integer INSTANCE_FIELD; // This will be reported unless you change the regex +}{%endraw%} +``` + +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|enumConstantPattern|\[A-Z\]\[A-Z0-9\_\]\*|Regex which applies to enum constant field names|no| +|constantPattern|\[A-Z\]\[A-Z0-9\_\]\*|Regex which applies to constant field names|no| +|finalPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to final field names|no| +|staticPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to static field names|no| +|instancePattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to instance field names|no| + +**Use this rule with the default properties by just referencing it:** +``` xml + +``` + +**Use this rule and customize it:** +``` xml + + + + + + + + + +``` + ## ForLoopsMustUseBraces **Since:** PMD 5.6.0 @@ -58,25 +132,64 @@ from the rest. **Example(s):** ``` java -for (int i = 0; i < 42; i++) // not recommended +{%raw%}for (int i = 0; i < 42; i++) // not recommended foo(); for (int i = 0; i < 42; i++) { // preferred approach foo(); -} +}{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml + +``` + +## FormalParameterNamingConventions + +**Since:** PMD 6.15.0 + +**Priority:** High (1) + +Configurable naming conventions for formal parameters of methods. +This rule reports formal parameters which do not match the regex that applies to their +specific kind (e.g. method parameter, or final method parameter). Each regex can be +configured through properties. + +By default this rule uses the standard Apex naming convention (Camel case). + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.FormalParameterNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsRule.java) + +**Example(s):** + +``` java +{%raw%}public class Foo { + public bar(Integer methodParameter) { } // This is in camel case, so it's ok + + public baz(Integer METHOD_PARAMETER) { } // This will be reported unless you change the regex +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| +|finalMethodParameterPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to final method parameter names|no| +|methodParameterPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to method parameter names|no| **Use this rule with the default properties by just referencing it:** ``` xml - + +``` + +**Use this rule and customize it:** +``` xml + + + + + + ``` ## IfElseStmtsMustUseBraces @@ -99,25 +212,17 @@ from the rest. **Example(s):** ``` java -// this is OK +{%raw%}// this is OK if (foo) x++; // but this is not if (foo) x = x+1; else - x = x-1; + x = x-1;{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -140,25 +245,66 @@ controlled from the rest. **Example(s):** ``` java -if (foo) // not recommended +{%raw%}if (foo) // not recommended x++; if (foo) { // preferred approach x++; -} +}{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml + +``` + +## LocalVariableNamingConventions + +**Since:** PMD 6.15.0 + +**Priority:** High (1) + +Configurable naming conventions for local variable declarations. +This rule reports variable declarations which do not match the regex that applies to their +specific kind (e.g. local variable, or final local variable). Each regex can be configured through +properties. + +By default this rule uses the standard Apex naming convention (Camel case). + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.LocalVariableNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsRule.java) + +**Example(s):** + +``` java +{%raw%}public class Foo { + public Foo() { + Integer localVariable; // This is in camel case, so it's ok + + Integer LOCAL_VARIABLE; // This will be reported unless you change the regex + } +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| +|finalLocalPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to final local variable names|no| +|localPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to local variable names|no| **Use this rule with the default properties by just referencing it:** ``` xml - + +``` + +**Use this rule and customize it:** +``` xml + + + + + + ``` ## MethodNamingConventions @@ -167,27 +313,32 @@ if (foo) { // preferred approach **Priority:** High (1) -Method names should always begin with a lower case character, and should not contain underscores. +Configurable naming conventions for method declarations. This rule reports +method declarations which do not match the regex that applies to their +specific kind (e.g. static method, or test method). Each regex can be +configured through properties. + +By default this rule uses the standard Apex naming convention (Camel case). **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.MethodNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/MethodNamingConventionsRule.java) **Example(s):** ``` java -public class Foo { - public void fooStuff() { - } -} +{%raw%}public class Foo { + public void instanceMethod() { } // This is in camel case, so it's ok + + public void INSTANCE_METHOD() { } // This will be reported unless you change the regex{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|skipTestMethodUnderscores|false|Skip underscores in test methods|no| +|skipTestMethodUnderscores|false|Deprecated Skip underscores in test methods|no| +|testPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to test method names|no| +|staticPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to static method names|no| +|instancePattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to instance method names|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -198,7 +349,9 @@ public class Foo { ``` xml - + + + ``` @@ -226,22 +379,19 @@ can lead to quite messy code. This rule looks for several declarations on the sa **Example(s):** ``` java -Integer a, b; // not recommended +{%raw%}Integer a, b; // not recommended Integer a, b; // ok by default, can be flagged setting the strictMode property Integer a; // preferred approach -Integer b; +Integer b;{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| |strictMode|false|If true, mark combined declaration even if the declarations are on separate lines.|no| **Use this rule with the default properties by just referencing it:** @@ -258,8 +408,57 @@ Integer b; ``` +## PropertyNamingConventions + +**Since:** PMD 6.15.0 + +**Priority:** High (1) + +Configurable naming conventions for property declarations. This rule reports +property declarations which do not match the regex that applies to their +specific kind (e.g. static property, or instance property). Each regex can be +configured through properties. + +By default this rule uses the standard Apex naming convention (Camel case). + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.PropertyNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsRule.java) + +**Example(s):** + +``` java +{%raw%}public class Foo { + public Integer instanceProperty { get; set; } // This is in camel case, so it's ok + + public Integer INSTANCE_PROPERTY { get; set; } // This will be reported unless you change the regex +}{%endraw%} +``` + +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|staticPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to static property names|no| +|instancePattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to instance property names|no| + +**Use this rule with the default properties by just referencing it:** +``` xml + +``` + +**Use this rule and customize it:** +``` xml + + + + + + +``` + ## VariableNamingConventions +Deprecated + **Since:** PMD 5.5.0 **Priority:** High (1) @@ -268,25 +467,28 @@ A variable naming conventions rule - customize this to your liking. Currently, checks for final variables that should be fully capitalized and non-final variables that should not include underscores. +This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced +by the more general rules {% rule "apex/codestyle/FieldNamingConventions" %}, +{% rule "apex/codestyle/FormalParameterNamingConventions" %}, +{% rule "apex/codestyle/LocalVariableNamingConventions" %}, and +{% rule "apex/codestyle/PropertyNamingConventions" %}. + **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.codestyle.VariableNamingConventionsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java) **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public static final Integer MY_NUM = 0; public String myTest = ''; DataModule dmTest = new DataModule(); -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|5|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| |checkMembers|true|Check member variables|no| |checkLocals|true|Check local variables|no| |checkParameters|true|Check constructor and method parameter variables|no| @@ -341,23 +543,15 @@ controlled from the rest. **Example(s):** ``` java -while (true) // not recommended +{%raw%}while (true) // not recommended x++; while (true) { // preferred approach x++; -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` diff --git a/docs/pages/pmd/rules/apex/design.md b/docs/pages/pmd/rules/apex/design.md index b7043622cf..4d562e0657 100644 --- a/docs/pages/pmd/rules/apex/design.md +++ b/docs/pages/pmd/rules/apex/design.md @@ -22,7 +22,7 @@ Avoid creating deeply nested if-then statements since they are harder to read an **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar(Integer x, Integer y, Integer z) { if (x>y) { if (y>z) { @@ -32,16 +32,13 @@ public class Foo { } } } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|200|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| |problemDepth|3|The if statement depth reporting threshold|no| **Use this rule with the default properties by just referencing it:** @@ -73,7 +70,7 @@ program. As such, they include all control flow statements, such as 'if', 'while Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. -Additionnally, classes with many methods of moderate complexity get reported as well once the total of their +Additionally, classes with many methods of moderate complexity get reported as well once the total of their methods' complexities reaches 40, even if none of the methods was directly reported. Reported methods should be broken down into several smaller methods. Reported classes should probably be broken down @@ -84,7 +81,7 @@ into subcomponents. **Example(s):** ``` java -public class Complicated { +{%raw%}public class Complicated { public void example() { // This method has a cyclomatic complexity of 12 int x = 0, y = 1, z = 2, t = 2; boolean a = false, b = true, c = false, d = true; @@ -106,16 +103,13 @@ public class Complicated { } } } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| |classReportLevel|40|Total class complexity reporting threshold|no| |methodReportLevel|10|Cyclomatic complexity reporting threshold|no| @@ -149,7 +143,7 @@ apart the code becomes more managable and ripe for reuse. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar1() { // 1000 lines of code } @@ -162,19 +156,14 @@ public class Foo { public void barN() { // 1000 lines of code } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|topscore||Deprecated Top score value|no| -|minimum|1000.0|Minimum reporting threshold|no| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|150|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|sigma||Deprecated Sigma value|no| +|minimum|1000|Threshold above which a node is reported|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -185,7 +174,7 @@ public class Foo { ``` xml - + ``` @@ -204,26 +193,21 @@ same datatype. These situations usually denote the need for new objects to wrap **Example(s):** ``` java -// too many arguments liable to be mixed up +{%raw%}// too many arguments liable to be mixed up public void addPerson(int birthYear, int birthMonth, int birthDate, int height, int weight, int ssn) { // ... } // preferred approach public void addPerson(Date birthdate, BodyMeasurements measurements, int ssn) { // ... -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|topscore||Deprecated Top score value|no| -|minimum|4.0|Minimum reporting threshold|no| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|50|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|sigma||Deprecated Sigma value|no| +|minimum|4|Threshold above which a node is reported|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -234,7 +218,7 @@ public void addPerson(Date birthdate, BodyMeasurements measurements, int ssn) { ``` xml - + ``` @@ -255,7 +239,7 @@ developed easily. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public String value; public Bar something; public Variable var; @@ -265,19 +249,14 @@ public class Foo { public void doMoreWork() {} public void doWorkAgain() {} // [... more more public methods ...] -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|topscore||Deprecated Top score value|no| -|minimum|20.0|Minimum reporting threshold|no| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|150|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|sigma||Deprecated Sigma value|no| +|minimum|20|Threshold above which a node is reported|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -288,7 +267,7 @@ public class Foo { ``` xml - + ``` @@ -308,7 +287,7 @@ lines of code that are split are counted as one. **Example(s):** ``` java -public class Foo extends Bar { +{%raw%}public class Foo extends Bar { //this constructor only has 1 NCSS lines public Foo() { super(); @@ -318,19 +297,14 @@ public class Foo extends Bar { super.foo(); } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|topscore||Deprecated Top score value|no| -|minimum|20.0|Minimum reporting threshold|no| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|50|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|sigma||Deprecated Sigma value|no| +|minimum|20|Threshold above which a node is reported|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -341,7 +315,7 @@ public class Foo extends Bar { ``` xml - + ``` @@ -361,7 +335,7 @@ lines of code that are split are counted as one. **Example(s):** ``` java -public class Foo extends Bar { +{%raw%}public class Foo extends Bar { //this method only has 1 NCSS lines public Integer methd() { super.methd(); @@ -370,19 +344,14 @@ public class Foo extends Bar { return 1; } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|topscore||Deprecated Top score value|no| -|minimum|40.0|Minimum reporting threshold|no| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|50|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|sigma||Deprecated Sigma value|no| +|minimum|40|Threshold above which a node is reported|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -393,7 +362,7 @@ public class Foo extends Bar { ``` xml - + ``` @@ -413,7 +382,7 @@ lines of code that are split are counted as one. **Example(s):** ``` java -//this class only has 6 NCSS lines +{%raw%}//this class only has 6 NCSS lines public class Foo extends Bar { public Foo() { super(); @@ -424,19 +393,14 @@ public class Foo extends Bar { super.foo(); } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|topscore||Deprecated Top score value|no| -|minimum|500.0|Minimum reporting threshold|no| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|250|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| -|sigma||Deprecated Sigma value|no| +|minimum|500|Threshold above which a node is reported|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -447,7 +411,7 @@ public class Foo extends Bar { ``` xml - + ``` @@ -468,7 +432,7 @@ high complexity, and 11+ is very high complexity. **Example(s):** ``` java -// This has a Cyclomatic Complexity = 12 +{%raw%}// This has a Cyclomatic Complexity = 12 public class Foo { 1 public void example() { 2 if (a == b || (c == d && e == f)) { @@ -503,16 +467,13 @@ public class Foo { break; } } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|250|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| |reportLevel|10|Cyclomatic Complexity reporting threshold|no| |showClassesComplexity|true|Add class average violations to the report|no| |showMethodsComplexity|true|Add method average violations to the report|no| @@ -548,7 +509,7 @@ city/state/zip fields could park them within a single Address field. **Example(s):** ``` java -public class Person { +{%raw%}public class Person { // too many separate fields int birthYear; int birthMonth; @@ -561,16 +522,13 @@ public class Person { // this is more manageable Date birthDate; BodyMeasurements measurements; -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|cc\_categories|Complexity|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|200|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| |maxfields|15|Max allowable fields|no| **Use this rule with the default properties by just referencing it:** diff --git a/docs/pages/pmd/rules/apex/documentation.md b/docs/pages/pmd/rules/apex/documentation.md index 20a24496e8..ebefb853e9 100644 --- a/docs/pages/pmd/rules/apex/documentation.md +++ b/docs/pages/pmd/rules/apex/documentation.md @@ -32,7 +32,7 @@ Method overrides and tests are both exempted from having ApexDoc. **Example(s):** ``` java -/** +{%raw%}/** * @description Hello World */ public class HelloWorld { @@ -41,18 +41,10 @@ public class HelloWorld { * @return Bar */ public Object bar() { return null; } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` diff --git a/docs/pages/pmd/rules/apex/errorprone.md b/docs/pages/pmd/rules/apex/errorprone.md index 2e1c5ae832..41321f5ce2 100644 --- a/docs/pages/pmd/rules/apex/errorprone.md +++ b/docs/pages/pmd/rules/apex/errorprone.md @@ -25,24 +25,16 @@ Avoid directly accessing Trigger.old and Trigger.new as it can lead to a bug. Tr **Example(s):** ``` java -trigger AccountTrigger on Account (before insert, before update) { +{%raw%}trigger AccountTrigger on Account (before insert, before update) { Account a = Trigger.new[0]; //Bad: Accessing the trigger array directly is not recommended. foreach ( Account a : Trigger.new ){ //Good: Iterate through the trigger.new array instead. } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -62,7 +54,7 @@ the logic can dynamically identify the proper data to operate against and not fa **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { void foo() { //Error - hardcoded the record type id if(a.RecordTypeId == '012500000009WAr'){ @@ -71,18 +63,10 @@ public without sharing class Foo { //do some logic here for a different record type... } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -103,22 +87,14 @@ A full list of supported annotations can be found at https://developer.salesforc **Example(s):** ``` java -@NonExistentAnnotation public class ClassWithNonexistentAnnotation { +{%raw%}@NonExistentAnnotation public class ClassWithNonexistentAnnotation { @NonExistentAnnotation public void methodWithNonExistentAnnotation() { // ... } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -141,25 +117,17 @@ or reported. **Example(s):** ``` java -public void doSomething() { +{%raw%}public void doSomething() { ... try { insert accounts; } catch (DmlException dmle) { // not good } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -181,24 +149,16 @@ Empty If Statement finds instances where a condition is checked but nothing is d **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar(Integer x) { if (x == 0) { // empty! } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -220,7 +180,7 @@ Empty block statements serve no purpose and should be removed. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int _bar; @@ -228,18 +188,10 @@ public class Foo { // empty } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -260,7 +212,7 @@ Avoid empty try or finally blocks - what's the point? **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { try { // empty ! @@ -278,18 +230,10 @@ public class Foo { // empty! } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -312,22 +256,14 @@ a while loop that does a lot in the exit expression, rewrite it to make it clear **Example(s):** ``` java -public void bar(Integer a, Integer b) { +{%raw%}public void bar(Integer a, Integer b) { while (a == b) { // empty! } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|1|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -345,23 +281,15 @@ Non-constructor methods should not have the same name as the enclosing class. **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { // this is OK because it is a constructor public MyClass() {} // this is bad because it is a method public void MyClass() {} -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Style|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|50|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` diff --git a/docs/pages/pmd/rules/apex/performance.md b/docs/pages/pmd/rules/apex/performance.md index d092b7820f..17da922379 100644 --- a/docs/pages/pmd/rules/apex/performance.md +++ b/docs/pages/pmd/rules/apex/performance.md @@ -22,7 +22,7 @@ Avoid DML statements inside loops to avoid hitting the DML governor limit. Inste **Example(s):** ``` java -public class Something { +{%raw%}public class Something { public void foo() { for (Integer i = 0; i < 151; i++) { Account account; @@ -30,18 +30,10 @@ public class Something { insert account; } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Performance|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|150|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -59,24 +51,16 @@ New objects created within loops should be checked to see if they can created ou **Example(s):** ``` java -public class Something { +{%raw%}public class Something { public static void main( String as[] ) { for (Integer i = 0; i < 10; i++) { List accounts = [SELECT Id FROM Account]; } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Performance|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|150|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -94,24 +78,16 @@ Sosl calls within loops can cause governor limit exceptions. **Example(s):** ``` java -public class Something { +{%raw%}public class Something { public static void main( String as[] ) { for (Integer i = 0; i < 10; i++) { List> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead]; } } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Performance|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|150|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` diff --git a/docs/pages/pmd/rules/apex/security.md b/docs/pages/pmd/rules/apex/security.md index e77159bddb..65a8bbe0ad 100644 --- a/docs/pages/pmd/rules/apex/security.md +++ b/docs/pages/pmd/rules/apex/security.md @@ -23,23 +23,15 @@ Hard-wiring these values greatly compromises the security of encrypted data. **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { Blob hardCodedIV = Blob.valueOf('Hardcoded IV 123'); Blob hardCodedKey = Blob.valueOf('0000000000000000'); Blob data = Blob.valueOf('Data to be encrypted'); Blob encrypted = Crypto.encrypt('AES128', hardCodedKey, hardCodedIV, data); -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -59,7 +51,7 @@ privilege and may produce runtime errors. This check forces you to handle such s **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public Contact foo(String status, String ID) { Contact c = [SELECT Status__c FROM Contact WHERE Id=:ID]; @@ -72,18 +64,10 @@ public class Foo { update c; return c; } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -102,7 +86,7 @@ modification of the database just by accessing a page. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public init() { insert data; } @@ -110,18 +94,10 @@ public class Foo { public Foo() { insert data; } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -146,22 +122,14 @@ of private data. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public Foo() { Configuration.disableTriggerCRUDSecurity(); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -180,23 +148,15 @@ Checks against accessing endpoints under plain **http**. You should always use **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { void foo() { HttpRequest req = new HttpRequest(); req.setEndpoint('http://localhost:com'); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -215,23 +175,15 @@ redirecting users to phishing sites. **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { String unsafeLocation = ApexPage.getCurrentPage().getParameters.get('url_param'); PageReference page() { return new PageReference(unsafeLocation); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -250,20 +202,12 @@ forces the developer to take access restrictions into account before modifying o **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { // DML operation here -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -281,22 +225,14 @@ Detects the usage of untrusted / unescaped variables in DML queries. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void test1(String t1) { Database.query('SELECT Id FROM Account' + t1); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -326,24 +262,16 @@ For more information, you can check [this](https://developer.salesforce.com/docs **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void foo(String username, String password) { Blob headerValue = Blob.valueOf(username + ':' + password); String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue); req.setHeader('Authorization', authorizationHeader); } -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -363,20 +291,12 @@ attacks if unescaped. **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { Trigger.new[0].addError(vulnerableHTMLGoesHere, false); -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|100|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` @@ -395,21 +315,13 @@ to avoid XSS attacks. **Example(s):** ``` java -public without sharing class Foo { +{%raw%}public without sharing class Foo { String unescapedstring = ApexPage.getCurrentPage().getParameters.get('url_param'); String usedLater = unescapedstring; -} +}{%endraw%} ``` -**This rule has the following properties:** - -|Name|Default Value|Description|Multivalued| -|----|-------------|-----------|-----------| -|cc\_categories|Security|Deprecated Code Climate Categories|yes. Delimiter is '\|'.| -|cc\_remediation\_points\_multiplier|50|Deprecated Code Climate Remediation Points multiplier|no| -|cc\_block\_highlighting|false|Deprecated Code Climate Block Highlighting|no| - -**Use this rule with the default properties by just referencing it:** +**Use this rule by referencing it:** ``` xml ``` diff --git a/docs/pages/pmd/rules/ecmascript/bestpractices.md b/docs/pages/pmd/rules/ecmascript/bestpractices.md index 9815aaf2f7..33d795d66d 100644 --- a/docs/pages/pmd/rules/ecmascript/bestpractices.md +++ b/docs/pages/pmd/rules/ecmascript/bestpractices.md @@ -25,9 +25,9 @@ Avoid using with - it's bad news **Example(s):** ``` javascript -with (object) { +{%raw%}with (object) { property = 3; // Might be on object, might be on window: who knows. -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -50,7 +50,7 @@ usage is likely a bug, or at best poor style. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok function foo() { if (condition1) { return true; @@ -64,7 +64,7 @@ function bar() { return; } return false; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -108,13 +108,13 @@ Global variables can lead to side-effects that are hard to debug. **Example(s):** ``` javascript -function(arg) { +{%raw%}function(arg) { notDeclaredVariable = 1; // this will create a global variable and trigger the rule var someVar = 1; // this is a local variable, that's ok window.otherGlobal = 2; // this will not trigger the rule, although it is a global variable. -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -143,7 +143,7 @@ is better to explicitly scope the variable name to the nearest enclosing scope w **Example(s):** ``` javascript -// Ok +{%raw%}// Ok function foo() { var p = 'clean'; function() { @@ -168,7 +168,7 @@ function bar() { }(); // 'p' is trashed and has value of 'dirty'! -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -200,9 +200,9 @@ See also: [parseInt()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/R **Example(s):** ``` javascript -parseInt("010"); // unclear, could be interpreted as 10 or 7 (with a base of 7) +{%raw%}parseInt("010"); // unclear, could be interpreted as 10 or 7 (with a base of 7) -parseInt("10", 10); // good +parseInt("10", 10); // good{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/ecmascript/codestyle.md b/docs/pages/pmd/rules/ecmascript/codestyle.md index 4ced64c596..a4529a14f8 100644 --- a/docs/pages/pmd/rules/ecmascript/codestyle.md +++ b/docs/pages/pmd/rules/ecmascript/codestyle.md @@ -36,7 +36,7 @@ indicative of the bug where the assignment operator '=' was used instead of the **Example(s):** ``` javascript -var x = 2; +{%raw%}var x = 2; // Bad if ((x = getX()) == 3) { alert('3!'); @@ -44,7 +44,7 @@ if ((x = getX()) == 3) { function getX() { return 3; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -95,14 +95,14 @@ Avoid using 'for' statements without using curly braces. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok for (var i = 0; i < 42; i++) { foo(); } // Bad for (var i = 0; i < 42; i++) - foo(); + foo();{%endraw%} ``` **Use this rule by referencing it:** @@ -128,7 +128,7 @@ Avoid using if..else statements without using curly braces. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok if (foo) { x++; } else { @@ -139,7 +139,7 @@ if (foo) { if (foo) x++; else - y++; + y++;{%endraw%} ``` **Use this rule by referencing it:** @@ -163,14 +163,14 @@ Avoid using if statements without using curly braces. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok if (foo) { x++; } // Bad if (foo) - x++; + x++;{%endraw%} ``` **Use this rule by referencing it:** @@ -197,7 +197,7 @@ See also: **Example(s):** ``` javascript -// Bad: +{%raw%}// Bad: if (x) { return y; } else { @@ -208,7 +208,7 @@ if (x) { if (x) { return y; } -return z; +return z;{%endraw%} ``` **Use this rule by referencing it:** @@ -238,14 +238,14 @@ be misleading. Considering removing this unnecessary Block. **Example(s):** ``` javascript -if (foo) { +{%raw%}if (foo) { // Ok } if (bar) { { // Bad } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -269,9 +269,9 @@ Unnecessary parentheses should be removed. **Example(s):** ``` javascript -var x = 1; // Ok +{%raw%}var x = 1; // Ok var y = (1 + 1); // Ok -var z = ((1 + 1)); // Bad +var z = ((1 + 1)); // Bad{%endraw%} ``` **Use this rule by referencing it:** @@ -302,7 +302,7 @@ will never execute. This is a bug, or extremely poor style. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok function foo() { return 1; } @@ -311,7 +311,7 @@ function bar() { var x = 1; return x; x = 2; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -335,14 +335,14 @@ Avoid using 'while' statements without using curly braces. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok while (true) { x++; } // Bad while (true) - x++; + x++;{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/ecmascript/errorprone.md b/docs/pages/pmd/rules/ecmascript/errorprone.md index a3cf0fd5fa..3b8ec3cb69 100644 --- a/docs/pages/pmd/rules/ecmascript/errorprone.md +++ b/docs/pages/pmd/rules/ecmascript/errorprone.md @@ -27,13 +27,13 @@ This rule helps improve code portability due to differences in browser treatment **Example(s):** ``` javascript -function(arg) { +{%raw%}function(arg) { var obj1 = { a : 1 }; // Ok var arr1 = [ 1, 2 ]; // Ok var obj2 = { a : 1, }; // Syntax error in some browsers! var arr2 = [ 1, 2, ]; // Length 2 or 3 depending on the browser! -} +}{%endraw%} ``` **This rule has the following properties:** @@ -80,7 +80,7 @@ same type. The === operator avoids the casting. **Example(s):** ``` javascript -// Ok +{%raw%}// Ok if (someVar === true) { ... } @@ -95,7 +95,7 @@ if (someVar == true) { // Bad if (someVar != 3) { ... -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -120,13 +120,13 @@ precision in a floating point number. This may result in numeric calculations b **Example(s):** ``` javascript -var a = 9; // Ok +{%raw%}var a = 9; // Ok var b = 999999999999999; // Ok var c = 999999999999999999999; // Not good var w = 1.12e-4; // Ok var x = 1.12; // Ok var y = 1.1234567890123; // Ok -var z = 1.12345678901234567; // Not good +var z = 1.12345678901234567; // Not good{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java.md b/docs/pages/pmd/rules/java.md index 80ca10856f..c293956270 100644 --- a/docs/pages/pmd/rules/java.md +++ b/docs/pages/pmd/rules/java.md @@ -23,6 +23,7 @@ folder: pmd/rules * [CheckResultSet](pmd_rules_java_bestpractices.html#checkresultset): Always check the return values of navigation methods (next, previous, first, last) of a ResultSet... * [ConstantsInInterface](pmd_rules_java_bestpractices.html#constantsininterface): Avoid constants in interfaces. Interfaces should define types, constants are implementation detai... * [DefaultLabelNotLastInSwitchStmt](pmd_rules_java_bestpractices.html#defaultlabelnotlastinswitchstmt): By convention, the default label should be the last label in a switch statement. +* [DoubleBraceInitialization](pmd_rules_java_bestpractices.html#doublebraceinitialization): Double brace initialisation is a pattern to initialise eg collections concisely. But it implicitl... * [ForLoopCanBeForeach](pmd_rules_java_bestpractices.html#forloopcanbeforeach): Reports loops that can be safely replaced with the foreach syntax. The rule considers loops overl... * [ForLoopVariableCount](pmd_rules_java_bestpractices.html#forloopvariablecount): Having a lot of control variables in a 'for' loop makes it harder to see what range of valuesthe ... * [GuardLogStatement](pmd_rules_java_bestpractices.html#guardlogstatement): Whenever using a log level, one should check if the loglevel is actually enabled, orotherwise ski... @@ -67,7 +68,7 @@ folder: pmd/rules * [AbstractNaming](pmd_rules_java_codestyle.html#abstractnaming): Deprecated Abstract classes should be named 'AbstractXXX'.This rule is deprecated and will be removed with P... * [AtLeastOneConstructor](pmd_rules_java_codestyle.html#atleastoneconstructor): Each non-static class should declare at least one constructor.Classes with solely static members ... * [AvoidDollarSigns](pmd_rules_java_codestyle.html#avoiddollarsigns): Avoid using dollar signs in variable/method/class/interface names. -* [AvoidFinalLocalVariable](pmd_rules_java_codestyle.html#avoidfinallocalvariable): Avoid using final local variables, turn them into fields. +* [AvoidFinalLocalVariable](pmd_rules_java_codestyle.html#avoidfinallocalvariable): Deprecated Avoid using final local variables, turn them into fields.Note that this is a controversial rule w... * [AvoidPrefixingMethodParameters](pmd_rules_java_codestyle.html#avoidprefixingmethodparameters): Deprecated Prefixing parameters by 'in' or 'out' pollutes the name of the parameters and reduces code readab... * [AvoidProtectedFieldInFinalClass](pmd_rules_java_codestyle.html#avoidprotectedfieldinfinalclass): Do not use protected fields in final classes since they cannot be subclassed.Clarify your intent ... * [AvoidProtectedMethodInFinalClassNotExtending](pmd_rules_java_codestyle.html#avoidprotectedmethodinfinalclassnotextending): Do not use protected methods in most final classes since they cannot be subclassed. This shouldon... @@ -75,7 +76,7 @@ folder: pmd/rules * [BooleanGetMethodName](pmd_rules_java_codestyle.html#booleangetmethodname): Methods that return boolean results should be named as predicate statements to denote this.I.e, '... * [CallSuperInConstructor](pmd_rules_java_codestyle.html#callsuperinconstructor): It is a good practice to call super() in a constructor. If super() is not called butanother const... * [ClassNamingConventions](pmd_rules_java_codestyle.html#classnamingconventions): Configurable naming conventions for type declarations. This rule reports type declarat... -* [CommentDefaultAccessModifier](pmd_rules_java_codestyle.html#commentdefaultaccessmodifier): To avoid mistakes if we want that a Method, Constructor, Field or Nested class have a default acc... +* [CommentDefaultAccessModifier](pmd_rules_java_codestyle.html#commentdefaultaccessmodifier): To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a... * [ConfusingTernary](pmd_rules_java_codestyle.html#confusingternary): Avoid negation within an "if" expression with an "else" clause. For example, rephrase:'if (x != ... * [ControlStatementBraces](pmd_rules_java_codestyle.html#controlstatementbraces): Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... els... * [DefaultPackage](pmd_rules_java_codestyle.html#defaultpackage): Use explicit scoping instead of accidental usage of default package private level.The rule allows... @@ -122,6 +123,7 @@ folder: pmd/rules * [UseDiamondOperator](pmd_rules_java_codestyle.html#usediamondoperator): Use the diamond operator to let the type be inferred automatically. With the Diamond operator it ... * [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses): Useless parentheses should be removed. * [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis): Reports qualified this usages in the same class. +* [UseShortArrayInitializer](pmd_rules_java_codestyle.html#useshortarrayinitializer): When declaring and initializing array fields or variables, it is not necessary to explicitly crea... * [UseUnderscoresInNumericLiterals](pmd_rules_java_codestyle.html#useunderscoresinnumericliterals): Since Java 1.7, numeric literals can use underscores to separate digits. This rule enforces that ... * [VariableNamingConventions](pmd_rules_java_codestyle.html#variablenamingconventions): Deprecated A variable naming conventions rule - customize this to your liking. Currently, itchecks for fina... * [WhileLoopsMustUseBraces](pmd_rules_java_codestyle.html#whileloopsmustusebraces): Deprecated Avoid using 'while' statements without using braces to surround the code block. If the code forma... @@ -220,7 +222,7 @@ folder: pmd/rules * [CloneMethodMustImplementCloneable](pmd_rules_java_errorprone.html#clonemethodmustimplementcloneable): The method clone() should only be implemented if the class implements the Cloneable interface wit... * [CloneMethodReturnTypeMustMatchClassName](pmd_rules_java_errorprone.html#clonemethodreturntypemustmatchclassname): If a class implements cloneable the return type of the method clone() must be the class name. Tha... * [CloneThrowsCloneNotSupportedException](pmd_rules_java_errorprone.html#clonethrowsclonenotsupportedexception): The method clone() should throw a CloneNotSupportedException. -* [CloseResource](pmd_rules_java_errorprone.html#closeresource): Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after... +* [CloseResource](pmd_rules_java_errorprone.html#closeresource): Ensure that resources (like 'java.sql.Connection', 'java.sql.Statement', and 'java.sql.ResultSet'... * [CompareObjectsWithEquals](pmd_rules_java_errorprone.html#compareobjectswithequals): Use equals() to compare object references; avoid comparing them with ==. * [ConstructorCallsOverridableMethod](pmd_rules_java_errorprone.html#constructorcallsoverridablemethod): Calling overridable methods during construction poses a risk of invoking methods on an incomplete... * [DataflowAnomalyAnalysis](pmd_rules_java_errorprone.html#dataflowanomalyanalysis): The dataflow analysis tracks local definitions, undefinitions and references to variables on diff... @@ -255,12 +257,12 @@ folder: pmd/rules * [JumbledIncrementer](pmd_rules_java_errorprone.html#jumbledincrementer): Avoid jumbled loop incrementers - its usually a mistake, and is confusing even if intentional. * [JUnitSpelling](pmd_rules_java_errorprone.html#junitspelling): Some JUnit framework methods are easy to misspell. * [JUnitStaticSuite](pmd_rules_java_errorprone.html#junitstaticsuite): The suite() method in a JUnit test needs to be both public and static. -* [LoggerIsNotStaticFinal](pmd_rules_java_errorprone.html#loggerisnotstaticfinal): In most cases, the Logger reference can be declared as static and final. +* [LoggerIsNotStaticFinal](pmd_rules_java_errorprone.html#loggerisnotstaticfinal): Deprecated In most cases, the Logger reference can be declared as static and final.This rule is deprecated a... * [MethodWithSameNameAsEnclosingClass](pmd_rules_java_errorprone.html#methodwithsamenameasenclosingclass): Non-constructor methods should not have the same name as the enclosing class. * [MisplacedNullCheck](pmd_rules_java_errorprone.html#misplacednullcheck): The null check here is misplaced. If the variable is null a NullPointerException will be thrown.E... * [MissingBreakInSwitch](pmd_rules_java_errorprone.html#missingbreakinswitch): Switch statements without break or return statements for each case optionmay indicate problematic... * [MissingSerialVersionUID](pmd_rules_java_errorprone.html#missingserialversionuid): Serializable classes should provide a serialVersionUID field.The serialVersionUID field is also n... -* [MissingStaticMethodInNonInstantiatableClass](pmd_rules_java_errorprone.html#missingstaticmethodinnoninstantiatableclass): A class that has private constructors and does not have any static methods or fields cannot be used. +* [MissingStaticMethodInNonInstantiatableClass](pmd_rules_java_errorprone.html#missingstaticmethodinnoninstantiatableclass): A class that has private constructors and does not have any static methods or fields cannot be us... * [MoreThanOneLogger](pmd_rules_java_errorprone.html#morethanonelogger): Normally only one logger is used in each class. * [NonCaseLabelInSwitchStatement](pmd_rules_java_errorprone.html#noncaselabelinswitchstatement): A non-case label (e.g. a named break/continue label) was present in a switch statement.This legal... * [NonStaticInitializer](pmd_rules_java_errorprone.html#nonstaticinitializer): A non-static initializer block will be called any time a constructor is invoked (just prior toinv... @@ -287,7 +289,7 @@ folder: pmd/rules * [UseCorrectExceptionLogging](pmd_rules_java_errorprone.html#usecorrectexceptionlogging): To make sure the full stacktrace is printed out, use the logging statement with two arguments: a ... * [UseEqualsToCompareStrings](pmd_rules_java_errorprone.html#useequalstocomparestrings): Using '==' or '!=' to compare strings only works if intern version is used on both sides.Use the ... * [UselessOperationOnImmutable](pmd_rules_java_errorprone.html#uselessoperationonimmutable): An operation on an Immutable object (String, BigDecimal or BigInteger) won't change the object it... -* [UseLocaleWithCaseConversions](pmd_rules_java_errorprone.html#uselocalewithcaseconversions): When doing String.toLowerCase()/toUpperCase() conversions, use Locales to avoids problems with la... +* [UseLocaleWithCaseConversions](pmd_rules_java_errorprone.html#uselocalewithcaseconversions): When doing 'String::toLowerCase()/toUpperCase()' conversions, use an explicit locale argument to ... * [UseProperClassLoader](pmd_rules_java_errorprone.html#useproperclassloader): In J2EE, the getClassLoader() method might not work as expected. Use Thread.currentThread().getCo... ## Multithreading @@ -540,7 +542,7 @@ folder: pmd/rules It contains the following rules: - [AbstractClassWithoutAnyMethod](pmd_rules_java_design.html#abstractclasswithoutanymethod), [AssignmentInOperand](pmd_rules_java_errorprone.html#assignmentinoperand), [AssignmentToNonFinalStatic](pmd_rules_java_errorprone.html#assignmenttononfinalstatic), [AvoidAccessibilityAlteration](pmd_rules_java_errorprone.html#avoidaccessibilityalteration), [AvoidBranchingStatementAsLastInLoop](pmd_rules_java_errorprone.html#avoidbranchingstatementaslastinloop), [AvoidCatchingThrowable](pmd_rules_java_errorprone.html#avoidcatchingthrowable), [AvoidDecimalLiteralsInBigDecimalConstructor](pmd_rules_java_errorprone.html#avoiddecimalliteralsinbigdecimalconstructor), [AvoidDollarSigns](pmd_rules_java_codestyle.html#avoiddollarsigns), [AvoidInstanceofChecksInCatchClause](pmd_rules_java_errorprone.html#avoidinstanceofchecksincatchclause), [AvoidMultipleUnaryOperators](pmd_rules_java_errorprone.html#avoidmultipleunaryoperators), [AvoidProtectedFieldInFinalClass](pmd_rules_java_codestyle.html#avoidprotectedfieldinfinalclass), [AvoidProtectedMethodInFinalClassNotExtending](pmd_rules_java_codestyle.html#avoidprotectedmethodinfinalclassnotextending), [AvoidStringBufferField](pmd_rules_java_bestpractices.html#avoidstringbufferfield), [AvoidThreadGroup](pmd_rules_java_multithreading.html#avoidthreadgroup), [AvoidUsingHardCodedIP](pmd_rules_java_bestpractices.html#avoidusinghardcodedip), [AvoidUsingOctalValues](pmd_rules_java_errorprone.html#avoidusingoctalvalues), [AvoidUsingVolatile](pmd_rules_java_multithreading.html#avoidusingvolatile), [BadComparison](pmd_rules_java_errorprone.html#badcomparison), [BigIntegerInstantiation](pmd_rules_java_performance.html#bigintegerinstantiation), [BooleanInstantiation](pmd_rules_java_performance.html#booleaninstantiation), [BrokenNullCheck](pmd_rules_java_errorprone.html#brokennullcheck), [CheckResultSet](pmd_rules_java_bestpractices.html#checkresultset), [CheckSkipResult](pmd_rules_java_errorprone.html#checkskipresult), [ClassCastExceptionWithToArray](pmd_rules_java_errorprone.html#classcastexceptionwithtoarray), [ClassNamingConventions](pmd_rules_java_codestyle.html#classnamingconventions), [ClassWithOnlyPrivateConstructorsShouldBeFinal](pmd_rules_java_design.html#classwithonlyprivateconstructorsshouldbefinal), [CloneMethodMustBePublic](pmd_rules_java_errorprone.html#clonemethodmustbepublic), [CloneMethodMustImplementCloneable](pmd_rules_java_errorprone.html#clonemethodmustimplementcloneable), [CloneMethodReturnTypeMustMatchClassName](pmd_rules_java_errorprone.html#clonemethodreturntypemustmatchclassname), [CloneThrowsCloneNotSupportedException](pmd_rules_java_errorprone.html#clonethrowsclonenotsupportedexception), [CloseResource](pmd_rules_java_errorprone.html#closeresource), [CompareObjectsWithEquals](pmd_rules_java_errorprone.html#compareobjectswithequals), [ConstantsInInterface](pmd_rules_java_bestpractices.html#constantsininterface), [ControlStatementBraces](pmd_rules_java_codestyle.html#controlstatementbraces), [DefaultLabelNotLastInSwitchStmt](pmd_rules_java_bestpractices.html#defaultlabelnotlastinswitchstmt), [DoNotCallGarbageCollectionExplicitly](pmd_rules_java_errorprone.html#donotcallgarbagecollectionexplicitly), [DoNotExtendJavaLangError](pmd_rules_java_design.html#donotextendjavalangerror), [DoNotExtendJavaLangThrowable](pmd_rules_java_errorprone.html#donotextendjavalangthrowable), [DontCallThreadRun](pmd_rules_java_multithreading.html#dontcallthreadrun), [DontImportJavaLang](pmd_rules_java_codestyle.html#dontimportjavalang), [DontUseFloatTypeForLoopIndices](pmd_rules_java_errorprone.html#dontusefloattypeforloopindices), [DoubleCheckedLocking](pmd_rules_java_multithreading.html#doublecheckedlocking), [DuplicateImports](pmd_rules_java_codestyle.html#duplicateimports), [EmptyCatchBlock](pmd_rules_java_errorprone.html#emptycatchblock), [EmptyFinalizer](pmd_rules_java_errorprone.html#emptyfinalizer), [EmptyFinallyBlock](pmd_rules_java_errorprone.html#emptyfinallyblock), [EmptyIfStmt](pmd_rules_java_errorprone.html#emptyifstmt), [EmptyInitializer](pmd_rules_java_errorprone.html#emptyinitializer), [EmptyStatementBlock](pmd_rules_java_errorprone.html#emptystatementblock), [EmptyStatementNotInLoop](pmd_rules_java_errorprone.html#emptystatementnotinloop), [EmptySwitchStatements](pmd_rules_java_errorprone.html#emptyswitchstatements), [EmptySynchronizedBlock](pmd_rules_java_errorprone.html#emptysynchronizedblock), [EmptyTryBlock](pmd_rules_java_errorprone.html#emptytryblock), [EmptyWhileStmt](pmd_rules_java_errorprone.html#emptywhilestmt), [EqualsNull](pmd_rules_java_errorprone.html#equalsnull), [ExtendsObject](pmd_rules_java_codestyle.html#extendsobject), [FinalFieldCouldBeStatic](pmd_rules_java_design.html#finalfieldcouldbestatic), [ForLoopCanBeForeach](pmd_rules_java_bestpractices.html#forloopcanbeforeach), [ForLoopShouldBeWhileLoop](pmd_rules_java_codestyle.html#forloopshouldbewhileloop), [FormalParameterNamingConventions](pmd_rules_java_codestyle.html#formalparameternamingconventions), [GenericsNaming](pmd_rules_java_codestyle.html#genericsnaming), [GuardLogStatement](pmd_rules_java_bestpractices.html#guardlogstatement), [IdempotentOperations](pmd_rules_java_errorprone.html#idempotentoperations), [IdenticalCatchBranches](pmd_rules_java_codestyle.html#identicalcatchbranches), [ImportFromSamePackage](pmd_rules_java_errorprone.html#importfromsamepackage), [InstantiationToGetClass](pmd_rules_java_errorprone.html#instantiationtogetclass), [JumbledIncrementer](pmd_rules_java_errorprone.html#jumbledincrementer), [LocalVariableNamingConventions](pmd_rules_java_codestyle.html#localvariablenamingconventions), [LogicInversion](pmd_rules_java_design.html#logicinversion), [LooseCoupling](pmd_rules_java_bestpractices.html#loosecoupling), [MethodNamingConventions](pmd_rules_java_codestyle.html#methodnamingconventions), [MisplacedNullCheck](pmd_rules_java_errorprone.html#misplacednullcheck), [MissingBreakInSwitch](pmd_rules_java_errorprone.html#missingbreakinswitch), [MissingOverride](pmd_rules_java_bestpractices.html#missingoverride), [MissingStaticMethodInNonInstantiatableClass](pmd_rules_java_errorprone.html#missingstaticmethodinnoninstantiatableclass), [NonCaseLabelInSwitchStatement](pmd_rules_java_errorprone.html#noncaselabelinswitchstatement), [NonStaticInitializer](pmd_rules_java_errorprone.html#nonstaticinitializer), [NonThreadSafeSingleton](pmd_rules_java_multithreading.html#nonthreadsafesingleton), [NoPackage](pmd_rules_java_codestyle.html#nopackage), [OneDeclarationPerLine](pmd_rules_java_bestpractices.html#onedeclarationperline), [OptimizableToArrayCall](pmd_rules_java_performance.html#optimizabletoarraycall), [OverrideBothEqualsAndHashcode](pmd_rules_java_errorprone.html#overridebothequalsandhashcode), [PackageCase](pmd_rules_java_codestyle.html#packagecase), [PositionLiteralsFirstInCaseInsensitiveComparisons](pmd_rules_java_bestpractices.html#positionliteralsfirstincaseinsensitivecomparisons), [PositionLiteralsFirstInComparisons](pmd_rules_java_bestpractices.html#positionliteralsfirstincomparisons), [PreserveStackTrace](pmd_rules_java_bestpractices.html#preservestacktrace), [ProperCloneImplementation](pmd_rules_java_errorprone.html#propercloneimplementation), [ProperLogger](pmd_rules_java_errorprone.html#properlogger), [ReturnEmptyArrayRatherThanNull](pmd_rules_java_errorprone.html#returnemptyarrayratherthannull), [ReturnFromFinallyBlock](pmd_rules_java_errorprone.html#returnfromfinallyblock), [SimplifiedTernary](pmd_rules_java_design.html#simplifiedternary), [SimplifyBooleanReturns](pmd_rules_java_design.html#simplifybooleanreturns), [SimplifyConditional](pmd_rules_java_design.html#simplifyconditional), [SingleMethodSingleton](pmd_rules_java_errorprone.html#singlemethodsingleton), [SingletonClassReturningNewInstance](pmd_rules_java_errorprone.html#singletonclassreturningnewinstance), [SingularField](pmd_rules_java_design.html#singularfield), [SuspiciousEqualsMethodName](pmd_rules_java_errorprone.html#suspiciousequalsmethodname), [SuspiciousHashcodeMethodName](pmd_rules_java_errorprone.html#suspicioushashcodemethodname), [SuspiciousOctalEscape](pmd_rules_java_errorprone.html#suspiciousoctalescape), [SwitchStmtsShouldHaveDefault](pmd_rules_java_bestpractices.html#switchstmtsshouldhavedefault), [UncommentedEmptyConstructor](pmd_rules_java_documentation.html#uncommentedemptyconstructor), [UncommentedEmptyMethodBody](pmd_rules_java_documentation.html#uncommentedemptymethodbody), [UnconditionalIfStatement](pmd_rules_java_errorprone.html#unconditionalifstatement), [UnnecessaryAnnotationValueElement](pmd_rules_java_codestyle.html#unnecessaryannotationvalueelement), [UnnecessaryConstructor](pmd_rules_java_codestyle.html#unnecessaryconstructor), [UnnecessaryConversionTemporary](pmd_rules_java_errorprone.html#unnecessaryconversiontemporary), [UnnecessaryFullyQualifiedName](pmd_rules_java_codestyle.html#unnecessaryfullyqualifiedname), [UnnecessaryLocalBeforeReturn](pmd_rules_java_codestyle.html#unnecessarylocalbeforereturn), [UnnecessaryModifier](pmd_rules_java_codestyle.html#unnecessarymodifier), [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn), [UnsynchronizedStaticFormatter](pmd_rules_java_multithreading.html#unsynchronizedstaticformatter), [UnusedFormalParameter](pmd_rules_java_bestpractices.html#unusedformalparameter), [UnusedImports](pmd_rules_java_bestpractices.html#unusedimports), [UnusedLocalVariable](pmd_rules_java_bestpractices.html#unusedlocalvariable), [UnusedNullCheckInEquals](pmd_rules_java_errorprone.html#unusednullcheckinequals), [UnusedPrivateField](pmd_rules_java_bestpractices.html#unusedprivatefield), [UnusedPrivateMethod](pmd_rules_java_bestpractices.html#unusedprivatemethod), [UseAssertEqualsInsteadOfAssertTrue](pmd_rules_java_bestpractices.html#useassertequalsinsteadofasserttrue), [UseAssertNullInsteadOfAssertTrue](pmd_rules_java_bestpractices.html#useassertnullinsteadofasserttrue), [UseAssertSameInsteadOfAssertTrue](pmd_rules_java_bestpractices.html#useassertsameinsteadofasserttrue), [UseAssertTrueInsteadOfAssertEquals](pmd_rules_java_bestpractices.html#useasserttrueinsteadofassertequals), [UseCollectionIsEmpty](pmd_rules_java_bestpractices.html#usecollectionisempty), [UseEqualsToCompareStrings](pmd_rules_java_errorprone.html#useequalstocomparestrings), [UselessOperationOnImmutable](pmd_rules_java_errorprone.html#uselessoperationonimmutable), [UselessOverridingMethod](pmd_rules_java_design.html#uselessoverridingmethod), [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses), [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis), [UseLocaleWithCaseConversions](pmd_rules_java_errorprone.html#uselocalewithcaseconversions), [UseNotifyAllInsteadOfNotify](pmd_rules_java_multithreading.html#usenotifyallinsteadofnotify), [UseUtilityClass](pmd_rules_java_design.html#useutilityclass) + [AbstractClassWithoutAnyMethod](pmd_rules_java_design.html#abstractclasswithoutanymethod), [AssignmentInOperand](pmd_rules_java_errorprone.html#assignmentinoperand), [AssignmentToNonFinalStatic](pmd_rules_java_errorprone.html#assignmenttononfinalstatic), [AvoidAccessibilityAlteration](pmd_rules_java_errorprone.html#avoidaccessibilityalteration), [AvoidBranchingStatementAsLastInLoop](pmd_rules_java_errorprone.html#avoidbranchingstatementaslastinloop), [AvoidCatchingThrowable](pmd_rules_java_errorprone.html#avoidcatchingthrowable), [AvoidDecimalLiteralsInBigDecimalConstructor](pmd_rules_java_errorprone.html#avoiddecimalliteralsinbigdecimalconstructor), [AvoidDollarSigns](pmd_rules_java_codestyle.html#avoiddollarsigns), [AvoidInstanceofChecksInCatchClause](pmd_rules_java_errorprone.html#avoidinstanceofchecksincatchclause), [AvoidMultipleUnaryOperators](pmd_rules_java_errorprone.html#avoidmultipleunaryoperators), [AvoidProtectedFieldInFinalClass](pmd_rules_java_codestyle.html#avoidprotectedfieldinfinalclass), [AvoidProtectedMethodInFinalClassNotExtending](pmd_rules_java_codestyle.html#avoidprotectedmethodinfinalclassnotextending), [AvoidStringBufferField](pmd_rules_java_bestpractices.html#avoidstringbufferfield), [AvoidThreadGroup](pmd_rules_java_multithreading.html#avoidthreadgroup), [AvoidUsingHardCodedIP](pmd_rules_java_bestpractices.html#avoidusinghardcodedip), [AvoidUsingOctalValues](pmd_rules_java_errorprone.html#avoidusingoctalvalues), [AvoidUsingVolatile](pmd_rules_java_multithreading.html#avoidusingvolatile), [BadComparison](pmd_rules_java_errorprone.html#badcomparison), [BigIntegerInstantiation](pmd_rules_java_performance.html#bigintegerinstantiation), [BooleanInstantiation](pmd_rules_java_performance.html#booleaninstantiation), [BrokenNullCheck](pmd_rules_java_errorprone.html#brokennullcheck), [CheckResultSet](pmd_rules_java_bestpractices.html#checkresultset), [CheckSkipResult](pmd_rules_java_errorprone.html#checkskipresult), [ClassCastExceptionWithToArray](pmd_rules_java_errorprone.html#classcastexceptionwithtoarray), [ClassNamingConventions](pmd_rules_java_codestyle.html#classnamingconventions), [ClassWithOnlyPrivateConstructorsShouldBeFinal](pmd_rules_java_design.html#classwithonlyprivateconstructorsshouldbefinal), [CloneMethodMustBePublic](pmd_rules_java_errorprone.html#clonemethodmustbepublic), [CloneMethodMustImplementCloneable](pmd_rules_java_errorprone.html#clonemethodmustimplementcloneable), [CloneMethodReturnTypeMustMatchClassName](pmd_rules_java_errorprone.html#clonemethodreturntypemustmatchclassname), [CloneThrowsCloneNotSupportedException](pmd_rules_java_errorprone.html#clonethrowsclonenotsupportedexception), [CloseResource](pmd_rules_java_errorprone.html#closeresource), [CompareObjectsWithEquals](pmd_rules_java_errorprone.html#compareobjectswithequals), [ConstantsInInterface](pmd_rules_java_bestpractices.html#constantsininterface), [ControlStatementBraces](pmd_rules_java_codestyle.html#controlstatementbraces), [DefaultLabelNotLastInSwitchStmt](pmd_rules_java_bestpractices.html#defaultlabelnotlastinswitchstmt), [DoNotCallGarbageCollectionExplicitly](pmd_rules_java_errorprone.html#donotcallgarbagecollectionexplicitly), [DoNotExtendJavaLangError](pmd_rules_java_design.html#donotextendjavalangerror), [DoNotExtendJavaLangThrowable](pmd_rules_java_errorprone.html#donotextendjavalangthrowable), [DontCallThreadRun](pmd_rules_java_multithreading.html#dontcallthreadrun), [DontImportJavaLang](pmd_rules_java_codestyle.html#dontimportjavalang), [DontUseFloatTypeForLoopIndices](pmd_rules_java_errorprone.html#dontusefloattypeforloopindices), [DoubleBraceInitialization](pmd_rules_java_bestpractices.html#doublebraceinitialization), [DoubleCheckedLocking](pmd_rules_java_multithreading.html#doublecheckedlocking), [DuplicateImports](pmd_rules_java_codestyle.html#duplicateimports), [EmptyCatchBlock](pmd_rules_java_errorprone.html#emptycatchblock), [EmptyFinalizer](pmd_rules_java_errorprone.html#emptyfinalizer), [EmptyFinallyBlock](pmd_rules_java_errorprone.html#emptyfinallyblock), [EmptyIfStmt](pmd_rules_java_errorprone.html#emptyifstmt), [EmptyInitializer](pmd_rules_java_errorprone.html#emptyinitializer), [EmptyStatementBlock](pmd_rules_java_errorprone.html#emptystatementblock), [EmptyStatementNotInLoop](pmd_rules_java_errorprone.html#emptystatementnotinloop), [EmptySwitchStatements](pmd_rules_java_errorprone.html#emptyswitchstatements), [EmptySynchronizedBlock](pmd_rules_java_errorprone.html#emptysynchronizedblock), [EmptyTryBlock](pmd_rules_java_errorprone.html#emptytryblock), [EmptyWhileStmt](pmd_rules_java_errorprone.html#emptywhilestmt), [EqualsNull](pmd_rules_java_errorprone.html#equalsnull), [ExtendsObject](pmd_rules_java_codestyle.html#extendsobject), [FinalFieldCouldBeStatic](pmd_rules_java_design.html#finalfieldcouldbestatic), [ForLoopCanBeForeach](pmd_rules_java_bestpractices.html#forloopcanbeforeach), [ForLoopShouldBeWhileLoop](pmd_rules_java_codestyle.html#forloopshouldbewhileloop), [FormalParameterNamingConventions](pmd_rules_java_codestyle.html#formalparameternamingconventions), [GenericsNaming](pmd_rules_java_codestyle.html#genericsnaming), [GuardLogStatement](pmd_rules_java_bestpractices.html#guardlogstatement), [IdempotentOperations](pmd_rules_java_errorprone.html#idempotentoperations), [IdenticalCatchBranches](pmd_rules_java_codestyle.html#identicalcatchbranches), [ImportFromSamePackage](pmd_rules_java_errorprone.html#importfromsamepackage), [InstantiationToGetClass](pmd_rules_java_errorprone.html#instantiationtogetclass), [JumbledIncrementer](pmd_rules_java_errorprone.html#jumbledincrementer), [LocalVariableNamingConventions](pmd_rules_java_codestyle.html#localvariablenamingconventions), [LogicInversion](pmd_rules_java_design.html#logicinversion), [LooseCoupling](pmd_rules_java_bestpractices.html#loosecoupling), [MethodNamingConventions](pmd_rules_java_codestyle.html#methodnamingconventions), [MisplacedNullCheck](pmd_rules_java_errorprone.html#misplacednullcheck), [MissingBreakInSwitch](pmd_rules_java_errorprone.html#missingbreakinswitch), [MissingOverride](pmd_rules_java_bestpractices.html#missingoverride), [MissingStaticMethodInNonInstantiatableClass](pmd_rules_java_errorprone.html#missingstaticmethodinnoninstantiatableclass), [NonCaseLabelInSwitchStatement](pmd_rules_java_errorprone.html#noncaselabelinswitchstatement), [NonStaticInitializer](pmd_rules_java_errorprone.html#nonstaticinitializer), [NonThreadSafeSingleton](pmd_rules_java_multithreading.html#nonthreadsafesingleton), [NoPackage](pmd_rules_java_codestyle.html#nopackage), [OneDeclarationPerLine](pmd_rules_java_bestpractices.html#onedeclarationperline), [OptimizableToArrayCall](pmd_rules_java_performance.html#optimizabletoarraycall), [OverrideBothEqualsAndHashcode](pmd_rules_java_errorprone.html#overridebothequalsandhashcode), [PackageCase](pmd_rules_java_codestyle.html#packagecase), [PositionLiteralsFirstInCaseInsensitiveComparisons](pmd_rules_java_bestpractices.html#positionliteralsfirstincaseinsensitivecomparisons), [PositionLiteralsFirstInComparisons](pmd_rules_java_bestpractices.html#positionliteralsfirstincomparisons), [PreserveStackTrace](pmd_rules_java_bestpractices.html#preservestacktrace), [ProperCloneImplementation](pmd_rules_java_errorprone.html#propercloneimplementation), [ProperLogger](pmd_rules_java_errorprone.html#properlogger), [ReturnEmptyArrayRatherThanNull](pmd_rules_java_errorprone.html#returnemptyarrayratherthannull), [ReturnFromFinallyBlock](pmd_rules_java_errorprone.html#returnfromfinallyblock), [SimplifiedTernary](pmd_rules_java_design.html#simplifiedternary), [SimplifyBooleanReturns](pmd_rules_java_design.html#simplifybooleanreturns), [SimplifyConditional](pmd_rules_java_design.html#simplifyconditional), [SingleMethodSingleton](pmd_rules_java_errorprone.html#singlemethodsingleton), [SingletonClassReturningNewInstance](pmd_rules_java_errorprone.html#singletonclassreturningnewinstance), [SingularField](pmd_rules_java_design.html#singularfield), [SuspiciousEqualsMethodName](pmd_rules_java_errorprone.html#suspiciousequalsmethodname), [SuspiciousHashcodeMethodName](pmd_rules_java_errorprone.html#suspicioushashcodemethodname), [SuspiciousOctalEscape](pmd_rules_java_errorprone.html#suspiciousoctalescape), [SwitchStmtsShouldHaveDefault](pmd_rules_java_bestpractices.html#switchstmtsshouldhavedefault), [UncommentedEmptyConstructor](pmd_rules_java_documentation.html#uncommentedemptyconstructor), [UncommentedEmptyMethodBody](pmd_rules_java_documentation.html#uncommentedemptymethodbody), [UnconditionalIfStatement](pmd_rules_java_errorprone.html#unconditionalifstatement), [UnnecessaryAnnotationValueElement](pmd_rules_java_codestyle.html#unnecessaryannotationvalueelement), [UnnecessaryConstructor](pmd_rules_java_codestyle.html#unnecessaryconstructor), [UnnecessaryConversionTemporary](pmd_rules_java_errorprone.html#unnecessaryconversiontemporary), [UnnecessaryFullyQualifiedName](pmd_rules_java_codestyle.html#unnecessaryfullyqualifiedname), [UnnecessaryLocalBeforeReturn](pmd_rules_java_codestyle.html#unnecessarylocalbeforereturn), [UnnecessaryModifier](pmd_rules_java_codestyle.html#unnecessarymodifier), [UnnecessaryReturn](pmd_rules_java_codestyle.html#unnecessaryreturn), [UnsynchronizedStaticFormatter](pmd_rules_java_multithreading.html#unsynchronizedstaticformatter), [UnusedFormalParameter](pmd_rules_java_bestpractices.html#unusedformalparameter), [UnusedImports](pmd_rules_java_bestpractices.html#unusedimports), [UnusedLocalVariable](pmd_rules_java_bestpractices.html#unusedlocalvariable), [UnusedNullCheckInEquals](pmd_rules_java_errorprone.html#unusednullcheckinequals), [UnusedPrivateField](pmd_rules_java_bestpractices.html#unusedprivatefield), [UnusedPrivateMethod](pmd_rules_java_bestpractices.html#unusedprivatemethod), [UseAssertEqualsInsteadOfAssertTrue](pmd_rules_java_bestpractices.html#useassertequalsinsteadofasserttrue), [UseAssertNullInsteadOfAssertTrue](pmd_rules_java_bestpractices.html#useassertnullinsteadofasserttrue), [UseAssertSameInsteadOfAssertTrue](pmd_rules_java_bestpractices.html#useassertsameinsteadofasserttrue), [UseAssertTrueInsteadOfAssertEquals](pmd_rules_java_bestpractices.html#useasserttrueinsteadofassertequals), [UseCollectionIsEmpty](pmd_rules_java_bestpractices.html#usecollectionisempty), [UseEqualsToCompareStrings](pmd_rules_java_errorprone.html#useequalstocomparestrings), [UselessOperationOnImmutable](pmd_rules_java_errorprone.html#uselessoperationonimmutable), [UselessOverridingMethod](pmd_rules_java_design.html#uselessoverridingmethod), [UselessParentheses](pmd_rules_java_codestyle.html#uselessparentheses), [UselessQualifiedThis](pmd_rules_java_codestyle.html#uselessqualifiedthis), [UseLocaleWithCaseConversions](pmd_rules_java_errorprone.html#uselocalewithcaseconversions), [UseNotifyAllInsteadOfNotify](pmd_rules_java_multithreading.html#usenotifyallinsteadofnotify), [UseUtilityClass](pmd_rules_java_design.html#useutilityclass) * Security Code Guidelines (`rulesets/java/sunsecure.xml`): diff --git a/docs/pages/pmd/rules/java/bestpractices.md b/docs/pages/pmd/rules/java/bestpractices.md index 4023ea302e..223db9a15c 100644 --- a/docs/pages/pmd/rules/java/bestpractices.md +++ b/docs/pages/pmd/rules/java/bestpractices.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_bestpractices.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/bestpractices.xml -keywords: Best Practices, AbstractClassWithoutAbstractMethod, AccessorClassGeneration, AccessorMethodGeneration, ArrayIsStoredDirectly, AvoidPrintStackTrace, AvoidReassigningLoopVariables, AvoidReassigningParameters, AvoidStringBufferField, AvoidUsingHardCodedIP, CheckResultSet, ConstantsInInterface, DefaultLabelNotLastInSwitchStmt, ForLoopCanBeForeach, ForLoopVariableCount, GuardLogStatement, JUnit4SuitesShouldUseSuiteAnnotation, JUnit4TestShouldUseAfterAnnotation, JUnit4TestShouldUseBeforeAnnotation, JUnit4TestShouldUseTestAnnotation, JUnitAssertionsShouldIncludeMessage, JUnitTestContainsTooManyAsserts, JUnitTestsShouldIncludeAssert, JUnitUseExpected, LooseCoupling, MethodReturnsInternalArray, MissingOverride, OneDeclarationPerLine, PositionLiteralsFirstInCaseInsensitiveComparisons, PositionLiteralsFirstInComparisons, PreserveStackTrace, ReplaceEnumerationWithIterator, ReplaceHashtableWithMap, ReplaceVectorWithList, SwitchStmtsShouldHaveDefault, SystemPrintln, UnusedFormalParameter, UnusedImports, UnusedLocalVariable, UnusedPrivateField, UnusedPrivateMethod, UseAssertEqualsInsteadOfAssertTrue, UseAssertNullInsteadOfAssertTrue, UseAssertSameInsteadOfAssertTrue, UseAssertTrueInsteadOfAssertEquals, UseCollectionIsEmpty, UseTryWithResources, UseVarargs, WhileLoopWithLiteralBoolean +keywords: Best Practices, AbstractClassWithoutAbstractMethod, AccessorClassGeneration, AccessorMethodGeneration, ArrayIsStoredDirectly, AvoidPrintStackTrace, AvoidReassigningLoopVariables, AvoidReassigningParameters, AvoidStringBufferField, AvoidUsingHardCodedIP, CheckResultSet, ConstantsInInterface, DefaultLabelNotLastInSwitchStmt, DoubleBraceInitialization, ForLoopCanBeForeach, ForLoopVariableCount, GuardLogStatement, JUnit4SuitesShouldUseSuiteAnnotation, JUnit4TestShouldUseAfterAnnotation, JUnit4TestShouldUseBeforeAnnotation, JUnit4TestShouldUseTestAnnotation, JUnitAssertionsShouldIncludeMessage, JUnitTestContainsTooManyAsserts, JUnitTestsShouldIncludeAssert, JUnitUseExpected, LooseCoupling, MethodReturnsInternalArray, MissingOverride, OneDeclarationPerLine, PositionLiteralsFirstInCaseInsensitiveComparisons, PositionLiteralsFirstInComparisons, PreserveStackTrace, ReplaceEnumerationWithIterator, ReplaceHashtableWithMap, ReplaceVectorWithList, SwitchStmtsShouldHaveDefault, SystemPrintln, UnusedFormalParameter, UnusedImports, UnusedLocalVariable, UnusedPrivateField, UnusedPrivateMethod, UseAssertEqualsInsteadOfAssertTrue, UseAssertNullInsteadOfAssertTrue, UseAssertSameInsteadOfAssertTrue, UseAssertTrueInsteadOfAssertEquals, UseCollectionIsEmpty, UseTryWithResources, UseVarargs, WhileLoopWithLiteralBoolean language: Java --- @@ -32,12 +32,12 @@ directly) a protected constructor can be provided prevent direct instantiation. **Example(s):** ``` java -public abstract class Foo { +{%raw%}public abstract class Foo { void int method1() { ... } void int method2() { ... } // consider using abstract methods or removing // the abstract modifier and adding protected constructors -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -62,14 +62,14 @@ This turns a private constructor effectively into one with package scope, and is **Example(s):** ``` java -public class Outer { +{%raw%}public class Outer { void method(){ Inner ic = new Inner();//Causes generation of accessor class } public class Inner { private Inner(){} } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -92,7 +92,7 @@ be avoided by changing the visibility of the field / method from private to pack **Example(s):** ``` java -public class OuterClass { +{%raw%}public class OuterClass { private int counter; /* package */ int id; @@ -105,7 +105,7 @@ public class OuterClass { return OuterClass.this.id; // id is package-private, no accessor method needed } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -127,13 +127,13 @@ This prevents future changes from the user from affecting the original array. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private String [] x; public void foo (String [] param) { // Don't do this, make a copy of the array at least this.x=param; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -159,7 +159,7 @@ Avoid printStackTrace(); use a logger call instead. **Example(s):** ``` java -class Foo { +{%raw%}class Foo { void bar() { try { // do something @@ -167,7 +167,7 @@ class Foo { e.printStackTrace(); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -200,7 +200,7 @@ In for-loops, configured by the `forReassign` property: **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private void foo() { for (String s : listOfStrings()) { s = s.trim(); // OK, when foreachReassign is "firstOnly" or "allow" @@ -220,7 +220,7 @@ public class Foo { doSomethingWith(i); } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -258,11 +258,11 @@ Reassigning values to incoming parameters is not recommended. Use temporary loc **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private void foo(String bar) { bar = "something else"; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -287,9 +287,9 @@ if held within objects with long lifetimes. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private StringBuffer buffer; // potential memory leak as an instance variable; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -311,9 +311,9 @@ Externalizing IP adresses is preferable. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private String ip = "127.0.0.1"; // not recommended -} +}{%endraw%} ``` **This rule has the following properties:** @@ -350,7 +350,7 @@ If the value return is 'false', it should be handled properly. **Example(s):** ``` java -Statement stat = conn.createStatement(); +{%raw%}Statement stat = conn.createStatement(); ResultSet rst = stat.executeQuery("SELECT name FROM person"); rst.next(); // what if it returns false? bad form String firstName = rst.getString(1); @@ -361,7 +361,7 @@ if (rst.next()) { // result is properly examined and used String firstName = rst.getString(1); } else { // handle missing data -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -386,7 +386,7 @@ better placed in classes or enums. See Effective Java, item 19. **Example(s):** ``` java -public interface ConstantInterface { +{%raw%}public interface ConstantInterface { public static final int CONST1 = 1; // violation, no fields allowed in interface! static final int CONST2 = 1; // violation, no fields allowed in interface! final int CONST3 = 1; // violation, no fields allowed in interface! @@ -405,7 +405,7 @@ public interface YetAnotherConstantInterface { public static final int CONST1 = 1; // no violation int anyMethod(); -} +}{%endraw%} ``` **This rule has the following properties:** @@ -446,7 +446,7 @@ By convention, the default label should be the last label in a switch statement. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar(int a) { switch (a) { case 1: // do something @@ -457,7 +457,7 @@ public class Foo { break; } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -465,6 +465,42 @@ public class Foo { ``` +## DoubleBraceInitialization + +**Since:** PMD 6.16.0 + +**Priority:** Medium (3) + +Double brace initialisation is a pattern to initialise eg collections concisely. But it implicitly +generates a new .class file, and the object holds a strong reference to the enclosing object. For those +reasons, it is preferable to initialize the object normally, even though it's verbose. + +This rule counts any anonymous class which only has a single initializer as an instance of double-brace +initialization. There is currently no way to find out whether a method called in the initializer is not +accessible from outside the anonymous class, and those legit cases should be suppressed for the time being. + +**This rule is defined by the following XPath expression:** +``` xpath +//AllocationExpression/ClassOrInterfaceBody[count(*)=1]/*/Initializer[@Static=false()] +``` + +**Example(s):** + +``` java +{%raw%}// this is double-brace initialization +return new ArrayList(){{ addAll("a","b","c"); }}; + +// the better way is to not create an anonymous class: +List a = new ArrayList<>(); +a.addAll("a","b","c"); +return a;{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## ForLoopCanBeForeach **Since:** PMD 6.0.0 @@ -483,7 +519,7 @@ element of the list or array left to right. **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { void loop(List l) { for (int i = 0; i < l.size(); i++) { // pre Java 1.5 System.out.println(l.get(i)); @@ -493,7 +529,7 @@ public class MyClass { System.out.println(s); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -518,9 +554,9 @@ the loop iterates over. By default this rule allows a regular 'for' loop with on **Example(s):** ``` java -// this will be reported with the default setting of at most one control variable in a for loop +{%raw%}// this will be reported with the default setting of at most one control variable in a for loop for (int i = 0, j = 0; i < 10; i++, j += 2) { - foo(); + foo();{%endraw%} ``` **This rule has the following properties:** @@ -557,9 +593,9 @@ otherwise skip the associate String creation and manipulation. **Example(s):** ``` java -// Add this for performance +{%raw%}// Add this for performance if (log.isDebugEnabled() { ... - log.debug("log something" + " and " + "concat strings"); + log.debug("log something" + " and " + "concat strings");{%endraw%} ``` **This rule has the following properties:** @@ -603,7 +639,7 @@ through the @RunWith(Suite.class) annotation. **Example(s):** ``` java -public class BadExample extends TestCase{ +{%raw%}public class BadExample extends TestCase{ public static Test suite(){ return new Suite(); @@ -613,7 +649,7 @@ public class BadExample extends TestCase{ @RunWith(Suite.class) @SuiteClasses( { TestOne.class, TestTwo.class }) public class GoodTest { -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -645,7 +681,7 @@ JUnit 5 introduced @AfterEach and @AfterAll annotations to execute methods after **Example(s):** ``` java -public class MyTest { +{%raw%}public class MyTest { public void tearDown() { bad(); } @@ -654,7 +690,7 @@ public class MyTest2 { @After public void tearDown() { good(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -686,7 +722,7 @@ JUnit 5 introduced @BeforeEach and @BeforeAll annotations to execute methods bef **Example(s):** ``` java -public class MyTest { +{%raw%}public class MyTest { public void setUp() { bad(); } @@ -695,7 +731,7 @@ public class MyTest2 { @Before public void setUp() { good(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -731,7 +767,7 @@ In JUnit 5, one of the following annotations should be used for tests: @Test, @R **Example(s):** ``` java -public class MyTest { +{%raw%}public class MyTest { public void testBad() { doSomething(); } @@ -740,7 +776,7 @@ public class MyTest { public void testGood() { doSomething(); } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -777,14 +813,14 @@ assertEquals(), not the two-argument version. **Example(s):** ``` java -public class Foo extends TestCase { +{%raw%}public class Foo extends TestCase { public void testSomething() { assertEquals("foo", "bar"); // Use the form: // assertEquals("Foo does not equals bar", "foo", "bar"); // instead } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -821,7 +857,7 @@ This rule checks for JUnit4, JUnit5 and TestNG Tests, as well as methods startin **Example(s):** ``` java -public class MyTestCase extends TestCase { +{%raw%}public class MyTestCase extends TestCase { // Ok public void testMyCaseWithOneAssert() { boolean myVar = false; @@ -834,7 +870,7 @@ public class MyTestCase extends TestCase { assertFalse("myVar should be false", myVar); assertEquals("should equals false", false, myVar); } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -871,14 +907,14 @@ with messages provide the developer a clearer idea of what the test does. **Example(s):** ``` java -public class Foo extends TestCase { +{%raw%}public class Foo extends TestCase { public void testSomething() { Bar b = findBar(); // This is better than having a NullPointerException // assertNotNull("bar not found", b); b.work(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -899,7 +935,7 @@ In JUnit4, use the @Test(expected) annotation to denote tests that should throw **Example(s):** ``` java -public class MyTest { +{%raw%}public class MyTest { @Test public void testBad() { try { @@ -913,7 +949,7 @@ public class MyTest { public void testGood() { doSomething(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -936,7 +972,7 @@ by their interface types (i.e, Set) provides much more flexibility. **Example(s):** ``` java -import java.util.ArrayList; +{%raw%}import java.util.ArrayList; import java.util.HashSet; public class Bar { @@ -953,7 +989,7 @@ public class Bar { public Set getFoo() { return new HashSet(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -975,13 +1011,13 @@ removed or replaced outside of the object that owns it. It is safer to return a **Example(s):** ``` java -public class SecureSystem { +{%raw%}public class SecureSystem { UserData [] ud; public UserData [] getUserData() { // Don't return directly the internal array, return a copy return ud; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1005,12 +1041,12 @@ the method really overrides one, which helps refactoring and clarifies intent. **Example(s):** ``` java -public class Foo implements Runnable { +{%raw%}public class Foo implements Runnable { // This method is overridden, and should have an @Override annotation public void run() { } - } + }{%endraw%} ``` **Use this rule by referencing it:** @@ -1042,14 +1078,14 @@ can lead to quite messy code. This rule looks for several declarations on the sa **Example(s):** ``` java -String name; // separate declarations +{%raw%}String name; // separate declarations String lastname; String name, lastname; // combined declaration, a violation String name, lastname; // combined declaration on multiple lines, no violation by default. - // Set property strictMode to true to mark this as violation. + // Set property strictMode to true to mark this as violation.{%endraw%} ``` **This rule has the following properties:** @@ -1102,11 +1138,11 @@ can be avoided, they will just return false. **Example(s):** ``` java -class Foo { +{%raw%}class Foo { boolean bar(String x) { return x.equalsIgnoreCase("2"); // should be "2".equalsIgnoreCase(x) } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1140,11 +1176,11 @@ can be avoided, they will just return false. **Example(s):** ``` java -class Foo { +{%raw%}class Foo { boolean bar(String x) { return x.equals("2"); // should be "2".equals(x) } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1167,7 +1203,7 @@ effectively. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void good() { try{ Integer.parseInt("a"); @@ -1187,7 +1223,7 @@ public class Foo { throw new Exception(e.getMessage()); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1211,7 +1247,7 @@ Consider replacing Enumeration usages with the newer java.util.Iterator **Example(s):** ``` java -public class Foo implements Enumeration { +{%raw%}public class Foo implements Enumeration { private int x = 42; public boolean hasMoreElements() { return true; @@ -1219,7 +1255,7 @@ public class Foo implements Enumeration { public Object nextElement() { return String.valueOf(i++); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1243,11 +1279,11 @@ Consider replacing Hashtable usage with the newer java.util.Map if thread safety **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { Hashtable h = new Hashtable(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1271,11 +1307,11 @@ Consider replacing Vector usages with the newer java.util.ArrayList if expensive **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { Vector v = new Vector(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1299,14 +1335,14 @@ All switch statements should include a default option to catch any unspecified v **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { int x = 2; switch (x) { case 1: int j = 6; case 2: int j = 8; // missing default: here } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1336,14 +1372,14 @@ will (and by priority) and avoid clogging the Standard out log. **Example(s):** ``` java -class Foo{ +{%raw%}class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); public void testA () { System.out.println("Entering test"); // Better use this log.fine("Entering test"); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1364,11 +1400,11 @@ Avoid passing parameters to methods or constructors without actually referencing **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private void bar(String howdy) { // howdy is not used } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1405,10 +1441,10 @@ This rule will also find unused on demand imports, i.e. import com.foo.*. **Example(s):** ``` java -import java.io.File; // not referenced or required +{%raw%}import java.io.File; // not referenced or required import java.util.*; // not referenced or required -public class Foo {} +public class Foo {}{%endraw%} ``` **Use this rule by referencing it:** @@ -1429,11 +1465,11 @@ Detects when a local variable is declared and/or assigned, but not used. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void doSomething() { int i = 5; // Unused } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1454,21 +1490,21 @@ Detects when a private field is declared and/or assigned a value, but not used. **Example(s):** ``` java -public class Something { +{%raw%}public class Something { private static int FOO = 2; // Unused private int i = 5; // Unused private int j = 6; public int addOne() { return j++; } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|ignoredAnnotations|lombok.Setter \| lombok.Getter \| lombok.Builder \| lombok.Data \| lombok.RequiredArgsConstructor \| lombok.AllArgsConstructor \| lombok.Value \| lombok.NoArgsConstructor \| java.lang.Deprecated \| javafx.fxml.FXML|Fully qualified names of the annotation types that should be ignored by this rule|yes. Delimiter is '\|'.| +|ignoredAnnotations|lombok.Setter \| lombok.Getter \| lombok.Builder \| lombok.Data \| lombok.RequiredArgsConstructor \| lombok.AllArgsConstructor \| lombok.Value \| lombok.NoArgsConstructor \| java.lang.Deprecated \| javafx.fxml.FXML \| lombok.experimental.Delegate|Fully qualified names of the annotation types that should be ignored by this rule|yes. Delimiter is '\|'.| **Use this rule with the default properties by just referencing it:** ``` xml @@ -1479,7 +1515,7 @@ public class Something { ``` xml - + ``` @@ -1497,9 +1533,9 @@ Unused Private Method detects when a private method is declared but is unused. **Example(s):** ``` java -public class Something { +{%raw%}public class Something { private void foo() {} // unused -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1551,13 +1587,13 @@ This rule detects JUnit assertions in object equality. These assertions should b **Example(s):** ``` java -public class FooTest extends TestCase { +{%raw%}public class FooTest extends TestCase { void testCode() { Object a, b; assertTrue(a.equals(b)); // bad usage assertEquals(?a should equals b?, a, b); // good usage } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1596,7 +1632,7 @@ more specific methods, like assertNull, assertNotNull. **Example(s):** ``` java -public class FooTest extends TestCase { +{%raw%}public class FooTest extends TestCase { void testCode() { Object a = doSomething(); assertTrue(a==null); // bad usage @@ -1604,7 +1640,7 @@ public class FooTest extends TestCase { assertTrue(a != null); // bad usage assertNotNull(a); // good usage } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1643,13 +1679,13 @@ by more specific methods, like assertSame, assertNotSame. **Example(s):** ``` java -public class FooTest extends TestCase { +{%raw%}public class FooTest extends TestCase { void testCode() { Object a, b; assertTrue(a == b); // bad usage assertSame(a, b); // good usage } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1679,7 +1715,7 @@ When asserting a value is the same as a literal or Boxed boolean, use assertTrue **Example(s):** ``` java -public class MyTestCase extends TestCase { +{%raw%}public class MyTestCase extends TestCase { public void testMyCase() { boolean myVar = true; // Ok @@ -1693,7 +1729,7 @@ public class MyTestCase extends TestCase { // Bad assertEquals("myVar is false", Boolean.FALSE, myVar); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1715,7 +1751,7 @@ Comparing the value of size() to 0 does not convey intent as well as the isEmpty **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void good() { List foo = getList(); if (foo.isEmpty()) { @@ -1729,7 +1765,7 @@ public class Foo { // blah } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1765,7 +1801,7 @@ preserved. **Example(s):** ``` java -public class TryWithResources { +{%raw%}public class TryWithResources { public void run() { InputStream in = null; try { @@ -1786,7 +1822,7 @@ public class TryWithResources { int i = in2.read(); } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1844,7 +1880,7 @@ having to deal with the creation of an array. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void foo(String s, Object[] args) { // Do something here... } @@ -1852,7 +1888,7 @@ public class Foo { public void bar(String s, Object... args) { // Ahh, varargs tastes much better... } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1883,14 +1919,14 @@ a block `{}` is sufficient. **Example(s):** ``` java -public class Example { +{%raw%}public class Example { { while (true) { } // allowed while (false) { } // disallowed do { } while (true); // disallowed do { } while (false); // disallowed } -} +}{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java/codestyle.md b/docs/pages/pmd/rules/java/codestyle.md index d2ff5b66c1..588e052abc 100644 --- a/docs/pages/pmd/rules/java/codestyle.md +++ b/docs/pages/pmd/rules/java/codestyle.md @@ -5,7 +5,7 @@ permalink: pmd_rules_java_codestyle.html folder: pmd/rules/java sidebaractiveurl: /pmd_rules_java.html editmepath: ../pmd-java/src/main/resources/category/java/codestyle.xml -keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, UseUnderscoresInNumericLiterals, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UseDiamondOperator, UselessParentheses, UselessQualifiedThis, VariableNamingConventions, WhileLoopsMustUseBraces +keywords: Code Style, AbstractNaming, AtLeastOneConstructor, AvoidDollarSigns, AvoidFinalLocalVariable, AvoidPrefixingMethodParameters, AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending, AvoidUsingNativeCode, BooleanGetMethodName, CallSuperInConstructor, ClassNamingConventions, CommentDefaultAccessModifier, ConfusingTernary, ControlStatementBraces, DefaultPackage, DontImportJavaLang, DuplicateImports, EmptyMethodInAbstractClassShouldBeAbstract, ExtendsObject, FieldDeclarationsShouldBeAtStartOfClass, FieldNamingConventions, ForLoopShouldBeWhileLoop, ForLoopsMustUseBraces, FormalParameterNamingConventions, GenericsNaming, IdenticalCatchBranches, IfElseStmtsMustUseBraces, IfStmtsMustUseBraces, LinguisticNaming, LocalHomeNamingConvention, LocalInterfaceSessionNamingConvention, LocalVariableCouldBeFinal, LocalVariableNamingConventions, LongVariable, MDBAndSessionBeanNamingConvention, MethodArgumentCouldBeFinal, MethodNamingConventions, MIsLeadingVariableName, NoPackage, UseUnderscoresInNumericLiterals, OnlyOneReturn, PackageCase, PrematureDeclaration, RemoteInterfaceNamingConvention, RemoteSessionInterfaceNamingConvention, ShortClassName, ShortMethodName, ShortVariable, SuspiciousConstantFieldName, TooManyStaticImports, UnnecessaryAnnotationValueElement, UnnecessaryConstructor, UnnecessaryFullyQualifiedName, UnnecessaryLocalBeforeReturn, UnnecessaryModifier, UnnecessaryReturn, UseDiamondOperator, UselessParentheses, UselessQualifiedThis, UseShortArrayInitializer, VariableNamingConventions, WhileLoopsMustUseBraces language: Java --- @@ -37,8 +37,8 @@ by {% rule java/codestyle/ClassNamingConventions %}. **Example(s):** ``` java -public abstract class Foo { // should be AbstractFoo -} +{%raw%}public abstract class Foo { // should be AbstractFoo +}{%endraw%} ``` **This rule has the following properties:** @@ -75,11 +75,11 @@ Classes with solely static members are ignored, refer to [UseUtilityClassRule](p **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { // missing constructor public void doSomething() { ... } public void doOtherThing { ... } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -115,8 +115,8 @@ Avoid using dollar signs in variable/method/class/interface names. **Example(s):** ``` java -public class Fo$o { // not a recommended name -} +{%raw%}public class Fo$o { // not a recommended name +}{%endraw%} ``` **Use this rule by referencing it:** @@ -126,12 +126,25 @@ public class Fo$o { // not a recommended name ## AvoidFinalLocalVariable +Deprecated + **Since:** PMD 4.1 **Priority:** Medium (3) Avoid using final local variables, turn them into fields. +Note that this is a controversial rule which is merely useful to enforce a certain code style +(which is contradictory to good coding practices in most of the cases it's applied to) and +avoid local literals being declared in a scope smaller than the class. + +Also note, that this rule is the opposite of {% rule "java/codestyle/LocalVariableCouldBeFinal" %}. +Having both rules enabled results in contradictory violations being reported. + +This rule is deprecated and will be removed with PMD 7.0.0. There is no replacement planned. +If the goal is to avoid defining constants in a scope smaller than the class, then the rule +{% rule "java/errorprone/AvoidDuplicateLiterals" %} should be used instead. + **This rule is defined by the following XPath expression:** ``` xpath //LocalVariableDeclaration[ @@ -149,11 +162,11 @@ Avoid using final local variables, turn them into fields. **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { public void foo() { final String finalLocalVariable; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -186,18 +199,18 @@ by the more general rule {% rule java/codestyle/FormalParameterNamingConventions **Example(s):** ``` java -// Not really clear +{%raw%}// Not really clear public class Foo { public void bar( int inLeftOperand, Result outRightOperand) { outRightOperand.setValue(inLeftOperand * outRightOperand.getValue()); } -} +}{%endraw%} ``` ``` java -// Far more useful +{%raw%}// Far more useful public class Foo { /** * @@ -209,7 +222,7 @@ public class Foo { Result rightOperand) { rightOperand.setValue(leftOperand * rightOperand.getValue()); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -236,11 +249,11 @@ Clarify your intent by using private or package access modifiers instead. **Example(s):** ``` java -public final class Bar { +{%raw%}public final class Bar { private int x; protected int y; // bar cannot be subclassed, so is y really private or package visible? Bar() {} -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -268,10 +281,10 @@ visibility cannot be reduced). Clarify your intent by using private or package a **Example(s):** ``` java -public final class Foo { +{%raw%}public final class Foo { private int bar() {} protected int baz() {} // Foo cannot be subclassed, and doesn't extend anything, so is baz() really private or package visible? -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -296,7 +309,7 @@ and increases the maintenance burden. **Example(s):** ``` java -public class SomeJNIClass { +{%raw%}public class SomeJNIClass { public SomeJNIClass() { System.loadLibrary("nativelib"); @@ -309,7 +322,7 @@ public class SomeJNIClass { public void invalidCallsInMethod() throws SecurityException, NoSuchMethodException { System.loadLibrary("nativelib"); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -341,9 +354,9 @@ and not(../Annotation//Name[@Image = 'Override']) **Example(s):** ``` java -public boolean getFoo(); // bad +{%raw%}public boolean getFoo(); // bad public boolean isFoo(); // ok -public boolean getFoo(boolean bar); // ok, unless checkParameterizedMethods=true +public boolean getFoo(boolean bar); // ok, unless checkParameterizedMethods=true{%endraw%} ``` **This rule has the following properties:** @@ -386,7 +399,7 @@ another constructor (such as an overloaded constructor) is called, this rule wil **Example(s):** ``` java -public class Foo extends Bar{ +{%raw%}public class Foo extends Bar{ public Foo() { // call the constructor of Bar super(); @@ -396,7 +409,7 @@ public class Foo extends Bar{ this(); // no problem with this } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -423,7 +436,7 @@ and reports utility class names not ending with 'Util'. **Example(s):** ``` java -// This is Pascal case, the recommended naming convention in Java +{%raw%}// This is Pascal case, the recommended naming convention in Java // Note that the default values of this rule don't allow underscores // or accented characters in type names public class FooBar {} @@ -434,7 +447,7 @@ public class FooBar {} public abstract class Thing {} // This class doesn't respect the convention, and will be flagged -public class Éléphant {} +public class Éléphant {}{%endraw%} ``` **This rule has the following properties:** @@ -473,7 +486,7 @@ public class Éléphant {} **Priority:** Medium (3) -To avoid mistakes if we want that a Method, Constructor, Field or Nested class have a default access modifier +To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default access modifier we must add a comment at the beginning of it's declaration. By default the comment must be `/* default */` or `/* package */`, if you want another, you have to provide a regular expression. This rule ignores by default all cases that have a @VisibleForTesting annotation. Use the @@ -484,7 +497,7 @@ property "ignoredAnnotations" to customize the recognized annotations. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { final String stringValue = "some string"; String getString() { return stringValue; @@ -503,7 +516,7 @@ public class Foo { /* default */ class NestedFoo { } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -512,6 +525,7 @@ public class Foo { |----|-------------|-----------|-----------| |ignoredAnnotations|com.google.common.annotations.VisibleForTesting \| android.support.annotation.VisibleForTesting|Fully qualified names of the annotation types that should be ignored by this rule|yes. Delimiter is '\|'.| |regex|\\/\\\*\\s+(default\|package)\\s+\\\*\\/|Regular expression|no| +|checkTopLevelTypes|false|Check for default access modifier in top-level classes, annotations, and enums|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -524,6 +538,7 @@ public class Foo { + ``` @@ -546,9 +561,9 @@ as "does the error case go first?" or "does the common case go fi **Example(s):** ``` java -boolean bar(int x, int y) { +{%raw%}boolean bar(int x, int y) { return (x != y) ? diff : same; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -613,12 +628,12 @@ and IfElseStmtMustUseBraces. **Example(s):** ``` java -while (true) // not recommended +{%raw%}while (true) // not recommended x++; while (true) { // preferred approach x++; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -692,7 +707,7 @@ Avoid importing anything from the package 'java.lang'. These classes are automa **Example(s):** ``` java -import java.lang.String; // this is unnecessary +{%raw%}import java.lang.String; // this is unnecessary public class Foo {} @@ -700,7 +715,7 @@ public class Foo {} import java.lang.*; // this is bad -public class Foo {} +public class Foo {}{%endraw%} ``` **Use this rule by referencing it:** @@ -721,9 +736,9 @@ Duplicate or overlapping import statements should be avoided. **Example(s):** ``` java -import java.lang.String; +{%raw%}import java.lang.String; import java.lang.*; -public class Foo {} +public class Foo {}{%endraw%} ``` **Use this rule by referencing it:** @@ -762,7 +777,7 @@ usage by developers who should be implementing their own versions in the concret **Example(s):** ``` java -public abstract class ShouldBeAbstract { +{%raw%}public abstract class ShouldBeAbstract { public Object couldBeAbstract() { // Should be abstract method ? return null; @@ -770,7 +785,7 @@ public abstract class ShouldBeAbstract { public void couldBeAbstract() { } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -794,8 +809,8 @@ No need to explicitly extend Object. **Example(s):** ``` java -public class Foo extends Object { // not required -} +{%raw%}public class Foo extends Object { // not required +}{%endraw%} ``` **Use this rule by referencing it:** @@ -816,7 +831,7 @@ Fields should be declared at the top of the class, before any method declaration **Example(s):** ``` java -public class HelloWorldBean { +{%raw%}public class HelloWorldBean { // Field declared before methods / inner classes - OK private String _thing; @@ -827,7 +842,7 @@ public class HelloWorldBean { // Field declared after methods / inner classes - avoid this private String _fieldInWrongLocation; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -872,7 +887,7 @@ convention for constants and enum constants. **Example(s):** ``` java -class Foo { +{%raw%}class Foo { int myField = 1; // This is in camel case, so it's ok int my_Field = 1; // This contains an underscore, it's not ok by default // but you may allow it, or even require the "my_" prefix @@ -887,7 +902,7 @@ class Foo { enum AnEnum { ORG, NET, COM; // These use a separate property but are set to ALL_UPPER by default } - } + }{%endraw%} ``` **This rule has the following properties:** @@ -900,7 +915,7 @@ class Foo { |finalFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to final field names|no| |staticFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to static field names|no| |defaultFieldPattern|\[a-z\]\[a-zA-Z0-9\]\*|Regex which applies to field names|no| -|exclusions|serialVersionUID|Names of fields to whitelist.|yes. Delimiter is '\|'.| +|exclusions|serialVersionUID \| serialPersistentFields|Names of fields to whitelist.|yes. Delimiter is '\|'.| **Use this rule with the default properties by just referencing it:** ``` xml @@ -917,7 +932,7 @@ class Foo { - + ``` @@ -942,11 +957,11 @@ Some for loops can be simplified to while loops, this makes them more concise. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { for (;true;) true; // No Init or Update part, may as well be: while (true) } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -977,8 +992,8 @@ by the rule {% rule java/codestyle/ControlStatementBraces %}. **Example(s):** ``` java -for (int i = 0; i < 42; i++) - foo(); +{%raw%}for (int i = 0; i < 42; i++) + foo();{%endraw%} ``` **Use this rule by referencing it:** @@ -1004,7 +1019,7 @@ By default this rule uses the standard Java naming convention (Camel case). **Example(s):** ``` java -class Foo { +{%raw%}class Foo { abstract void bar(int myInt); // This is Camel case, so it's ok @@ -1022,7 +1037,7 @@ class Foo { } - } + }{%endraw%} ``` **This rule has the following properties:** @@ -1071,7 +1086,7 @@ Names for references to generic values should be limited to a single uppercase l **Example(s):** ``` java -public interface GenericDao extends BaseDao { +{%raw%}public interface GenericDao extends BaseDao { // This is ok... } @@ -1085,7 +1100,7 @@ public interface GenericDao { public interface GenericDao { // 'EF' is not ok. -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1110,7 +1125,7 @@ branch. **Example(s):** ``` java -try { +{%raw%}try { // do something } catch (IllegalArgumentException e) { throw e; @@ -1122,7 +1137,7 @@ try { // do something } catch (IllegalArgumentException | IllegalStateException e) { // This is better throw e; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1156,14 +1171,14 @@ by the rule {% rule java/codestyle/ControlStatementBraces %}. **Example(s):** ``` java -// this is OK +{%raw%}// this is OK if (foo) x++; // but this is not if (foo) x = x+1; else - x = x-1; + x = x-1;{%endraw%} ``` **Use this rule by referencing it:** @@ -1194,12 +1209,12 @@ by the rule {% rule java/codestyle/ControlStatementBraces %}. **Example(s):** ``` java -if (foo) // not recommended +{%raw%}if (foo) // not recommended x++; if (foo) { // preferred approach x++; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1230,7 +1245,7 @@ Developers Perceive Them](https://doi.org/10.1007/s10664-014-9350-8). **Example(s):** ``` java -public class LinguisticNaming { +{%raw%}public class LinguisticNaming { int isValid; // the field name indicates a boolean, but it is an int. boolean isTrue; // correct type of the field @@ -1266,7 +1281,7 @@ public class LinguisticNaming { void grapeToWine() { // nothing to return? } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1335,9 +1350,9 @@ The Local Home interface of a Session EJB should be suffixed by 'LocalHome'. **Example(s):** ``` java -public interface MyBeautifulLocalHome extends javax.ejb.EJBLocalHome {} // proper name +{%raw%}public interface MyBeautifulLocalHome extends javax.ejb.EJBLocalHome {} // proper name -public interface MissingProperSuffix extends javax.ejb.EJBLocalHome {} // non-standard name +public interface MissingProperSuffix extends javax.ejb.EJBLocalHome {} // non-standard name{%endraw%} ``` **Use this rule by referencing it:** @@ -1371,9 +1386,9 @@ The Local Interface of a Session EJB should be suffixed by 'Local'. **Example(s):** ``` java -public interface MyLocal extends javax.ejb.EJBLocalObject {} // proper name +{%raw%}public interface MyLocal extends javax.ejb.EJBLocalObject {} // proper name -public interface MissingProperSuffix extends javax.ejb.EJBLocalObject {} // non-standard name +public interface MissingProperSuffix extends javax.ejb.EJBLocalObject {} // non-standard name{%endraw%} ``` **Use this rule by referencing it:** @@ -1394,12 +1409,12 @@ A local variable assigned only once can be declared final. **Example(s):** ``` java -public class Bar { +{%raw%}public class Bar { public void foo () { String txtA = "a"; // if txtA will not be assigned again it is better to do this: final String txtB = "b"; } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1440,7 +1455,7 @@ By default this rule uses the standard Java naming convention (Camel case). **Example(s):** ``` java -class Foo { +{%raw%}class Foo { void bar() { int localVariable = 1; // This is in camel case, so it's ok int local_variable = 1; // This will be reported unless you change the regex @@ -1454,7 +1469,7 @@ class Foo { } } - } + }{%endraw%} ``` **This rule has the following properties:** @@ -1497,7 +1512,7 @@ Fields, formal arguments, or local variable names that are too long can make the **Example(s):** ``` java -public class Something { +{%raw%}public class Something { int reallyLongIntName = -3; // VIOLATION - Field public static void main( String argumentsList[] ) { // VIOLATION - Formal int otherReallyLongName = -5; // VIOLATION - Local @@ -1505,7 +1520,7 @@ public class Something { interestingIntIndex < 10; interestingIntIndex ++ ) { } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1556,9 +1571,9 @@ The EJB Specification states that any MessageDrivenBean or SessionBean should be **Example(s):** ``` java -public class SomeBean implements SessionBean{} // proper name +{%raw%}public class SomeBean implements SessionBean{} // proper name -public class MissingTheProperSuffix implements SessionBean {} // non-standard name +public class MissingTheProperSuffix implements SessionBean {} // non-standard name{%endraw%} ``` **Use this rule by referencing it:** @@ -1579,13 +1594,13 @@ A method argument that is never re-assigned within the method can be declared fi **Example(s):** ``` java -public void foo1 (String param) { // do stuff with param never assigning it +{%raw%}public void foo1 (String param) { // do stuff with param never assigning it } public void foo2 (final String param) { // better, do stuff with param never assigning it -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1611,10 +1626,10 @@ By default this rule uses the standard Java naming convention (Camel case). **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void fooStuff() { } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1670,12 +1685,12 @@ by the more general rule **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int m_foo; // OK public void bar(String m_baz) { // Bad int m_boz = 42; // Bad } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1699,9 +1714,9 @@ Detects when a class, interface, enum or annotation does not have a package defi **Example(s):** ``` java -// no package declaration +{%raw%}// no package declaration public class ClassInDefaultPackage { -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1722,14 +1737,14 @@ A method should have only one exit point, and that should be the last statement **Example(s):** ``` java -public class OneReturnOnly1 { +{%raw%}public class OneReturnOnly1 { public void foo(int x) { if (x > 0) { return "hey"; // first exit } return "hi"; // second exit } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1753,10 +1768,10 @@ Detects when a package definition contains uppercase characters. **Example(s):** ``` java -package com.MyCompany; // should be lowercase name +{%raw%}package com.MyCompany; // should be lowercase name public class SomeClass { -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1777,7 +1792,7 @@ Checks for variables that are defined before they might be used. A reference is **Example(s):** ``` java -public int getLength(String[] strings) { +{%raw%}public int getLength(String[] strings) { int length = 0; // declared prematurely @@ -1788,7 +1803,7 @@ public int getLength(String[] strings) { } return length; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1825,14 +1840,14 @@ Remote Interface of a Session EJB should not have a suffix. **Example(s):** ``` java -/* Poor Session suffix */ +{%raw%}/* Poor Session suffix */ public interface BadSuffixSession extends javax.ejb.EJBObject {} /* Poor EJB suffix */ public interface BadSuffixEJB extends javax.ejb.EJBObject {} /* Poor Bean suffix */ -public interface BadSuffixBean extends javax.ejb.EJBObject {} +public interface BadSuffixBean extends javax.ejb.EJBObject {}{%endraw%} ``` **Use this rule by referencing it:** @@ -1866,9 +1881,9 @@ A Remote Home interface type of a Session EJB should be suffixed by 'Home'. **Example(s):** ``` java -public interface MyBeautifulHome extends javax.ejb.EJBHome {} // proper name +{%raw%}public interface MyBeautifulHome extends javax.ejb.EJBHome {} // proper name -public interface MissingProperSuffix extends javax.ejb.EJBHome {} // non-standard name +public interface MissingProperSuffix extends javax.ejb.EJBHome {} // non-standard name{%endraw%} ``` **Use this rule by referencing it:** @@ -1892,8 +1907,8 @@ Short Classnames with fewer than e.g. five characters are not recommended. **Example(s):** ``` java -public class Foo { -} +{%raw%}public class Foo { +}{%endraw%} ``` **This rule has the following properties:** @@ -1932,10 +1947,10 @@ Method names that are very short are not helpful to the reader. **Example(s):** ``` java -public class ShortMethod { +{%raw%}public class ShortMethod { public void a( int i ) { // Violation } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1982,7 +1997,7 @@ Fields, local variables, or parameter names that are very short are not helpful **Example(s):** ``` java -public class Something { +{%raw%}public class Something { private int q = 15; // field - too short public static void main( String as[] ) { // formal arg - too short int r = 20 + q; // local var - too short @@ -1993,7 +2008,7 @@ public class Something { r += q; } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2041,12 +2056,12 @@ by the more general rule {% rule java/codestyle/FieldNamingConventions %}. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { // this is bad, since someone could accidentally // do PI = 2.71828; which is actually e // final double PI = 3.16; is ok double PI = 3.16; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2073,11 +2088,11 @@ which class a static member comes from (Sun 1.5 Language Guide). **Example(s):** ``` java -import static Lennon; +{%raw%}import static Lennon; import static Ringo; import static George; import static Paul; -import static Yoko; // Too much ! +import static Yoko; // Too much !{%endraw%} ``` **This rule has the following properties:** @@ -2113,7 +2128,7 @@ Avoid the use of value in annotations when it's the only element. **Example(s):** ``` java -@TestClassAnnotation(value = "TEST") +{%raw%}@TestClassAnnotation(value = "TEST") public class Foo { @TestMemberAnnotation(value = "TEST") @@ -2139,7 +2154,7 @@ public class Foo { int x = 42; return; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2162,9 +2177,9 @@ modifier as the declaring class. In an enum type, the default constructor is imp **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public Foo() {} -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2201,12 +2216,12 @@ which is covered by an import statement is redundant. Consider using the non-fu **Example(s):** ``` java -import java.util.List; +{%raw%}import java.util.List; public class Foo { private java.util.List list1; // Unnecessary FQN private List list2; // More appropriate given import of 'java.util.List' -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2227,12 +2242,12 @@ Avoid the creation of unnecessary local variables **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public int foo() { int x = doSomething(); return x; // instead, just 'return doSomething();' } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2272,7 +2287,7 @@ For historical reasons, modifiers which are implied by the context are accepted **Example(s):** ``` java -public @interface Annotation { +{%raw%}public @interface Annotation { public abstract void bar(); // both abstract and public are ignored by the compiler public static final int X = 0; // public, static, and final all ignored public static class Bar {} // public, static ignored @@ -2289,7 +2304,7 @@ public class Bar { public static enum FoorBar { // static ignored FOO; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2310,12 +2325,12 @@ Avoid the use of unnecessary return statements. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { int x = 42; return; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2352,8 +2367,8 @@ which makes the code also more readable. **Example(s):** ``` java -List strings = new ArrayList(); // unnecessary duplication of type parameters -List stringsWithDiamond = new ArrayList<>(); // using the diamond operator is more concise +{%raw%}List strings = new ArrayList(); // unnecessary duplication of type parameters +List stringsWithDiamond = new ArrayList<>(); // using the diamond operator is more concise{%endraw%} ``` **Use this rule by referencing it:** @@ -2430,7 +2445,7 @@ Useless parentheses should be removed. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int _bar1; private Integer _bar2; @@ -2439,7 +2454,7 @@ public class Foo { _bar1 = Integer.valueOf((n)); // here _bar2 = (n); // and here } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2468,7 +2483,7 @@ Reports qualified this usages in the same class. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { final Foo otherFoo = Foo.this; // use "this" directly public void doSomething() { @@ -2491,7 +2506,7 @@ public class Foo { private class Foo2 { final Foo2 myFoo2 = Foo2.this; // Use "this" direclty } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2499,6 +2514,36 @@ public class Foo { ``` +## UseShortArrayInitializer + +**Since:** PMD 6.15.0 + +**Priority:** Medium (3) + +When declaring and initializing array fields or variables, it is not necessary to explicitly create a new array +using `new`. Instead one can simply define the initial content of the array as a expression in curly braces. + +E.g. `int[] x = new int[] { 1, 2, 3 };` can be written as `int[] x = { 1, 2, 3 };`. + +**This rule is defined by the following XPath expression:** +``` xpath +//VariableDeclarator + [VariableDeclaratorId[@ArrayType = true() and @TypeInferred = false()]] + [VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression/ArrayDimsAndInits/ArrayInitializer] +``` + +**Example(s):** + +``` java +{%raw%}Foo[] x = new Foo[] { ... }; // Overly verbose +Foo[] x = { ... }; //Equivalent to above line{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml + +``` + ## UseUnderscoresInNumericLiterals **Since:** PMD 6.10.0 @@ -2543,9 +2588,9 @@ that are misplaced (not making groups of 3 digits) are reported. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int num = 1000000; // should be 1_000_000 -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2590,11 +2635,11 @@ by the more general rules {% rule java/codestyle/FieldNamingConventions %}, **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public static final int MY_NUM = 0; public String myTest = ""; DataModule dmTest = new DataModule(); -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2662,12 +2707,12 @@ by the rule {% rule java/codestyle/ControlStatementBraces %}. **Example(s):** ``` java -while (true) // not recommended +{%raw%}while (true) // not recommended x++; while (true) { // preferred approach x++; -} +}{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java/design.md b/docs/pages/pmd/rules/java/design.md index b0647c24cd..eaa90e4965 100644 --- a/docs/pages/pmd/rules/java/design.md +++ b/docs/pages/pmd/rules/java/design.md @@ -30,10 +30,10 @@ protected constructor in order to prevent instantiation than make the class misl **Example(s):** ``` java -public abstract class Example { +{%raw%}public abstract class Example { String field; int otherField; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -60,7 +60,7 @@ Avoid catching generic exceptions such as NullPointerException, RuntimeException **Example(s):** ``` java -package com.igate.primitive; +{%raw%}package com.igate.primitive; public class PrimitiveType { @@ -75,7 +75,7 @@ public class PrimitiveType { e.printStackTrace(); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -96,7 +96,7 @@ Avoid creating deeply nested if-then statements since they are harder to read an **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar(int x, int y, int z) { if (x>y) { if (y>z) { @@ -106,7 +106,7 @@ public class Foo { } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -148,13 +148,13 @@ Catch blocks that merely rethrow a caught exception only add to code size and ru **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { try { // do something } catch (SomeException se) { throw se; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -187,14 +187,14 @@ code size and runtime complexity. **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { try { // do something } catch (SomeException se) { // harmless comment throw new SomeException(se); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -244,11 +244,11 @@ public class Foo { **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { throw new NullPointerException(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -282,11 +282,11 @@ or **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() throws Exception { throw new Exception(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -315,8 +315,8 @@ exceptional cases with a `@throws` Javadoc tag, which allows being more descript **Example(s):** ``` java -public void foo() throws RuntimeException { -} +{%raw%}public void foo() throws RuntimeException { +}{%endraw%} ``` **Use this rule by referencing it:** @@ -345,9 +345,9 @@ TypeDeclaration[count(../TypeDeclaration) = 1]/ClassOrInterfaceDeclaration **Example(s):** ``` java -public class Foo { //Should be final +{%raw%}public class Foo { //Should be final private Foo() { } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -376,7 +376,7 @@ Sometimes two consecutive 'if' statements can be consolidated by separating thei **Example(s):** ``` java -void bar() { +{%raw%}void bar() { if (x) { // original implementation if (y) { // do stuff @@ -388,7 +388,7 @@ void bar() { if (x && y) { // optimized implementation // do stuff } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -410,7 +410,7 @@ A number higher than the specified threshold can indicate a high degree of coupl **Example(s):** ``` java -import com.Blah; +{%raw%}import com.Blah; import org.Bar; import org.Bardo; @@ -425,7 +425,7 @@ public class Foo { ObjectZ var93; return something; } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -464,7 +464,7 @@ details on the calculation, see the documentation of the [Cyclo metric](pmd_java Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. -Additionnally, classes with many methods of moderate complexity get reported as well once the total of their +Additionally, classes with many methods of moderate complexity get reported as well once the total of their methods' complexities reaches 80, even if none of the methods was directly reported. Reported methods should be broken down into several smaller methods. Reported classes should probably be broken down @@ -475,7 +475,7 @@ into subcomponents. **Example(s):** ``` java -class Foo { +{%raw%}class Foo { void baseCyclo() { // Cyclo = 1 highCyclo(); } @@ -498,7 +498,7 @@ class Foo { } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -550,7 +550,7 @@ into the former client classes. **Example(s):** ``` java -public class DataClass { +{%raw%}public class DataClass { public int bar = 0; public int na = 0; @@ -559,7 +559,7 @@ public class DataClass { public void setBee(int n) { bee = n; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -584,7 +584,7 @@ Errors are system exceptions. Do not extend them. **Example(s):** ``` java -public class Foo extends Error { } +{%raw%}public class Foo extends Error { }{%endraw%} ``` **Use this rule by referencing it:** @@ -606,7 +606,7 @@ Either add the necessary validation or use an alternate control structure. **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { try { try { } catch (Exception e) { @@ -616,7 +616,7 @@ public void bar() { } catch (WrapperException e) { // do some more stuff } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -639,7 +639,7 @@ apart the code becomes more manageable and ripe for reuse. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar1() { // 1000 lines of code } @@ -653,7 +653,7 @@ public class Foo { public void barN() { // 1000 lines of code } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -693,12 +693,12 @@ user-specified threshold. **Example(s):** ``` java -import blah.blah.Baz; +{%raw%}import blah.blah.Baz; import blah.blah.Bif; // 18 others from the same package elided public class Foo { public void doWork() {} -} +}{%endraw%} ``` **This rule has the following properties:** @@ -739,11 +739,11 @@ Try to reduce the method length by creating helper methods and removing any copy **Example(s):** ``` java -public void doSomething() { +{%raw%}public void doSomething() { System.out.println("Hello world!"); System.out.println("Hello world!"); // 98 copies omitted for brevity. -} +}{%endraw%} ``` **This rule has the following properties:** @@ -782,7 +782,7 @@ same datatype. These situations usually denote the need for new objects to wrap **Example(s):** ``` java -public void addPerson( // too many arguments liable to be mixed up +{%raw%}public void addPerson( // too many arguments liable to be mixed up int birthYear, int birthMonth, int birthDate, int height, int weight, int ssn) { . . . . @@ -792,7 +792,7 @@ public void addPerson( // preferred approach Date birthdate, BodyMeasurements measurements, int ssn) { . . . . -} +}{%endraw%} ``` **This rule has the following properties:** @@ -833,7 +833,7 @@ developed easily. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public String value; public Bar something; public Variable var; @@ -843,7 +843,7 @@ public class Foo { public void doMoreWork() {} public void doWorkAgain() {} // [... more more public methods ...] -} +}{%endraw%} ``` **This rule has the following properties:** @@ -888,9 +888,9 @@ in each object at runtime. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public final int BAR = 42; // this could be static and save some space -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -936,7 +936,7 @@ of the field or by a constructor. This helps in converting existing classes to **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int x; // could be final public Foo() { x = 7; @@ -944,7 +944,7 @@ public class Foo { public void foo() { int a = x + 2; } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -988,7 +988,7 @@ See also the references: **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { /** * This example will result in two violations. */ @@ -1008,7 +1008,7 @@ public class Foo { // this method call is ok, because we have create the new instance of D locally. d.doSomethingElse(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1032,7 +1032,7 @@ Use opposite operator instead of negating the whole expression with a logic comp **Example(s):** ``` java -public boolean bar(int a, int b) { +{%raw%}public boolean bar(int a, int b) { if (!(a == b)) { // use != return false; @@ -1043,7 +1043,7 @@ public boolean bar(int a, int b) { } return true; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1065,13 +1065,13 @@ except when using one of the configured allowed classes. **Example(s):** ``` java -package some.package; +{%raw%}package some.package; import some.other.package.subpackage.subsubpackage.DontUseThisClass; public class Bar { DontUseThisClass boo = new DontUseThisClass(); -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1118,7 +1118,7 @@ by the rule {% rule java/design/CyclomaticComplexity %}. **Example(s):** ``` java -public class Foo { // This has a Cyclomatic Complexity = 9 +{%raw%}public class Foo { // This has a Cyclomatic Complexity = 9 1 public void example() { 2 if (a == b) { 3 if (a1 == b1) { @@ -1153,7 +1153,7 @@ public class Foo { // This has a Cyclomatic Complexity = 9 } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1200,7 +1200,7 @@ by the rule {% rule java/design/NcssCount %}. **Example(s):** ``` java -public class Foo extends Bar { +{%raw%}public class Foo extends Bar { public Foo() { super(); @@ -1211,7 +1211,7 @@ public class Foo extends Bar { //this constructor only has 1 NCSS lines super.foo(); } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1245,14 +1245,14 @@ public class Foo extends Bar { This rule uses the NCSS (Non-Commenting Source Statements) metric to determine the number of lines of code in a class, method or constructor. NCSS ignores comments, blank lines, and only counts actual statements. For more details on the calculation, see the documentation of -the [NCSS metric](/pmd_java_metrics_index.html#non-commenting-source-statements-ncss). +the [NCSS metric](pmd_java_metrics_index.html#non-commenting-source-statements-ncss). **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.design.NcssCountRule](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/NcssCountRule.java) **Example(s):** ``` java -import java.util.Collections; // +0 +{%raw%}import java.util.Collections; // +0 import java.io.IOException; // +0 class Foo { // +1, total Ncss = 12 @@ -1276,7 +1276,7 @@ class Foo { // +1, total Ncss = 12 assert false; // +1 } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1323,7 +1323,7 @@ by the rule {% rule java/design/NcssCount %}. **Example(s):** ``` java -public class Foo extends Bar { +{%raw%}public class Foo extends Bar { public int methd() { super.methd(); @@ -1335,7 +1335,7 @@ public class Foo extends Bar { //this method only has 1 NCSS lines return 1; } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1380,7 +1380,7 @@ by the rule {% rule java/design/NcssCount %}. **Example(s):** ``` java -public class Foo extends Bar { +{%raw%}public class Foo extends Bar { public Foo() { //this class only has 6 NCSS lines super(); @@ -1391,7 +1391,7 @@ public class Foo extends Bar { super.foo(); } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1426,7 +1426,7 @@ The NPath complexity of a method is the number of acyclic execution paths throug While cyclomatic complexity counts the number of decision points in a method, NPath counts the number of full paths from the beginning to the end of the block of the method. That metric grows exponentially, as it multiplies the complexity of statements in the same block. For more details on the calculation, see the -documentation of the [NPath metric](/pmd_java_metrics_index.html#npath-complexity-npath). +documentation of the [NPath metric](pmd_java_metrics_index.html#npath-complexity-npath). A threshold of 200 is generally considered the point where measures should be taken to reduce complexity and increase readability. @@ -1436,7 +1436,7 @@ complexity and increase readability. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public static void bar() { // Ncss = 252: reported! boolean a, b = true; try { // 2 * 2 + 2 = 6 @@ -1469,7 +1469,7 @@ public class Foo { List buz = new ArrayList(); } while (a && j++ < 30); } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1509,8 +1509,8 @@ derived from RuntimeException or a checked exception. **Example(s):** ``` java -public void foo() throws Exception { -} +{%raw%}public void foo() throws Exception { +}{%endraw%} ``` **This rule has the following properties:** @@ -1559,7 +1559,7 @@ or **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public boolean test() { return condition ? true : something(); // can be as simple as return condition || something(); } @@ -1575,7 +1575,7 @@ public class Foo { public void test4() { final boolean otherValue = condition ? something() : false; // can be as simple as condition && something(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1622,12 +1622,12 @@ PrimaryExpression/PrimarySuffix/Arguments/ArgumentList **Example(s):** ``` java -public class SimpleTest extends TestCase { +{%raw%}public class SimpleTest extends TestCase { public void testX() { assertTrue("not empty", !r.isEmpty()); // replace with assertFalse("not empty", r.isEmpty()) assertFalse(!r.isEmpty()); // replace with assertTrue(r.isEmpty()) } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1652,13 +1652,13 @@ Avoid unnecessary comparisons in boolean expressions, they serve no purpose and **Example(s):** ``` java -public class Bar { +{%raw%}public class Bar { // can be simplified to // bar = isFoo(); private boolean bar = (isFoo() == true); public isFoo() { return false;} -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1680,7 +1680,7 @@ the conditional test can be returned instead. **Example(s):** ``` java -public boolean isBarEqualTo(int x) { +{%raw%}public boolean isBarEqualTo(int x) { if (bar == x) { // this bit of code... return true; } else { @@ -1690,7 +1690,7 @@ public boolean isBarEqualTo(int x) { public boolean isBarEqualTo(int x) { return bar == x; // can be replaced with this -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1737,13 +1737,13 @@ InstanceOfExpression **Example(s):** ``` java -class Foo { +{%raw%}class Foo { void bar(Object x) { if (x != null && x instanceof Bar) { // just drop the "x != null" check } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1766,20 +1766,20 @@ within those methods. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int x; // no reason to exist at the Foo instance level public void foo(int y) { x = y + 5; return x; } -} +}{%endraw%} ``` **This rule has the following properties:** |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| -|ignoredAnnotations|lombok.Setter \| lombok.Getter \| lombok.Builder \| lombok.Data \| lombok.RequiredArgsConstructor \| lombok.AllArgsConstructor \| lombok.Value \| lombok.NoArgsConstructor|Fully qualified names of the annotation types that should be ignored by this rule|yes. Delimiter is '\|'.| +|ignoredAnnotations|lombok.Setter \| lombok.Getter \| lombok.Builder \| lombok.Data \| lombok.RequiredArgsConstructor \| lombok.AllArgsConstructor \| lombok.Value \| lombok.NoArgsConstructor \| lombok.experimental.Delegate|Fully qualified names of the annotation types that should be ignored by this rule|yes. Delimiter is '\|'.| |checkInnerClasses|false|Check inner classes|no| |disallowNotAssignment|false|Disallow violations where the first usage is not an assignment|no| @@ -1792,7 +1792,7 @@ public class Foo { ``` xml - + @@ -1820,7 +1820,7 @@ by the rule {% rule java/design/CyclomaticComplexity %}. **Example(s):** ``` java -public class Foo { // This has a Cyclomatic Complexity = 12 +{%raw%}public class Foo { // This has a Cyclomatic Complexity = 12 1 public void example() { 2 if (a == b || (c == d && e == f)) { // Only one 3 if (a1 == b1) { @@ -1855,7 +1855,7 @@ public class Foo { // This has a Cyclomatic Complexity = 12 } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1897,7 +1897,7 @@ on the switch variable. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar(int x) { switch (x) { case 1: { @@ -1909,7 +1909,7 @@ public class Foo { } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1949,7 +1949,7 @@ city/state/zip fields could park them within a single Address field. **Example(s):** ``` java -public class Person { // too many separate fields +{%raw%}public class Person { // too many separate fields int birthYear; int birthMonth; int birthDate; @@ -1960,7 +1960,7 @@ public class Person { // too many separate fields public class Person { // this is more manageable Date birthDate; BodyMeasurements measurements; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2041,7 +2041,7 @@ The overriding method merely calls the same method defined in a superclass. **Example(s):** ``` java -public void foo(String bar) { +{%raw%}public void foo(String bar) { super.foo(bar); // why bother overriding? } @@ -2052,7 +2052,7 @@ public String foo() { @Id public Long getId() { return super.getId(); // OK if 'ignoreAnnotations' is false, which is the default behavior -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2098,7 +2098,7 @@ your API. **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { public void connect(String username, String pssd, String databaseName, @@ -2110,7 +2110,7 @@ public class MyClass { { } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2135,14 +2135,29 @@ remember to add a private constructor to prevent instantiation. **Example(s):** ``` java -public class MaybeAUtility { +{%raw%}public class MaybeAUtility { public static void foo() {} public static void bar() {} -} +}{%endraw%} ``` -**Use this rule by referencing it:** +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|ignoredAnnotations|lombok.experimental.UtilityClass|Fully qualified names of the annotation types that should be ignored by this rule|yes. Delimiter is '\|'.| + +**Use this rule with the default properties by just referencing it:** ``` xml ``` +**Use this rule and customize it:** +``` xml + + + + + +``` + diff --git a/docs/pages/pmd/rules/java/documentation.md b/docs/pages/pmd/rules/java/documentation.md index a8cf2374fa..2abf433d4f 100644 --- a/docs/pages/pmd/rules/java/documentation.md +++ b/docs/pages/pmd/rules/java/documentation.md @@ -22,7 +22,7 @@ A rule for the politically correct... we don't want to offend anyone. **Example(s):** ``` java -//OMG, this is horrible, Bob is an idiot !!! +{%raw%}//OMG, this is horrible, Bob is an idiot !!!{%endraw%} ``` **This rule has the following properties:** @@ -60,11 +60,11 @@ Denotes whether comments are required (or unwanted) for specific language elemen **Example(s):** ``` java -/** +{%raw%}/** * * * @author Jon Doe -*/ +*/{%endraw%} ``` **This rule has the following properties:** @@ -79,6 +79,7 @@ Denotes whether comments are required (or unwanted) for specific language elemen |protectedMethodCommentRequirement|Required|Protected method constructor comments. Possible values: \[Required, Ignored, Unwanted\]|no| |enumCommentRequirement|Required|Enum comments. Possible values: \[Required, Ignored, Unwanted\]|no| |serialVersionUIDCommentRequired|Ignored|Serial version UID comments. Possible values: \[Required, Ignored, Unwanted\]|no| +|serialPersistentFieldsCommentRequired|Ignored|Serial persistent fields comments. Possible values: \[Required, Ignored, Unwanted\]|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -97,6 +98,7 @@ Denotes whether comments are required (or unwanted) for specific language elemen + ``` @@ -114,7 +116,7 @@ Determines whether the dimensions of non-header comments found are within the sp **Example(s):** ``` java -/** +{%raw%}/** * * too many lines! * @@ -129,7 +131,7 @@ Determines whether the dimensions of non-header comments found are within the sp * * * -*/ +*/{%endraw%} ``` **This rule has the following properties:** @@ -175,9 +177,9 @@ and unintentional empty constructors. **Example(s):** ``` java -public Foo() { +{%raw%}public Foo() { // This constructor is intentionally empty. Nothing special is needed here. -} +}{%endraw%} ``` **This rule has the following properties:** @@ -219,8 +221,8 @@ empty methods. **Example(s):** ``` java -public void doSomething() { -} +{%raw%}public void doSomething() { +}{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java/errorprone.md b/docs/pages/pmd/rules/java/errorprone.md index adb805ee8b..5998b4fab6 100644 --- a/docs/pages/pmd/rules/java/errorprone.md +++ b/docs/pages/pmd/rules/java/errorprone.md @@ -22,12 +22,12 @@ Avoid assignments in operands; this can make code more complicated and harder to **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { int x = 2; if ((x = getX()) == 3) { System.out.println("3!"); } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -69,12 +69,12 @@ Identifies a possible unsafe usage of a static field. **Example(s):** ``` java -public class StaticField { +{%raw%}public class StaticField { static int x; public FinalFields(int y) { x = y; // unsafe } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -121,7 +121,7 @@ and **Example(s):** ``` java -import java.lang.reflect.AccessibleObject; +{%raw%}import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; import java.security.PrivilegedAction; @@ -147,7 +147,7 @@ public class Violation { // Possible call to forbidden PrivilegedAction PrivilegedAction priv = (PrivilegedAction) new Object(); priv.run(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -171,11 +171,11 @@ Use of the term 'assert' will conflict with newer versions of Java since it is a **Example(s):** ``` java -public class A { +{%raw%}public class A { public class Foo { String assert = "foo"; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -197,7 +197,7 @@ Ensure that the usage is not a bug, or consider using another approach. **Example(s):** ``` java -// unusual use of branching statement in a loop +{%raw%}// unusual use of branching statement in a loop for (int i = 0; i < 10; i++) { if (i*i <= 25) { continue; @@ -210,7 +210,7 @@ for (int i = 0; i < 10; i++) { if (i*i > 25) { break; } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -253,10 +253,10 @@ Note that Oracle has declared Object.finalize() as deprecated since JDK 9. **Example(s):** ``` java -void foo() { +{%raw%}void foo() { Bar b = new Bar(); b.finalize(); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -282,14 +282,14 @@ original error, causing other, more subtle problems later on. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { try { // do something } catch (NullPointerException npe) { } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -311,13 +311,13 @@ OutOfMemoryError that should be exposed and managed separately. **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { try { // do something } catch (Throwable th) { // should not catch Throwable th.printStackTrace(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -367,11 +367,11 @@ exactly equal to 0.1, as one would expect. Therefore, it is generally recommend **Example(s):** ``` java -BigDecimal bd = new BigDecimal(1.123); // loss of precision, this would trigger the rule +{%raw%}BigDecimal bd = new BigDecimal(1.123); // loss of precision, this would trigger the rule BigDecimal bd = new BigDecimal("1.123"); // preferred approach -BigDecimal bd = new BigDecimal(12); // preferred approach, ok for integer values +BigDecimal bd = new BigDecimal(12); // preferred approach, ok for integer values{%endraw%} ``` **Use this rule by referencing it:** @@ -392,13 +392,13 @@ Code containing duplicate String literals can usually be improved by declaring t **Example(s):** ``` java -private void bar() { +{%raw%}private void bar() { buz("Howdy"); buz("Howdy"); buz("Howdy"); buz("Howdy"); } -private void buz(String x) {} +private void buz(String x) {}{%endraw%} ``` **This rule has the following properties:** @@ -446,11 +446,11 @@ Use of the term 'enum' will conflict with newer versions of Java since it is a r **Example(s):** ``` java -public class A { +{%raw%}public class A { public class Foo { String enum = "foo"; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -473,12 +473,12 @@ Smalltalk often prefer this approach as the methods denote accessor methods. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { Object bar; // bar is data or an action or both? void bar() { } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -500,9 +500,9 @@ This probably means that type and/or field names should be chosen more carefully **Example(s):** ``` java -public class Foo extends Bar { +{%raw%}public class Foo extends Bar { int foo; // There is probably a better name that can be used -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -531,7 +531,7 @@ Each caught exception type should be handled in its own catch clause. **Example(s):** ``` java -try { // Avoid this +{%raw%}try { // Avoid this // do something } catch (Exception ee) { if (ee instanceof IOException) { @@ -543,7 +543,7 @@ try { // Prefer this: // do something } catch (IOException ee) { cleanup(); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -572,7 +572,7 @@ More exceptions can be defined with the property "ignoreMagicNumbers". **Example(s):** ``` java -private static final int MAX_NUMBER_OF_REQUESTS = 10; +{%raw%}private static final int MAX_NUMBER_OF_REQUESTS = 10; public void checkRequests() { @@ -589,7 +589,7 @@ public void checkRequests() { if (aDouble > 0.0) {} // magic number 0.0 if (aDouble >= Double.MIN_VALUE) {} // preferred approach -} +}{%endraw%} ``` **This rule has the following properties:** @@ -640,13 +640,13 @@ only add to code size. Either remove the invocation, or use the return result. **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { try { // do something } catch (SomeException se) { se.getMessage(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -668,7 +668,7 @@ Ensure that the intended usage is not a bug, or consider simplifying the express **Example(s):** ``` java -// These are typo bugs, or at best needlessly complex and confusing: +{%raw%}// These are typo bugs, or at best needlessly complex and confusing: int i = - -1; int j = + - +1; int z = ~~2; @@ -684,7 +684,7 @@ boolean c = false; // And these just make your brain hurt: int i = ~-2; -int j = -~7; +int j = -~7;{%endraw%} ``` **Use this rule by referencing it:** @@ -706,9 +706,9 @@ interpreted as an octal value. **Example(s):** ``` java -int i = 012; // set i with 10 not 12 +{%raw%}int i = 012; // set i with 10 not 12 int j = 010; // set j with 8 not 10 -k = i * j; // set k with 80 not 120 +k = i * j; // set k with 80 not 120{%endraw%} ``` **This rule has the following properties:** @@ -750,7 +750,7 @@ precision when comparing floating point numbers these are likely to cause logic **Example(s):** ``` java -boolean x = (y == Double.NaN); +{%raw%}boolean x = (y == Double.NaN);{%endraw%} ``` **Use this rule by referencing it:** @@ -774,7 +774,7 @@ naming conventions, i.e. for a variable named foo, getFoo() and setFoo() accesso **Example(s):** ``` java -private transient int someFoo; // good, it's transient +{%raw%}private transient int someFoo; // good, it's transient private static int otherFoo; // also OK private int moreFoo; // OK, has proper accessors, see below private int badFoo; // bad, should be marked transient @@ -785,7 +785,7 @@ private void setMoreFoo(int moreFoo){ private int getMoreFoo(){ return this.moreFoo; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -824,14 +824,14 @@ It is likely that you used || instead of && or vice versa. **Example(s):** ``` java -public String bar(String string) { +{%raw%}public String bar(String string) { // should be && if (string!=null || !string.equals("")) return string; // should be || if (string==null && string.equals("")) return string; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -871,12 +871,12 @@ Super should be called at the start of the method **Example(s):** ``` java -public class DummyActivity extends Activity { +{%raw%}public class DummyActivity extends Activity { public void onCreate(Bundle bundle) { // missing call to super.onCreate(bundle) foo(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -914,12 +914,12 @@ Super should be called at the end of the method **Example(s):** ``` java -public class DummyActivity extends Activity { +{%raw%}public class DummyActivity extends Activity { public void onPause() { foo(); // missing call to super.onPause() } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -940,7 +940,7 @@ The skip() method may skip a smaller number of bytes than requested. Check the r **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private FileInputStream _s = new FileInputStream("file"); @@ -955,7 +955,7 @@ public class Foo { throw new EOFException(); n -= skipped; } - } + }{%endraw%} ``` **Use this rule by referencing it:** @@ -989,7 +989,7 @@ count(PrimarySuffix) = 1 **Example(s):** ``` java -Collection c = new ArrayList(); +{%raw%}Collection c = new ArrayList(); Integer obj = new Integer(1); c.add(obj); @@ -997,7 +997,7 @@ c.add(obj); Integer[] a = (Integer [])c.toArray(); // this is fine and will not trigger the rule -Integer[] b = (Integer [])c.toArray(new Integer[c.size()]); +Integer[] b = (Integer [])c.toArray(new Integer[c.size()]);{%endraw%} ``` **Use this rule by referencing it:** @@ -1024,7 +1024,7 @@ Object.clone (which is protected) with a public method." **Example(s):** ``` java -public class Foo implements Cloneable { +{%raw%}public class Foo implements Cloneable { @Override protected Object clone() throws CloneNotSupportedException { // Violation, must be public } @@ -1039,7 +1039,7 @@ public class Foo implements Cloneable { public class Foo implements Cloneable { @Override public Object clone() // Ok -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1063,11 +1063,11 @@ The rule can also detect, if the class implements or extends a Cloneable class. **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { public Object clone() throws CloneNotSupportedException { return foo; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1101,7 +1101,7 @@ and not (ResultType//ClassOrInterfaceType/@Image = ancestor::ClassOrInterfaceDec **Example(s):** ``` java -public class Foo implements Cloneable { +{%raw%}public class Foo implements Cloneable { @Override protected Object clone() { // Violation, Object must be Foo } @@ -1111,7 +1111,7 @@ public class Foo implements Cloneable { @Override public Foo clone() { //Ok } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1144,12 +1144,12 @@ and count(NameList/Name[contains **Example(s):** ``` java -public class MyClass implements Cloneable{ +{%raw%}public class MyClass implements Cloneable{ public Object clone() { // will cause an error MyClass clone = (MyClass)super.clone(); return clone; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1163,26 +1163,47 @@ public class MyClass implements Cloneable{ **Priority:** Medium (3) -Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after use. +Ensure that resources (like `java.sql.Connection`, `java.sql.Statement`, and `java.sql.ResultSet` objects +and any subtype of `java.lang.AutoCloseable`) are always closed after use. +Failing to do so might result in resource leaks. + +Note: It suffices to configure the super type, e.g. `java.lang.AutoClosable`, so that this rule automatically triggers +on any subtype (e.g. `java.io.FileInputStream`). Additionally specifying `java.sql.Connection` helps in detecting +the types, if the type resolution / auxclasspath is not correctly setup. + +Note: Since PMD 6.16.0 the default value for the property `types` contains `java.lang.AutoCloseable` and detects +now cases where the standard `java.io.*Stream` classes are involved. In order to restore the old behaviour, +just remove "AutoCloseable" from the types. **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.errorprone.CloseResourceRule](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java) **Example(s):** ``` java -public class Bar { - public void foo() { - Connection c = pool.getConnection(); - try { - // do stuff - } catch (SQLException ex) { - // handle exception - } finally { - // oops, should close the connection using 'close'! - // c.close(); +{%raw%}public class Bar { + public void withSQL() { + Connection c = pool.getConnection(); + try { + // do stuff + } catch (SQLException ex) { + // handle exception + } finally { + // oops, should close the connection using 'close'! + // c.close(); + } } - } -} + + public void withFile() { + InputStream file = new FileInputStream(new File("/tmp/foo")); + try { + int c = file.in(); + } catch (IOException e) { + // handle exception + } finally { + // TODO: close file + } + } +}{%endraw%} ``` **This rule has the following properties:** @@ -1190,8 +1211,9 @@ public class Bar { |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| |closeTargets||Methods which may close this resource|yes. Delimiter is ','.| -|types|java.sql.Connection , java.sql.Statement , java.sql.ResultSet|Affected types|yes. Delimiter is ','.| +|types|java.lang.AutoCloseable , java.sql.Connection , java.sql.Statement , java.sql.ResultSet|Affected types|yes. Delimiter is ','.| |closeAsDefaultTarget|true|Consider 'close' as a target by default|no| +|allowedResourceTypes|java.io.ByteArrayOutputStream \| java.io.ByteArrayInputStream \| java.io.StringWriter \| java.io.CharArrayWriter|Exact class names that do not need to be closed|yes. Delimiter is '\|'.| **Use this rule with the default properties by just referencing it:** ``` xml @@ -1203,8 +1225,9 @@ public class Bar { - + + ``` @@ -1222,11 +1245,11 @@ Use equals() to compare object references; avoid comparing them with ==. **Example(s):** ``` java -class Foo { +{%raw%}class Foo { boolean bar(String a, String b) { return a == b; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1253,7 +1276,7 @@ private method bar() that calls a public method buz(), this denotes a problem. **Example(s):** ``` java -public class SeniorClass { +{%raw%}public class SeniorClass { public SeniorClass(){ toString(); //may throw NullPointerException if overridden } @@ -1270,7 +1293,7 @@ public class JuniorClass extends SeniorClass { public String toString(){ return name.toUpperCase(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1296,12 +1319,12 @@ From those informations there can be found various problems. **Example(s):** ``` java -public void foo() { +{%raw%}public void foo() { int buz = 5; buz = 6; // redefinition of buz -> dd-anomaly foo(buz); buz = 2; -} // buz is undefined when leaving scope -> du-anomaly +} // buz is undefined when leaving scope -> du-anomaly{%endraw%} ``` **This rule has the following properties:** @@ -1360,7 +1383,7 @@ should be annotated with @Test and @Ignore. **Example(s):** ``` java -public class MyTest { +{%raw%}public class MyTest { @Test public void someTest() { } @@ -1369,7 +1392,7 @@ public class MyTest { public void someOtherTest () { } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1404,7 +1427,7 @@ starts-with(@Image,'Runtime.getRuntime') and **Example(s):** ``` java -public class GCCall { +{%raw%}public class GCCall { public GCCall() { // Explicit gc call ! System.gc(); @@ -1424,7 +1447,7 @@ public class GCCall { // Explicit gc call ! Runtime.getRuntime().gc(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1453,12 +1476,12 @@ application server should stop the JVM. This rule also checks for the equivalent **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { System.exit(0); // never call this when running in an application server! } public void foo() { Runtime.getRuntime().exit(0); // never stop the JVM manually, the container will do this. -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1483,7 +1506,7 @@ Extend Exception or RuntimeException instead of Throwable. **Example(s):** ``` java -public class Foo extends Throwable { } +{%raw%}public class Foo extends Throwable { }{%endraw%} ``` **Use this rule by referencing it:** @@ -1507,13 +1530,13 @@ Use Environment.getExternalStorageDirectory() instead of "/sdcard" **Example(s):** ``` java -public class MyActivity extends Activity { +{%raw%}public class MyActivity extends Activity { protected void foo() { String storageLocation = "/sdcard/mypackage"; // hard-coded, poor approach storageLocation = Environment.getExternalStorageDirectory() + "/mypackage"; // preferred approach } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1539,7 +1562,7 @@ Note: This is a PMD implementation of the Lint4j rule "A throw in a finally **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { try { // Here do some stuff @@ -1550,7 +1573,7 @@ public class Foo { throw new Exception(); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1571,8 +1594,8 @@ Avoid importing anything from the 'sun.*' packages. These packages are not port **Example(s):** ``` java -import sun.misc.foo; -public class Foo {} +{%raw%}import sun.misc.foo; +public class Foo {}{%endraw%} ``` **Use this rule by referencing it:** @@ -1599,7 +1622,7 @@ performance need (space or time). **Example(s):** ``` java -public class Count { +{%raw%}public class Count { public static void main(String[] args) { final int START = 2000000000; int count = 0; @@ -1609,7 +1632,7 @@ public class Count { System.out.println(count); //The termination test misbehaves due to floating point granularity. } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1640,13 +1663,13 @@ or reported. **Example(s):** ``` java -public void doSomething() { +{%raw%}public void doSomething() { try { FileInputStream fis = new FileInputStream("/tmp/bugger"); } catch (IOException ioe) { // not good } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -1688,9 +1711,9 @@ Empty finalize methods serve no purpose and should be removed. Note that Oracle **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { protected void finalize() {} -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1714,7 +1737,7 @@ Empty finally blocks serve no purpose and should be removed. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { try { int x=2; @@ -1722,7 +1745,7 @@ public class Foo { // empty! } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1747,13 +1770,13 @@ Empty If Statement finds instances where a condition is checked but nothing is d **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar(int x) { if (x == 0) { // empty! } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1777,13 +1800,13 @@ Empty initializers serve no purpose and should be removed. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { static {} // Why ? {} // Again, why ? -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1807,7 +1830,7 @@ Empty block statements serve no purpose and should be removed. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private int _bar; @@ -1816,7 +1839,7 @@ public class Foo { {} // But remove this. } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1851,12 +1874,12 @@ and should be removed. **Example(s):** ``` java -public void doit() { +{%raw%}public void doit() { // this is probably not what you meant to do ; // the extra semicolon here this is not necessary System.out.println("look at the extra semicolon");; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1880,13 +1903,13 @@ Empty switch statements serve no purpose and should be removed. **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { int x = 2; switch (x) { // once there was code here // but it's been commented out or something } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1910,13 +1933,13 @@ Empty synchronized blocks serve no purpose and should be removed. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { synchronized (this) { // empty! } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1940,14 +1963,14 @@ Avoid empty try blocks - what's the point? **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { try { } catch (Exception e) { e.printStackTrace(); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1973,11 +1996,11 @@ a while loop that does a lot in the exit expression, rewrite it to make it clear **Example(s):** ``` java -void bar(int a, int b) { +{%raw%}void bar(int a, int b) { while (a == b) { // empty! } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2013,7 +2036,7 @@ Tests for null should not use the equals() method. The '==' operator should be u **Example(s):** ``` java -String x = "foo"; +{%raw%}String x = "foo"; if (x.equals(null)) { // bad form doSomething(); @@ -2021,7 +2044,7 @@ if (x.equals(null)) { // bad form if (x == null) { // preferred doSomething(); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2058,10 +2081,10 @@ If the finalize() is implemented, its last action should be to call super.finali **Example(s):** ``` java -protected void finalize() { +{%raw%}protected void finalize() { something(); // neglected to call super.finalize() -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2091,9 +2114,9 @@ If the finalize() is implemented, it should do something besides just calling su **Example(s):** ``` java -protected void finalize() { +{%raw%}protected void finalize() { super.finalize(); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2121,11 +2144,11 @@ Note that Oracle has declared Object.finalize() as deprecated since JDK 9. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { // this is confusing and probably a bug protected void finalize(int a) { } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2154,9 +2177,9 @@ Note that Oracle has declared Object.finalize() as deprecated since JDK 9. **Example(s):** ``` java -public void finalize() { +{%raw%}public void finalize() { // do something -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2177,12 +2200,12 @@ Avoid idempotent operations - they have no effect. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void bar() { int x = 2; x = x; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2203,12 +2226,12 @@ There is no need to import a type that lives in the same package. **Example(s):** ``` java -package foo; +{%raw%}package foo; import foo.Buz; // no need for this import foo.*; // or this -public class Bar{} +public class Bar{}{%endraw%} ``` **Use this rule by referencing it:** @@ -2237,11 +2260,11 @@ Avoid instantiating an object just to call getClass() on it; use the .class publ **Example(s):** ``` java -// replace this +{%raw%}// replace this Class c = new String().getClass(); // with this: -Class c = String.class; +Class c = String.class;{%endraw%} ``` **Use this rule by referencing it:** @@ -2262,9 +2285,9 @@ Check for messages in slf4j loggers with non matching number of arguments and pl **Example(s):** ``` java -LOGGER.error("forget the arg {}"); +{%raw%}LOGGER.error("forget the arg {}"); LOGGER.error("too many args {}", "arg1", "arg2"); -LOGGER.error("param {}", "arg1", new IllegalStateException("arg")); //The exception is shown separately, so is correct. +LOGGER.error("param {}", "arg1", new IllegalStateException("arg")); //The exception is shown separately, so is correct.{%endraw%} ``` **Use this rule by referencing it:** @@ -2293,7 +2316,7 @@ Avoid jumbled loop incrementers - its usually a mistake, and is confusing even i **Example(s):** ``` java -public class JumbledIncrementerRule1 { +{%raw%}public class JumbledIncrementerRule1 { public void foo() { for (int i = 0; i < 10; i++) { // only references 'i' for (int k = 0; k < 20; i++) { // references both 'i' and 'k' @@ -2301,7 +2324,7 @@ public class JumbledIncrementerRule1 { } } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2337,12 +2360,12 @@ Some JUnit framework methods are easy to misspell. **Example(s):** ``` java -import junit.framework.*; +{%raw%}import junit.framework.*; public class Foo extends TestCase { public void setup() {} // oops, should be setUp public void TearDown() {} // oops, should be tearDown -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2376,12 +2399,12 @@ The suite() method in a JUnit test needs to be both public and static. **Example(s):** ``` java -import junit.framework.*; +{%raw%}import junit.framework.*; public class Foo extends TestCase { public void suite() {} // oops, should be static private static void suite() {} // oops, should be public -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2391,12 +2414,17 @@ public class Foo extends TestCase { ## LoggerIsNotStaticFinal +Deprecated + **Since:** PMD 2.0 **Priority:** Medium High (2) In most cases, the Logger reference can be declared as static and final. +This rule is deprecated and will be removed with PMD 7.0.0. +The rule is replaced by {% rule java/errorprone/ProperLogger %}. + **This rule is defined by the following XPath expression:** ``` xpath //VariableDeclarator @@ -2410,11 +2438,11 @@ In most cases, the Logger reference can be declared as static and final. **Example(s):** ``` java -public class Foo{ +{%raw%}public class Foo{ Logger log = Logger.getLogger(Foo.class.getName()); // not recommended static final Logger log = Logger.getLogger(Foo.class.getName()); // preferred approach -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2435,12 +2463,12 @@ Non-constructor methods should not have the same name as the enclosing class. **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { public MyClass() {} // this is OK because it is a constructor public void MyClass() {} // this is bad because it is a method -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2481,19 +2509,19 @@ Either the check is useless (the variable will never be "null") or it **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { if (a.equals(baz) && a != null) {} } -} +}{%endraw%} ``` ``` java -public class Foo { +{%raw%}public class Foo { void bar() { if (a.equals(baz) || a == null) {} } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2526,7 +2554,7 @@ may indicate problematic behaviour. Empty cases are ignored as these indicate an **Example(s):** ``` java -public void bar(int status) { +{%raw%}public void bar(int status) { switch(status) { case CANCELLED: doCancelled(); @@ -2542,7 +2570,7 @@ public void bar(int status) { doErrorHandling(); break; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2572,11 +2600,11 @@ chain needs an own serialVersionUID field. See also [Should an abstract class ha **Example(s):** ``` java -public class Foo implements java.io.Serializable { +{%raw%}public class Foo implements java.io.Serializable { String name; // Define serialization id to avoid serialization related bugs // i.e., public static final long serialVersionUID = 4328743; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2592,28 +2620,39 @@ public class Foo implements java.io.Serializable { A class that has private constructors and does not have any static methods or fields cannot be used. +When one of the private constructors is annotated with one of the annotations, then the class is not considered +non-instantiatable anymore and no violation will be reported. +See the property `annotations`. + **This rule is defined by the following XPath expression:** ``` xpath -//ClassOrInterfaceDeclaration[@Nested='false'] +//ClassOrInterfaceDeclaration[@Nested=false()] [ ( + (: at least one constructor :) ./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration and - count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true']) + (: only private constructors :) + count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private=true()]) + and + (: all constructors must not be annotated :) + (every $x in $annotations satisfies + not(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration/ + ../Annotation/MarkerAnnotation/Name[pmd-java:typeIs($x)])) ) and - not(.//MethodDeclaration[@Static='true']) + not(.//MethodDeclaration[@Static=true()]) and - not(.//FieldDeclaration[@Private='false'][@Static='true']) + not(.//FieldDeclaration[@Private=false()][@Static=true()]) and - not(.//ClassOrInterfaceDeclaration[@Nested='true'] - [@Public='true'] - [@Static='true'] - [not(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) or ./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Public='true']] + not(.//ClassOrInterfaceDeclaration[@Nested=true()] + [@Public=true()] + [@Static=true()] + [not(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) or ./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Public=true()]] [./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration - [@Public='true'] + [@Public=true()] [./ResultType/Type/ReferenceType/ClassOrInterfaceType - [@Image = //ClassOrInterfaceDeclaration[@Nested='false']/@Image] + [@Image = //ClassOrInterfaceDeclaration[@Nested=false()]/@Image] ] ] ) @@ -2623,21 +2662,36 @@ A class that has private constructors and does not have any static methods or fi **Example(s):** ``` java -// This class is unusable, since it cannot be +{%raw%}// This class is unusable, since it cannot be // instantiated (private constructor), // and no static method can be called. public class Foo { private Foo() {} void foo() {} -} +}{%endraw%} ``` -**Use this rule by referencing it:** +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|annotations|org.springframework.beans.factory.annotation.Autowired , javax.inject.Inject|If a constructor is annotated with one of these annotations, then the class is ignored.|yes. Delimiter is ','.| + +**Use this rule with the default properties by just referencing it:** ``` xml ``` +**Use this rule and customize it:** +``` xml + + + + + +``` + ## MoreThanOneLogger **Since:** PMD 2.0 @@ -2651,12 +2705,12 @@ Normally only one logger is used in each class. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { Logger log = Logger.getLogger(Foo.class.getName()); // It is very rare to see two loggers on a class, normally // log information is multiplexed by levels Logger log2= Logger.getLogger(Foo.class.getName()); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2681,7 +2735,7 @@ This legal, but confusing. It is easy to mix up the case labels and the non-case **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar(int a) { switch (a) { case 1: @@ -2693,7 +2747,7 @@ public class Foo { break; } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2713,18 +2767,18 @@ confusing. **This rule is defined by the following XPath expression:** ``` xpath -//Initializer[@Static='false'] +//Initializer[@Static=false()][not(ancestor::*[3][self::AllocationExpression or self::EnumConstant])] ``` **Example(s):** ``` java -public class MyClass { +{%raw%}public class MyClass { // this block gets run before any call to a constructor { System.out.println("I am about to construct myself"); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2748,13 +2802,13 @@ NOTE: This sort of assignment may used in some cases to dereference objects and **Example(s):** ``` java -public void bar() { +{%raw%}public void bar() { Object x = null; // this is OK x = new Object(); // big, complex piece of code here x = null; // this is not required // big, complex piece of code here -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2775,7 +2829,7 @@ Override both public boolean Object.equals(Object other), and public int Object. **Example(s):** ``` java -public class Bar { // poor, missing a hashcode() method +{%raw%}public class Bar { // poor, missing a hashcode() method public boolean equals(Object o) { // do some comparison } @@ -2794,7 +2848,7 @@ public class Foo { // perfect, both methods provided public int hashCode() { // return some hash value } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2826,11 +2880,11 @@ ClassOrInterfaceDeclaration[1]/@Image) **Example(s):** ``` java -class Foo{ +{%raw%}class Foo{ public Object clone(){ return new Foo(); // This is bad } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2845,32 +2899,47 @@ class Foo{ **Priority:** Medium (3) A logger should normally be defined private static final and be associated with the correct class. -Private final Log log; is also allowed for rare cases where loggers need to be passed around, +`private final Log log;` is also allowed for rare cases where loggers need to be passed around, with the restriction that the logger needs to be passed into the constructor. **This rule is defined by the following XPath expression:** ``` xpath -//ClassOrInterfaceBodyDeclaration[FieldDeclaration//ClassOrInterfaceType[@Image='Log'] - and - not(FieldDeclaration[@Final='true'][@Static='true'][@Private='true'][.//VariableDeclaratorId[@Image=$staticLoggerName]] - and - //ArgumentList//ClassOrInterfaceType[@Image = ancestor::ClassOrInterfaceDeclaration/@Image or @Image = ancestor::EnumDeclaration/@Image]) - and - not(FieldDeclaration[@Final='true'][@Private='true'][.//VariableDeclaratorId[@Image='log']] - [count(.//VariableInitializer)=0] - [ancestor::ClassOrInterfaceBody//StatementExpression[.//PrimaryExpression/descendant::*[@Image='log']][count(.//AllocationExpression)=0]] - )] +//FieldDeclaration +[.//ClassOrInterfaceType[pmd-java:typeIs($loggerClass)]] +[ + (: check modifiers :) + (@Private = false() or @Final = false()) + (: check logger name :) + or (@Static and .//VariableDeclaratorId[@Image != $staticLoggerName]) + or (@Static = false() and .//VariableDeclaratorId[@Image != $loggerName]) + + (: check logger argument type matches class or enum name :) + or .//ArgumentList//ClassOrInterfaceType[@Image != ancestor::ClassOrInterfaceDeclaration/@Image] + or .//ArgumentList//ClassOrInterfaceType[@Image != ancestor::EnumDeclaration/@Image] +] +[not( + (: special case - final logger initialized inside constructor :) + count(.//VariableInitializer)=0 + and @Static = false() + and + ancestor::ClassOrInterfaceBody//ConstructorDeclaration//StatementExpression + [PrimaryExpression[PrimaryPrefix[@ThisModifier]]/PrimarySuffix[@Image=$loggerName]] + [AssignmentOperator[@Image = '=']] + [Expression/PrimaryExpression/PrimaryPrefix/Name[@Image = ancestor::ConstructorDeclaration//FormalParameter/VariableDeclaratorId/@Image]] + [count(.//AllocationExpression)=0] + ) +] ``` **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private static final Log LOG = LogFactory.getLog(Foo.class); // proper way protected Log LOG = LogFactory.getLog(Testclass.class); // wrong approach -} +}{%endraw%} ``` **This rule has the following properties:** @@ -2878,6 +2947,8 @@ public class Foo { |Name|Default Value|Description|Multivalued| |----|-------------|-----------|-----------| |staticLoggerName|LOG|Name of the static Logger variable|no| +|loggerName|log|Name of the Logger instance variable|no| +|loggerClass|Log|Class name of the logger|no| **Use this rule with the default properties by just referencing it:** ``` xml @@ -2889,6 +2960,8 @@ public class Foo { + + ``` @@ -2916,7 +2989,7 @@ and **Example(s):** ``` java -public class Example { +{%raw%}public class Example { // Not a good idea... public int[] badBehavior() { // ... @@ -2928,7 +3001,7 @@ public class Example { //... return new String[0]; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2952,7 +3025,7 @@ Avoid returning from a finally block, this can discard exceptions. **Example(s):** ``` java -public class Bar { +{%raw%}public class Bar { public String foo() { try { throw new Exception( "My Exception" ); @@ -2962,7 +3035,7 @@ public class Bar { return "A. O. K."; // return not recommended here } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -2989,10 +3062,10 @@ formatting is used. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { // Should specify Locale.US (or whatever) private SimpleDateFormat sdf = new SimpleDateFormat("pattern"); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3015,7 +3088,7 @@ for each call and new objects will be created for every invocation. **Example(s):** ``` java -public class Singleton { +{%raw%}public class Singleton { private static Singleton singleton = new Singleton( ); @@ -3029,7 +3102,7 @@ public class Singleton { Singleton singleton = (Singleton) obj; return singleton; //violation } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3052,14 +3125,14 @@ for each call and new objects will be created for every invocation. **Example(s):** ``` java -class Singleton { +{%raw%}class Singleton { private static Singleton instance = null; public static Singleton getInstance() { synchronized(Singleton.class) { return new Singleton(); } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3103,12 +3176,12 @@ behavior especially when instances are distributed by the container on several J **Example(s):** ``` java -public class SomeEJB extends EJBObject implements EJBLocalHome { +{%raw%}public class SomeEJB extends EJBObject implements EJBLocalHome { private static int CountA; // poor, field can be edited private static final int CountB; // preferred, read-only access -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3153,14 +3226,14 @@ Literal **Example(s):** ``` java -// misleading instantiation, these buffers +{%raw%}// misleading instantiation, these buffers // are actually sized to 99 characters long StringBuffer sb1 = new StringBuffer('c'); StringBuilder sb2 = new StringBuilder('c'); // in these forms, just single characters are allocated StringBuffer sb3 = new StringBuffer("c"); -StringBuilder sb4 = new StringBuilder("c"); +StringBuilder sb4 = new StringBuilder("c");{%endraw%} ``` **Use this rule by referencing it:** @@ -3203,7 +3276,7 @@ intention to override the equals(Object) method. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public int equals(Object o) { // oops, this probably was supposed to be boolean equals } @@ -3213,7 +3286,7 @@ public class Foo { public boolean equals(Object o1, Object o2) { // oops, this probably was supposed to be equals(Object) } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3235,10 +3308,10 @@ to override the hashCode() method. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public int hashcode() { // oops, this probably was supposed to be 'hashCode' } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3268,10 +3341,10 @@ the literal character "8". **Example(s):** ``` java -public void foo() { +{%raw%}public void foo() { // interpreted as octal 12, followed by character '8' System.out.println("suspicious: \128"); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3293,14 +3366,14 @@ since most people will assume it is a test case. Test classes have test methods **Example(s):** ``` java -//Consider changing the name of the class if it is not a test +{%raw%}//Consider changing the name of the class if it is not a test //Consider adding test methods if it is a test public class CarTest { public static void main(String[] args) { // do something } // code -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3326,13 +3399,13 @@ Do not use "if" statements whose conditionals are always true or alway **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { public void close() { if (true) { // fixed conditional, not recommended // ... } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3376,11 +3449,11 @@ UnaryExpressionNotPlusMinus[@Image='!'] **Example(s):** ``` java -public class SimpleTest extends TestCase { +{%raw%}public class SimpleTest extends TestCase { public void testX() { assertTrue(true); // serves no real purpose } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3401,9 +3474,9 @@ Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals() **Example(s):** ``` java -boolean answer1 = buz.toUpperCase().equals("baz"); // should be buz.equalsIgnoreCase("baz") +{%raw%}boolean answer1 = buz.toUpperCase().equals("baz"); // should be buz.equalsIgnoreCase("baz") -boolean answer2 = buz.toUpperCase().equalsIgnoreCase("baz"); // another unnecessary toUpperCase() +boolean answer2 = buz.toUpperCase().equalsIgnoreCase("baz"); // another unnecessary toUpperCase(){%endraw%} ``` **Use this rule by referencing it:** @@ -3425,11 +3498,11 @@ on the wrapper classes instead. **Example(s):** ``` java -public String convert(int x) { +{%raw%}public String convert(int x) { String foo = new Integer(x).toString(); // this wastes an object return Integer.toString(x); // preferred approach -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3459,7 +3532,7 @@ After checking an object reference for null, you should invoke equals() on that **Example(s):** ``` java -public class Test { +{%raw%}public class Test { public String method1() { return "ok";} public String method2() { return null;} @@ -3493,7 +3566,7 @@ public class Test { } } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3523,7 +3596,7 @@ concat(ancestor::ClassOrInterfaceDeclaration/ClassOrInterfaceBody/ClassOrInterfa **Example(s):** ``` java -public class Main { +{%raw%}public class Main { private static final Log _LOG = LogFactory.getLog( Main.class ); void bar() { try { @@ -3533,7 +3606,7 @@ public class Main { _LOG.error( oe.getMessage(), oe ); //Correct } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3562,11 +3635,11 @@ and count(PrimarySuffix) = 0)] **Example(s):** ``` java -public boolean test(String s) { +{%raw%}public boolean test(String s) { if (s == "one") return true; // unreliable if ("two".equals(s)) return true; // better return false; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3588,7 +3661,7 @@ since the result of the operation is a new object. Therefore, ignoring the opera **Example(s):** ``` java -import java.math.*; +{%raw%}import java.math.*; class Test { void method1() { @@ -3599,7 +3672,7 @@ class Test { BigDecimal bd=new BigDecimal(10); bd = bd.add(new BigDecimal(5)); // this won't trigger the rule } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -3613,8 +3686,19 @@ class Test { **Priority:** Medium (3) -When doing String.toLowerCase()/toUpperCase() conversions, use Locales to avoids problems with languages that -have unusual conventions, i.e. Turkish. +When doing `String::toLowerCase()/toUpperCase()` conversions, use an explicit locale argument to specify the case transformation rules. + +Using `String::toLowerCase()` without arguments implicitly uses `Locale::getDefault()`. +The problem is that the default locale depends on the current JVM setup (and usually on the system in which it is running). +Using the system default may be exactly what you want (e.g. if you are manipulating strings you got through standard input), +but it may as well not be the case (e.g. if you are getting the string over the network or a file, and the encoding is well-defined +and independent of the environment). In the latter case, using the default locale makes the case transformation brittle, as +it may yield unexpected results on a machine whose locale has other case translation rules. For example, in Turkish, the +uppercase form of `i` is `İ` (U+0130, not ASCII) and not `I` (U+0049) as in English. + +The rule is intended to *force* developers to think about locales when dealing with strings. By taking a conscious decision about +the choice of locale at the time of writing, you reduce the risk of surprising behaviour down the line, and communicate your intent +to future readers. **This rule is defined by the following XPath expression:** ``` xpath @@ -3636,20 +3720,20 @@ PrimarySuffix **Example(s):** ``` java -class Foo { - // BAD - if (x.toLowerCase().equals("list")) { } +{%raw%}// violation - implicitly system-dependent conversion +if (x.toLowerCase().equals("list")) {} - /* - * This will not match "LIST" when in Turkish locale - * The above could be - * if (x.toLowerCase(Locale.US).equals("list")) { } - * or simply - * if (x.equalsIgnoreCase("list")) { } - */ - // GOOD - String z = a.toLowerCase(Locale.EN); -} +// The above will not match "LIST" on a system with a Turkish locale. +// It could be replaced with +if (x.toLowerCase(Locale.US).equals("list")) { } +// or simply +if (x.equalsIgnoreCase("list")) { } + +// ok - system independent conversion +String z = a.toLowerCase(Locale.ROOT); + +// ok - explicit system-dependent conversion +String z2 = a.toLowerCase(Locale.getDefault());{%endraw%} ``` **Use this rule by referencing it:** @@ -3674,9 +3758,9 @@ Thread.currentThread().getContextClassLoader() instead. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { ClassLoader cl = Bar.class.getClassLoader(); -} +}{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java/multithreading.md b/docs/pages/pmd/rules/java/multithreading.md index 43373006ee..cffce2e683 100644 --- a/docs/pages/pmd/rules/java/multithreading.md +++ b/docs/pages/pmd/rules/java/multithreading.md @@ -27,7 +27,7 @@ gets it. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { // Try to avoid this: synchronized void foo() { } @@ -46,7 +46,7 @@ public class Foo { synchronized(Foo.class) { } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -72,14 +72,14 @@ it contains methods that are not thread-safe. **Example(s):** ``` java -public class Bar { +{%raw%}public class Bar { void buz() { ThreadGroup tg = new ThreadGroup("My threadgroup"); tg = new ThreadGroup(tg, "my thread group"); tg = Thread.currentThread().getThreadGroup(); tg = System.getSecurityManager().getThreadGroup(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -105,10 +105,10 @@ the volatile keyword should not be used for maintenance purpose and portability. **Example(s):** ``` java -public class ThrDeux { +{%raw%}public class ThrDeux { private volatile String var1; // not suggested private String var2; // preferred -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -132,7 +132,7 @@ The J2EE specification explicitly forbids the use of threads. **Example(s):** ``` java -// This is not allowed +{%raw%}// This is not allowed public class UsingThread extends Thread { } @@ -143,7 +143,7 @@ public class OtherThread implements Runnable { public void methode() { Runnable thread = new Thread(); thread.run(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -177,9 +177,9 @@ Explicitly calling Thread.run() method will execute in the caller's thread of co **Example(s):** ``` java -Thread t = new Thread(); +{%raw%}Thread t = new Thread(); t.run(); // use t.start() instead -new Thread().run(); // same violation +new Thread().run(); // same violation{%endraw%} ``` **Use this rule by referencing it:** @@ -207,7 +207,7 @@ or **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { /*volatile */ Object baz = null; // fix for Java5 and later: volatile Object bar() { if (baz == null) { // baz may be non-null yet not fully created @@ -219,7 +219,7 @@ public class Foo { } return baz; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -250,7 +250,7 @@ See Effective Java, item 48. **Example(s):** ``` java -private static Foo foo = null; +{%raw%}private static Foo foo = null; //multiple simultaneous callers may see partially initialized objects public static Foo getFoo() { @@ -258,7 +258,7 @@ public static Foo getFoo() { foo = new Foo(); } return foo; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -293,7 +293,7 @@ public static Foo getFoo() { SimpleDateFormat instances are not synchronized. Sun recommends using separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be -synchronized either on method or block level. +synchronized on block level. This rule has been deprecated in favor of the rule {% rule UnsynchronizedStaticFormatter %}. @@ -302,22 +302,39 @@ This rule has been deprecated in favor of the rule {% rule UnsynchronizedStaticF **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private static final SimpleDateFormat sdf = new SimpleDateFormat(); void bar() { sdf.format(); // poor, no thread-safety } - synchronized void foo() { - sdf.format(); // preferred + void foo() { + synchronized (sdf) { // preferred + sdf.format(); + } } -} +}{%endraw%} ``` -**Use this rule by referencing it:** +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|allowMethodLevelSynchronization|false|If true, method level synchronization is allowed as well as synchronized block. Otherwise only synchronized blocks are allowed.|no| + +**Use this rule with the default properties by just referencing it:** ``` xml ``` +**Use this rule and customize it:** +``` xml + + + + + +``` + ## UnsynchronizedStaticFormatter **Since:** PMD 6.11.0 @@ -327,29 +344,46 @@ public class Foo { Instances of `java.text.Format` are generally not synchronized. Sun recommends using separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be -synchronized either on method or block level. +synchronized on block level. **This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.java.rule.multithreading.UnsynchronizedStaticFormatterRule](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java) **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private static final SimpleDateFormat sdf = new SimpleDateFormat(); void bar() { sdf.format(); // poor, no thread-safety } - synchronized void foo() { - sdf.format(); // preferred + void foo() { + synchronized (sdf) { // preferred + sdf.format(); + } } -} +}{%endraw%} ``` -**Use this rule by referencing it:** +**This rule has the following properties:** + +|Name|Default Value|Description|Multivalued| +|----|-------------|-----------|-----------| +|allowMethodLevelSynchronization|false|If true, method level synchronization is allowed as well as synchronized block. Otherwise only synchronized blocks are allowed.|no| + +**Use this rule with the default properties by just referencing it:** ``` xml ``` +**Use this rule and customize it:** +``` xml + + + + + +``` + ## UseConcurrentHashMap **Since:** PMD 4.2.6 @@ -370,7 +404,7 @@ perform efficient map reads without blocking other threads. **Example(s):** ``` java -public class ConcurrentApp { +{%raw%}public class ConcurrentApp { public void getMyInstance() { Map map1 = new HashMap(); // fine for single-threaded access Map map2 = new ConcurrentHashMap(); // preferred for use with multiple threads @@ -378,7 +412,7 @@ public class ConcurrentApp { // the following case will be ignored by this rule Map map3 = someModule.methodThatReturnMap(); // might be OK, if the returned map is already thread-safe } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -411,12 +445,12 @@ one is chosen. The thread chosen is arbitrary; thus its usually safer to call n **Example(s):** ``` java -void bar() { +{%raw%}void bar() { x.notify(); // If many threads are monitoring x, only one (and you won't know which) will be notified. // use instead: x.notifyAll(); - } + }{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java/performance.md b/docs/pages/pmd/rules/java/performance.md index 039c9bf319..26b5419bcb 100644 --- a/docs/pages/pmd/rules/java/performance.md +++ b/docs/pages/pmd/rules/java/performance.md @@ -26,8 +26,8 @@ It is much better to use one of the type-specific toString() methods instead. **Example(s):** ``` java -String s = "" + 123; // inefficient -String t = Integer.toString(456); // preferred approach +{%raw%}String s = "" + 123; // inefficient +String t = Integer.toString(456); // preferred approach{%endraw%} ``` **Use this rule by referencing it:** @@ -48,11 +48,11 @@ Avoid concatenating characters as strings in StringBuffer/StringBuilder.append m **Example(s):** ``` java -StringBuffer sb = new StringBuffer(); +{%raw%}StringBuffer sb = new StringBuffer(); sb.append("a"); // avoid this StringBuffer sb = new StringBuffer(); -sb.append('a'); // use this instead +sb.append('a'); // use this instead{%endraw%} ``` **Use this rule by referencing it:** @@ -91,7 +91,7 @@ or AdditiveExpression) and count(.//PrimaryPrefix/Name)=1] **Example(s):** ``` java -public class Test { +{%raw%}public class Test { public void bar() { int[] a = new int[10]; int[] b = new int[10]; @@ -105,7 +105,7 @@ public class Test { b[i]=a[c[i]]; } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -151,7 +151,7 @@ that one covers both. **Example(s):** ``` java -// these instantiations cause garbage collection pauses, even if properly closed +{%raw%}// these instantiations cause garbage collection pauses, even if properly closed FileInputStream fis = new FileInputStream(fileName); FileOutputStream fos = new FileOutputStream(fileName); @@ -167,7 +167,7 @@ that one covers both. try(BufferedReader br = Files.newBufferedReader(Paths.get(fileName), StandardCharsets.UTF_8)) { } try(BufferedWriter wr = Files.newBufferedWriter(Paths.get(fileName), StandardCharsets.UTF_8)) { - } + }{%endraw%} ``` **Use this rule by referencing it:** @@ -188,13 +188,13 @@ New objects created within loops should be checked to see if they can created ou **Example(s):** ``` java -public class Something { +{%raw%}public class Something { public static void main( String as[] ) { for (int i = 0; i < 10; i++) { Foo f = new Foo(); // Avoid this whenever you can it's really expensive } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -231,14 +231,14 @@ adverse impacts on performance. **Example(s):** ``` java -public class UsingShort { +{%raw%}public class UsingShort { private short doNotUseShort = 0; public UsingShort() { short shouldNotBeUsed = 1; doNotUseShort += shouldNotBeUsed; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -260,11 +260,11 @@ for Java 1.5 onwards, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal **Example(s):** ``` java -BigInteger bi = new BigInteger(1); // reference BigInteger.ONE instead +{%raw%}BigInteger bi = new BigInteger(1); // reference BigInteger.ONE instead BigInteger bi2 = new BigInteger("0"); // reference BigInteger.ZERO instead BigInteger bi3 = new BigInteger(0.0); // reference BigInteger.ZERO instead BigInteger bi4; -bi4 = new BigInteger(0); // reference BigInteger.ZERO instead +bi4 = new BigInteger(0); // reference BigInteger.ZERO instead{%endraw%} ``` **Use this rule by referencing it:** @@ -286,8 +286,8 @@ Note that new Boolean() is deprecated since JDK 9 for that reason. **Example(s):** ``` java -Boolean bar = new Boolean("true"); // unnecessary creation, just reference Boolean.TRUE; -Boolean buz = Boolean.valueOf(false); // ...., just reference Boolean.FALSE; +{%raw%}Boolean bar = new Boolean("true"); // unnecessary creation, just reference Boolean.TRUE; +Boolean buz = Boolean.valueOf(false); // ...., just reference Boolean.FALSE;{%endraw%} ``` **Use this rule by referencing it:** @@ -315,9 +315,9 @@ and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Byte')]] **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private Byte i = new Byte(0); // change to Byte i = Byte.valueOf(0); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -339,7 +339,7 @@ by producing a smaller bytecode, reducing overhead and improving inlining. A com **Example(s):** ``` java -String foo = " "; +{%raw%}String foo = " "; StringBuffer buf = new StringBuffer(); buf.append("Hello"); // poor @@ -347,7 +347,7 @@ buf.append(foo); buf.append("World"); StringBuffer buf = new StringBuffer(); -buf.append("Hello").append(foo).append("World"); // good +buf.append("Hello").append(foo).append("World"); // good{%endraw%} ``` **Use this rule by referencing it:** @@ -370,7 +370,7 @@ can be appended in a single method call. **Example(s):** ``` java -StringBuilder buf = new StringBuilder(); +{%raw%}StringBuilder buf = new StringBuilder(); buf.append("Hello").append(" ").append("World"); // poor buf.append("Hello World"); // good @@ -378,7 +378,7 @@ buf.append('h').append('e').append('l').append('l').append('o'); // poor buf.append("hello"); // good buf.append(1).append('m'); // poor -buf.append("1m"); // good +buf.append("1m"); // good{%endraw%} ``` **This rule has the following properties:** @@ -434,11 +434,11 @@ include the check for != null). **Example(s):** ``` java -public void bar(String string) { +{%raw%}public void bar(String string) { if (string != null && string.trim().length() > 0) { doSomething(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -460,12 +460,12 @@ need to be be created and destroyed by the JVM. **Example(s):** ``` java -// Avoid this, two buffers are actually being created here +{%raw%}// Avoid this, two buffers are actually being created here StringBuffer sb = new StringBuffer("tmp = "+System.getProperty("java.io.tmpdir")); // do this instead StringBuffer sb = new StringBuffer("tmp = "); -sb.append(System.getProperty("java.io.tmpdir")); +sb.append(System.getProperty("java.io.tmpdir"));{%endraw%} ``` **Use this rule by referencing it:** @@ -490,11 +490,11 @@ is assumed if the length of the constructor can not be determined. **Example(s):** ``` java -StringBuffer bad = new StringBuffer(); +{%raw%}StringBuffer bad = new StringBuffer(); bad.append("This is a long string that will exceed the default 16 characters"); StringBuffer good = new StringBuffer(41); -good.append("This is a long string, which is pre-sized"); +good.append("This is a long string, which is pre-sized");{%endraw%} ``` **Use this rule by referencing it:** @@ -522,9 +522,9 @@ Note that new Integer() is deprecated since JDK 9 for that reason. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private Integer i = new Integer(0); // change to Integer i = Integer.valueOf(0); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -552,9 +552,9 @@ and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Long')]] **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private Long i = new Long(0); // change to Long i = Long.valueOf(0); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -596,14 +596,14 @@ PrimarySuffix/Arguments/ArgumentList/Expression **Example(s):** ``` java -List foos = getFoos(); +{%raw%}List foos = getFoos(); // much better; this one allows the jvm to allocate an array of the correct size and effectively skip // the zeroing, since each array element will be overridden anyways Foo[] fooArray = foos.toArray(new Foo[0]); // inefficient, the array needs to be zeroed out by the jvm before it is handed over to the toArray method -Foo[] fooArray = foos.toArray(new Foo[foos.size()]); +Foo[] fooArray = foos.toArray(new Foo[foos.size()]);{%endraw%} ``` **Use this rule by referencing it:** @@ -625,7 +625,7 @@ is redundant and results in a larger class file (approximately three additional **Example(s):** ``` java -public class C { +{%raw%}public class C { boolean b = false; // examples of redundant initializers byte by = 0; short s = 0; @@ -643,7 +643,7 @@ public class C { class Nested { boolean b = false; } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -671,9 +671,9 @@ and ClassOrInterfaceType[pmd-java:typeIs('java.lang.Short')]] **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { private Short i = new Short(0); // change to Short i = Short.valueOf(0); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -707,7 +707,7 @@ at the expense of some readability. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { boolean checkIt(String x) { return x.startsWith("a"); // suboptimal @@ -716,7 +716,7 @@ public class Foo { boolean fasterCheckIt(String x) { return x.charAt(0) == 'a'; // faster approach } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -737,7 +737,7 @@ Avoid instantiating String objects; this is usually unnecessary since they are i **Example(s):** ``` java -private String bar = new String("bar"); // just do a String bar = "bar"; +{%raw%}private String bar = new String("bar"); // just do a String bar = "bar";{%endraw%} ``` **Use this rule by referencing it:** @@ -758,10 +758,10 @@ Avoid calling toString() on objects already known to be string instances; this i **Example(s):** ``` java -private String baz() { +{%raw%}private String baz() { String bar = "howdy"; return bar.toString(); -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -789,7 +789,7 @@ if-then statement to increase code readability. **Example(s):** ``` java -// With a minimumNumberCaseForASwitch of 3 +{%raw%}// With a minimumNumberCaseForASwitch of 3 public class Foo { public void bar() { switch (condition) { @@ -800,7 +800,7 @@ public class Foo { break; // not enough for a 'switch' stmt, a simple 'if' stmt would have been more appropriate } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -838,7 +838,7 @@ garbage-collected later. **Example(s):** ``` java -public int convert(String s) { +{%raw%}public int convert(String s) { int i, i2; i = Integer.valueOf(s).intValue(); // this wastes an object @@ -851,7 +851,7 @@ public int convert(String s) { s3 = Integer.toString(i2); // this is better return i2; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -877,12 +877,12 @@ ArrayList is a much better Collection implementation than Vector if thread-safe **Example(s):** ``` java -public class SimpleTest extends TestCase { +{%raw%}public class SimpleTest extends TestCase { public void testX() { Collection c1 = new Vector(); Collection c2 = new ArrayList(); // achieves the same with much better performance } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -943,7 +943,7 @@ You must use new ArrayList<>(Arrays.asList(...)) if that is inconvenient f **Example(s):** ``` java -public class Test { +{%raw%}public class Test { public void foo(Integer[] ints) { // could just use Arrays.asList(ints) List l= new ArrayList<>(100); @@ -954,7 +954,7 @@ public class Test { l.add(a[i].toString()); // won't trigger the rule } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -975,11 +975,11 @@ Use String.indexOf(char) when checking for the index of a single character; it e **Example(s):** ``` java -String s = "hello world"; +{%raw%}String s = "hello world"; // avoid this if (s.indexOf("d") {} // instead do this -if (s.indexOf('d') {} +if (s.indexOf('d') {}{%endraw%} ``` **Use this rule by referencing it:** @@ -1000,12 +1000,12 @@ No need to call String.valueOf to append to a string; just use the valueOf() arg **Example(s):** ``` java -public String convert(int i) { +{%raw%}public String convert(int i) { String s; s = "a" + String.valueOf(i); // not required s = "a" + i; // preferred approach return s; -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1028,7 +1028,7 @@ threadsafe StringBuffer is recommended to avoid this. **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void bar() { String a; a = "foo"; @@ -1037,7 +1037,7 @@ public class Foo { // StringBuilder a = new StringBuilder("foo"); // a.append(" bar"); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -1059,11 +1059,11 @@ or StringBuffer.toString().length() == ... **Example(s):** ``` java -StringBuffer sb = new StringBuffer(); +{%raw%}StringBuffer sb = new StringBuffer(); if (sb.toString().equals("")) {} // inefficient -if (sb.length() == 0) {} // preferred +if (sb.length() == 0) {} // preferred{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/java/security.md b/docs/pages/pmd/rules/java/security.md index 8fe84a69b6..2ada23a5ad 100644 --- a/docs/pages/pmd/rules/java/security.md +++ b/docs/pages/pmd/rules/java/security.md @@ -22,7 +22,7 @@ Do not use hard coded values for cryptographic operations. Please store keys out **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void good() { SecretKeySpec secretKeySpec = new SecretKeySpec(Properties.getKey(), "AES"); } @@ -30,7 +30,7 @@ public class Foo { void bad() { SecretKeySpec secretKeySpec = new SecretKeySpec("my secret here".getBytes(), "AES"); } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -51,7 +51,7 @@ Do not use hard coded initialization vector in cryptographic operations. Please **Example(s):** ``` java -public class Foo { +{%raw%}public class Foo { void good() { SecureRandom random = new SecureRandom(); byte iv[] = new byte[16]; @@ -65,7 +65,7 @@ public class Foo { void alsoBad() { byte[] iv = "secret iv in here".getBytes(); } -} +}{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/jsp/bestpractices.md b/docs/pages/pmd/rules/jsp/bestpractices.md index 87c1175a20..efeb91efee 100644 --- a/docs/pages/pmd/rules/jsp/bestpractices.md +++ b/docs/pages/pmd/rules/jsp/bestpractices.md @@ -25,7 +25,7 @@ Do not nest JSF component custom actions inside a custom action that iterates ov **Example(s):** ``` jsp - +{%raw%}
    @@ -33,7 +33,7 @@ Do not nest JSF component custom actions inside a custom action that iterates ov
- +{%endraw%} ``` **Use this rule by referencing it:** @@ -57,9 +57,9 @@ Do not use an attribute called 'class'. Use "styleclass" for CSS style **Example(s):** ``` jsp - +{%raw%}

Some text

- + {%endraw%} ``` **Use this rule by referencing it:** @@ -85,13 +85,13 @@ little other purpose. Consider switching to JSP comments. **Example(s):** ``` jsp -bad example><BODY> +{%raw%}<HTML><title>bad example><BODY> <!-- HTML comment --> </BODY> </HTML> <HTML><title>good example><BODY> <%-- JSP comment --%> -</BODY> </HTML> +</BODY> </HTML>{%endraw%} ``` **Use this rule by referencing it:** @@ -115,7 +115,7 @@ Do not do a forward from within a JSP file. **Example(s):** ``` jsp -<jsp:forward page='UnderConstruction.jsp'/> +{%raw%}<jsp:forward page='UnderConstruction.jsp'/>{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/jsp/codestyle.md b/docs/pages/pmd/rules/jsp/codestyle.md index 56412f2e82..de425db9e5 100644 --- a/docs/pages/pmd/rules/jsp/codestyle.md +++ b/docs/pages/pmd/rules/jsp/codestyle.md @@ -22,7 +22,7 @@ Avoid duplicate import statements inside JSP's. **Example(s):** ``` jsp -<%@ page import=\"com.foo.MyClass,com.foo.MyClass\"%><html><body><b><img src=\"<%=Some.get()%>/foo\">xx</img>text</b></body></html> +{%raw%}<%@ page import=\"com.foo.MyClass,com.foo.MyClass\"%><html><body><b><img src=\"<%=Some.get()%>/foo\">xx</img>text</b></body></html>{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/jsp/design.md b/docs/pages/pmd/rules/jsp/design.md index d9fc103a59..c54e2acd3b 100644 --- a/docs/pages/pmd/rules/jsp/design.md +++ b/docs/pages/pmd/rules/jsp/design.md @@ -42,7 +42,7 @@ tags, or attributes like "align='center'". **Example(s):** ``` jsp -<html><body><p align='center'><b>text</b></p></body></html> +{%raw%}<html><body><p align='center'><b>text</b></p></body></html>{%endraw%} ``` **Use this rule by referencing it:** @@ -66,7 +66,7 @@ Scripts should be part of Tag Libraries, rather than part of JSP pages. **Example(s):** ``` jsp -<HTML> +{%raw%}<HTML> <BODY> <!--Java Script--> <SCRIPT language="JavaScript" type="text/javascript"> @@ -86,7 +86,7 @@ onload=calcDays; //--> </SCRIPT> </BODY> -</HTML> +</HTML>{%endraw%} ``` **Use this rule by referencing it:** @@ -112,7 +112,7 @@ Scriptlets should be factored into Tag Libraries or JSP declarations, rather tha **Example(s):** ``` jsp -<HTML> +{%raw%}<HTML> <HEAD> <% response.setHeader("Pragma", "No-cache"); @@ -121,7 +121,7 @@ response.setHeader("Pragma", "No-cache"); <BODY> <jsp:scriptlet>String title = "Hello world!";</jsp:scriptlet> </BODY> -</HTML> +</HTML>{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/jsp/errorprone.md b/docs/pages/pmd/rules/jsp/errorprone.md index 9006c497fe..0cf946ee62 100644 --- a/docs/pages/pmd/rules/jsp/errorprone.md +++ b/docs/pages/pmd/rules/jsp/errorprone.md @@ -31,11 +31,11 @@ and **Example(s):** ``` jsp -Most browsers should be able to interpret the following headers: +{%raw%}Most browsers should be able to interpret the following headers: <%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> -<meta http-equiv="Content-Type"  content="text/html; charset=UTF-8" /> +<meta http-equiv="Content-Type"  content="text/html; charset=UTF-8" />{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/jsp/security.md b/docs/pages/pmd/rules/jsp/security.md index 88a56a136e..72c3daf482 100644 --- a/docs/pages/pmd/rules/jsp/security.md +++ b/docs/pages/pmd/rules/jsp/security.md @@ -26,13 +26,13 @@ through SSL. See http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q261188 **Example(s):** ``` jsp -<HTML><title>bad example><BODY> +{%raw%}<HTML><title>bad example><BODY> <iframe></iframe> </BODY> </HTML> <HTML><title>good example><BODY> <iframe src="foo"></iframe> -</BODY> </HTML> +</BODY> </HTML>{%endraw%} ``` **Use this rule by referencing it:** @@ -54,11 +54,11 @@ would be interpreted by the browser directly (e.g. "<script>alert('he **Example(s):** ``` jsp -<%@ page contentType="text/html; charset=UTF-8" %> +{%raw%}<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> ${expression} <!-- don't use this --> ${fn:escapeXml(expression)} <!-- instead, escape it --> -<c:out value="${expression}" /> <!-- or use c:out --> +<c:out value="${expression}" /> <!-- or use c:out -->{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/plsql/bestpractices.md b/docs/pages/pmd/rules/plsql/bestpractices.md index 3dc2813b31..7d07f7e024 100644 --- a/docs/pages/pmd/rules/plsql/bestpractices.md +++ b/docs/pages/pmd/rules/plsql/bestpractices.md @@ -25,7 +25,7 @@ language: PLSQL **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE BODY update_planned_hrs +{%raw%}CREATE OR REPLACE PACKAGE BODY update_planned_hrs IS PROCEDURE set_new_planned (p_emp_id IN NUMBER, p_project_id IN NUMBER, p_hours IN NUMBER) @@ -64,7 +64,7 @@ BEGIN END existing_planned; END update_planned_hrs; -/ +/{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/plsql/codestyle.md b/docs/pages/pmd/rules/plsql/codestyle.md index 949599d55b..01c9ca1636 100644 --- a/docs/pages/pmd/rules/plsql/codestyle.md +++ b/docs/pages/pmd/rules/plsql/codestyle.md @@ -82,7 +82,7 @@ Calling a procedure: **Example(s):** ``` sql -BEGIN +{%raw%}BEGIN -- select columns each on a separate line SELECT cmer_id ,version @@ -108,7 +108,7 @@ BEGIN ,slt_code_in => NULL ); -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -157,7 +157,7 @@ In case you have loops please name the loop variables more meaningful. **Example(s):** ``` sql --- good example +{%raw%}-- good example BEGIN FOR company IN (SELECT * FROM companies) LOOP FOR contact IN (SELECT * FROM contacts) LOOP @@ -179,7 +179,7 @@ FOR c1 IN (SELECT * FROM companies) LOOP END LOOP; END LOOP; END; -/ +/{%endraw%} ``` **This rule has the following properties:** @@ -258,7 +258,7 @@ https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/static.htm#BABIIHBJ **Example(s):** ``` sql -create or replace package inline_pragma_error is +{%raw%}create or replace package inline_pragma_error is end; / @@ -273,7 +273,7 @@ create or replace package body inline_pragma_error is end do_transaction; end inline_pragma_error; -/ +/{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/plsql/design.md b/docs/pages/pmd/rules/plsql/design.md index b1f6ff27f7..3cb5697e57 100644 --- a/docs/pages/pmd/rules/plsql/design.md +++ b/docs/pages/pmd/rules/plsql/design.md @@ -25,7 +25,7 @@ high complexity, and 11+ is very high complexity. **Example(s):** ``` sql --- Cyclomatic Complexity of 25 +{%raw%}-- Cyclomatic Complexity of 25 CREATE OR REPLACE PACKAGE BODY pkg_pmd_working_sequence AS 1 PROCEDURE ty_logger IS BEGIN 2 IF true @@ -138,7 +138,7 @@ CREATE OR REPLACE PACKAGE BODY pkg_pmd_working_sequence AS END IF; END; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -181,12 +181,12 @@ Try to reduce the method length by creating helper methods and removing any copy **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE PROCEDURE doSomething BEGIN DBMS_OUTPUT.PUT_LINE("Hello world!"); DBMS_OUTPUT.PUT_LINE("Hello world!"); -- 98 copies omitted for brevity. -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -226,7 +226,7 @@ apart the code becomes more managable and ripe for reuse. **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE PACKAGE BODY Foo AS PROCEDURE bar1 IS BEGIN -- 1000 lines of code @@ -242,7 +242,7 @@ PACKAGE BODY Foo AS PROCEDURE barN IS BEGIN -- 1000 lines of code END barn; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -282,7 +282,7 @@ apart the code becomes more managable and ripe for reuse. **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE PACKAGE BODY Foo AS PROCEDURE bar1 IS BEGIN -- 1000 lines of code @@ -298,7 +298,7 @@ PACKAGE BODY Foo AS PROCEDURE barN IS BEGIN -- 1000 lines of code END barn; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -338,7 +338,7 @@ apart the code becomes more managable and ripe for reuse. **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE PACKAGE Foo AS PROCEDURE bar1; PROCEDURE bar2; @@ -347,7 +347,7 @@ PACKAGE Foo AS ... PROCEDURE barN; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -386,7 +386,7 @@ same datatype. These situations usually denote the need for new objects to wrap **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE PROCEDURE addPerson( -- too many arguments liable to be mixed up birthYear pls_integer, birthMonth pls_integer, birthDate pls_integer, height pls_integer, weight pls_integer, ssn pls_integer) { @@ -398,7 +398,7 @@ PROCEDURE addPerson( -- preferred approach birthdate DATE, measurements BodyMeasurements , ssn INTEGER) BEGIN . . . . -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -438,7 +438,7 @@ apart the code becomes more managable and ripe for reuse. **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE TYPE BODY Foo AS MEMBER PROCEDURE bar1 IS BEGIN -- 1000 lines of code @@ -454,7 +454,7 @@ TYPE BODY Foo AS MEMBER PROCEDURE barN IS BEGIN -- 1000 lines of code END barn; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -494,12 +494,12 @@ lines of code that are split are counted as one. **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE BODY AS +{%raw%}CREATE OR REPLACE PACKAGE BODY AS FUNCTION methd RETURN INTEGER IS BEGIN RETURN 1;; END; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -539,14 +539,14 @@ lines of code that are split are counted as one. **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE pkg_ +{%raw%}CREATE OR REPLACE PACKAGE pkg_ PROCEDURE Foo IS BEGIN --this class only has 6 NCSS lines super(); super(); END; -} +}{%endraw%} ``` **This rule has the following properties:** @@ -586,7 +586,7 @@ complexity and increase readability. **Example(s):** ``` sql -CREATE OR REPLACE +{%raw%}CREATE OR REPLACE PROCEDURE bar AS BEGIN -- this is something more complex than it needs to be, if (y) THEN -- it should be broken down into smaller methods or functions for j IN 0 .. j-1 LOOP @@ -617,7 +617,7 @@ PROCEDURE bar AS BEGIN -- this is something more complex than it needs to be, log_problem; END; END; -END; +END;{%endraw%} ``` **This rule has the following properties:** @@ -657,12 +657,12 @@ city/state/zip fields could park them within a single Address field. **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE pkg_too_many_fields AS +{%raw%}CREATE OR REPLACE PACKAGE pkg_too_many_fields AS C_CHAR_A CONSTANT CHAR(1 CHAR) := 'A'; C_CHAR_B CONSTANT CHAR(1 CHAR) := 'B'; ... C_CHAR_Z CONSTANT CHAR(1 CHAR) := 'Z'; -END pkg_too_many_fields; +END pkg_too_many_fields;{%endraw%} ``` **This rule has the following properties:** diff --git a/docs/pages/pmd/rules/plsql/errorprone.md b/docs/pages/pmd/rules/plsql/errorprone.md index 92385aacf9..da02816663 100644 --- a/docs/pages/pmd/rules/plsql/errorprone.md +++ b/docs/pages/pmd/rules/plsql/errorprone.md @@ -27,7 +27,7 @@ TO_DATE(TO_CHAR(date-variable)) used to remove time component - use TRUNC(date-v **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE BODY date_utilities +{%raw%}CREATE OR REPLACE PACKAGE BODY date_utilities IS -- Take single parameter, relying on current default NLS date format @@ -39,7 +39,7 @@ END strip_time; END date_utilities; -/ +/{%endraw%} ``` **Use this rule by referencing it:** @@ -64,7 +64,7 @@ TO_DATE without date format- use TO_DATE(expression, date-format) **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE BODY date_utilities +{%raw%}CREATE OR REPLACE PACKAGE BODY date_utilities IS -- Take single parameter, relying on current default NLS date format @@ -89,7 +89,7 @@ BEGIN END to_date_three_parameters; END date_utilities; -/ +/{%endraw%} ``` **Use this rule by referencing it:** @@ -114,7 +114,7 @@ TO_TIMESTAMP without date format- use TO_TIMESTAMP(expression, date-format) **Example(s):** ``` sql -CREATE OR REPLACE PACKAGE BODY date_utilities +{%raw%}CREATE OR REPLACE PACKAGE BODY date_utilities IS -- Take single parameter, relying on current default NLS date format @@ -139,7 +139,7 @@ BEGIN END to_timestamp_three_parameters; END date_utilities; -/ +/{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/pom/errorprone.md b/docs/pages/pmd/rules/pom/errorprone.md index aeb3e52dc9..abc289d563 100644 --- a/docs/pages/pmd/rules/pom/errorprone.md +++ b/docs/pages/pmd/rules/pom/errorprone.md @@ -28,7 +28,7 @@ The following types are considered valid: pom, jar, maven-plugin, ejb, war, ear, **Example(s):** ``` xml -<project...> +{%raw%}<project...> ... <dependencyManagement> ... @@ -41,7 +41,7 @@ The following types are considered valid: pom, jar, maven-plugin, ejb, war, ear, </dependency> ... </dependencyManagement> -</project> +</project>{%endraw%} ``` **This rule has the following properties:** @@ -87,13 +87,13 @@ By far the most common problem is the use of ${project.version} in a BOM or pare **Example(s):** ``` xml -<project...> +{%raw%}<project...> ... <dependency> ... <version>${project.dependency}</version> </dependency> -</project> +</project>{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/swift.md b/docs/pages/pmd/rules/swift.md new file mode 100644 index 0000000000..c8419e49b1 --- /dev/null +++ b/docs/pages/pmd/rules/swift.md @@ -0,0 +1,23 @@ +--- +title: Swift Rules +tags: [rule_references, swift] +summary: Index of all built-in rules available for Swift +language_name: Swift +permalink: pmd_rules_swift.html +folder: pmd/rules +--- +<!-- DO NOT EDIT THIS FILE. This file is generated. --> +## Best Practices + +{% include callout.html content="Rules which enforce generally accepted best practices." %} + +* [ProhibitedInterfaceBuilder](pmd_rules_swift_bestpractices.html#prohibitedinterfacebuilder): Creating views using Interface Builder should be avoided. Defining views by code allow... +* [UnavailableFunction](pmd_rules_swift_bestpractices.html#unavailablefunction): Due to Objective-C and Swift interoperability some functions are often required to be implemented... + +## Error Prone + +{% include callout.html content="Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors." %} + +* [ForceCast](pmd_rules_swift_errorprone.html#forcecast): Force casts should be avoided. This may lead to a crash if it's not used carefully. Fo... +* [ForceTry](pmd_rules_swift_errorprone.html#forcetry): Force tries should be avoided. If the code being wrapped happens to raise and exception, our appl... + diff --git a/docs/pages/pmd/rules/swift/bestpractices.md b/docs/pages/pmd/rules/swift/bestpractices.md new file mode 100644 index 0000000000..0fd5d54ae0 --- /dev/null +++ b/docs/pages/pmd/rules/swift/bestpractices.md @@ -0,0 +1,71 @@ +--- +title: Best Practices +summary: Rules which enforce generally accepted best practices. +permalink: pmd_rules_swift_bestpractices.html +folder: pmd/rules/swift +sidebaractiveurl: /pmd_rules_swift.html +editmepath: ../pmd-swift/src/main/resources/category/swift/bestpractices.xml +keywords: Best Practices, ProhibitedInterfaceBuilder, UnavailableFunction +language: Swift +--- +<!-- DO NOT EDIT THIS FILE. This file is generated from file ../pmd-swift/src/main/resources/category/swift/bestpractices.xml. --> +## ProhibitedInterfaceBuilder + +**Since:** PMD 7.0 + +**Priority:** Medium High (2) + +Creating views using Interface Builder should be avoided. +Defining views by code allows the compiler to detect issues that otherwise will be runtime errors. +It's difficult to review the auto-generated code and allow concurrent modifications of those files. +Consider building views programmatically. + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.swift.rule.bestpractices.ProhibitedInterfaceBuilderRule](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderRule.java) + +**Example(s):** + +``` swift +{%raw%}class ViewController: UIViewController { + @IBOutlet var label: UILabel! // violation, referencing a IBOutlet +} + +class ViewController: UIViewController { + var label: UILabel! +}{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml +<rule ref="category/swift/bestpractices.xml/ProhibitedInterfaceBuilder" /> +``` + +## UnavailableFunction + +**Since:** PMD 7.0 + +**Priority:** Medium (3) + +Due to Objective-C and Swift interoperability some functions are often required to be implemented but +aren't really needed. It is extremely common that the sole implementation of the functions consist of throwing +a fatal error. Marking these functions as unavailable prevents them from being executed while still making +the compiler happy. + +**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.swift.rule.bestpractices.UnavailableFunctionRule](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java) + +**Example(s):** + +``` swift +{%raw%}required init?(coder _: NSCoder) { // violation, no unavailable attribute added to the function declaration + fatalError("init(coder:) has not been implemented") +} + +@available(*, unavailable) // no violation +required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented"){%endraw%} +``` + +**Use this rule by referencing it:** +``` xml +<rule ref="category/swift/bestpractices.xml/UnavailableFunction" /> +``` + diff --git a/docs/pages/pmd/rules/swift/errorprone.md b/docs/pages/pmd/rules/swift/errorprone.md new file mode 100644 index 0000000000..b9dea77cc6 --- /dev/null +++ b/docs/pages/pmd/rules/swift/errorprone.md @@ -0,0 +1,66 @@ +--- +title: Error Prone +summary: Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors. +permalink: pmd_rules_swift_errorprone.html +folder: pmd/rules/swift +sidebaractiveurl: /pmd_rules_swift.html +editmepath: ../pmd-swift/src/main/resources/category/swift/errorprone.xml +keywords: Error Prone, ForceCast, ForceTry +language: Swift +--- +<!-- DO NOT EDIT THIS FILE. This file is generated from file ../pmd-swift/src/main/resources/category/swift/errorprone.xml. --> +## ForceCast + +**Since:** PMD 7.0 + +**Priority:** Medium (3) + +Force casts should be avoided. This may lead to a crash if it's not used carefully. +For example assuming a JSON property has a given type, or your reused Cell has a certain contract. +Consider using conditional casting and handling the resulting optional. + +**This rule is defined by the following XPath expression:** +``` xpath +//TypeCastingOperator[starts-with(@Text,'as!')] +``` + +**Example(s):** + +``` swift +{%raw%}NSNumber() as! Int // violation, force casting + +NSNumber() as? Int // no violation{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml +<rule ref="category/swift/errorprone.xml/ForceCast" /> +``` + +## ForceTry + +**Since:** PMD 7.0 + +**Priority:** Medium (3) + +Force tries should be avoided. If the code being wrapped happens to raise and exception, our application will crash. +Consider using a conditional try and handling the resulting optional, or wrapping the try statement in a do-catch block. + +**This rule is defined by the following XPath expression:** +``` xpath +//TryOperator[@Text='try!'] +``` + +**Example(s):** + +``` swift +{%raw%}let x = try! someThrowingFunction() // violation, force trying + +let x = try? someThrowingFunction() // no violation{%endraw%} +``` + +**Use this rule by referencing it:** +``` xml +<rule ref="category/swift/errorprone.xml/ForceTry" /> +``` + diff --git a/docs/pages/pmd/rules/vf/security.md b/docs/pages/pmd/rules/vf/security.md index 86f8e57ef5..eba7e27f1a 100644 --- a/docs/pages/pmd/rules/vf/security.md +++ b/docs/pages/pmd/rules/vf/security.md @@ -22,7 +22,7 @@ Avoid calling VF action upon page load as the action becomes vulnerable to CSRF. **Example(s):** ``` vf -<apex:page controller="AcRestActionsController" action="{!csrfInitMethod}" > +{%raw%}<apex:page controller="AcRestActionsController" action="{!csrfInitMethod}" >{%endraw%} ``` **Use this rule by referencing it:** @@ -43,7 +43,7 @@ Avoid unescaped user controlled content in EL as it results in XSS. **Example(s):** ``` vf -<apex:outputText value="Potential XSS is {! here }" escape="false" /> +{%raw%}<apex:outputText value="Potential XSS is {! here }" escape="false" />{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/xml.md b/docs/pages/pmd/rules/xml.md index 0b10fd891b..fca26968bb 100644 --- a/docs/pages/pmd/rules/xml.md +++ b/docs/pages/pmd/rules/xml.md @@ -11,7 +11,7 @@ folder: pmd/rules {% include callout.html content="Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors." %} -* [MistypedCDATASection](pmd_rules_xml_errorprone.html#mistypedcdatasection): An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and ends with a ]]> mar... +* [MistypedCDATASection](pmd_rules_xml_errorprone.html#mistypedcdatasection): An XML CDATA section begins with a <![CDATA[ marker, which has only one [, and ends with a ]]> ma... ## Additional rulesets diff --git a/docs/pages/pmd/rules/xml/errorprone.md b/docs/pages/pmd/rules/xml/errorprone.md index 2ddd87c822..7ab8b27fcd 100644 --- a/docs/pages/pmd/rules/xml/errorprone.md +++ b/docs/pages/pmd/rules/xml/errorprone.md @@ -15,7 +15,7 @@ language: XML **Priority:** Medium (3) -An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and ends with a ]]> marker, which has only two ]. +An XML CDATA section begins with a <![CDATA[ marker, which has only one [, and ends with a ]]> marker, which has two ]. **This rule is defined by the following XPath expression:** ``` xpath @@ -25,7 +25,18 @@ An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and **Example(s):** ``` xml -An extra [ looks like <!CDATA[[]]>, and an extra ] looks like <!CDATA[]]]>. +{%raw%}<root> + <child> + <![CDATA[[ character data ]]> - this cdata section is valid, but it contains an + additional square bracket at the beginning. + It should probably be just <![CDATA[ character data ]]>. + </child> + <child> + <![CDATA[ character data ]]]> - this cdata section is valid, but it contains an + additional square bracket in the end. + It should probably be just <![CDATA[ character data ]]>. + </child> +</root>{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/xsl/codestyle.md b/docs/pages/pmd/rules/xsl/codestyle.md index a0c276933e..e664ae3c8e 100644 --- a/docs/pages/pmd/rules/xsl/codestyle.md +++ b/docs/pages/pmd/rules/xsl/codestyle.md @@ -26,8 +26,8 @@ The XPath concat() functions accepts as many arguments as required so you can ha **Example(s):** ``` xsl -<xsl:variable name="var" select="concat("Welcome",concat("to you ",$name))"/> -<xsl:variable name="var" select="concat("Welcome","to you ",$name))"> +{%raw%}<xsl:variable name="var" select="concat("Welcome",concat("to you ",$name))"/> +<xsl:variable name="var" select="concat("Welcome","to you ",$name))">{%endraw%} ``` **Use this rule by referencing it:** diff --git a/docs/pages/pmd/rules/xsl/performance.md b/docs/pages/pmd/rules/xsl/performance.md index 3b5cca3dd4..c89ae0d35f 100644 --- a/docs/pages/pmd/rules/xsl/performance.md +++ b/docs/pages/pmd/rules/xsl/performance.md @@ -41,7 +41,7 @@ cutting through 100% of the document. **Example(s):** ``` xsl -<xsl:variable name="var" select="//item/descendant::child"/> +{%raw%}<xsl:variable name="var" select="//item/descendant::child"/>{%endraw%} ``` **This rule has the following properties:** diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index 68909b97a1..57356e4a5e 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -181,7 +181,7 @@ This behavior has been introduced to ease PMD integration into scripts or hooks, * [plsql](pmd_rules_plsql.html) * [vf](pmd_rules_vf.html) (Salesforce VisualForce) * [vm](pmd_rules_vm.html) (Apache Velocity) -* [xml and xsl](/pmd_rules_xml.html) +* [xml and xsl](pmd_rules_xml.html) ## Available Report Formats diff --git a/docs/pages/pmd/userdocs/cpd.md b/docs/pages/pmd/userdocs/cpd.md index 492776d5df..e9843661fe 100644 --- a/docs/pages/pmd/userdocs/cpd.md +++ b/docs/pages/pmd/userdocs/cpd.md @@ -17,7 +17,7 @@ It can also be run with Maven by using the `cpd-check` goal on the [Maven PMD Pl Your own language is missing? -See how to add it [here](/pmd_devdocs_major_adding_new_cpd_language.html). +See how to add it [here](pmd_devdocs_major_adding_new_cpd_language.html). ### Why should you care about duplicates? @@ -199,7 +199,7 @@ Please note that if CPD detects duplicated source code, it will exit with status This behavior has been introduced to ease CPD integration into scripts or hooks, such as SVN hooks. <table> -<tr><td>0</td><td>Everything is fine, now code duplications found</td></tr> +<tr><td>0</td><td>Everything is fine, no code duplications found</td></tr> <tr><td>1</td><td>Couldn't understand command line parameters or CPD exited with an exception</td></tr> <tr><td>4</td><td>At least one code duplication has been detected unless '--failOnViolation false' is used.</td></tr> </table> @@ -218,6 +218,7 @@ This behavior has been introduced to ease CPD integration into scripts or hooks, * Java * Jsp * Kotlin +* Lua * Matlab * Objective-C * Perl @@ -366,7 +367,7 @@ Here's a screenshot of CPD after running on the JDK 8 java.lang package: ## Suppression Arbitrary blocks of code can be ignored through comments on **Java**, **C/C++**, **Dart**, **Go**, **Javascript**, -**Kotlin**, **Matlab**, **Objective-C**, **PL/SQL**, **Python** and **Swift** by including the keywords `CPD-OFF` and `CPD-ON`. +**Kotlin**, **Lua**, **Matlab**, **Objective-C**, **PL/SQL**, **Python** and **Swift** by including the keywords `CPD-OFF` and `CPD-ON`. ```java public Object someParameterizedFactoryMethod(int x) throws Exception { diff --git a/docs/pages/pmd/userdocs/extending/designer_reference.md b/docs/pages/pmd/userdocs/extending/designer_reference.md new file mode 100644 index 0000000000..de1293707f --- /dev/null +++ b/docs/pages/pmd/userdocs/extending/designer_reference.md @@ -0,0 +1,254 @@ +--- +title: The rule designer +short_title: Rule designer +tags: [extending, userdocs] +summary: "Learn about the usage and features of the rule designer." +last_updated: August 2019 (6.18.0) +permalink: pmd_userdocs_extending_designer_reference.html +author: Clément Fournier <clement.fournier76@gmail.com> +--- + +## Installing, running, updating + +The designer is part of PMD's binary distributions. To **install a distribution**, see the [documentation page about installing PMD](pmd_userdocs_installation.html). + +The app needs JRE 1.8 or above to run. Be aware that on JRE 11+, the JavaFX distribution should be installed separately. Visit the [JavaFX download page](https://gluonhq.com/products/javafx/) to download a distribution, extract it, and set the JAVAFX_HOME environment variable. + +If the bin directory of your PMD distribution is on your shell's path, then you can **launch the app** with + + run.sh designer on Linux/ OSX + designer.bat on Windows + + +{% include note.html content="pmd-ui.jar is not a runnable jar, because it doesn't include any PMD language module, or PMD Core. " %} + + +This is to allow easy updating, and let you choose the dependencies you're interested in. +The available language modules are those on the classpath of the app's JVM. That's why it's recommended to use the standard PMD startup scripts, which setup the classpath with the available PMD libraries. + + +### Updating + +The latest version of the designer currently **works with PMD 6.12.0 and above**. You can simply replace pmd-ui-6.X.Y.jar with the [latest build](https://github.com/pmd/pmd-designer/releases) in the installation folder of your PMD distribution, and run it normally. Note that updating may cause some persisted state to get lost, for example the code snippet. + + +# Usage reference + + +The rule designer is both a tool to inspect the tree on which PMD rules run on, and to write XPath rules in an integrated manner. This page describes the features that enable this. + + +## AST inspection + + +![Designer top UI](images/designer/designer-top.png) + + +You can enter source code in the middle zone. +* Make sure to select the correct language and version for your source code: + * Language is set app-wide with the blue button in the menu-bar + * If the language has several language versions, you can select a specific one with the choicebox just above the code area +* If the source is valid using this setting, the tree to the right will update to display the AST of the code +* When selecting a node, the left panel updates with information about a node + +### Selecting nodes + +There are several ways to focus a node for inspection: +* **From the tree view:** just click on an item + * Since 6.16.0, the tree view is also searchable: press CTRL+F when it's focused, or click on the `Search` button and enter a search query. You can cycle through results with `CTRL+TAB` or `CTRL+F3`, and cycle back with `CTRL+SHIFT+TAB` or `CTRL+SHIFT+F3` +* **From the crumb bar:** the crumb bar below the code area shows the ancestors of the currently selected node, and is empty if you have no selection: + +{% details Ancestor crumb bar demo %} + +![Ancestor crumb bar demo](images/designer/parents-bar.gif) + +{% enddetails %} + + +* **From the source code:** maintain **CTRL** for a second until the code area becomes mostly blue. Then, each node you hover over on the code area will be selected automatically. Example: + +{% details CTRL-hover selection demo %} + +![CTRL-hover selection demo](images/designer/hover-selection.gif) + +{% enddetails %} + +### Node inspection + +The left panel displays the following information: + +* **XPath attributes:** this basically are all the attributes available in XPath queries. Those attributes are wrappers around a Java getter, so you can obtain documentation on the relevant Javadoc (that's not yet integrated into the designer) +* **Metrics:** for nodes that support it, the values of metrics are displayed in this panel +* **Scopes:** This is java specific and displays some representation of the symbol table. You mostly don't need it. If you select eg a variable id, its usages are already highlighted automatically without opening the panel: + +![Usages highlight example](images/designer/usages.gif) + + +## XPath rule design + + +The bottom part of the UI is dedicated to designing XPath rules: + +![Bottom UI](images/designer/bottom-ui.png) + + +The center is an XPath expression. As you type it, the matched nodes are updated on the right, and highlighted on the code area. Autocompletion is available on some languages. + +Note: you can keep several rules in the editor (there's a tab for each of them). + +### Rule properties + +Above the XPath expression area, the **"Properties"** button allows you to [define new properties](pmd_userdocs_extending_defining_properties.html#for-xpath-rules) for your prototype rule. You can also edit the existing properties. + +When you click on it, a small popup appears: + +![Property definition popup](images/designer/property-defs.png) + +The popup contains in the center a list of currently defined properties, displaying their name and expected type. + +* **Adding**: the "Add property" button adds a row to the table +* **Deleting**: each item has a "Trash" button to delete the property +* **Editing**: each property can be further edited by clicking on the "Ellipsis" button on the right + +#### Editing properties + +The edition menu of a property looks like the following: + +![Property edition popup](images/designer/property-edit.png) + +* You can edit the name, description, expected type, and default value of the property +* All this information is exported with the rule definition (see [Exporting to an XML rule](#exporting-to-an-xml-rule)) +* The default value is used unless you're editing a test case, and you set a custom value for the test case. TODO link + +### Exporting to an XML rule + +The little **export icon** next to the gear icon opens a menu to export your rule. This menu lets you fill-in the metadata necessary for an XPath rule to be included in a ruleset. + +{% details Rule export demo %} + + +![Rule export demo](images/designer/export-example.gif) + +{% enddetails %} + +## Testing a rule + +PMD has its own XML format to describe rule tests and execute them using our test framework. The designer includes a test editor, which allows you to edit such files or create a new one directly as you edit the rule. This is what the panel left of the XPath expression area is for. + +See also [the test framework documentation](pmd_userdocs_extending_testing.html). + +### Testing model + +A rule test describes +* the configuration of the rule +* the source on which to run +* the expected violations +* a description (to name the test) + +When executing a test, the rule is run on the source with the given configuration, then the violations it finds are compared to the expected ones. + +### Adding tests + +Tests can be added in one of four ways: +* **From an XML file:** if you already have a test XML file for your tests, you can load all the tests it defines easily. + +{% details Test import demo %} + +![Test import example](images/designer/tests/import.gif) + +{% enddetails %} + + +* **From the current source:** A new test case with a default configuration is created, with the source that is currently in the editor + +* **With an empty source:** A new test case with a default configuration is created, with an empty source file. You must edit the source yourself then. + +* **From an existing test case:** Each test case list item has a "Copy" button which duplicates the test and loads the new one. + +### Test status + +In the designer, the test panel is a list of test cases. Their status (passing, failing, error, unknown) is color coded. + +{% details Test status color coding examples %} + +All tests passing (green): + +![All green](images/designer/tests/all-green.png) + +A failing test (orange): + +![Failing](images/designer/tests/failing.png) + +{% enddetails %} + +### Loading a test case + +Each test has a piece of source, which you can edit independently of the others, when the test is **loaded in the editor**. Additional rule configuration options can be chosen when the test is loaded. + +Loading is done with the **Load** button: + + +{% details Test loading demo %} + +![Test loading demo](images/designer/tests/load.gif) + +{% enddetails %} + + +Only one test case may be loaded at a time. If the loaded test is unloaded, the editor reverts back to the state it had before the first test case was loaded. + +### Editing a loaded test case + +When a test is loaded, *the source you edit in the code area is the source of the test*. Changes are independent from other tests, and from the piece of source that was previously in the editor. + +When a test is loaded, an additional toolbar shows up at the top of the code area: + +![Failing](images/designer/tests/toolbar.png) + +#### Expected violations + +The **"Expected violations"** button is used to add or edit the expected violations. + +Initially the list of violations is empty. You can add violations by **dragging and dropping nodes** onto the button or its popup, from any control that displays nodes. For example: + +{% details Adding a violation demo %} + + +![Add violation gif](images/designer/tests/add-violation.gif) + +{% enddetails %} + +#### Test case rule configuration + +Rule properties can be configured for each test case independently using the **"Property mapping"** button. For example: + +{% details Test rule property demo %} + +![Configure properties demo](images/designer/tests/property.gif) + +{% enddetails %} + +This configuration will be used when executing the test to check its status. + +### Exporting tests + +When you're done editing tests, it's a good idea to save the test file to an XML file. Exporting is done using the **"Export"** button above the list of test cases: + +{% details Test export demo %} + +![Test export demo](images/designer/tests/export.gif) + +{% enddetails %} + +Note that the exported file does not contain any information about the rule. The rule must be in a ruleset file somewhere else. + +If you want to use PMD's test framework to use the test file in your build, please refer to the conventions explained in [the test framework documentation](pmd_userdocs_extending_testing.html#where-to-place-the-test-code). + + + + + + + + + diff --git a/docs/pages/pmd/userdocs/installation.md b/docs/pages/pmd/userdocs/installation.md index 31734de6a7..7339d1b986 100644 --- a/docs/pages/pmd/userdocs/installation.md +++ b/docs/pages/pmd/userdocs/installation.md @@ -22,7 +22,7 @@ sidebar: pmd_sidebar ### Installation -PMD is distributed as a zip archive, which includes both [PMD](#running-pmd-via-command-line) and [CPD](/pmd_userdocs_cpd.html). +PMD is distributed as a zip archive, which includes both [PMD](#running-pmd-via-command-line) and [CPD](pmd_userdocs_cpd.html). You can download the latest binary distribution from [the github releases page](https://github.com/pmd/pmd/releases). Unzip it into any directory, optionally add the `bin` subdirectory in your `PATH`, and you're good to go! @@ -79,7 +79,7 @@ Additionally, the following options, are specified most of the time even though <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="linux"> <figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="gp">~ $ </span><span class="s2">cd</span> ~/bin/pmd-bin-{{site.pmd.version}}/bin -<span class="gp">~/.../bin $ </span><span class="s2">./run.sh</span> pmd -d ../../../src/main/java/ -f text -R rulesets/java/basic.xml +<span class="gp">~/.../bin $ </span><span class="s2">./run.sh</span> pmd -d ../../../src/main/java/ -f text -R rulesets/java/quickstart.xml .../src/main/java/com/me/RuleSet.java:123 These nested if statements could be combined .../src/main/java/com/me/RuleSet.java:231 Useless parentheses. @@ -89,7 +89,7 @@ Additionally, the following options, are specified most of the time even though </div> <div role="tabpanel" class="tab-pane" id="windows"> <figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="gp">C:\ > </span><span class="s2">cd</span> C:\pmd-bin-{{site.pmd.version}}\bin -<span class="gp">C:\...\bin > </span><span class="s2">.\pmd.bat</span> -d ..\..\src\main\java\ -f text -R rulesets/java/basic.xml +<span class="gp">C:\...\bin > </span><span class="s2">.\pmd.bat</span> -d ..\..\src\main\java\ -f text -R rulesets/java/quickstart.xml .../src/main/java/com/me/RuleSet.java:123 These nested if statements could be combined .../src/main/java/com/me/RuleSet.java:231 Useless parentheses. diff --git a/docs/pages/pmd/userdocs/suppressing_warnings.md b/docs/pages/pmd/userdocs/suppressing_warnings.md index 20ab95452d..78860877d0 100644 --- a/docs/pages/pmd/userdocs/suppressing_warnings.md +++ b/docs/pages/pmd/userdocs/suppressing_warnings.md @@ -187,10 +187,15 @@ of no use. ### The property `violationSuppressXPath` This property defines an XPath query to be executed *using the -violation node as the starting point*. If the XPath query matches anything, -then the violation will be suppressed. +violation node as the context node*. If the XPath query matches anything, +then the violation will be suppressed. Note that the query shouldn't be finding +the violation nodes to suppress, but rather, finding a non-empty sequence of nodes +when evaluated with the violation node as a context node. -For example, to suppress reporting specifically typed parameters which are unused: +The XPath version used by those queries is XPath 1.0, so it doesn't support various XPath 2.0 +features. This will be updated with PMD 7.0.0. + +For example, to suppress reporting specifically "String" parameters which are unused: ```xml <rule ref="rulesets/java/unusedcode.xml/UnusedFormalParameter"> @@ -200,6 +205,25 @@ For example, to suppress reporting specifically typed parameters which are unuse </rule> ``` +Note the use of `.` to refer to the context node. Using `//` at the start of the +expression should be avoided, as it would test all nodes in the file, and suppress +more violations than expected. + +Another example, to suppress violations occurring in classes whose name contains `Bean`: +```xml +<property name="violationSuppressXPath" value="./ancestor::ClassOrInterfaceDeclaration[contains(@Image, 'Bean')]"/> +``` + +You can also use regex for string comparison. The next example suppresses violations in classes ending with `Bean`: +```xml +<property name="violationSuppressXPath" value="./ancestor::ClassOrInterfaceDeclaration[matches(@Image, '^.*Bean$')]"/> +``` + + +Note here the usage of the `./ancestor::` axis instead of `//`. The latter would match +any ClassOrInterfaceDeclaration in the file, while the former matches only class +declaration nodes that *enclose the violation node*, which is usually what you'd want. + Note for XPath based suppression to work, you must know how to write an XPath query that matches the AST structure of the nodes of the violations you wish to suppress. XPath queries are explained in diff --git a/docs/pages/pmd/userdocs/tools/ant.md b/docs/pages/pmd/userdocs/tools/ant.md index d85c588782..5939a05ffa 100644 --- a/docs/pages/pmd/userdocs/tools/ant.md +++ b/docs/pages/pmd/userdocs/tools/ant.md @@ -14,6 +14,38 @@ author: > Runs a set of static code analysis rules on some source code files and generates a list of problems found. +### Installation + +Before you can use the `pmd` task in your ant `build.xml` file, you need to install PMD and its libraries into +ant's classpath, as described in [Optional Tasks](https://ant.apache.org/manual/install.html#optionalTasks). + +First you need to download PMD's binary distribution zip file. +Then you can either copy all "*.jar" files from PMD's lib folder into one of ANT's library folders +(`ANT_HOME/lib`, `${user.home}/.ant/lib`) or using the `-lib` command line parameter. + +However, the preferred way is to define a `<classpath>` for pmd itself and use this classpath when +adding the PMD Task. Assuming, you have extracted the PMD zip file to `/home/joe/pmd-bin-{{site.pmd.version}}`, +then you can make use of the PMD Task like this: + + <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"> + <classpath> + <fileset dir="/home/joe/pmd-bin-{{site.pmd.version}}/lib"> + <include name="*.jar"/> + </fileset> + </classpath> + </taskdef> + +Alternatively, a path can be defined and used via `classpathref`: + + <path id="pmd.classpath"> + <fileset dir="/home/joe/pmd-bin-{{site.pmd.version}}/lib"> + <include name="*.jar"/> + </fileset> + </path> + <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath" /> + +The examples below won't repeat this taskdef element, as this is always required. + ### Parameters <table> @@ -93,7 +125,8 @@ Runs a set of static code analysis rules on some source code files and generates </table> -`formatter` nested element - specifies the format of and the files to which the report is written. +`formatter` nested element - specifies the format of and the files to which the report is written. You can +configure multiple formatters. <table> <tr><th>Name</th><th>Values</th></tr> @@ -120,47 +153,58 @@ Runs a set of static code analysis rules on some source code files and generates <dt>encoding</dt> <dd>Specifies the encoding to be used in the generated report (only honored when used with `toFile`). When rendering `toConsole` PMD will automatically detect the terminal's encoding and use it, unless the output is being redirected / piped, in which case `file.encoding` is used. See example below.</dd> <dt>linkPrefix</dt> - <dd>Used for linking to online HTMLized source (like <a href="xref/net/sourceforge/pmd/PMD.html">this</a>). See example below.</dd> + <dd>Used for linking to online HTMLized source (like <a href="https://maven.apache.org/plugins/maven-pmd-plugin/xref/org/apache/maven/plugins/pmd/PmdReport.html">this</a>). See example below. Note, this only works with [maven-jxr-plugin](https://maven.apache.org/jxr/maven-jxr-plugin/index.html).</dd> <dt>linePrefix</dt> - <dd>Used for linking to online HTMLized source (like <a href="xref/net/sourceforge/pmd/PMD.html#102">this</a>). See example below.</dd> + <dd>Used for linking to online HTMLized source (like <a href="https://maven.apache.org/plugins/maven-pmd-plugin/xref/org/apache/maven/plugins/pmd/PmdReport.html#L375">this</a>). See example below. Note, this only works with [maven-jxr-plugin](https://maven.apache.org/jxr/maven-jxr-plugin/index.html).</dd> </dl> </td> </tr> </table> -`classpath` nested element - useful for specifying custom rule. More details on the `classpath` -element are in the Ant documentation [here](http://ant.apache.org/manual/using.html#path) and there's +`classpath` nested element - useful for specifying custom rules. More details on the `classpath` +element are in the Ant documentation for [path-like structures](https://ant.apache.org/manual/using.html#path) and there's an example below. -`auxclasspath` nested element - extra classpath used for Type Resolution rules. +`auxclasspath` nested element - extra classpath used for type resolution. Some rules make use of type resolution +in order to avoid false positives. The `auxclasspath` is configured also with [path-like structures](https://ant.apache.org/manual/using.html#path). It should contain the compiled classes of the project that is being analyzed and all the compile time +dependencies. `sourceLanguage` nested element - specify which language (Java, Ecmascript, XML,...) -and the associated version (1.5, 1.6,...) +and the associated version (1.5, 1.6,...). This element is optional. The language is determined by file extension +automatically and the latest language version is used. -`ruleset` nested element - another way to specify rulesets. Here's an example: +`ruleset` nested element - another way to specify rulesets. You can specify multiple elements. Here's an example: <target name="pmd"> <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> <pmd shortFilenames="true"> - <sourceLanguage name="java" version="1.6"/> <ruleset>rulesets/java/design.xml</ruleset> <ruleset>java-basic</ruleset> - <formatter type="html" toFile="pmd_report.html"> - <param name="linkPrefix" value="http://pmd.sourceforge.net/xref/"/> - </formatter> <fileset dir="/usr/local/j2sdk1.4.1_01/src/"> <include name="java/lang/*.java"/> </fileset> </pmd> </target> +`fileset` nested element - specify the actual java source files, that PMD should analyze. You can use multiple +fileset elements. See [FileSet](https://ant.apache.org/manual/Types/fileset.html) for the syntax and usage. + ### Language version selection -The specific version of a language to be used for parsing is selected via the `sourceLanguage` +PMD selects the language automatically using the file extension. If multiple versions of a language are +supported, PMD uses the latest version as default. This is currently the case for Java only, which has +support for multiple versions. + +If a languages supports multiple versions, you can select a specific version here, so that e.g. rules, that only apply +to specific versions, are not executed. E.g. the rule {% rule "java/bestpractices/UseTryWithResources" %} only makes +sense with Java 1.7 and later. If your project uses Java 1.5, then you should configure the `sourceLanguage` +accordingly and this rule won't be executed. + +The specific version of a language to be used is selected via the `sourceLanguage` nested element. Possible values are: - <sourceLanguage name="apex" version=""/> + <sourceLanguage name="apex" version="45"/> <sourceLanguage name="ecmascript" version="3"/> <sourceLanguage name="java" version="1.3"/> <sourceLanguage name="java" version="1.4"/> @@ -169,6 +213,9 @@ nested element. Possible values are: <sourceLanguage name="java" version="1.7"/> <sourceLanguage name="java" version="1.8"/> <sourceLanguage name="java" version="9"/> + <sourceLanguage name="java" version="10"/> + <sourceLanguage name="java" version="11"/> + <sourceLanguage name="java" version="12"/> <!-- this is the default --> <sourceLanguage name="jsp" version=""/> <sourceLanguage name="pom" version=""/> <sourceLanguage name="plsql" version=""/> @@ -183,22 +230,21 @@ Several folks (most recently, Wouter Zelle) have written XSLT scripts which you can use to transform the XML report into nifty HTML. To do this, make sure you use the XML formatter in the PMD task invocation, i.e.: - <formatter type="xml" toFile="${tempbuild}/$report_pmd.xml"> + <formatter type="xml" toFile="${tempbuild}/report_pmd.xml"> <param name="encoding" value="UTF-8" /> <!-- enforce UTF-8 encoding for the XML --> </formatter> Then, after the end of the PMD task, do this: - <xslt in="${tempbuild}/$report_pmd.xml" style="${pmdConfig}/wz-pmd-report.xslt" out="${pmdOutput}/$report_pmd.html" /> + <xslt in="${tempbuild}/report_pmd.xml" style="${pmdConfig}/wz-pmd-report.xslt" out="${pmdOutput}/report_pmd.html" /> ### Examples +#### One ruleset + Running one ruleset to produce a HTML report (and printing the report to the console as well) using a file cache - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> - <target name="pmd"> - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> <pmd rulesetfiles="java-imports" cacheLocation="build/pmd/pmd.cache"> <formatter type="html" toFile="pmd_report.html" toConsole="true"/> <fileset dir="C:\j2sdk1.4.1_01\src\java\lang\"> @@ -207,12 +253,11 @@ Running one ruleset to produce a HTML report (and printing the report to the con </pmd> </target> +#### Multiple rulesets + Running multiple rulesets to produce an XML report with the same analysis cache - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> - <target name="pmd"> - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> <pmd rulesetfiles="rulesets/java/imports.xml,java-unusedcode" cacheLocation="build/pmd/pmd.cache"> <formatter type="xml" toFile="c:\pmd_report.xml"/> <fileset dir="C:\j2sdk1.4.1_01\src\java\lang\"> @@ -221,9 +266,19 @@ Running multiple rulesets to produce an XML report with the same analysis cache </pmd> </target> -Using a custom renderer +#### Custom renderer - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> +Using a custom renderer. For this to work, you need to add you custom renderer to the classpath of PMD. This +need to be configured when defining the task: + + <path id="pmd.classpath"> + <fileset dir="/home/joe/pmd-bin-{{site.pmd.version}}/lib"> + <include name="*.jar"/> + </fileset> + <!-- the custom renderer is expected to be in /home/joe/pmd-addons/com/company/MyRenderer.class --> + <pathelement location="/home/joe/pmd-addons" /> + </path> + <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath" /> <target name="pmd"> <pmd rulesetfiles="rulesets/java/design.xml"> @@ -234,27 +289,57 @@ Using a custom renderer </pmd> </target> -Using a classpath reference in the taskdef +#### Full example with auxclasspath - <path id="pmd.classpath"> - <pathelement location="${build}"/> - <fileset dir="/path/to/my/pmd/lib/"> - <include name="*.jar"/> - </fileset> - </path> +Full build file example using the correct auxclasspath configuration. +Your project needs to be compiled first which happens in the target "compile": - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath"/> + <project name="MyProject" default="pmd" basedir="."> + <property name="src" location="src"/> + <property name="build" location="build"/> + <path id="project.dependencies"> + <pathelement location="lib/third-party.jar"/> + <pathelement location="lib/xyz.jar"/> + </path> + <path id="pmd.classpath"> + <fileset dir="/home/joe/pmd-bin-{{site.pmd.version}}/lib"> + <include name="*.jar"/> + </fileset> + </path> + <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask" classpathref="pmd.classpath" /> + + <target name="init"> + <mkdir dir="${build}"/> + </target> + + <target name="compile" depends="init"> + <javac srcdir="${src}" destdir="${build}" classpathref="project.dependencies" + source="1.8" target="1.8" /> + </target> + + <target name="pmd" depends="compile"> + <pmd cacheLocation="${build}/pmd.cache"> + <auxclasspath> + <pathelement location="${build}"/> + <path refid="project.dependencies"/> + </auxclasspath> + <ruleset>rulesets/java/quickstart.xml</ruleset> + <formatter type="html" toFile="${build}/pmd_report.html"/> + <sourceLanguage name="java" version="1.8"/> + <fileset dir="${src}"> + <include name="**/*.java"/> + </fileset> + </pmd> + </target> + + <target name="clean"> + <delete dir="${build}"/> + </target> + </project> - <target name="pmd"> - <pmd rulesetfiles="rulesets/java/design.xml"> - <formatter type="net.sourceforge.pmd.renderers.HTMLRenderer" toFile="foo.html"/> - <fileset dir="/path/to/java/src"> - <include name="**/*.java"/> - </fileset> - </pmd> - </target> +You can run pmd then with `ant pmd`. -Getting verbose output +#### Getting verbose output [tom@hal bin]$ ant -v pmd Apache Ant version 1.6.2 compiled on July 16 2004 @@ -287,27 +372,16 @@ Getting verbose output Total time: 2 seconds [tom@hal bin]$ -An HTML report with the "linkPrefix" gizmo +#### HTML report with linkPrefix + +An HTML report with the "linkPrefix" and "linePrefix" properties: <target name="pmd"> <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> <pmd rulesetfiles="java-basic" shortFilenames="true"> <formatter type="html" toFile="pmd_report.html"> - <param name="linkPrefix" value="http://pmd.sourceforge.net/xref/"/> - </formatter> - <fileset dir="/usr/local/j2sdk1.4.1_01/src/"> - <include name="java/lang/*.java"/> - </fileset> - </pmd> - </target> - -An HTML report with the "linePrefix" gizmo - - <target name="pmd"> - <taskdef name="pmd" classname="net.sourceforge.pmd.ant.PMDTask"/> - <pmd rulesetfiles="java-basic" shortFilenames="true"> - <formatter type="html" toFile="pmd_report.html"> - <param name="linePrefix" value=".line"/> + <param name="linkPrefix" value="https://maven.apache.org/plugins/maven-pmd-plugin/xref/"/> + <param name="linePrefix" value="L"/> </formatter> <fileset dir="/usr/local/j2sdk1.4.1_01/src/"> <include name="java/lang/*.java"/> diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 8abb75f161..1196e64327 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,10 +19,27 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### New rule designer documentation + +The documentation for the rule designer is now available on the main PMD documentation page: +[Rule Designer Reference](pmd_userdocs_extending_designer_reference.html). Check it out to learn +about the usage and features of the rule designer. + ### Fixed Issues +* java-codestyle + * [#1951](https://github.com/pmd/pmd/issues/1951): \[java] UnnecessaryFullyQualifiedName rule triggered when variable name clashes with package name + ### API Changes +#### Deprecated APIs + +##### For removal + +* The methods {% jdoc java::ast.ASTImportDeclaration#getImportedNameNode() %} and + {% jdoc java::ast.ASTImportDeclaration#getPackage() %} have been deprecated and + will be removed with PMD 7.0.0. + ### External Contributions {% endtocmaker %} diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 7ec5ac3a96..2a8f8b20ac 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -5,6 +5,422 @@ permalink: pmd_release_notes_old.html Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases +## 28-July-2019 - 6.17.0 + +The PMD team is pleased to announce PMD 6.17.0. + +This is a minor release. + +### Table Of Contents + +* [New and noteworthy](#new-and-noteworthy) + * [Updated PMD Designer](#updated-pmd-designer) + * [Lua support](#lua-support) + * [Modified Rules](#modified-rules) +* [Fixed Issues](#fixed-issues) +* [External Contributions](#external-contributions) + +### New and noteworthy + +#### Updated PMD Designer + +This PMD release ships a new version of the pmd-designer. +For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.17.0). +It contains a new feature to edit test cases directly within the designer. Any feedback is highly appreciated. + +#### Lua support + +Thanks to the contribution from [Maikel Steneker](https://github.com/maikelsteneker), and built on top of the ongoing efforts to fully support Antlr-based languages, +PMD now has CPD support for [Lua](https://www.lua.org/). + +Being based on a proper Antlr grammar, CPD can: +* ignore comments +* honor [comment-based suppressions](pmd_userdocs_cpd.html#suppression) + +#### Modified Rules + +* The Java rule [`CloseResource`](https://pmd.github.io/pmd-6.17.0/pmd_rules_java_errorprone.html#closeresource) (`java-errorprone`) ignores now by default + `java.io.ByteArrayInputStream` and `java.io.CharArrayWriter`. Such streams/writers do not need to be closed. + +* The Java rule [`MissingStaticMethodInNonInstantiatableClass`](https://pmd.github.io/pmd-6.17.0/pmd_rules_java_errorprone.html#missingstaticmethodinnoninstantiatableclass) (`java-errorprone`) has now + the new property `annotations`. + When one of the private constructors is annotated with one of the annotations, then the class is not considered + non-instantiatable anymore and no violation will be reported. By default, Spring's `@Autowired` and + Java EE's `@Inject` annotations are recognized. + +### Fixed Issues + +* core + * [#1913](https://github.com/pmd/pmd/issues/1913): \[core] "-help" CLI option ends with status code != 0 +* doc + * [#1896](https://github.com/pmd/pmd/issues/1896): \[doc] Error in changelog 6.16.0 due to not properly closed rule tag + * [#1898](https://github.com/pmd/pmd/issues/1898): \[doc] Incorrect code example for DoubleBraceInitialization in documentation on website + * [#1906](https://github.com/pmd/pmd/issues/1906): \[doc] Broken link for adding own CPD languages + * [#1909](https://github.com/pmd/pmd/issues/1909): \[doc] Sample usage example refers to deprecated ruleset "basic.xml" instead of "quickstart.xml" +* java + * [#1910](https://github.com/pmd/pmd/issues/1910): \[java] ATFD calculation problem +* java-errorprone + * [#1749](https://github.com/pmd/pmd/issues/1749): \[java] DD False Positive in DataflowAnomalyAnalysis + * [#1832](https://github.com/pmd/pmd/issues/1832): \[java] False positives for MissingStaticMethodInNonInstantiatableClass when DI is used + * [#1921](https://github.com/pmd/pmd/issues/1921): \[java] CloseResource false positive with ByteArrayInputStream +* java-multithreading + * [#1903](https://github.com/pmd/pmd/issues/1903): \[java] UnsynchronizedStaticFormatter doesn't allow block-level synchronization when using allowMethodLevelSynchronization=true +* plsql + * [#1902](https://github.com/pmd/pmd/issues/1902): \[pslql] ParseException when parsing (+) +* xml + * [#1666](https://github.com/pmd/pmd/issues/1666): \[xml] wrong cdata rule description and examples + +### External Contributions + +* [#1869](https://github.com/pmd/pmd/pull/1869): \[xml] fix #1666 wrong cdata rule description and examples - [Artem](https://github.com/KroArtem) +* [#1892](https://github.com/pmd/pmd/pull/1892): \[lua] \[cpd] Added CPD support for Lua - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1905](https://github.com/pmd/pmd/pull/1905): \[java] DataflowAnomalyAnalysis Rule in right order - [YoonhoChoi96](https://github.com/YoonhoChoi96) +* [#1908](https://github.com/pmd/pmd/pull/1908): \[doc] Update ruleset filename from deprecated basic.xml to quickstart.xml - [crunsk](https://github.com/crunsk) +* [#1916](https://github.com/pmd/pmd/pull/1916): \[java] Exclude Autowired and Inject for MissingStaticMethodInNonInstantiatableClass - [AnthonyKot](https://github.com/AnthonyKot) +* [#1917](https://github.com/pmd/pmd/pull/1917): \[core] Add 'no error' return option, and assign it to the cli when the help command is invoked - [Renato Oliveira](https://github.com/renatoliveira) + +## 30-June-2019 - 6.16.0 + +The PMD team is pleased to announce PMD 6.16.0. + +This is a minor release. + +### Table Of Contents + +* [New and noteworthy](#new-and-noteworthy) + * [Updated PMD Designer](#updated-pmd-designer) + * [PLSQL Grammar Updates](#plsql-grammar-updates) + * [New Rules](#new-rules) + * [Modified Rules](#modified-rules) + * [Deprecated Rules](#deprecated-rules) +* [Fixed Issues](#fixed-issues) +* [API Changes](#api-changes) + * [Deprecated APIs](#deprecated-apis) + * [In ASTs](#in-asts) +* [External Contributions](#external-contributions) + +### New and noteworthy + +#### Updated PMD Designer + +This PMD release ships a new version of the pmd-designer. +For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/6.16.0). + +#### PLSQL Grammar Updates + +The grammar has been updated to support inline constraints in CREATE TABLE statements. Additionally, the +CREATE TABLE statement may now be followed by physical properties and table properties. However, these +properties are skipped over during parsing. + +The CREATE VIEW statement now supports subquery views. + +The EXTRACT function can now be parsed correctly. It is used to extract values from a specified +datetime field. Also date time literals are parsed now correctly. + +The CASE expression can now be properly used within SELECT statements. + +Table aliases are now supported when specifying columns in INSERT INTO clauses. + +#### New Rules + +* The Java rule [`DoubleBraceInitialization`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_bestpractices.html#doublebraceinitialization) (`java-bestpractices`) + detects non static initializers in anonymous classes also known as "double brace initialization". + This can be problematic, since a new class file is generated and object holds a strong reference + to the surrounding class. + + Note: This rule is also part of the Java quickstart ruleset (`rulesets/java/quickstart.xml`). + +#### Modified Rules + +* The Java rule [`UnusedPrivateField`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_bestpractices.html#unusedprivatefield) (`java-bestpractices`) now ignores by + default fields, that are annotated with the Lombok experimental annotation `@Delegate`. This can be + customized with the property `ignoredAnnotations`. + +* The Java rule [`SingularField`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_design.html#singularfield) (`java-design`) now ignores by + default fields, that are annotated with the Lombok experimental annotation `@Delegate`. This can be + customized with the property `ignoredAnnotations`. + +* The Java rules [`UnsynchronizedStaticFormatter`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_multithreading.html#unsynchronizedstaticformatter) and + [`UnsynchronizedStaticDateFormatter`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_multithreading.html#unsynchronizedstaticdateformatter) (`java-multithreading`) + now prefer synchronized blocks by default. They will raise a violation, if the synchronization is implemented + on the method level. To allow the old behavior, the new property `allowMethodLevelSynchronization` can + be enabled. + +* The Java rule [`UseUtilityClass`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_design.html#useutilityclass) (`java-design`) has a new property `ignoredAnnotations`. + By default, classes that are annotated with Lombok's `@UtilityClass` are ignored now. + +* The Java rule [`NonStaticInitializer`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_errorprone.html#nonstaticinitializer) (`java-errorprone`) does not report + non static initializers in anonymous classes anymore. For this use case, there is a new rule now: + [`DoubleBraceInitialization`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_bestpractices.html#doublebraceinitialization) (`java-bestpractices`). + +* The Java rule [`CommentDefaultAccessModifier`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#commentdefaultaccessmodifier) (`java-codestyle`) was enhanced + in the last version 6.15.0 to check also top-level types by default. This created many new violations. + Missing the access modifier for top-level types is not so critical, since it only decreases the visibility + of the type. + + The default behaviour has been restored. If you want to enable the check for top-level types, you can + use the new property `checkTopLevelTypes`. + +* The Java rule [`CloseResource`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_errorprone.html#closeresource) (`java-errorprone`) now by default searches + for any unclosed `java.lang.AutoCloseable` resource. This includes now the standard `java.io.*Stream` classes. + Previously only SQL-related resources were considered by this rule. The types can still be configured + via the `types` property. Some resources do not need to be closed (e.g. `ByteArrayOutputStream`). These + exceptions can be configured via the new property `allowedResourceTypes`. + In order to restore the old behaviour, just remove the type `java.lang.AutoCloseable` from the `types` + property and keep the remaining SQL-related classes. + +#### Deprecated Rules + +* The Java rule [`AvoidFinalLocalVariable`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#avoidfinallocalvariable) (`java-codestyle`) has been deprecated + and will be removed with PMD 7.0.0. The rule is controversial and also contradicts other existing + rules such as [`LocalVariableCouldBeFinal`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#localvariablecouldbefinal). If the goal is to avoid defining + constants in a scope smaller than the class, then the rule [`AvoidDuplicateLiterals`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_errorprone.html#avoidduplicateliterals) + should be used instead. + +### Fixed Issues + +* apex + * [#1664](https://github.com/pmd/pmd/issues/1664): \[apex] False positive ApexSharingViolationsRule, unsupported Apex feature +* java + * [#1848](https://github.com/pmd/pmd/issues/1848): \[java] Local classes should preserve their modifiers +* java-bestpractices + * [#1703](https://github.com/pmd/pmd/issues/1703): \[java] UnusedPrivateField on member annotated with lombok @Delegate + * [#1845](https://github.com/pmd/pmd/issues/1845): \[java] Regression in MethodReturnsInternalArray not handling enums + * [#1854](https://github.com/pmd/pmd/issues/1854): \[java] Rule to check for double brace initialisation +* java-codestyle + * [#1612](https://github.com/pmd/pmd/issues/1612): \[java] Deprecate AvoidFinalLocalVariable + * [#1880](https://github.com/pmd/pmd/issues/1880): \[java] CommentDefaultAccessModifier should be configurable for top-level classes +* java-design + * [#1094](https://github.com/pmd/pmd/issues/1094): \[java] UseUtilityClass should be LombokAware +* java-errorprone + * [#1000](https://github.com/pmd/pmd/issues/1000): \[java] The rule CloseResource should deal with IO stream as default + * [#1853](https://github.com/pmd/pmd/issues/1853): \[java] False positive for NonStaticInitializer in anonymous class +* java-multithreading + * [#1814](https://github.com/pmd/pmd/issues/1814): \[java] UnsynchronizedStaticFormatter documentation and implementation wrong + * [#1815](https://github.com/pmd/pmd/issues/1815): \[java] False negative in UnsynchronizedStaticFormatter +* plsql + * [#1828](https://github.com/pmd/pmd/issues/1828): \[plsql] Parentheses stopped working + * [#1850](https://github.com/pmd/pmd/issues/1850): \[plsql] Parsing errors with INSERT using returning or records and TRIM expression + * [#1873](https://github.com/pmd/pmd/issues/1873): \[plsql] Expression list not working + * [#1878](https://github.com/pmd/pmd/issues/1878): \[pslql] ParseException when parsing USING + * [#1879](https://github.com/pmd/pmd/issues/1879): \[pslql] ParseException when parsing LEFT JOIN + +### API Changes + +#### Deprecated APIs + +> Reminder: Please don't use members marked with the annotation [`InternalApi`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.16.0/net/sourceforge/pmd/annotation/InternalApi.html#), as they will likely be removed, hidden, or otherwise intentionally broken with 7.0.0. + + +##### In ASTs + +As part of the changes we'd like to do to AST classes for 7.0.0, we would like to +hide some methods and constructors that rule writers should not have access to. +The following usages are now deprecated **in the Java AST** (with other languages to come): + +* Manual instantiation of nodes. **Constructors of node classes are deprecated** and marked [`InternalApi`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.16.0/net/sourceforge/pmd/annotation/InternalApi.html#). Nodes should only be obtained from the parser, which for rules, means that never need to instantiate node themselves. Those constructors will be made package private with 7.0.0. +* **Subclassing of abstract node classes, or usage of their type**. Version 7.0.0 will bring a new set of abstractions that will be public API, but the base classes are and will stay internal. You should not couple your code to them. + * In the meantime you should use interfaces like [`JavaNode`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.16.0/net/sourceforge/pmd/lang/java/ast/JavaNode.html#) or [`Node`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.16.0/net/sourceforge/pmd/lang/ast/Node.html#), or the other published interfaces in this package, to refer to nodes generically. + * Concrete node classes will **be made final** with 7.0.0. +* Setters found in any node class or interface. **Rules should consider the AST immutable**. We will make those setters package private with 7.0.0. + +Please look at [`net.sourceforge.pmd.lang.java.ast`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.16.0/net/sourceforge/pmd/lang/java/ast/package-summary.html#) to find out the full list +of deprecations. + + + + + +### External Contributions + +* [#1482](https://github.com/pmd/pmd/pull/1482): \[java] Explain the existence of AvoidFinalLocalVariable in it's description - [Karl-Philipp Richter](https://github.com/krichter722) +* [#1792](https://github.com/pmd/pmd/pull/1792): \[java] Added lombok.experimental to AbstractLombokAwareRule - [jakivey32](https://github.com/jakivey32) +* [#1808](https://github.com/pmd/pmd/pull/1808): \[plsql] Fix PL/SQL Syntax errors - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1829](https://github.com/pmd/pmd/pull/1829): \[java] Fix false negative in UnsynchronizedStaticFormatter - [Srinivasan Venkatachalam](https://github.com/Srini1993) +* [#1847](https://github.com/pmd/pmd/pull/1847): \[java] Regression in MethodReturnsInternalArray not handling enums - [Artem](https://github.com/KroArtem) +* [#1863](https://github.com/pmd/pmd/pull/1863): \[plsql] Add Table InlineConstraint - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1864](https://github.com/pmd/pmd/pull/1864): \[plsql] Add support for Subquery Views - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1865](https://github.com/pmd/pmd/pull/1865): \[plsql] Add Support for Extract Expression - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1874](https://github.com/pmd/pmd/pull/1874): \[plsql] Add parenthesis equation support for Update - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1876](https://github.com/pmd/pmd/pull/1876): \[plsql] Datetime support for queries - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1883](https://github.com/pmd/pmd/pull/1883): \[plsql] Fix #1873 Expression list not working - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1884](https://github.com/pmd/pmd/pull/1884): \[plsql] fix #1878 Support explicit INNER word for INNER JOIN - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1885](https://github.com/pmd/pmd/pull/1885): \[plsql] Correct case expression - [Hugo Araya Nash](https://github.com/kabroxiko) +* [#1886](https://github.com/pmd/pmd/pull/1886): \[plsql] Support table alias for Insert Clause - [Hugo Araya Nash](https://github.com/kabroxiko) + +## 26-May-2019 - 6.15.0 + +The PMD team is pleased to announce PMD 6.15.0. + +This is a minor release. + +### Table Of Contents + +* [New and noteworthy](#new-and-noteworthy) + * [Enhanced Matlab support](#enhanced-matlab-support) + * [Enhanced C++ support](#enhanced-c++-support) + * [New Rules](#new-rules) + * [Modified Rules](#modified-rules) + * [Deprecated Rules](#deprecated-rules) +* [Fixed Issues](#fixed-issues) +* [API Changes](#api-changes) + * [Deprecated APIs](#deprecated-apis) + * [For removal](#for-removal) +* [External Contributions](#external-contributions) + +### New and noteworthy + +#### Enhanced Matlab support + +Thanks to the contributions from [Maikel Steneker](https://github.com/maikelsteneker) CPD for Matlab can +now parse Matlab programs which use the question mark operator to specify access to +class members: + +``` +classdef Class1 +properties (SetAccess = ?Class2) +``` + +CPD also understands now double quoted strings, which are supported since version R2017a of Matlab: + +``` +str = "This is a string" +``` + +#### Enhanced C++ support + +CPD now supports digit separators in C++ (language module "cpp"). This is a C++14 feature. + +Example: `auto integer_literal = 1'000'000;` + +The single quotes can be used to add some structure to large numbers. + +CPD also parses raw string literals now correctly (see [#1784](https://github.com/pmd/pmd/issues/1784)). + +#### New Rules + +* The new Apex rule [`FieldNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#fieldnamingconventions) (`apex-codestyle`) checks the naming + conventions for field declarations. By default this rule uses the standard Apex naming convention (Camel case), + but it can be configured through properties. + +* The new Apex rule [`FormalParameterNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#formalparameternamingconventions) (`apex-codestyle`) checks the + naming conventions for formal parameters of methods. By default this rule uses the standard Apex naming + convention (Camel case), but it can be configured through properties. + +* The new Apex rule [`LocalVariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#localvariablenamingconventions) (`apex-codestyle`) checks the + naming conventions for local variable declarations. By default this rule uses the standard Apex naming + convention (Camel case), but it can be configured through properties. + +* The new Apex rule [`PropertyNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#propertynamingconventions) (`apex-codestyle`) checks the naming + conventions for property declarations. By default this rule uses the standard Apex naming convention (Camel case), + but it can be configured through properties. + +* The new Java rule [`UseShortArrayInitializer`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_codestyle.html#useshortarrayinitializer) (`java-codestyle`) searches for + array initialization expressions, which can be written shorter. + +#### Modified Rules + +* The Apex rule [`ClassNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#classnamingconventions) (`apex-codestyle`) can now be configured + using various properties for the specific kind of type declarations (e.g. class, interface, enum). + As before, this rule uses by default the standard Apex naming convention (Pascal case). + +* The Apex rule [`MethodNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#methodnamingconventions) (`apex-codestyle`) can now be configured + using various properties to differenciate e.g. static methods and test methods. + As before, this rule uses by default the standard Apex naming convention (Camel case). + +* The Java rule [`FieldNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_codestyle.html#fieldnamingconventions) (`java-codestyle`) now by default ignores + the field `serialPersistentFields`. Since this is a field which needs to have this special name, no + field naming conventions can be applied here. It is excluded the same way like `serialVersionUID` via the + property `exclusions`. + +* The Java rule [`CommentRequired`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_documentation.html#commentrequired) (`java-documentation`) has a new property + `serialPersistentFieldsCommentRequired` with the default value "Ignored". This means that from now + on comments for the field `serialPersistentFields` are not required anymore. You can change the property + to restore the old behavior. + +* The Java rule [`ProperLogger`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#properlogger) (`java-errorprone`) has two new properties + to configure the logger class (e.g. "org.slf4j.Logger") and the logger name of the special case, + when the logger is not static. The name of the static logger variable was already configurable. + The new property "loggerClass" allows to use this rule for different logging frameworks. + This rule covers all the cases of the now deprecated rule [`LoggerIsNotStaticFinal`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#loggerisnotstaticfinal). + +* The Java rule [`CommentDefaultAccessModifier`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_codestyle.html#commentdefaultaccessmodifier) (`java-codestyle`) now reports also + missing comments for top-level classes and annotations, that are package-private. + +#### Deprecated Rules + +* The Apex rule [`VariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#variablenamingconventions) (`apex-codestyle`) has been deprecated and + will be removed with PMD 7.0.0. The rule is replaced by the more general rules + [`FieldNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#fieldnamingconventions), + [`FormalParameterNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#formalparameternamingconventions), + [`LocalVariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#localvariablenamingconventions), and + [`PropertyNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#propertynamingconventions). + +* The Java rule [`LoggerIsNotStaticFinal`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#loggerisnotstaticfinal) (`java-errorprone`) has been deprecated + and will be removed with PMD 7.0.0. The rule is replaced by [`ProperLogger`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#properlogger). + +### Fixed Issues + +* apex + * [#1321](https://github.com/pmd/pmd/issues/1321): \[apex] Should VariableNamingConventions require properties to start with a lowercase letter? + * [#1783](https://github.com/pmd/pmd/issues/1783): \[apex] comments on constructor not recognized when the Class has inner class +* cpp + * [#1784](https://github.com/pmd/pmd/issues/1784): \[cpp] Improve support for raw string literals +* dart + * [#1809](https://github.com/pmd/pmd/issues/1809): \[dart] \[cpd] Parse error with escape sequences +* java + * [#1842](https://github.com/pmd/pmd/issues/1842): \[java] Annotated module declarations cause parse error +* java-bestpractices + * [#1738](https://github.com/pmd/pmd/issues/1738): \[java] MethodReturnsInternalArray does not work in inner classes +* java-codestyle + * [#1495](https://github.com/pmd/pmd/issues/1495): \[java] Rule to detect overly verbose array initializiation + * [#1684](https://github.com/pmd/pmd/issues/1684): \[java] Properly whitelist serialPersistentFields + * [#1804](https://github.com/pmd/pmd/issues/1804): \[java] NPE in UnnecessaryLocalBeforeReturnRule +* python + * [#1810](https://github.com/pmd/pmd/issues/1810): \[python] \[cpd] Parse error when using Python 2 backticks +* matlab + * [#1830](https://github.com/pmd/pmd/issues/1830): \[matlab] \[cpd] Parse error with comments + * [#1793](https://github.com/pmd/pmd/issues/1793): \[java] CommentDefaultAccessModifier not working for classes + +### API Changes + +#### Deprecated APIs + +##### For removal + +* The `DumpFacades` in all languages, that could be used to transform a AST into a textual representation, + will be removed with PMD 7. The rule designer is a better way to inspect nodes. + * [`net.sourceforge.pmd.lang.apex.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-apex/6.15.0/net/sourceforge/pmd/lang/apex/ast/DumpFacade.html#) + * [`net.sourceforge.pmd.lang.java.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-java/6.15.0/net/sourceforge/pmd/lang/java/ast/DumpFacade.html#) + * [`net.sourceforge.pmd.lang.ecmascript.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-javascript/6.15.0/net/sourceforge/pmd/lang/ecmascript/ast/DumpFacade.html#) + * [`net.sourceforge.pmd.lang.jsp.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-jsp/6.15.0/net/sourceforge/pmd/lang/jsp/ast/DumpFacade.html#) + * [`net.sourceforge.pmd.lang.plsql.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-plsql/6.15.0/net/sourceforge/pmd/lang/plsql/ast/DumpFacade.html#) + * [`net.sourceforge.pmd.lang.vf.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-visualforce/6.15.0/net/sourceforge/pmd/lang/vf/ast/DumpFacade.html#) + * [`net.sourceforge.pmd.lang.vm.ast.AbstractVmNode#dump`](https://javadoc.io/page/net.sourceforge.pmd/pmd-vm/6.15.0/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.html#dump(String,boolean,Writer)) + * [`net.sourceforge.pmd.lang.xml.ast.DumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-xml/6.15.0/net/sourceforge/pmd/lang/xml/ast/DumpFacade.html#) +* The method [`LanguageVersionHandler#getDumpFacade`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.15.0/net/sourceforge/pmd/lang/LanguageVersionHandler.html#getDumpFacade(Writer,String,boolean)) will be + removed as well. It is deprecated, along with all its implementations in the subclasses of [`LanguageVersionHandler`](https://javadoc.io/page/net.sourceforge.pmd/pmd-core/6.15.0/net/sourceforge/pmd/lang/LanguageVersionHandler.html#). + +### External Contributions + +* [#1647](https://github.com/pmd/pmd/pull/1647): \[java] Rule to detect overly verbose array initialization - [Victor](https://github.com/IDoCodingStuffs) +* [#1762](https://github.com/pmd/pmd/pull/1762): \[java] LoggerIsNotStaticFinal and ProperLogger - make class-name configurable - [Ivo Šmíd](https://github.com/bedla) +* [#1798](https://github.com/pmd/pmd/pull/1798): \[java] Make CommentDefaultAccessModifier work for top-level classes - [Boris Petrov](https://github.com/boris-petrov) +* [#1799](https://github.com/pmd/pmd/pull/1799): \[java] MethodReturnsInternalArray does not work in inner classes - Fixed #1738 - [Srinivasan Venkatachalam](https://github.com/Srini1993) +* [#1802](https://github.com/pmd/pmd/pull/1802): \[python] \[cpd] Add support for Python 2 backticks - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1803](https://github.com/pmd/pmd/pull/1803): \[dart] \[cpd] Dart escape sequences - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1807](https://github.com/pmd/pmd/pull/1807): \[ci] Fix missing local branch issues when executing pmd-regression-tester - [BBG](https://github.com/djydewang) +* [#1813](https://github.com/pmd/pmd/pull/1813): \[matlab] \[cpd] Matlab comments - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1816](https://github.com/pmd/pmd/pull/1816): \[apex] Fix ApexDoc handling with inner classes - [Jeff Hube](https://github.com/jeffhube) +* [#1817](https://github.com/pmd/pmd/pull/1817): \[apex] Add configurable naming convention rules - [Jeff Hube](https://github.com/jeffhube) +* [#1819](https://github.com/pmd/pmd/pull/1819): \[cpp] \[cpd] Add support for digit separators - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1820](https://github.com/pmd/pmd/pull/1820): \[cpp] \[cpd] Improve support for raw string literals - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1821](https://github.com/pmd/pmd/pull/1821): \[matlab] \[cpd] Matlab question mark token - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1822](https://github.com/pmd/pmd/pull/1822): \[matlab] \[cpd] Double quoted string - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1837](https://github.com/pmd/pmd/pull/1837): \[core] Minor performance improvements - [Michael Hausegger](https://github.com/TheRealHaui) +* [#1838](https://github.com/pmd/pmd/pull/1838): \[dart] [cpd] Improved string tokenization - [Maikel Steneker](https://github.com/maikelsteneker) +* [#1840](https://github.com/pmd/pmd/pull/1840): \[java] Whitelist serialPersistentFields - [Marcel Härle](https://github.com/marcelhaerle) + ## 28-April-2019 - 6.14.0 The PMD team is pleased to announce PMD 6.14.0. diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java index 87f94bc3ce..08a7eb2857 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClass.java @@ -4,11 +4,8 @@ package net.sourceforge.pmd.lang.apex.ast; -import java.lang.reflect.Field; - import net.sourceforge.pmd.Rule; -import apex.jorje.data.Identifier; import apex.jorje.semantic.ast.compilation.UserClass; public class ASTUserClass extends ApexRootNode<UserClass> implements ASTUserClassOrInterface<UserClass>, @@ -29,14 +26,8 @@ public class ASTUserClass extends ApexRootNode<UserClass> implements ASTUserClas @Override public String getImage() { - try { - Field field = node.getClass().getDeclaredField("name"); - field.setAccessible(true); - Identifier name = (Identifier) field.get(node); - return name.getValue(); - } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } + String apexName = node.getDefiningType().getApexName(); + return apexName.substring(apexName.lastIndexOf('.') + 1); } @Override diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java index 7249cba5ce..54e5034fdc 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnum.java @@ -19,7 +19,8 @@ public class ASTUserEnum extends ApexRootNode<UserEnum> { @Override public String getImage() { - return node.getClass().getName(); + String apexName = node.getDefiningType().getApexName(); + return apexName.substring(apexName.lastIndexOf('.') + 1); } public ASTModifierNode getModifiers() { diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java index af6ccb8100..645b6e02aa 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterface.java @@ -4,11 +4,8 @@ package net.sourceforge.pmd.lang.apex.ast; -import java.lang.reflect.Field; - import net.sourceforge.pmd.Rule; -import apex.jorje.data.Identifier; import apex.jorje.semantic.ast.compilation.UserInterface; public class ASTUserInterface extends ApexRootNode<UserInterface> implements ASTUserClassOrInterface<UserInterface>, @@ -27,14 +24,8 @@ public class ASTUserInterface extends ApexRootNode<UserInterface> implements AST @Override public String getImage() { - try { - Field field = node.getClass().getDeclaredField("name"); - field.setAccessible(true); - Identifier name = (Identifier) field.get(node); - return name.getValue(); - } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } + String apexName = node.getDefiningType().getApexName(); + return apexName.substring(apexName.lastIndexOf('.') + 1); } @Override diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java index 3360750889..66c9b32004 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTUserTrigger.java @@ -4,9 +4,6 @@ package net.sourceforge.pmd.lang.apex.ast; -import java.lang.reflect.Field; - -import apex.jorje.data.Identifier; import apex.jorje.semantic.ast.compilation.UserTrigger; public class ASTUserTrigger extends ApexRootNode<UserTrigger> { @@ -22,14 +19,7 @@ public class ASTUserTrigger extends ApexRootNode<UserTrigger> { @Override public String getImage() { - try { - Field field = node.getClass().getDeclaredField("name"); - field.setAccessible(true); - Identifier name = (Identifier) field.get(node); - return name.getValue(); - } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { - throw new RuntimeException(e); - } + return node.getDefiningType().getApexName(); } public ASTModifierNode getModifiers() { diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNodeBase.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNodeBase.java index 8ba32fe4a7..c03bc464f6 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNodeBase.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/AbstractApexNodeBase.java @@ -38,13 +38,12 @@ public abstract class AbstractApexNodeBase extends AbstractNode { * Accept the visitor. * */ public Object childrenAccept(ApexParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - // we know that the children here are all ApexNodes - AbstractApexNodeBase apexNode = (AbstractApexNodeBase) children[i]; - apexNode.jjtAccept(visitor, data); - } + for (int i = 0; i < children.length; ++i) { + // we know that the children here are all ApexNodes + AbstractApexNodeBase apexNode = (AbstractApexNodeBase) children[i]; + apexNode.jjtAccept(visitor, data); } + return data; } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java index fc44166cb6..75a5fc0904 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.java @@ -6,10 +6,9 @@ package net.sourceforge.pmd.lang.apex.ast; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; -import java.util.ListIterator; import java.util.Map; import java.util.Stack; @@ -19,6 +18,8 @@ import org.antlr.runtime.Token; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.SourceCodePositioner; +import apex.jorje.data.Location; +import apex.jorje.data.Locations; import apex.jorje.parser.impl.ApexLexer; import apex.jorje.semantic.ast.AstNode; import apex.jorje.semantic.ast.compilation.AnonymousClass; @@ -221,17 +222,17 @@ public final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> { // The Apex nodes with children to build. private Stack<AstNode> parents = new Stack<>(); - + private AdditionalPassScope scope = new AdditionalPassScope(Errors.createErrors()); private final SourceCodePositioner sourceCodePositioner; private final String sourceCode; - private ListIterator<TokenLocation> apexDocTokenLocations; + private List<ApexDocTokenLocation> apexDocTokenLocations; public ApexTreeBuilder(String sourceCode) { this.sourceCode = sourceCode; sourceCodePositioner = new SourceCodePositioner(sourceCode); - apexDocTokenLocations = buildApexDocTokenLocations(sourceCode).listIterator(); + apexDocTokenLocations = buildApexDocTokenLocations(sourceCode); } static <T extends AstNode> AbstractApexNode<T> createNodeAdapter(T node) { @@ -273,60 +274,87 @@ public final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> { nodes.pop(); parents.pop(); + if (nodes.isEmpty()) { + // add the comments only at the end of the processing as the last step + addFormalComments(); + } + return node; } - private void buildFormalComment(AstNode node) { - if (parents.peek() == node) { - ApexNode<?> parent = (ApexNode<?>) nodes.peek(); - TokenLocation tokenLocation = getApexDocTokenLocation(getApexDocIndex(parent)); - if (tokenLocation != null) { + private void addFormalComments() { + for (ApexDocTokenLocation tokenLocation : apexDocTokenLocations) { + ApexNode<?> parent = tokenLocation.nearestNode; + if (parent != null) { ASTFormalComment comment = new ASTFormalComment(tokenLocation.token); comment.calculateLineNumbers(sourceCodePositioner, tokenLocation.index, tokenLocation.index + tokenLocation.token.length()); + + // move existing nodes so that we can insert the comment as the first node + for (int i = parent.jjtGetNumChildren(); i > 0; i--) { + parent.jjtAddChild(parent.jjtGetChild(i - 1), i); + } + parent.jjtAddChild(comment, 0); comment.jjtSetParent(parent); } } } - private int getApexDocIndex(ApexNode<?> node) { - final int index = node.getNode().getLoc().getStartIndex(); - return sourceCode.lastIndexOf('\n', index); - } - - private TokenLocation getApexDocTokenLocation(int index) { - TokenLocation last = null; - while (apexDocTokenLocations.hasNext()) { - final TokenLocation location = apexDocTokenLocations.next(); - if (location.index >= index) { - // rollback, the next token corresponds to a different node - apexDocTokenLocations.previous(); - - if (last != null) { - return last; - } - return null; - } - last = location; + private void buildFormalComment(AstNode node) { + if (parents.peek() == node) { + ApexNode<?> parent = (ApexNode<?>) nodes.peek(); + assignApexDocTokenToNode(node, parent); } - return last; } - private static List<TokenLocation> buildApexDocTokenLocations(String source) { + /** + * Only remembers the node, to which the comment could belong. + * Since the visiting order of the nodes does not match the source order, + * the nodes appearing later in the source might be visiting first. + * The correct node will then be visited afterwards, and since the distance + * to the comment is smaller, it overrides the remembered node. + * @param jorjeNode the original node + * @param node the potential parent node, to which the comment could belong + */ + private void assignApexDocTokenToNode(AstNode jorjeNode, ApexNode<?> node) { + Location loc = jorjeNode.getLoc(); + if (!Locations.isReal(loc)) { + // Synthetic nodes such as "<clinit>" don't have a location in the + // source code, since they are generated by the compiler + return; + } + // find the token, that appears as close as possible before the node + int nodeStart = loc.getStartIndex(); + for (ApexDocTokenLocation tokenLocation : apexDocTokenLocations) { + if (tokenLocation.index > nodeStart) { + // this and all remaining tokens are after the node + // so no need to check the remaining tokens. + break; + } + + int distance = nodeStart - tokenLocation.index; + if (tokenLocation.nearestNode == null || distance < tokenLocation.nearestNodeDistance) { + tokenLocation.nearestNode = node; + tokenLocation.nearestNodeDistance = distance; + } + } + } + + private static List<ApexDocTokenLocation> buildApexDocTokenLocations(String source) { ANTLRStringStream stream = new ANTLRStringStream(source); ApexLexer lexer = new ApexLexer(stream); - ArrayList<TokenLocation> tokenLocations = new ArrayList<>(); + List<ApexDocTokenLocation> tokenLocations = new LinkedList<>(); int startIndex = 0; Token token = lexer.nextToken(); int endIndex = lexer.getCharIndex(); + while (token.getType() != Token.EOF) { if (token.getType() == ApexLexer.BLOCK_COMMENT) { - // Filter only block comments starting with "/**" if (token.getText().startsWith("/**")) { - tokenLocations.add(new TokenLocation(startIndex, token.getText())); + tokenLocations.add(new ApexDocTokenLocation(startIndex, token.getText())); } } // TODO : Check other non-doc comments and tokens of type ApexLexer.EOL_COMMENT for "NOPMD" suppressions @@ -338,11 +366,13 @@ public final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> { return tokenLocations; } - private static class TokenLocation { + private static class ApexDocTokenLocation { int index; String token; + ApexNode<?> nearestNode; + int nearestNodeDistance; - TokenLocation(int index, String token) { + ApexDocTokenLocation(int index, String token) { this.index = index; this.token = token; } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java new file mode 100644 index 0000000000..53e6fa6894 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/AbstractNamingConventionsRule.java @@ -0,0 +1,46 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import static net.sourceforge.pmd.properties.PropertyFactory.regexProperty; + +import java.util.Map; +import java.util.regex.Pattern; + +import net.sourceforge.pmd.lang.apex.ast.ApexNode; +import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.properties.PropertyBuilder; +import net.sourceforge.pmd.properties.PropertyDescriptor; + +abstract class AbstractNamingConventionsRule extends AbstractApexRule { + protected static final Pattern CAMEL_CASE = Pattern.compile("[a-z][a-zA-Z0-9]*"); + protected static final Pattern CAMEL_CASE_WITH_UNDERSCORES = Pattern.compile("[a-z][a-zA-Z0-9_]*"); + protected static final Pattern PASCAL_CASE_WITH_UNDERSCORES = Pattern.compile("[A-Z][a-zA-Z0-9_]*"); + protected static final Pattern ALL_CAPS = Pattern.compile("[A-Z][A-Z0-9_]*"); + + abstract String displayName(String name); + + protected void checkMatches(PropertyDescriptor<Pattern> propertyDescriptor, ApexNode<?> node, Object data) { + Pattern regex = getProperty(propertyDescriptor); + String name = node.getImage(); + if (!regex.matcher(name).matches()) { + String displayName = displayName(propertyDescriptor.name()); + addViolation(data, node, new Object[] { displayName, name, regex.toString() }); + } + } + + protected void checkMatches(PropertyDescriptor<Pattern> propertyDescriptor, Pattern overridePattern, ApexNode<?> node, Object data) { + String name = node.getImage(); + if (!overridePattern.matcher(name).matches()) { + String displayName = displayName(propertyDescriptor.name()); + addViolation(data, node, new Object[] { displayName, name, overridePattern.toString() }); + } + } + + protected static PropertyBuilder.RegexPropertyBuilder prop(String name, String displayName, Map<String, String> descriptorToDisplayNames) { + descriptorToDisplayNames.put(name, displayName); + return regexProperty(name).desc("Regex which applies to " + displayName + " names"); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/ClassNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/ClassNamingConventionsRule.java index 1d1529793e..a2e235f127 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/ClassNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/ClassNamingConventionsRule.java @@ -4,25 +4,74 @@ package net.sourceforge.pmd.lang.apex.rule.codestyle; -import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; -import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; -public class ClassNamingConventionsRule extends AbstractApexRule { +import net.sourceforge.pmd.lang.apex.ast.ASTUserClass; +import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; +import net.sourceforge.pmd.lang.apex.ast.ASTUserInterface; +import net.sourceforge.pmd.properties.PropertyDescriptor; + +public class ClassNamingConventionsRule extends AbstractNamingConventionsRule { + private static final Map<String, String> DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>(); + + private static final PropertyDescriptor<Pattern> TEST_CLASS_REGEX = prop("testClassPattern", "test class", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(PASCAL_CASE_WITH_UNDERSCORES).build(); + + private static final PropertyDescriptor<Pattern> ABSTRACT_CLASS_REGEX = prop("abstractClassPattern", "abstract class", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(PASCAL_CASE_WITH_UNDERSCORES).build(); + + private static final PropertyDescriptor<Pattern> CLASS_REGEX = prop("classPattern", "class", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(PASCAL_CASE_WITH_UNDERSCORES).build(); + + private static final PropertyDescriptor<Pattern> INTERFACE_REGEX = prop("interfacePattern", "interface", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(PASCAL_CASE_WITH_UNDERSCORES).build(); + + private static final PropertyDescriptor<Pattern> ENUM_REGEX = prop("enumPattern", "enum", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(PASCAL_CASE_WITH_UNDERSCORES).build(); + + public ClassNamingConventionsRule() { + definePropertyDescriptor(TEST_CLASS_REGEX); + definePropertyDescriptor(ABSTRACT_CLASS_REGEX); + definePropertyDescriptor(CLASS_REGEX); + definePropertyDescriptor(INTERFACE_REGEX); + definePropertyDescriptor(ENUM_REGEX); + + addRuleChainVisit(ASTUserClass.class); + addRuleChainVisit(ASTUserInterface.class); + addRuleChainVisit(ASTUserEnum.class); + } @Override public Object visit(ASTUserClass node, Object data) { - if (Character.isLowerCase(node.getImage().charAt(0))) { - addViolation(data, node); + if (node.getModifiers().isTest()) { + checkMatches(TEST_CLASS_REGEX, node, data); + } else if (node.getModifiers().isAbstract()) { + checkMatches(ABSTRACT_CLASS_REGEX, node, data); + } else { + checkMatches(CLASS_REGEX, node, data); } + return data; } @Override public Object visit(ASTUserInterface node, Object data) { - if (Character.isLowerCase(node.getImage().charAt(0))) { - addViolation(data, node); - } + checkMatches(INTERFACE_REGEX, node, data); + return data; } + + @Override + public Object visit(ASTUserEnum node, Object data) { + checkMatches(ENUM_REGEX, node, data); + + return data; + } + + @Override + protected String displayName(String name) { + return DESCRIPTOR_TO_DISPLAY_NAME.get(name); + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsRule.java new file mode 100644 index 0000000000..27f464bca5 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsRule.java @@ -0,0 +1,72 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import net.sourceforge.pmd.lang.apex.ast.ASTField; +import net.sourceforge.pmd.lang.apex.ast.ASTModifierNode; +import net.sourceforge.pmd.lang.apex.ast.ASTProperty; +import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; +import net.sourceforge.pmd.properties.PropertyDescriptor; + +public class FieldNamingConventionsRule extends AbstractNamingConventionsRule { + private static final Map<String, String> DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>(); + + private static final PropertyDescriptor<Pattern> ENUM_CONSTANT_REGEX = prop("enumConstantPattern", "enum constant field", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(ALL_CAPS).build(); + + private static final PropertyDescriptor<Pattern> CONSTANT_REGEX = prop("constantPattern", "constant field", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(ALL_CAPS).build(); + + private static final PropertyDescriptor<Pattern> FINAL_REGEX = prop("finalPattern", "final field", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> STATIC_REGEX = prop("staticPattern", "static field", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> INSTANCE_REGEX = prop("instancePattern", "instance field", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + public FieldNamingConventionsRule() { + definePropertyDescriptor(ENUM_CONSTANT_REGEX); + definePropertyDescriptor(CONSTANT_REGEX); + definePropertyDescriptor(FINAL_REGEX); + definePropertyDescriptor(STATIC_REGEX); + definePropertyDescriptor(INSTANCE_REGEX); + + addRuleChainVisit(ASTField.class); + } + + @Override + public Object visit(ASTField node, Object data) { + if (node.getFirstParentOfType(ASTProperty.class) != null) { + return data; + } + + ASTModifierNode modifiers = node.getModifiers(); + + if (node.getFirstParentOfType(ASTUserEnum.class) != null) { + checkMatches(ENUM_CONSTANT_REGEX, node, data); + } else if (modifiers.isFinal() && modifiers.isStatic()) { + checkMatches(CONSTANT_REGEX, node, data); + } else if (modifiers.isFinal()) { + checkMatches(FINAL_REGEX, node, data); + } else if (modifiers.isStatic()) { + checkMatches(STATIC_REGEX, node, data); + } else { + checkMatches(INSTANCE_REGEX, node, data); + } + + return data; + } + + @Override + protected String displayName(String name) { + return DESCRIPTOR_TO_DISPLAY_NAME.get(name); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsRule.java new file mode 100644 index 0000000000..ae1a606409 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsRule.java @@ -0,0 +1,50 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import net.sourceforge.pmd.lang.apex.ast.ASTParameter; +import net.sourceforge.pmd.properties.PropertyDescriptor; + +public class FormalParameterNamingConventionsRule extends AbstractNamingConventionsRule { + private static final Map<String, String> DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>(); + + private static final PropertyDescriptor<Pattern> FINAL_METHOD_PARAMETER_REGEX = prop("finalMethodParameterPattern", "final method parameter", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> METHOD_PARAMETER_REGEX = prop("methodParameterPattern", "method parameter", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + public FormalParameterNamingConventionsRule() { + definePropertyDescriptor(FINAL_METHOD_PARAMETER_REGEX); + definePropertyDescriptor(METHOD_PARAMETER_REGEX); + + addRuleChainVisit(ASTParameter.class); + } + + @Override + public Object visit(ASTParameter node, Object data) { + // classes that extend Exception will contains methods that have parameters with null names + if (node.getImage() == null) { + return data; + } + + if (node.getModifiers().isFinal()) { + checkMatches(FINAL_METHOD_PARAMETER_REGEX, node, data); + } else { + checkMatches(METHOD_PARAMETER_REGEX, node, data); + } + + return data; + } + + @Override + protected String displayName(String name) { + return DESCRIPTOR_TO_DISPLAY_NAME.get(name); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsRule.java new file mode 100644 index 0000000000..4969f429b1 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsRule.java @@ -0,0 +1,46 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration; +import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclarationStatements; +import net.sourceforge.pmd.properties.PropertyDescriptor; + +public class LocalVariableNamingConventionsRule extends AbstractNamingConventionsRule { + private static final Map<String, String> DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>(); + + private static final PropertyDescriptor<Pattern> FINAL_REGEX = prop("finalLocalPattern", "final local variable", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> LOCAL_REGEX = prop("localPattern", "local variable", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + public LocalVariableNamingConventionsRule() { + definePropertyDescriptor(FINAL_REGEX); + definePropertyDescriptor(LOCAL_REGEX); + + addRuleChainVisit(ASTVariableDeclaration.class); + } + + @Override + public Object visit(ASTVariableDeclaration node, Object data) { + if (node.getFirstParentOfType(ASTVariableDeclarationStatements.class).getModifiers().isFinal()) { + checkMatches(FINAL_REGEX, node, data); + } else { + checkMatches(LOCAL_REGEX, node, data); + } + + return data; + } + + @Override + protected String displayName(String name) { + return DESCRIPTOR_TO_DISPLAY_NAME.get(name); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/MethodNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/MethodNamingConventionsRule.java index 23d2d8ec63..9c551f951d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/MethodNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/MethodNamingConventionsRule.java @@ -6,21 +6,39 @@ package net.sourceforge.pmd.lang.apex.rule.codestyle; import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + import net.sourceforge.pmd.lang.apex.ast.ASTMethod; import net.sourceforge.pmd.lang.apex.ast.ASTProperty; -import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; +import net.sourceforge.pmd.lang.apex.ast.ASTUserEnum; import net.sourceforge.pmd.properties.PropertyDescriptor; -public class MethodNamingConventionsRule extends AbstractApexRule { +public class MethodNamingConventionsRule extends AbstractNamingConventionsRule { + private static final Map<String, String> DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>(); + + private static final PropertyDescriptor<Pattern> TEST_REGEX = prop("testPattern", "test method", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> STATIC_REGEX = prop("staticPattern", "static method", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> INSTANCE_REGEX = prop("instancePattern", "instance method", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); private static final PropertyDescriptor<Boolean> SKIP_TEST_METHOD_UNDERSCORES_DESCRIPTOR = booleanProperty("skipTestMethodUnderscores") - .desc("Skip underscores in test methods") + .desc("deprecated! Skip underscores in test methods") .defaultValue(false) .build(); public MethodNamingConventionsRule() { definePropertyDescriptor(SKIP_TEST_METHOD_UNDERSCORES_DESCRIPTOR); + definePropertyDescriptor(TEST_REGEX); + definePropertyDescriptor(STATIC_REGEX); + definePropertyDescriptor(INSTANCE_REGEX); + addRuleChainVisit(ASTMethod.class); } @@ -29,21 +47,35 @@ public class MethodNamingConventionsRule extends AbstractApexRule { if (isOverriddenMethod(node) || isPropertyAccessor(node) || isConstructor(node)) { return data; } - if (isTestMethod(node) && getProperty(SKIP_TEST_METHOD_UNDERSCORES_DESCRIPTOR)) { + + if ("<clinit>".equals(node.getImage()) || "clone".equals(node.getImage())) { return data; } - String methodName = node.getImage(); + if (node.getFirstParentOfType(ASTUserEnum.class) != null) { + return data; + } - if (Character.isUpperCase(methodName.charAt(0))) { - addViolationWithMessage(data, node, "Method names should not start with capital letters"); - } - if (methodName.indexOf('_') >= 0) { - addViolationWithMessage(data, node, "Method names should not contain underscores"); + if (node.getModifiers().isTest()) { + if (getProperty(SKIP_TEST_METHOD_UNDERSCORES_DESCRIPTOR)) { + checkMatches(TEST_REGEX, CAMEL_CASE_WITH_UNDERSCORES, node, data); + } else { + checkMatches(TEST_REGEX, node, data); + } + } else if (node.getModifiers().isStatic()) { + checkMatches(STATIC_REGEX, node, data); + } else { + checkMatches(INSTANCE_REGEX, node, data); } + return data; } + @Override + protected String displayName(String name) { + return DESCRIPTOR_TO_DISPLAY_NAME.get(name); + } + private boolean isOverriddenMethod(ASTMethod node) { return node.getModifiers().isOverride(); } @@ -55,8 +87,4 @@ public class MethodNamingConventionsRule extends AbstractApexRule { private boolean isConstructor(ASTMethod node) { return node.isConstructor(); } - - private boolean isTestMethod(ASTMethod node) { - return node.getModifiers().isTest(); - } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsRule.java new file mode 100644 index 0000000000..376bc93b92 --- /dev/null +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsRule.java @@ -0,0 +1,50 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import net.sourceforge.pmd.lang.apex.ast.ASTField; +import net.sourceforge.pmd.lang.apex.ast.ASTProperty; +import net.sourceforge.pmd.properties.PropertyDescriptor; + +public class PropertyNamingConventionsRule extends AbstractNamingConventionsRule { + private static final Map<String, String> DESCRIPTOR_TO_DISPLAY_NAME = new HashMap<>(); + + private static final PropertyDescriptor<Pattern> STATIC_REGEX = prop("staticPattern", "static property", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + private static final PropertyDescriptor<Pattern> INSTANCE_REGEX = prop("instancePattern", "instance property", + DESCRIPTOR_TO_DISPLAY_NAME).defaultValue(CAMEL_CASE).build(); + + public PropertyNamingConventionsRule() { + definePropertyDescriptor(STATIC_REGEX); + definePropertyDescriptor(INSTANCE_REGEX); + + addRuleChainVisit(ASTField.class); + } + + @Override + public Object visit(ASTField node, Object data) { + if (node.getFirstParentOfType(ASTProperty.class) == null) { + return data; + } + + if (node.getModifiers().isStatic()) { + checkMatches(STATIC_REGEX, node, data); + } else { + checkMatches(INSTANCE_REGEX, node, data); + } + + return data; + } + + @Override + protected String displayName(String name) { + return DESCRIPTOR_TO_DISPLAY_NAME.get(name); + } +} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java index 830403adaf..b5ba653d29 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/codestyle/VariableNamingConventionsRule.java @@ -21,6 +21,7 @@ import net.sourceforge.pmd.lang.apex.ast.ApexNode; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.properties.PropertyDescriptor; +@Deprecated public class VariableNamingConventionsRule extends AbstractApexRule { private boolean checkMembers; diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSharingViolationsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSharingViolationsRule.java index 52e8abcea7..c4b90e83bb 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSharingViolationsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSharingViolationsRule.java @@ -90,7 +90,8 @@ public class ApexSharingViolationsRule extends AbstractApexRule { * @return */ private boolean isSharingPresent(ASTUserClass node) { - return node.getModifiers().isWithoutSharing() || node.getModifiers().isWithSharing(); + return node.getModifiers().isWithoutSharing() || node.getModifiers().isWithSharing() + || node.getModifiers().isInheritedSharing(); } } diff --git a/pmd-apex/src/main/resources/category/apex/codestyle.xml b/pmd-apex/src/main/resources/category/apex/codestyle.xml index ef53ac90d0..262b6f9757 100644 --- a/pmd-apex/src/main/resources/category/apex/codestyle.xml +++ b/pmd-apex/src/main/resources/category/apex/codestyle.xml @@ -11,16 +11,23 @@ Rules which enforce a specific coding style. <rule name="ClassNamingConventions" since="5.5.0" - message="Class names should begin with an uppercase character" + message="The {0} name ''{1}'' doesn''t match ''{2}''" class="net.sourceforge.pmd.lang.apex.rule.codestyle.ClassNamingConventionsRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#classnamingconventions"> <description> -Class names should always begin with an upper case character. + Configurable naming conventions for type declarations. This rule reports + type declarations which do not match the regex that applies to their + specific kind (e.g. enum or interface). Each regex can be configured through + properties. + + By default this rule uses the standard Apex naming convention (Pascal case). </description> <priority>1</priority> <example> -<![CDATA[ -public class Foo {} + <![CDATA[ +public class FooClass { } // This is in pascal case, so it's ok + +public class fooClass { } // This will be reported unless you change the regex ]]> </example> </rule> @@ -95,6 +102,30 @@ if (foo) { // preferred approach </example> </rule> + <rule name="FieldNamingConventions" + since="6.15.0" + message="The {0} name ''{1}'' doesn''t match ''{2}''" + class="net.sourceforge.pmd.lang.apex.rule.codestyle.FieldNamingConventionsRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#fieldnamingconventions"> + <description> + Configurable naming conventions for field declarations. This rule reports variable declarations + which do not match the regex that applies to their specific kind ---e.g. constants (static final), + static field, final field. Each regex can be configured through properties. + + By default this rule uses the standard Apex naming convention (Camel case). + </description> + <priority>1</priority> + <example> +<![CDATA[ +public class Foo { + Integer instanceField; // This is in camel case, so it's ok + + Integer INSTANCE_FIELD; // This will be reported unless you change the regex +} +]]> + </example> + </rule> + <rule name="ForLoopsMustUseBraces" language="apex" since="5.6.0" @@ -130,25 +161,82 @@ for (int i = 0; i < 42; i++) { // preferred approach </example> </rule> - <rule name="MethodNamingConventions" - since="5.5.0" - message="Method name does not begin with a lower case character." - class="net.sourceforge.pmd.lang.apex.rule.codestyle.MethodNamingConventionsRule" - externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#methodnamingconventions"> + <rule name="FormalParameterNamingConventions" + since="6.15.0" + message="The {0} name ''{1}'' doesn''t match ''{2}''" + class="net.sourceforge.pmd.lang.apex.rule.codestyle.FormalParameterNamingConventionsRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#formalparameternamingconventions"> <description> -Method names should always begin with a lower case character, and should not contain underscores. + Configurable naming conventions for formal parameters of methods. + This rule reports formal parameters which do not match the regex that applies to their + specific kind (e.g. method parameter, or final method parameter). Each regex can be + configured through properties. + + By default this rule uses the standard Apex naming convention (Camel case). </description> <priority>1</priority> <example> <![CDATA[ public class Foo { - public void fooStuff() { + public bar(Integer methodParameter) { } // This is in camel case, so it's ok + + public baz(Integer METHOD_PARAMETER) { } // This will be reported unless you change the regex +} +]]> + </example> + </rule> + + <rule name="LocalVariableNamingConventions" + since="6.15.0" + message="The {0} name ''{1}'' doesn''t match ''{2}''" + class="net.sourceforge.pmd.lang.apex.rule.codestyle.LocalVariableNamingConventionsRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#localvariablenamingconventions"> + <description> + Configurable naming conventions for local variable declarations. + This rule reports variable declarations which do not match the regex that applies to their + specific kind (e.g. local variable, or final local variable). Each regex can be configured through + properties. + + By default this rule uses the standard Apex naming convention (Camel case). + </description> + <priority>1</priority> + <example> +<![CDATA[ +public class Foo { + public Foo() { + Integer localVariable; // This is in camel case, so it's ok + + Integer LOCAL_VARIABLE; // This will be reported unless you change the regex } } ]]> </example> </rule> + <rule name="MethodNamingConventions" + since="5.5.0" + message="The {0} name ''{1}'' doesn''t match ''{2}''" + class="net.sourceforge.pmd.lang.apex.rule.codestyle.MethodNamingConventionsRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#methodnamingconventions"> + <description> + Configurable naming conventions for method declarations. This rule reports + method declarations which do not match the regex that applies to their + specific kind (e.g. static method, or test method). Each regex can be + configured through properties. + + By default this rule uses the standard Apex naming convention (Camel case). + </description> + <priority>1</priority> + <example> +<![CDATA[ +public class Foo { + public void instanceMethod() { } // This is in camel case, so it's ok + + public void INSTANCE_METHOD() { } // This will be reported unless you change the regex +]]> + </example> + </rule> + <rule name="OneDeclarationPerLine" since="6.7.0" message="Use one statement for each line, it enhances code readability." @@ -190,8 +278,34 @@ Integer b; </example> </rule> + <rule name="PropertyNamingConventions" + since="6.15.0" + message="The {0} name ''{1}'' doesn''t match ''{2}''" + class="net.sourceforge.pmd.lang.apex.rule.codestyle.PropertyNamingConventionsRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#propertynamingconventions"> + <description> + Configurable naming conventions for property declarations. This rule reports + property declarations which do not match the regex that applies to their + specific kind (e.g. static property, or instance property). Each regex can be + configured through properties. + + By default this rule uses the standard Apex naming convention (Camel case). + </description> + <priority>1</priority> + <example> +<![CDATA[ +public class Foo { + public Integer instanceProperty { get; set; } // This is in camel case, so it's ok + + public Integer INSTANCE_PROPERTY { get; set; } // This will be reported unless you change the regex +} +]]> + </example> + </rule> + <rule name="VariableNamingConventions" since="5.5.0" + deprecated="true" message="{0} variable {1} should begin with {2}" class="net.sourceforge.pmd.lang.apex.rule.codestyle.VariableNamingConventionsRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_codestyle.html#variablenamingconventions"> @@ -199,6 +313,12 @@ Integer b; A variable naming conventions rule - customize this to your liking. Currently, it checks for final variables that should be fully capitalized and non-final variables that should not include underscores. + +This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced +by the more general rules {% rule "apex/codestyle/FieldNamingConventions" %}, +{% rule "apex/codestyle/FormalParameterNamingConventions" %}, +{% rule "apex/codestyle/LocalVariableNamingConventions" %}, and +{% rule "apex/codestyle/PropertyNamingConventions" %}. </description> <priority>1</priority> <example> diff --git a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml index 1d815e3e18..2f2d831230 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/quickstart.xml @@ -99,7 +99,18 @@ <rule ref="category/apex/errorprone.xml/MethodWithSameNameAsEnclosingClass" message="Classes should not have non-constructor methods with the same name as the class"> <priority>3</priority> </rule> - <rule ref="category/apex/codestyle.xml/VariableNamingConventions" message="{0} variable {1} should begin with {2}"> + + <!-- NAMING --> + <rule ref="category/apex/codestyle.xml/FieldNamingConventions"> + <priority>3</priority> + </rule> + <rule ref="category/apex/codestyle.xml/FormalParameterNamingConventions"> + <priority>3</priority> + </rule> + <rule ref="category/apex/codestyle.xml/LocalVariableNamingConventions"> + <priority>3</priority> + </rule> + <rule ref="category/apex/codestyle.xml/PropertyNamingConventions"> <priority>3</priority> </rule> diff --git a/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml b/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml index e925546a20..257b5e659d 100644 --- a/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml +++ b/pmd-apex/src/main/resources/rulesets/apex/ruleset.xml @@ -23,7 +23,9 @@ <rule ref="rulesets/apex/quickstart.xml/ClassNamingConventions" deprecated="true" /> <rule ref="rulesets/apex/quickstart.xml/MethodNamingConventions" deprecated="true" /> <rule ref="rulesets/apex/quickstart.xml/MethodWithSameNameAsEnclosingClass" deprecated="true" /> - <rule ref="rulesets/apex/quickstart.xml/VariableNamingConventions" deprecated="true" /> + <rule ref="category/apex/codestyle.xml/VariableNamingConventions" deprecated="true" message="{0} variable {1} should begin with {2}"> + <priority>3</priority> + </rule> <rule ref="rulesets/apex/quickstart.xml/ApexUnitTestClassShouldHaveAsserts" deprecated="true" /> <rule ref="rulesets/apex/quickstart.xml/ApexUnitTestShouldNotUseSeeAllDataTrue" deprecated="true" /> <rule ref="rulesets/apex/quickstart.xml/ApexSharingViolations" deprecated="true" /> diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/DefaultRulesetTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/DefaultRulesetTest.java index 9646085c85..2f5eeda3a4 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/DefaultRulesetTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/DefaultRulesetTest.java @@ -4,6 +4,11 @@ package net.sourceforge.pmd.lang.apex; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.junit.After; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -26,10 +31,31 @@ public class DefaultRulesetTest { Assert.assertNotNull(ruleset); } + @After + public void cleanup() { + Handler[] handlers = Logger.getLogger(RuleSetFactory.class.getName()).getHandlers(); + for (Handler handler : handlers) { + Logger.getLogger(RuleSetFactory.class.getName()).removeHandler(handler); + } + } + @Test public void loadQuickstartRuleset() throws Exception { + Logger.getLogger(RuleSetFactory.class.getName()).addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + Assert.fail("No Logging expected: " + record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); RuleSet ruleset = factory.createRuleSet("rulesets/apex/quickstart.xml"); Assert.assertNotNull(ruleset); - Assert.assertTrue(systemErrRule.getLog().isEmpty()); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassTest.java new file mode 100644 index 0000000000..7e2ea41201 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserClassTest.java @@ -0,0 +1,31 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import static net.sourceforge.pmd.lang.apex.ast.ApexParserTestHelpers.parse; + +import org.junit.Assert; +import org.junit.Test; + +import apex.jorje.semantic.ast.compilation.Compilation; + +public class ASTUserClassTest { + + @Test + public void testClassName() { + ApexNode<Compilation> node = parse("class Foo { }"); + Assert.assertSame(ASTUserClass.class, node.getClass()); + Assert.assertEquals("Foo", node.getImage()); + } + + @Test + public void testInnerClassName() { + ApexNode<Compilation> node = parse("class Foo { class Bar { } }"); + Assert.assertSame(ASTUserClass.class, node.getClass()); + ASTUserClass innerNode = node.getFirstDescendantOfType(ASTUserClass.class); + Assert.assertNotNull(innerNode); + Assert.assertEquals("Bar", innerNode.getImage()); + } +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnumTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnumTest.java new file mode 100644 index 0000000000..827833e4bd --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserEnumTest.java @@ -0,0 +1,24 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import static net.sourceforge.pmd.lang.apex.ast.ApexParserTestHelpers.parse; + +import org.junit.Assert; +import org.junit.Test; + +import apex.jorje.semantic.ast.compilation.Compilation; + +public class ASTUserEnumTest { + + @Test + public void testEnumName() { + ApexNode<Compilation> node = parse("class Foo { enum Bar { } }"); + Assert.assertSame(ASTUserClass.class, node.getClass()); + ASTUserEnum enumNode = node.getFirstDescendantOfType(ASTUserEnum.class); + Assert.assertNotNull(enumNode); + Assert.assertEquals("Bar", enumNode.getImage()); + } +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterfaceTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterfaceTest.java new file mode 100644 index 0000000000..f7944db734 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ASTUserInterfaceTest.java @@ -0,0 +1,31 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.ast; + +import static net.sourceforge.pmd.lang.apex.ast.ApexParserTestHelpers.parse; + +import org.junit.Assert; +import org.junit.Test; + +import apex.jorje.semantic.ast.compilation.Compilation; + +public class ASTUserInterfaceTest { + + @Test + public void testInterfaceName() { + ApexNode<Compilation> node = parse("interface Foo { }"); + Assert.assertSame(ASTUserInterface.class, node.getClass()); + Assert.assertEquals("Foo", node.getImage()); + } + + @Test + public void testInnerInterfaceName() { + ApexNode<Compilation> node = parse("class Foo { interface Bar { } }"); + Assert.assertSame(ASTUserClass.class, node.getClass()); + ASTUserInterface innerNode = node.getFirstDescendantOfType(ASTUserInterface.class); + Assert.assertNotNull(innerNode); + Assert.assertEquals("Bar", innerNode.getImage()); + } +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsTest.java new file mode 100644 index 0000000000..823a7f32fc --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FieldNamingConventionsTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class FieldNamingConventionsTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsTest.java new file mode 100644 index 0000000000..45dba2964e --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/FormalParameterNamingConventionsTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class FormalParameterNamingConventionsTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsTest.java new file mode 100644 index 0000000000..6ddf91a354 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/LocalVariableNamingConventionsTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class LocalVariableNamingConventionsTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsTest.java new file mode 100644 index 0000000000..413e80ed09 --- /dev/null +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/codestyle/PropertyNamingConventionsTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.apex.rule.codestyle; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class PropertyNamingConventionsTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml index 4f9f93b79f..8817e4f30b 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/ClassNamingConventions.xml @@ -20,5 +20,143 @@ public class foo {}; public class FooBar {}; ]]></code> </test-code> + + <test-code> + <description>test class all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +@isTest +public class TestClass { } + ]]></code> + </test-code> + + <test-code> + <description>abstract class all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public abstract class AbstractClass { } + ]]></code> + </test-code> + + <test-code> + <description>class all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class FooClass { } + ]]></code> + </test-code> + + <test-code> + <description>interface all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public interface FooInterface { } + ]]></code> + </test-code> + + <test-code> + <description>enum all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public enum FooEnum { } +} + ]]></code> + </test-code> + + <test-code> + <description>test class default is title case</description> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The test class name 'testClass' doesn't match '[A-Z][a-zA-Z0-9_]*'</message> + </expected-messages> + <code><![CDATA[ +@isTest +public class testClass { } + ]]></code> + </test-code> + + <test-code> + <description>abstract class default is title case</description> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The abstract class name 'abstractClass' doesn't match '[A-Z][a-zA-Z0-9_]*'</message> + </expected-messages> + <code><![CDATA[ +public abstract class abstractClass { } + ]]></code> + </test-code> + + <test-code> + <description>class default is title case</description> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The class name 'fooClass' doesn't match '[A-Z][a-zA-Z0-9_]*'</message> + </expected-messages> + <code><![CDATA[ +public class fooClass { } + ]]></code> + </test-code> + + <test-code> + <description>interface default is title case</description> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The interface name 'fooInterface' doesn't match '[A-Z][a-zA-Z0-9_]*'</message> + </expected-messages> + <code><![CDATA[ +public interface fooInterface { } + ]]></code> + </test-code> + + <test-code> + <description>enum default is title case</description> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The enum name 'fooEnum' doesn't match '[A-Z][a-zA-Z0-9_]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public enum fooEnum { } +} + ]]></code> + </test-code> + + <test-code> + <description>custom test class pattern</description> + <rule-property name="testClassPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +@isTest +public class TEST_CLASS { } + ]]></code> + </test-code> + + <test-code> + <description>custom abstract class pattern</description> + <rule-property name="abstractClassPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public abstract class ABSTRACT_CLASS { } + ]]></code> + </test-code> + + <test-code> + <description>custom class pattern</description> + <rule-property name="classPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class FOO_CLASS { } + ]]></code> + </test-code> + + <test-code> + <description>custom interface pattern</description> + <rule-property name="interfacePattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public interface FOO_INTERFACE { } + ]]></code> + </test-code> </test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/FieldNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/FieldNamingConventions.xml new file mode 100644 index 0000000000..b5de65a6b6 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/FieldNamingConventions.xml @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + + <test-code> + <description>all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + final static Integer CONSTANT_FIELD; + final Integer finalField; + static Integer staticField; + Integer instanceField; + enum FooEnum { + DEFAULT + } +} + ]]></code> + </test-code> + + <test-code> + <description>default is all caps for constants, camel case for others</description> + <expected-problems>4</expected-problems> + <expected-messages> + <message>The constant field name 'constantField' doesn't match '[A-Z][A-Z0-9_]*'</message> + <message>The final field name 'FINAL_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The static field name 'STATIC_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance field name 'INSTANCE_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + final static Integer constantField; + final Integer FINAL_FIELD; + static Integer STATIC_FIELD; + Integer INSTANCE_FIELD; +} + ]]></code> +</test-code> + + <test-code> + <description>enum default is all caps and underscores</description> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The enum constant field name 'default' doesn't match '[A-Z][A-Z0-9_]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + enum FooEnum { + default + } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores properties</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + Integer BAR { get; set; } +} + ]]></code> + </test-code> + + <test-code> + <description>custom enum constant pattern</description> + <rule-property name="enumConstantPattern">[a-zA-Z0-9]+</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + enum FooEnum { + default + } +} + ]]></code> + </test-code> + + <test-code> + <description>custom constant pattern</description> + <rule-property name="constantPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>3</expected-problems> + <expected-messages> + <message>The final field name 'FINAL_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The static field name 'STATIC_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance field name 'INSTANCE_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + final static Integer constantField; + final Integer FINAL_FIELD; + static Integer STATIC_FIELD; + Integer INSTANCE_FIELD; +} + ]]></code> + </test-code> + + <test-code> + <description>custom final pattern</description> + <rule-property name="finalPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>3</expected-problems> + <expected-messages> + <message>The constant field name 'constantField' doesn't match '[A-Z][A-Z0-9_]*'</message> + <message>The static field name 'STATIC_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance field name 'INSTANCE_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + final static Integer constantField; + final Integer FINAL_FIELD; + static Integer STATIC_FIELD; + Integer INSTANCE_FIELD; +} + ]]></code> + </test-code> + + <test-code> + <description>custom static pattern</description> + <rule-property name="staticPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>3</expected-problems> + <expected-messages> + <message>The constant field name 'constantField' doesn't match '[A-Z][A-Z0-9_]*'</message> + <message>The final field name 'FINAL_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance field name 'INSTANCE_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + final static Integer constantField; + final Integer FINAL_FIELD; + static Integer STATIC_FIELD; + Integer INSTANCE_FIELD; +} + ]]></code> + </test-code> + + <test-code> + <description>custom instance pattern</description> + <rule-property name="instancePattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>3</expected-problems> + <expected-messages> + <message>The constant field name 'constantField' doesn't match '[A-Z][A-Z0-9_]*'</message> + <message>The final field name 'FINAL_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The static field name 'STATIC_FIELD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + final static Integer constantField; + final Integer FINAL_FIELD; + static Integer STATIC_FIELD; + Integer INSTANCE_FIELD; +} + ]]></code> + </test-code> + +</test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/FormalParameterNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/FormalParameterNamingConventions.xml new file mode 100644 index 0000000000..7cc3fc943d --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/FormalParameterNamingConventions.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + + <test-code> + <description>all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public Foo(final Integer finalMethodParameter, Integer methodParameter) { } +} + ]]></code> + </test-code> + + <test-code> + <description>default is camel case</description> + <expected-problems>2</expected-problems> + <expected-messages> + <message>The final method parameter name 'FINAL_METHOD_PARAMETER' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The method parameter name 'METHOD_PARAMETER' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public Foo(final Integer FINAL_METHOD_PARAMETER, Integer METHOD_PARAMETER) { } +} + ]]></code> + </test-code> + + <test-code> + <description>custom final method parameter pattern</description> + <rule-property name="finalMethodParameterPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The method parameter name 'METHOD_PARAMETER' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public Foo(final Integer FINAL_METHOD_PARAMETER, Integer METHOD_PARAMETER) { } +} + ]]></code> + </test-code> + + <test-code> + <description>custom method parameter pattern</description> + <rule-property name="methodParameterPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The final method parameter name 'FINAL_METHOD_PARAMETER' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public Foo(final Integer FINAL_METHOD_PARAMETER, Integer METHOD_PARAMETER) { } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores null parameter names</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public with sharing class MyException extends Exception { } + ]]></code> + </test-code> + +</test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/LocalVariableNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/LocalVariableNamingConventions.xml new file mode 100644 index 0000000000..ff5098dfd2 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/LocalVariableNamingConventions.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + + <test-code> + <description>all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public Foo() { + final Integer finalLocalVariable; + Integer localVariable; + } +} + ]]></code> + </test-code> + + <test-code> + <description>default is camel case</description> + <expected-problems>2</expected-problems> + <expected-messages> + <message>The final local variable name 'FINAL_LOCAL_VARIABLE' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The local variable name 'LOCAL_VARIABLE' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public Foo() { + final Integer FINAL_LOCAL_VARIABLE; + Integer LOCAL_VARIABLE; + } +} + ]]></code> + </test-code> + + <test-code> + <description>custom final local pattern</description> + <rule-property name="finalLocalPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The local variable name 'LOCAL_VARIABLE' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public Foo() { + Integer LOCAL_VARIABLE; + final Integer FINAL_LOCAL_VARIABLE; + } +} + ]]></code> + </test-code> + + <test-code> + <description>custom local pattern</description> + <rule-property name="localPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The final local variable name 'FINAL_LOCAL_VARIABLE' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public Foo() { + Integer LOCAL_VARIABLE; + final Integer FINAL_LOCAL_VARIABLE; + } +} + ]]></code> + </test-code> + +</test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml index 0a1798e969..ea9db4a8d0 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/MethodNamingConventions.xml @@ -100,4 +100,131 @@ public class Foo { } ]]></code> </test-code> + + <test-code> + <description>all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + @isTest + public static void testMethod() { } + public static void staticMethod() { } + public void instanceMethod() { } +} + ]]></code> + </test-code> + + <test-code> + <description>default is camel case</description> + <expected-problems>3</expected-problems> + <expected-messages> + <message>The test method name 'TEST_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The static method name 'STATIC_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance method name 'INSTANCE_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + @isTest + public static void TEST_METHOD() { } + public static void STATIC_METHOD() { } + public void INSTANCE_METHOD() { } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores overrides</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public override Integer BAR() { } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores properties</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public Integer BAR { get; set; } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores constructors</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class FOO { + public FOO() { } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores enum methods</description> + <rule-property name="instancePattern">Z</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + enum Bar { + } +} + ]]></code> + </test-code> + + <test-code> + <description>custom test method pattern</description> + <rule-property name="testPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>2</expected-problems> + <expected-messages> + <message>The static method name 'STATIC_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance method name 'INSTANCE_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + @isTest + public static void TEST_METHOD() { } + public static void STATIC_METHOD() { } + public void INSTANCE_METHOD() { } +} + ]]></code> + </test-code> + + <test-code> + <description>custom static method pattern</description> + <rule-property name="staticPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>2</expected-problems> + <expected-messages> + <message>The test method name 'TEST_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance method name 'INSTANCE_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + @isTest + public static void TEST_METHOD() { } + public static void STATIC_METHOD() { } + public void INSTANCE_METHOD() { } +} + ]]></code> + </test-code> + + <test-code> + <description>custom instance method pattern</description> + <rule-property name="instancePattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>2</expected-problems> + <expected-messages> + <message>The test method name 'TEST_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The static method name 'STATIC_METHOD' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + @isTest + public static void TEST_METHOD() { } + public static void STATIC_METHOD() { } + public void INSTANCE_METHOD() { } +} + ]]></code> + </test-code> </test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/PropertyNamingConventions.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/PropertyNamingConventions.xml new file mode 100644 index 0000000000..4fdd885597 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/codestyle/xml/PropertyNamingConventions.xml @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + + <test-code> + <description>all is well</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public static Integer staticProperty { get; set; } + public Integer instanceProperty { get; set; } +} + ]]></code> + </test-code> + + <test-code> + <description>default is camel case</description> + <expected-problems>2</expected-problems> + <expected-messages> + <message>The static property name 'STATIC_PROPERTY' doesn't match '[a-z][a-zA-Z0-9]*'</message> + <message>The instance property name 'INSTANCE_PROPERTY' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public static Integer STATIC_PROPERTY { get; set; } + public Integer INSTANCE_PROPERTY { get; set; } +} + ]]></code> + </test-code> + + <test-code> + <description>ignores methods</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public void BAR() { } +} + ]]></code> + </test-code> + + <test-code> + <description>custom static property pattern</description> + <rule-property name="staticPattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The instance property name 'INSTANCE_PROPERTY' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public static Integer STATIC_PROPERTY { get; set; } + public Integer INSTANCE_PROPERTY { get; set; } +} + ]]></code> + </test-code> + + <test-code> + <description>custom instance property pattern</description> + <rule-property name="instancePattern">[a-zA-Z0-9_]+</rule-property> + <expected-problems>1</expected-problems> + <expected-messages> + <message>The static property name 'STATIC_PROPERTY' doesn't match '[a-z][a-zA-Z0-9]*'</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public static Integer STATIC_PROPERTY { get; set; } + public Integer INSTANCE_PROPERTY { get; set; } +} + ]]></code> + </test-code> + +</test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/documentation/xml/ApexDoc.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/documentation/xml/ApexDoc.xml index 0e890cd274..28946ce929 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/documentation/xml/ApexDoc.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/documentation/xml/ApexDoc.xml @@ -52,6 +52,10 @@ private class Foo { } <test-code> <description>class comment should have description</description> <expected-problems>1</expected-problems> + <expected-linenumbers>3</expected-linenumbers> + <expected-messages> + <message>Missing ApexDoc @description</message> + </expected-messages> <code><![CDATA[ /** */ @@ -398,4 +402,49 @@ public class Foo { ]]></code> </test-code> + <test-code> + <description>#1783 correct comments for constructor and inner class</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +/** + * @description Foo + */ +public class Foo { + + /** + * @description Foo + */ + public Foo() { + } + + /** + * @description Bar + */ + public class Bar { + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1783 correct comments for constructor and inner class - false negative</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>12</expected-linenumbers> + <code><![CDATA[ +/** + * @description Foo + */ +public class Foo { + + /** + * @description Foo + */ + public Foo() { + } + + public class Bar { + } +} + ]]></code> + </test-code> </test-data> diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSharingViolations.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSharingViolations.xml index 196a9782cd..3e5df59843 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSharingViolations.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSharingViolations.xml @@ -97,4 +97,15 @@ public without sharing class Foo { ]]></code> </test-code> + <test-code> + <description>Apex class with inherited sharing doing a safe SOQL query</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public inherited sharing class MyClass { + public List<Contact> getAllTheSecrets(){ + return [SELECT Name FROM Contact]; + } +} + ]]></code> + </test-code> </test-data> diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index c78aabfa37..9443265f3b 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -143,6 +143,12 @@ <version>2.8.5</version> </dependency> + <dependency> + <groupId>org.checkerframework</groupId> + <artifactId>checker-qual</artifactId> + <version>2.5.2</version> + </dependency> + <dependency> <groupId>net.sourceforge.saxon</groupId> diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/Rule.java b/pmd-core/src/main/java/net/sourceforge/pmd/Rule.java index 00f4272a0f..c8a7328a8f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/Rule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/Rule.java @@ -421,10 +421,12 @@ public interface Rule extends PropertySource { void addRuleChainVisit(Class<? extends Node> nodeClass); /** - * Adds an AST node by name to be visited by the Rule on the RuleChain. + * Adds an AST node by XPath name to be visited by the Rule on the RuleChain. * * @param astNodeName - * the AST node to add to the RuleChain visit list as string + * the XPath name of the node to add to the RuleChain visit list + * + * @see Node#getXPathNodeName() */ void addRuleChainVisit(String astNodeName); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java index 03fe697a36..24ed254d6a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java @@ -27,6 +27,7 @@ public final class PMDCommandLineInterface { public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit"; public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status"; + private static final int NO_ERRORS_STATUS = 0; public static final int ERROR_STATUS = 1; public static final int VIOLATIONS_FOUND = 4; @@ -41,7 +42,7 @@ public final class PMDCommandLineInterface { if (arguments.isHelp()) { jcommander.usage(); System.out.println(buildUsageText(jcommander)); - setStatusCodeOrExit(ERROR_STATUS); + setStatusCodeOrExit(NO_ERRORS_STATUS); } } catch (ParameterException e) { jcommander.usage(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java index 91aaba88df..aee45308ad 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java @@ -26,8 +26,9 @@ import com.beust.jcommander.ParameterException; public final class CPDCommandLineInterface { private static final Logger LOGGER = Logger.getLogger(CPDCommandLineInterface.class.getName()); - private static final int DUPLICATE_CODE_FOUND = 4; + private static final int NO_ERRORS_STATUS = 0; private static final int ERROR_STATUS = 1; + private static final int DUPLICATE_CODE_FOUND = 4; public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit"; public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status"; @@ -66,7 +67,7 @@ public final class CPDCommandLineInterface { if (arguments.isHelp()) { jcommander.usage(); System.out.println(buildUsageText()); - setStatusCodeOrExit(ERROR_STATUS); + setStatusCodeOrExit(NO_ERRORS_STATUS); return; } } catch (ParameterException e) { @@ -96,10 +97,10 @@ public final class CPDCommandLineInterface { if (arguments.isFailOnViolation()) { setStatusCodeOrExit(DUPLICATE_CODE_FOUND); } else { - setStatusCodeOrExit(0); + setStatusCodeOrExit(NO_ERRORS_STATUS); } } else { - setStatusCodeOrExit(0); + setStatusCodeOrExit(NO_ERRORS_STATUS); } } catch (IOException | RuntimeException e) { e.printStackTrace(); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java index 916276502a..fd7e436af2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java @@ -421,7 +421,7 @@ public class GUI implements CPDListener { ignoreAnnotationsCheckbox.setEnabled(current.canIgnoreAnnotations()); ignoreUsingsCheckbox.setEnabled(current.canIgnoreUsings()); extensionField.setText(current.extensions()[0]); - boolean enableExtension = current.extensions()[0].length() == 0; + boolean enableExtension = current.extensions()[0].isEmpty(); extensionField.setEnabled(enableExtension); extensionLabel.setEnabled(enableExtension); } @@ -611,7 +611,7 @@ public class GUI implements CPDListener { private boolean isLegalPath(String path, LanguageConfig config) { String[] extensions = config.extensions(); for (int i = 0; i < extensions.length; i++) { - if (path.endsWith(extensions[i]) && extensions[i].length() > 0) { + if (path.endsWith(extensions[i]) && !extensions[i].isEmpty()) { return true; } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java index 21120cc0a3..3e9490938d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/AbstractLanguageVersionHandler.java @@ -50,6 +50,7 @@ public abstract class AbstractLanguageVersionHandler implements LanguageVersionH return VisitorStarter.DUMMY; } + @Deprecated @Override public VisitorStarter getMultifileFacade() { return VisitorStarter.DUMMY; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AbstractAntlrVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AbstractAntlrVisitor.java new file mode 100644 index 0000000000..2a8c7a832e --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AbstractAntlrVisitor.java @@ -0,0 +1,88 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.antlr; + +import java.util.List; + +import org.antlr.v4.runtime.tree.ErrorNode; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeVisitor; +import org.antlr.v4.runtime.tree.RuleNode; +import org.antlr.v4.runtime.tree.TerminalNode; + +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.AntlrBaseNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRule; + +public abstract class AbstractAntlrVisitor<T> extends AbstractRule implements ParseTreeVisitor<T> { + + protected RuleContext data; + + @Override + public void start(RuleContext ctx) { + data = ctx; + } + + @Override + public T visit(ParseTree tree) { + if (tree instanceof AntlrBaseNode) { + return visit((AntlrBaseNode) tree); + } + return tree.accept(this); + } + + @Override + public T visitChildren(RuleNode node) { + T result = this.defaultResult(); + final int n = node.getChildCount(); + + for (int i = 0; i < n && this.shouldVisitNextChild(node, result); ++i) { + final ParseTree c = node.getChild(i); + final T childResult = visit(c); + result = this.aggregateResult(result, childResult); + } + + return result; + } + + @Override + public T visitTerminal(TerminalNode node) { + return this.defaultResult(); + } + + @Override + public T visitErrorNode(ErrorNode node) { + return this.defaultResult(); + } + + protected T defaultResult() { + return null; + } + + protected T aggregateResult(T aggregate, T nextResult) { + return nextResult; + } + + protected boolean shouldVisitNextChild(RuleNode node, T currentResult) { + return true; + } + + @Override + public void apply(List<? extends Node> nodes, RuleContext ctx) { + visitAll(nodes); + } + + protected void visitAll(List<? extends Node> nodes) { + for (Node n : nodes) { + AntlrBaseNode node = (AntlrBaseNode) n; + visit(node); + } + } + + public T visit(final AntlrBaseNode node) { + return node.accept(this); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrBaseParser.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrBaseParser.java new file mode 100644 index 0000000000..acca252b9c --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrBaseParser.java @@ -0,0 +1,65 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.antlr; + +import java.io.IOException; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +import org.antlr.v4.runtime.Lexer; + +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.TokenManager; +import net.sourceforge.pmd.lang.ast.AntlrBaseNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.ParseException; + +/** + * Generic Antlr parser adapter for all Antlr parsers. + */ +public abstract class AntlrBaseParser<T extends org.antlr.v4.runtime.Parser> implements Parser { + + protected final ParserOptions parserOptions; + + public AntlrBaseParser(final ParserOptions parserOptions) { + this.parserOptions = parserOptions; + } + + @Override + public ParserOptions getParserOptions() { + return parserOptions; + } + + @Override + public TokenManager getTokenManager(final String fileName, final Reader source) { + try { + return new AntlrTokenManager(getLexer(source), fileName); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public Node parse(final String fileName, final Reader source) throws ParseException { + try { + return getRootNode(getParser(getLexer(source))); + } catch (final IOException e) { + throw new ParseException(e); + } + } + + @Override + public Map<Integer, String> getSuppressMap() { + return new HashMap<>(); + } + + protected abstract AntlrBaseNode getRootNode(T parser); + + protected abstract Lexer getLexer(Reader source) throws IOException; + + protected abstract T getParser(Lexer lexer); +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrRuleChainVisitor.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrRuleChainVisitor.java new file mode 100644 index 0000000000..b20d6146de --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrRuleChainVisitor.java @@ -0,0 +1,42 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.antlr; + +import java.util.List; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.lang.ast.AntlrBaseNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRuleChainVisitor; +import net.sourceforge.pmd.lang.rule.XPathRule; + +public class AntlrRuleChainVisitor extends AbstractRuleChainVisitor { + @Override + protected void visit(Rule rule, Node node, RuleContext ctx) { + if (rule instanceof AbstractAntlrVisitor) { + ((AntlrBaseNode) node).accept((AbstractAntlrVisitor) rule); + } else { + ((XPathRule) rule).evaluate(node, ctx); + } + } + + @Override + protected void indexNodes(List<Node> nodes, RuleContext ctx) { + final AbstractAntlrVisitor antlrVisitor = new AbstractAntlrVisitor<Object>() { + // Perform a visitation of the AST to index nodes which need + // visiting by type + @Override + public Object visit(final AntlrBaseNode node) { + indexNode(node); + return super.visit(node); + } + }; + + for (final Node node : nodes) { + antlrVisitor.visit((AntlrBaseNode) node); + } + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrRuleViolationFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrRuleViolationFactory.java new file mode 100644 index 0000000000..8d2584643e --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrRuleViolationFactory.java @@ -0,0 +1,36 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.antlr; + +import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.RuleContext; +import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.ast.AntlrBaseNode; +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.rule.AbstractRuleViolationFactory; +import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +public final class AntlrRuleViolationFactory extends AbstractRuleViolationFactory { + public static final RuleViolationFactory INSTANCE = new AntlrRuleViolationFactory(); + + private AntlrRuleViolationFactory() { + } + + @Override + protected RuleViolation createRuleViolation(final Rule rule, final RuleContext ruleContext, final Node node, + final String message) { + return new ParametricRuleViolation<>(rule, ruleContext, (AntlrBaseNode) node, message); + } + + @Override + protected RuleViolation createRuleViolation(final Rule rule, final RuleContext ruleContext, final Node node, + final String message, final int beginLine, final int endLine) { + final ParametricRuleViolation<AntlrBaseNode> violation = new ParametricRuleViolation<>(rule, ruleContext, + (AntlrBaseNode) node, message); + violation.setLines(beginLine, endLine); + return violation; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrTokenManager.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrTokenManager.java index 48434eca01..55cb99e124 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrTokenManager.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/antlr/AntlrTokenManager.java @@ -67,7 +67,7 @@ public class AntlrTokenManager implements TokenManager { @Override public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line, - final int charPositionInLine, final String msg, final RecognitionException ex) { + final int charPositionInLine, final String msg, final RecognitionException ex) { throw new ANTLRSyntaxError(msg, line, charPositionInLine, ex); } } @@ -78,7 +78,7 @@ public class AntlrTokenManager implements TokenManager { private final int column; /* default */ ANTLRSyntaxError(final String msg, final int line, final int column, - final RecognitionException cause) { + final RecognitionException cause) { super(msg, cause); this.line = line; this.column = column; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java index a03c22221d..e8fecf0161 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AbstractNode.java @@ -5,11 +5,9 @@ package net.sourceforge.pmd.lang.ast; import java.util.Objects; -import java.util.logging.Logger; import org.apache.commons.lang3.ArrayUtils; -import net.sourceforge.pmd.PMDVersion; import net.sourceforge.pmd.lang.dfa.DataFlowNode; /** @@ -17,10 +15,11 @@ import net.sourceforge.pmd.lang.dfa.DataFlowNode; */ public abstract class AbstractNode implements Node { - private static final Logger LOG = Logger.getLogger(AbstractNode.class.getName()); + private static final Node[] EMPTY_ARRAY = new Node[0]; protected Node parent; - protected Node[] children; + // never null, never contains null elements + protected Node[] children = EMPTY_ARRAY; protected int childIndex; protected int id; @@ -74,15 +73,14 @@ public abstract class AbstractNode implements Node { @Override public void jjtAddChild(final Node child, final int index) { - if (children == null) { - children = new Node[index + 1]; - } else if (index >= children.length) { + if (index >= children.length) { final Node[] newChildren = new Node[index + 1]; System.arraycopy(children, 0, newChildren, 0, children.length); children = newChildren; } children[index] = child; child.jjtSetChildIndex(index); + child.jjtSetParent(this); } @Override @@ -102,7 +100,7 @@ public abstract class AbstractNode implements Node { @Override public int jjtGetNumChildren() { - return children == null ? 0 : children.length; + return children.length; } @Override @@ -137,7 +135,7 @@ public abstract class AbstractNode implements Node { @Override public int getBeginColumn() { if (beginColumn == -1) { - if (children != null && children.length > 0) { + if (children.length > 0) { return children[0].getBeginColumn(); } else { throw new RuntimeException("Unable to determine beginning line of Node."); @@ -231,6 +229,8 @@ public abstract class AbstractNode implements Node { public void jjtSetFirstToken(final GenericToken token) { this.firstToken = token; + this.beginLine = token.getBeginLine(); + this.beginColumn = token.getBeginColumn(); } public GenericToken jjtGetLastToken() { @@ -239,6 +239,8 @@ public abstract class AbstractNode implements Node { public void jjtSetLastToken(final GenericToken token) { this.lastToken = token; + this.endLine = token.getEndLine(); + this.endColumn = token.getEndColumn(); } @Override @@ -265,21 +267,8 @@ public abstract class AbstractNode implements Node { } } - /** - * {@inheritDoc} - * <p> - * <p>This default implementation adds compatibility with the previous - * way to get the xpath node name, which used {@link Object#toString()}. - * <p> - * <p>Please override it. It may be removed in a future major version. - */ @Override - // @Deprecated // FUTURE 7.0.0 make abstract - public String getXPathNodeName() { - LOG.warning("getXPathNodeName should be overriden in classes derived from AbstractNode. " - + "The implementation is provided for compatibility with existing implementors," - + "but could be declared abstract as soon as release " + PMDVersion.getNextMajorRelease() - + "."); - return toString(); + public String toString() { + return getXPathNodeName(); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrBaseNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrBaseNode.java index 679de92918..c3db1237e2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrBaseNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrBaseNode.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.ast; +import java.util.stream.Stream; + import org.antlr.v4.runtime.ParserRuleContext; import net.sourceforge.pmd.lang.dfa.DataFlowNode; @@ -83,17 +85,31 @@ public class AntlrBaseNode extends ParserRuleContext implements AntlrNode { @Override public Node jjtGetChild(final int index) { - return (Node) children.get(index); // TODO: review if all children are Nodes + try { + return (Node) childrenStream().skip(index).findFirst().orElse(null); + } catch (final ClassCastException e) { + throw new IllegalArgumentException("Accessing invalid Antlr node", e); + } + } + + @Override + public String getImage() { + return null; } @Override public int jjtGetNumChildren() { - return children == null ? 0 : children.size(); + return (int) childrenStream().count(); + } + + private Stream<Node> childrenStream() { + return children == null ? Stream.empty() : children.stream().filter(e -> e instanceof Node).map(e -> (Node) e); } // TODO: should we make it abstract due to the comment in AbstractNode ? @Override public String getXPathNodeName() { - return toString(); + final String simpleName = getClass().getSimpleName(); + return simpleName.substring(0, simpleName.length() - "Context".length()); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrNode.java index ded0f8a900..a246f368de 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AntlrNode.java @@ -47,12 +47,12 @@ public interface AntlrNode extends Node { } @Override - default String getImage() { + default void setImage(final String image) { throw new UnsupportedOperationException("Out of scope for antlr current implementations"); } @Override - default void setImage(final String image) { + default String getImage() { throw new UnsupportedOperationException("Out of scope for antlr current implementations"); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java index 3a66e90d1c..839fca5c1b 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/Node.java @@ -82,6 +82,8 @@ public interface Node { * This method returns a child node. The children are numbered from zero, left to right. * * @param index the child index. Must be nonnegative and less than {@link #jjtGetNumChildren}. + * + * @throws IndexOutOfBoundsException If the index is less than zero or greater or equal to {@link #jjtGetNumChildren()} */ Node jjtGetChild(int index); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRule.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRule.java index af4ddbf1b0..0c9bc0923a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRule.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractRule.java @@ -317,11 +317,17 @@ public abstract class AbstractRule extends AbstractPropertySource implements Rul @Override public void addRuleChainVisit(Class<? extends Node> nodeClass) { - if (!nodeClass.getSimpleName().startsWith("AST")) { + // FIXME : These assume the implementation of getXPathNodeName() for all nodes… + final String simpleName = nodeClass.getSimpleName(); + + if (simpleName.startsWith("AST")) { // JavaCC node // Classes under the Comment hierarchy and stuff need to be refactored in the Java AST - throw new IllegalArgumentException("Node class does not start with 'AST' prefix: " + nodeClass); + addRuleChainVisit(nodeClass.getSimpleName().substring("AST".length())); + } else if (nodeClass.getSimpleName().endsWith("Context")) { // Antlr node + addRuleChainVisit(nodeClass.getSimpleName().substring(0, simpleName.length() - "Context".length())); + } else { + throw new IllegalArgumentException("Node class does not start with 'AST' prefix nor ends with 'Context' suffix: " + nodeClass); } - addRuleChainVisit(nodeClass.getSimpleName().substring("AST".length())); } @Override diff --git a/pmd-core/src/main/resources/rulesets/releases/6150.xml b/pmd-core/src/main/resources/rulesets/releases/6150.xml new file mode 100644 index 0000000000..13d3e58a90 --- /dev/null +++ b/pmd-core/src/main/resources/rulesets/releases/6150.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> + +<ruleset name="6150" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + <description> +This ruleset contains links to rules that are new in PMD v6.15.0 + </description> + + <rule ref="category/apex/codestyle.xml/FieldNamingConventions"/> + <rule ref="category/apex/codestyle.xml/FormalParameterNamingConventions"/> + <rule ref="category/apex/codestyle.xml/LocalVariableNamingConventions"/> + <rule ref="category/apex/codestyle.xml/PropertyNamingConventions"/> + + <rule ref="category/java/codestyle.xml/UseShortArrayInitializer"/> +</ruleset> + diff --git a/pmd-core/src/main/resources/rulesets/releases/6160.xml b/pmd-core/src/main/resources/rulesets/releases/6160.xml new file mode 100644 index 0000000000..8bd7619fd2 --- /dev/null +++ b/pmd-core/src/main/resources/rulesets/releases/6160.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> + +<ruleset name="6160" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + <description> +This ruleset contains links to rules that are new in PMD v6.16.0 + </description> + + <rule ref="category/java/bestpractices.xml/DoubleBraceInitialization"/> +</ruleset> + diff --git a/pmd-cpp/etc/grammar/cpp.jj b/pmd-cpp/etc/grammar/cpp.jj index a39effe982..4e9c4586c0 100644 --- a/pmd-cpp/etc/grammar/cpp.jj +++ b/pmd-cpp/etc/grammar/cpp.jj @@ -96,7 +96,7 @@ public final class CppParser { if (t.kind != ID && t.kind != SCOPE) return null; - StringBuffer s = new StringBuffer(); + StringBuilder s = new StringBuilder(); int i; if (t.kind != SCOPE) @@ -284,37 +284,100 @@ TOKEN : TOKEN [IGNORE_CASE] : { - < OCTALINT : "0" (["0"-"7"])* > + < OCTALINT : "0" (["'", "0"-"7"])* > | < OCTALLONG : <OCTALINT> "l" > | < UNSIGNED_OCTALINT : <OCTALINT> "u" > | < UNSIGNED_OCTALLONG : <OCTALINT> ("ul" | "lu") > -| < DECIMALINT : ["1"-"9"] (["0"-"9"])* > +| < #DECIMALDIGIT : ["'", "0"-"9"] > + +| < DECIMALINT : ["1"-"9"] (<DECIMALDIGIT>)* > | < DECIMALLONG : <DECIMALINT> ["u","l"] > | < UNSIGNED_DECIMALINT : <DECIMALINT> "u" > | < UNSIGNED_DECIMALLONG : <DECIMALINT> ("ul" | "lu") > -| < HEXADECIMALINT : "0x" (["0"-"9","a"-"f"])+ > +| < HEXADECIMALINT : "0x" (<DECIMALDIGIT> | ["a"-"f"])+ > | < HEXADECIMALLONG : <HEXADECIMALINT> (["u","l"])? > | < UNSIGNED_HEXADECIMALINT : <HEXADECIMALINT> "u" > | < UNSIGNED_HEXADECIMALLONG : <HEXADECIMALINT> ("ul" | "lu") > -| < FLOATONE : ((["0"-"9"])+ "." (["0"-"9"])* | (["0"-"9"])* "." (["0"-"9"])+) - ("e" (["-","+"])? (["0"-"9"])+)? (["f","l"])? > +| < FLOATONE : (["0"-"9"](<DECIMALDIGIT>)* "." + | "." (<DECIMALDIGIT>)+ + | ["0"-"9"](<DECIMALDIGIT>)* "." (<DECIMALDIGIT>)+) + ("e" (["-","+"])? (<DECIMALDIGIT>)+)? (["f","l"])? > -| < FLOATTWO : (["0"-"9"])+ "e" (["-","+"])? (["0"-"9"])+ (["f","l"])? > +| < FLOATTWO : ["0"-"9"](<DECIMALDIGIT>)* "e" (["-","+"])? (<DECIMALDIGIT>)+ (["f","l"])? > } TOKEN : { + < #CHRPREF : <STRPREF>> +| < CHARACTER : <CHRPREF> + "'" ( ( ~["'","\\","\r","\n"] ) | ( "\\" ( ~["\n","\r"] ) ) )* "'" > - < CHARACTER : ("L")? "'" ( ( ~["'","\\","\r","\n"] ) | ( "\\" ( ~["\n","\r"] ) ) )* "'" > +| < #STRPREF : ("L" | "u" | "U" | "u8")? > +| < STRING : <STRPREF> + "\"" ( ( ~["\"","\\","\r","\n"] ) | ( "\\" ( ~["\n","\r"] | "\n" | "\r\n" ) ) )* "\"" > -| < STRING : ("L")? "\"" ( ( ~["\"","\\","\r","\n"] ) | ( "\\" ( ~["\n","\r"] | "\n" | "\r\n" ) ) )* "\"" > +} -| < RSTRING : "R\"(" ( ~[")"] | ( ")" ~["\""] ) )* ")\"" > +// Raw C++11 string literal support +// https://en.cppreference.com/w/cpp/language/string_literal +TOKEN : +{ + < RSTRING : <STRPREF> "R\"" > + { + StringBuilder sb = new StringBuilder(16); + + // delim ------+ + // vvv + // Matching R"...(...)..." + // ^ + for (;;) { + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return; } + if (curChar == '(') break; + sb.append(curChar); + } + final String delim = sb.toString(); + +rstringbody: + // Matching R"...(...)..." + // ^ + for (;;) { + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return; } + if (curChar == ')') { + // delim --------------+ + // vvv + // Matching R"...(...)..." + // ^^^ + for (int i = 0; i < delim.length(); i++) { + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return; } + if (delim.charAt(i) != curChar) { + input_stream.backup(1); + continue rstringbody; + } + } + // Matching R"...(...)..." + // ^ + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return; } + if (curChar != '"') { + input_stream.backup(1); + continue rstringbody; + } + break; + } + } + // Setting final token image + matchedToken.image = input_stream.GetImage(); + matchedToken.endLine = input_stream.getEndLine(); + matchedToken.endColumn = input_stream.getEndColumn(); + } } TOKEN : diff --git a/pmd-cpp/src/test/java/net/sourceforge/pmd/cpd/CPPTokenizerTest.java b/pmd-cpp/src/test/java/net/sourceforge/pmd/cpd/CPPTokenizerTest.java index 4bffb5208d..c8caeb354e 100644 --- a/pmd-cpp/src/test/java/net/sourceforge/pmd/cpd/CPPTokenizerTest.java +++ b/pmd-cpp/src/test/java/net/sourceforge/pmd/cpd/CPPTokenizerTest.java @@ -159,6 +159,86 @@ public class CPPTokenizerTest { tokenizer.tokenize(code, new Tokens()); } + public void testStringPrefix(String code, String expToken, int tokenIndex, int expNoTokens) { + final Tokens tokens = parse(code); + final TokenEntry token = tokens.getTokens().get(tokenIndex); + assertEquals(expNoTokens, tokens.size()); + assertEquals(expToken, token.toString()); + } + + public void testCharacterPrefix(String code, String expToken) { + testStringPrefix(code, expToken, 3, 6); + } + + public void testStringPrefix(String code, String expToken) { + testStringPrefix(code, expToken, 5, 8); + } + + @Test + public void testCharacterPrefixNoPrefix() { + testCharacterPrefix("char a = '\\x30';", "'\\x30'"); + } + + @Test + public void testCharacterPrefixWideCharacter() { + testCharacterPrefix("wchar_t b = L'\\xFFEF';", "L'\\xFFEF'"); + } + + @Test + public void testCharacterPrefixChar16() { + testCharacterPrefix("char16_t c = u'\\u00F6';", "u'\\u00F6'"); + } + + @Test + public void testCharacterPrefixChar32() { + testCharacterPrefix("char32_t d = U'\\U0010FFFF';", "U'\\U0010FFFF'"); + } + + @Test + public void testStringPrefixNoPrefix() { + testStringPrefix("char A[] = \"Hello\\x0A\";", "\"Hello\\x0A\""); + } + + @Test + public void testStringPrefixWideString() { + testStringPrefix("wchar_t B[] = L\"Hell\\xF6\\x0A\";", "L\"Hell\\xF6\\x0A\""); + } + + @Test + public void testStringPrefixChar16() { + testStringPrefix("char16_t C[] = u\"Hell\\u00F6\";", "u\"Hell\\u00F6\""); + } + + @Test + public void testStringPrefixChar32() { + testStringPrefix("char32_t D[] = U\"Hell\\U000000F6\\U0010FFFF\";", "U\"Hell\\U000000F6\\U0010FFFF\""); + } + + @Test + public void testStringPrefixUtf8() { + testStringPrefix("auto E[] = u8\"\\u00F6\\U0010FFFF\";", "u8\"\\u00F6\\U0010FFFF\""); + } + + @Test + public void testRawStringLiterals() throws IOException { + final String code = IOUtils.toString(CPPTokenizerTest.class.getResourceAsStream("cpp/issue-1784.cpp"), StandardCharsets.UTF_8); + Tokens tokens = parse(code); + assertTrue(TokenEntry.getEOF() != tokens.getTokens().get(0)); + assertEquals(16, tokens.size()); + } + + @Test + public void testDigitSeparators() { + final String code = "auto integer_literal = 1'000'000;" + PMD.EOL + + "auto floating_point_literal = 0.000'015'3;" + PMD.EOL + + "auto hex_literal = 0x0F00'abcd'6f3d;" + PMD.EOL + + "auto silly_example = 1'0'0'000'00;"; + Tokens tokens = parse(code); + assertTrue(TokenEntry.getEOF() != tokens.getTokens().get(0)); + assertEquals("1'000'000", tokens.getTokens().get(3).toString()); + assertEquals(21, tokens.size()); + } + private Tokens parse(String snippet) { try { return parse(snippet, false, new Tokens()); diff --git a/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1559.cpp b/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1559.cpp index 010ec09fc6..cdf47c53e6 100644 --- a/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1559.cpp +++ b/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1559.cpp @@ -4,7 +4,7 @@ namespace ABC { #ifdef USE_QT - const char* perPixelQml = R"QML( + const char* perPixelQml = "QML( // provoking a parser error )QML"; } } diff --git a/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1784.cpp b/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1784.cpp new file mode 100644 index 0000000000..29d644f449 --- /dev/null +++ b/pmd-cpp/src/test/resources/net/sourceforge/pmd/cpd/cpp/issue-1784.cpp @@ -0,0 +1,12 @@ +namespace ABC +{ + namespace DEF + { + +#ifdef USE_QT + const char* perPixelQml = R"QML( + )NOTTHEND"; +)QML"; + } +} +#endif // USE_QT diff --git a/pmd-dart/src/main/antlr4/net/sourceforge/pmd/lang/dart/antlr4/Dart2.g4 b/pmd-dart/src/main/antlr4/net/sourceforge/pmd/lang/dart/antlr4/Dart2.g4 index aae6073e6a..7d8793edab 100644 --- a/pmd-dart/src/main/antlr4/net/sourceforge/pmd/lang/dart/antlr4/Dart2.g4 +++ b/pmd-dart/src/main/antlr4/net/sourceforge/pmd/lang/dart/antlr4/Dart2.g4 @@ -340,57 +340,49 @@ booleanLiteral | 'false' ; -//stringLiteral: (MultilineString | SingleLineString)+; -stringLiteral: SingleLineString; -//stringLiteral: SingleLineString; +stringLiteral: (MultiLineString | SingleLineString)+; + SingleLineString - : '"' (~["] | '\\"')* '"' - | '\'' (~['] | '\\\'')* '\'' -// | 'r\'' (~('\'' | NEWLINE))* '\'' // TODO -// | 'r"' (~('\'' | NEWLINE))* '"' + : '"' StringContentDQ* '"' + | '\'' StringContentSQ* '\'' + | 'r\'' (~('\'' | '\n' | '\r'))* '\'' + | 'r"' (~('"' | '\n' | '\r'))* '"' ; -//MultilineString -// : '"""' StringContentTDQ* '"""' -// | '\'\'\'' StringContentTDQ* '\'\'\'' -// | 'r"""' (~'"""')* '"""' // TODO -// | 'r\'\'\'' (~'\'\'\'')* '\'\'\'' -// ; -//StringContentSQ: .;// TODO -//StringContentTDQ: .;// TODO fragment -ESCAPE_SEQUENCE - : '\\n' - | '\\r' - | '\\f' - | '\\b' - | '\\t' - | '\\v' - | '\\x' HEX_DIGIT HEX_DIGIT - | '\\u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT - | '\\u{' HEX_DIGIT_SEQUENCE '}' +StringContentDQ + : ~('\\' | '"' /*| '$'*/ | '\n' | '\r') + | '\\' ~('\n' | '\r') + //| stringInterpolation ; + fragment -HEX_DIGIT_SEQUENCE - : HEX_DIGIT HEX_DIGIT? HEX_DIGIT? - HEX_DIGIT? HEX_DIGIT? HEX_DIGIT? +StringContentSQ + : ~('\\' | '\'' /*| '$'*/ | '\n' | '\r') + | '\\' ~('\n' | '\r') + //| stringInterpolation ; -/*TODO -<stringContentDQ> ::= \~{}( `\\' | `"' | `$' | <NEWLINE> ) - \alt `\\' \~{}( <NEWLINE> ) - \alt <stringInterpolation> -<stringContentSQ> ::= \~{}( `\\' | `\'' | `$' | <NEWLINE> ) - \alt `\\' \~{}( <NEWLINE> ) - \alt <stringInterpolation> -<stringContentTDQ> ::= \~{}( `\\' | `"""' | `$') - \alt `\\' \~{}( <NEWLINE> ) - \alt <stringInterpolation> +MultiLineString + : '"""' StringContentTDQ* '"""' + | '\'\'\'' StringContentTSQ* '\'\'\'' + | 'r"""' (~'"' | '"' ~'"' | '""' ~'"')* '"""' + | 'r\'\'\'' (~'\'' | '\'' ~'\'' | '\'\'' ~'\'')* '\'\'\'' + ; + +fragment +StringContentTDQ + : ~('\\' | '"' /*| '$'*/) + | '"' ~'"' | '""' ~'"' + //| stringInterpolation + ; + +fragment StringContentTSQ + : ~('\\' | '\'' /*| '$'*/) + | '\'' ~'\'' | '\'\'' ~'\'' + //| stringInterpolation + ; -<stringContentTSQ> ::= \~{}( `\\' | `\'\'\'' | `$') - \alt `\\' \~{}( <NEWLINE> ) - \alt <stringInterpolation> -*/ NEWLINE : '\n' | '\r' diff --git a/pmd-dart/src/test/java/net/sourceforge/pmd/cpd/DartTokenizerTest.java b/pmd-dart/src/test/java/net/sourceforge/pmd/cpd/DartTokenizerTest.java index 919001cd09..dc1e125322 100644 --- a/pmd-dart/src/test/java/net/sourceforge/pmd/cpd/DartTokenizerTest.java +++ b/pmd-dart/src/test/java/net/sourceforge/pmd/cpd/DartTokenizerTest.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.cpd; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; @@ -31,9 +32,16 @@ public class DartTokenizerTest extends AbstractTokenizerTest { public static Collection<Object[]> data() { return Arrays.asList( new Object[] { "comment.dart", 5 }, + new Object[] { "escape_sequences.dart", 13 }, + new Object[] { "escaped_backslash.dart", 14 }, new Object[] { "escaped_string.dart", 17 }, new Object[] { "increment.dart", 185 }, - new Object[] { "imports.dart", 1 } + new Object[] { "imports.dart", 1 }, + new Object[] { "regex.dart", 13 }, + new Object[] { "regex2.dart", 13 }, + new Object[] { "regex3.dart", 13 }, + new Object[] { "string_with_backslashes.dart", 9 }, + new Object[] { "string_multiline.dart", 13 } ); } @@ -46,7 +54,7 @@ public class DartTokenizerTest extends AbstractTokenizerTest { @Override public String getSampleCode() throws IOException { - return IOUtils.toString(DartTokenizer.class.getResourceAsStream(this.filename)); + return IOUtils.toString(DartTokenizer.class.getResourceAsStream(this.filename), StandardCharsets.UTF_8); } @Test diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/escape_sequences.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/escape_sequences.dart new file mode 100644 index 0000000000..7d70500426 --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/escape_sequences.dart @@ -0,0 +1,3 @@ +var newline = '\n'; +var dollar = '$'; +var escaped_dollar = "\$"; \ No newline at end of file diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/escaped_backslash.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/escaped_backslash.dart new file mode 100644 index 0000000000..ee9c4a6419 --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/escaped_backslash.dart @@ -0,0 +1,2 @@ +var separator = '\\'; +var separators = const ['/', '\\']; \ No newline at end of file diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex.dart new file mode 100644 index 0000000000..14f45f2955 --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex.dart @@ -0,0 +1,3 @@ +class MyClass { + final regex = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$'); +} diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex2.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex2.dart new file mode 100644 index 0000000000..57decc436c --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex2.dart @@ -0,0 +1,3 @@ +class MyClass { + final regex = new RegExp(r"(^[a-zA-Z][-+.a-zA-Z\d]*://|[^/])$"); +} diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex3.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex3.dart new file mode 100644 index 0000000000..c5de8271b7 --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/regex3.dart @@ -0,0 +1,3 @@ +class MyClass { + final regex = new RegExp(r'''[ \t\r\n"'\\/]'''); +} diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/string_multiline.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/string_multiline.dart new file mode 100644 index 0000000000..a9ae19668e --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/string_multiline.dart @@ -0,0 +1,9 @@ +class MyClass { + var s1 = ''' +You can create +multi-line strings like this one. +'''; + + var s2 = """This is also a +multi-line string."""; +} diff --git a/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/string_with_backslashes.dart b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/string_with_backslashes.dart new file mode 100644 index 0000000000..bc7168870c --- /dev/null +++ b/pmd-dart/src/test/resources/net/sourceforge/pmd/cpd/string_with_backslashes.dart @@ -0,0 +1,3 @@ +class MyClass { + final stringWithBackslashes = "Escaping\ spaces\ should work"; +} diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 6350871018..63c5e0b7f7 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -127,6 +127,11 @@ <artifactId>pmd-groovy</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>net.sourceforge.pmd</groupId> + <artifactId>pmd-lua</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>net.sourceforge.pmd</groupId> <artifactId>pmd-java</artifactId> diff --git a/pmd-dist/src/main/resources/assemblies/pmd-src.xml b/pmd-dist/src/main/resources/assemblies/pmd-src.xml index 8c8820d03c..a049343e8a 100644 --- a/pmd-dist/src/main/resources/assemblies/pmd-src.xml +++ b/pmd-dist/src/main/resources/assemblies/pmd-src.xml @@ -11,22 +11,36 @@ <fileSets> <fileSet> - <useDefaultExcludes>true</useDefaultExcludes> + <useDefaultExcludes>false</useDefaultExcludes> <directory>${project.basedir}/..</directory> <outputDirectory>/</outputDirectory> <excludes> + <exclude>.git/**</exclude> <exclude>**/target/**</exclude> <exclude>**/bin/**</exclude> - <exclude>**/.settings</exclude> + + <exclude>**/.settings/**</exclude> <exclude>**/.project</exclude> <exclude>**/.classpath</exclude> <exclude>**/.checkstyle</exclude> <exclude>**/.pmd</exclude> + <exclude>**/.pmdruleset.xml</exclude> <exclude>**/.ruleset</exclude> - <exclude>**/.git</exclude> - <exclude>**/.travis/secrets.tar</exclude> - <exclude>**/.travis/id_rsa</exclude> - <exclude>**/.travis/*.gpg</exclude> + <exclude>**/.idea/**</exclude> + <exclude>**/*.iml</exclude> + + <exclude>.travis/secrets.tar</exclude> + <exclude>.travis/id_rsa</exclude> + <exclude>.travis/*.gpg</exclude> + + <exclude>.bundle/**</exclude> + <exclude>vendor/**</exclude> + <exclude>Gemfile.lock</exclude> + <exclude>docs/.bundle/**</exclude> + <exclude>docs/vendor/**</exclude> + <exclude>docs/_site/**</exclude> + + <exclude>pmd-core/dependency-reduced-pom.xml</exclude> </excludes> <directoryMode>0755</directoryMode> <fileMode>0644</fileMode> diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java index 5da0b5f5a1..7404b8bff9 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java @@ -95,7 +95,7 @@ public class BinaryDistributionIT { ExecutionResult result; result = PMDExecutor.runPMD(tempDir, "-h"); - result.assertExecutionResult(1, "apex, ecmascript, java, jsp, plsql, pom, vf, vm, wsdl, xml, xsl"); + result.assertExecutionResult(0, "apex, ecmascript, java, jsp, plsql, pom, swift, vf, vm, wsdl, xml, xsl"); result = PMDExecutor.runPMDRules(tempDir, srcDir, "src/test/resources/rulesets/sample-ruleset.xml"); result.assertExecutionResult(4, "JumbledIncrementer.java:8:"); @@ -111,8 +111,7 @@ public class BinaryDistributionIT { ExecutionResult result; result = CpdExecutor.runCpd(tempDir, "-h"); - - result.assertExecutionResult(1, "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, go, groovy, java, jsp, kotlin, matlab, objectivec, perl, php, plsql, python, ruby, scala, swift, vf]"); + result.assertExecutionResult(0, "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, go, groovy, java, jsp, kotlin, lua, matlab, objectivec, perl, php, plsql, python, ruby, scala, swift, vf]"); result = CpdExecutor.runCpd(tempDir, "--minimum-tokens", "10", "--format", "text", "--files", srcDir); result.assertExecutionResult(4, "Found a 10 line (55 tokens) duplication in the following files:"); diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/SourceDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/SourceDistributionIT.java index 0564cb0433..d483644813 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/SourceDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/SourceDistributionIT.java @@ -7,18 +7,39 @@ package net.sourceforge.pmd.it; import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import org.junit.Assert; import org.junit.Test; import net.sourceforge.pmd.PMDVersion; public class SourceDistributionIT { + private static final String BASE_PATH = "pmd-src-" + PMDVersion.VERSION; + private static final Pattern GPG_PATTERN = Pattern.compile(Pattern.quote(BASE_PATH + "/.travis/") + ".+\\.[gG][pP][gG]"); + private File getSourceDistribution() { - return new File(".", "target/pmd-src-" + PMDVersion.VERSION + ".zip"); + return new File(".", "target/" + BASE_PATH + ".zip"); } @Test public void testFileExistence() { assertTrue(getSourceDistribution().exists()); } + + @Test + public void verifyExclusions() throws Exception { + Set<String> exclusions = new HashSet<>(); + exclusions.add(BASE_PATH + "/.travis/secrets.tar"); + exclusions.add(BASE_PATH + "/.travis/id_rsa"); + List<String> files = ZipFileExtractor.readZipFile(getSourceDistribution().toPath()); + + for (String file : files) { + Assert.assertFalse("File " + file + " must not be included", exclusions.contains(file) + || GPG_PATTERN.matcher(file).matches()); + } + } } diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/ZipFileExtractor.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/ZipFileExtractor.java index 0e024dda14..d31051fd04 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/ZipFileExtractor.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/ZipFileExtractor.java @@ -11,7 +11,9 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipFile; @@ -59,4 +61,25 @@ public class ZipFileExtractor { zip.close(); } } + + /** + * Compiles a list of all the files/directories contained in the given zip file. + * @param zipPath the zip file to look into + * @return list of all entries + * @throws Exception if any error happens during read of the zip file + */ + public static List<String> readZipFile(Path zipPath) throws Exception { + List<String> result = new ArrayList<>(); + ZipFile zip = new ZipFile(zipPath.toFile()); + try { + Enumeration<ZipArchiveEntry> entries = zip.getEntries(); + while (entries.hasMoreElements()) { + ZipArchiveEntry entry = entries.nextElement(); + result.add(entry.getName()); + } + } finally { + zip.close(); + } + return result; + } } diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index a32ffb5d99..c634b441ed 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -44,6 +44,19 @@ </arguments> </configuration> </execution> + <execution> + <id>check-rule-tags</id> + <goals> + <goal>java</goal> + </goals> + <phase>verify</phase> + <configuration> + <mainClass>net.sourceforge.pmd.docs.RuleTagChecker</mainClass> + <arguments> + <argument>${project.basedir}</argument> + </arguments> + </configuration> + </execution> </executions> </plugin> </plugins> diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/DeadLinksChecker.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/DeadLinksChecker.java index 75e2aff439..1ab25d40a6 100644 --- a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/DeadLinksChecker.java +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/DeadLinksChecker.java @@ -30,6 +30,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; +import java.util.concurrent.RunnableFuture; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -48,7 +49,7 @@ public class DeadLinksChecker { private static final boolean CHECK_EXTERNAL_LINKS = Boolean.parseBoolean(System.getProperty(CHECK_EXTERNAL_LINKS_PROPERTY)); // Markdown-Link: something in []'s followed by something in ()'s - private static final Pattern LOCAL_LINK_PATTERN = Pattern.compile("\\[.*?\\]\\((.*?)\\)"); + private static final Pattern LOCAL_LINK_PATTERN = Pattern.compile("(!)?\\[.*?]\\((.*?)\\)"); // Markdown permalink-header and captions private static final Pattern MD_HEADER_PERMALINK = Pattern.compile("permalink:\\s*(.*)"); @@ -77,9 +78,11 @@ public class DeadLinksChecker { public void checkDeadLinks(Path rootDirectory) { final Path pagesDirectory = rootDirectory.resolve("docs/pages"); + final Path docsDirectory = rootDirectory.resolve("docs"); if (!Files.isDirectory(pagesDirectory)) { - LOG.warning("can't check for dead links, didn't find \"pages\" directory at: " + pagesDirectory); + // docsDirectory is implicitly checked by this statement too + LOG.severe("can't check for dead links, didn't find \"pages\" directory at: " + pagesDirectory); System.exit(1); } @@ -110,10 +113,14 @@ public class DeadLinksChecker { linkCheck: while (matcher.find()) { final String linkText = matcher.group(); - final String linkTarget = matcher.group(1).replaceAll("^/+", ""); // remove the leading "/" + final boolean isImageLink = matcher.group(1) != null; + final String linkTarget = matcher.group(2); boolean linkOk; - if (linkTarget.startsWith(LOCAL_FILE_PREFIX)) { + if (linkTarget.charAt(0) == '/') { + // links must never start with / - they must be relative or start with https?//... + linkOk = false; + } else if (linkTarget.startsWith(LOCAL_FILE_PREFIX)) { String localLinkPart = linkTarget.substring(LOCAL_FILE_PREFIX.length()); if (localLinkPart.contains("#")) { localLinkPart = localLinkPart.substring(0, localLinkPart.indexOf('#')); @@ -164,11 +171,20 @@ public class DeadLinksChecker { continue; } - linkOk = linkTarget.isEmpty() || htmlPages.contains(linkTarget); + if (isImageLink) { + Path localResource = docsDirectory.resolve(linkTarget); + linkOk = Files.exists(localResource); + } else { + linkOk = linkTarget.isEmpty() || htmlPages.contains(linkTarget); + } } if (!linkOk) { - addDeadLink(fileToDeadLinks, mdFile, new FutureTask<>(() -> String.format("%8d: %s", lineNo, linkText))); + RunnableFuture<String> futureTask = new FutureTask<>(() -> String.format("%8d: %s", lineNo, linkText)); + // execute this task immediately in this thread. + // External links are checked by another executor and don't end up here. + futureTask.run(); + addDeadLink(fileToDeadLinks, mdFile, futureTask); } } } @@ -322,6 +338,12 @@ public class DeadLinksChecker { public static void main(String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Wrong arguments!"); + System.err.println(); + System.err.println("java " + DeadLinksChecker.class.getSimpleName() + " <project base directory>"); + System.exit(1); + } final Path rootDirectory = Paths.get(args[0]).resolve("..").toRealPath(); DeadLinksChecker deadLinksChecker = new DeadLinksChecker(); diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java index acf13282e6..8b6f68f16a 100644 --- a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleDocGenerator.java @@ -422,7 +422,7 @@ public class RuleDocGenerator { lines.add(""); for (String example : rule.getExamples()) { lines.add("``` " + mapLanguageForHighlighting(languageTersename)); - lines.addAll(toLines(StringUtils.stripToEmpty(example))); + lines.addAll(toLines("{%raw%}" + StringUtils.stripToEmpty(example) + "{%endraw%}")); lines.add("```"); lines.add(""); } diff --git a/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleTagChecker.java b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleTagChecker.java new file mode 100644 index 0000000000..55603bace4 --- /dev/null +++ b/pmd-doc/src/main/java/net/sourceforge/pmd/docs/RuleTagChecker.java @@ -0,0 +1,139 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.docs; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RuleTagChecker { + private static final Logger LOG = Logger.getLogger(DeadLinksChecker.class.getName()); + + private static final Pattern RULE_TAG = Pattern.compile("\\{%\\s*rule\\s+\"(.*?)\"\\s*"); + private static final Pattern RULE_REFERENCE = Pattern.compile("(\\w+)\\/(\\w+)\\/(\\w+)"); + + private final Path pagesDirectory; + private final List<String> issues = new ArrayList<>(); + private final Map<Path, Set<String>> rulesCache = new HashMap<>(); + + public RuleTagChecker(Path rootDirectory) { + final Path pagesDirectory = rootDirectory.resolve("docs/pages"); + + if (!Files.isDirectory(pagesDirectory)) { + LOG.severe("can't check rule tags, didn't find \"docs/pages\" directory at: " + pagesDirectory); + System.exit(1); + } + + this.pagesDirectory = pagesDirectory; + } + + public List<String> check() throws IOException { + Files.walkFileTree(pagesDirectory, new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + checkFile(file); + return super.visitFile(file, attrs); + } + }); + return issues; + } + + private void checkFile(Path file) throws IOException { + if (file == null || !file.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".md")) { + return; + } + + LOG.finer("Checking " + file); + int lineNo = 0; + for (String line : Files.readAllLines(file, StandardCharsets.UTF_8)) { + lineNo++; + Matcher ruleTagMatcher = RULE_TAG.matcher(line); + while (ruleTagMatcher.find()) { + String ruleReference = ruleTagMatcher.group(1); + int pos = ruleTagMatcher.end(); + if (line.charAt(pos) != '%' || line.charAt(pos + 1) != '}') { + addIssue(file, lineNo, "Rule tag for " + ruleReference + " is not closed properly"); + } else if (!ruleReferenceTargetExists(ruleReference)) { + addIssue(file, lineNo, "Rule " + ruleReference + " is not found"); + } + } + } + } + + private boolean ruleReferenceTargetExists(String ruleReference) { + Matcher ruleRefMatcher = RULE_REFERENCE.matcher(ruleReference); + if (ruleRefMatcher.matches()) { + String language = ruleRefMatcher.group(1); + String category = ruleRefMatcher.group(2); + String rule = ruleRefMatcher.group(3); + + Path ruleDocPage = pagesDirectory.resolve("pmd/rules/" + language + "/" + category.toLowerCase(Locale.ROOT) + ".md"); + Set<String> rules = getRules(ruleDocPage); + return rules.contains(rule); + } + return false; + } + + private Set<String> getRules(Path ruleDocPage) { + Set<String> result = rulesCache.get(ruleDocPage); + + if (result == null) { + result = new HashSet<>(); + try { + for (String line : Files.readAllLines(ruleDocPage, StandardCharsets.UTF_8)) { + if (line.startsWith("## ")) { + result.add(line.substring(3)); + } + rulesCache.put(ruleDocPage, result); + } + } catch (NoSuchFileException e) { + LOG.warning("File " + ruleDocPage + " not found."); + } catch (IOException e) { + LOG.log(Level.SEVERE, "Unable to read rules from " + ruleDocPage, e); + } + } + + return result; + } + + private void addIssue(Path file, int lineNo, String message) { + issues.add(String.format("%s:%2d: %s", pagesDirectory.relativize(file).toString(), lineNo, message)); + } + + public static void main(String[] args) throws IOException { + if (args.length != 1) { + System.err.println("Wrong arguments!"); + System.err.println(); + System.err.println("java " + RuleTagChecker.class.getSimpleName() + " <project base directory>"); + System.exit(1); + } + final Path rootDirectory = Paths.get(args[0]).resolve("..").toRealPath(); + + RuleTagChecker ruleTagChecker = new RuleTagChecker(rootDirectory); + List<String> issues = ruleTagChecker.check(); + + if (!issues.isEmpty()) { + issues.forEach(System.err::println); + throw new AssertionError("Wrong rule tags detected"); + } + } +} diff --git a/pmd-doc/src/test/java/net/sourceforge/pmd/docs/RuleTagCheckerTest.java b/pmd-doc/src/test/java/net/sourceforge/pmd/docs/RuleTagCheckerTest.java new file mode 100644 index 0000000000..3b9a6fc777 --- /dev/null +++ b/pmd-doc/src/test/java/net/sourceforge/pmd/docs/RuleTagCheckerTest.java @@ -0,0 +1,29 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + + +package net.sourceforge.pmd.docs; + +import java.nio.file.FileSystems; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +public class RuleTagCheckerTest { + + @Test + public void testAllChecks() throws Exception { + RuleTagChecker checker = new RuleTagChecker(FileSystems.getDefault().getPath("src/test/resources/ruletagchecker")); + List<String> issues = checker.check(); + + Assert.assertEquals(3, issues.size()); + Assert.assertEquals("ruletag-examples.md: 8: Rule tag for java/bestpractices/AvoidPrintStackTrace is not closed properly", + issues.get(0)); + Assert.assertEquals("ruletag-examples.md:10: Rule java/notexistingcategory/AvoidPrintStackTrace is not found", + issues.get(1)); + Assert.assertEquals("ruletag-examples.md:12: Rule java/bestpractices/NotExistingRule is not found", + issues.get(2)); + } +} diff --git a/pmd-doc/src/test/resources/expected/sample.md b/pmd-doc/src/test/resources/expected/sample.md index 866bb6815c..79b91c61a8 100644 --- a/pmd-doc/src/test/resources/expected/sample.md +++ b/pmd-doc/src/test/resources/expected/sample.md @@ -50,7 +50,7 @@ Avoid jumbled loop incrementers - its usually a mistake, and is confusing even i **Example(s):** ``` java -public class JumbledIncrementerRule1 { +{%raw%}public class JumbledIncrementerRule1 { public void foo() { for (int i = 0; i < 10; i++) { // only references 'i' for (int k = 0; k < 20; i++) { // references both 'i' and 'k' @@ -58,7 +58,7 @@ public class JumbledIncrementerRule1 { } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -123,7 +123,7 @@ Avoid jumbled loop incrementers - its usually a mistake, and is confusing even i **Example(s):** ``` java -public class JumbledIncrementerRule1 { +{%raw%}public class JumbledIncrementerRule1 { public void foo() { for (int i = 0; i < 10; i++) { // only references 'i' for (int k = 0; k < 20; i++) { // references both 'i' and 'k' @@ -131,7 +131,7 @@ public class JumbledIncrementerRule1 { } } } -} +}{%endraw%} ``` **Use this rule by referencing it:** @@ -162,7 +162,7 @@ Third paragraph. **Example(s):** ``` java -public class Bar { // poor, missing a hashcode() method +{%raw%}public class Bar { // poor, missing a hashcode() method public boolean equals(Object o) { // do some comparison } @@ -182,6 +182,13 @@ public class Foo { // perfect, both methods provided // return some hash value } } + +// A sample with double braces (#1898) +public class Foo { + public List<String> bar() { + return new ArrayList<String>(){{ addAll("a","b","c"); }}; + } +}{%endraw%} ``` **Use this rule by referencing it:** @@ -214,7 +221,7 @@ Avoid jumbled loop incrementers - its usually a mistake, and is confusing even i **Example(s):** ``` java -public class JumbledIncrementerRule1 { +{%raw%}public class JumbledIncrementerRule1 { public void foo() { for (int i = 0; i < 10; i++) { // only references 'i' for (int k = 0; k < 20; i++) { // references both 'i' and 'k' @@ -222,7 +229,7 @@ public class JumbledIncrementerRule1 { } } } -} +}{%endraw%} ``` **This rule has the following properties:** @@ -312,14 +319,14 @@ if (0 > 1 && 0 < 1) { **Example(s):** ``` java -public class Bar { +{%raw%}public class Bar { public boolean foo() { if (0 < 1) { // less-than should not be escaped in markdown String s = "abc"; // the quotes should not be escaped in markdown. } } // <script>alert('XSS');</script> -} +}{%endraw%} ``` **This rule has the following properties:** diff --git a/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml b/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml index aa49c9a6f2..44e2bb76fb 100644 --- a/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml +++ b/pmd-doc/src/test/resources/rulesets/ruledoctest/sample.xml @@ -123,6 +123,13 @@ public class Foo { // perfect, both methods provided // return some hash value } } + +// A sample with double braces (#1898) +public class Foo { + public List<String> bar() { + return new ArrayList<String>(){{ addAll("a","b","c"); }}; + } +} ]]> </example> </rule> diff --git a/pmd-doc/src/test/resources/ruletagchecker/docs/pages/pmd/rules/java/bestpractices.md b/pmd-doc/src/test/resources/ruletagchecker/docs/pages/pmd/rules/java/bestpractices.md new file mode 100644 index 0000000000..7de208cf28 --- /dev/null +++ b/pmd-doc/src/test/resources/ruletagchecker/docs/pages/pmd/rules/java/bestpractices.md @@ -0,0 +1,4 @@ + +## AvoidPrintStackTrace + +Sample rule doc for tests. diff --git a/pmd-doc/src/test/resources/ruletagchecker/docs/pages/ruletag-examples.md b/pmd-doc/src/test/resources/ruletagchecker/docs/pages/ruletag-examples.md new file mode 100644 index 0000000000..89bdeb6a01 --- /dev/null +++ b/pmd-doc/src/test/resources/ruletagchecker/docs/pages/ruletag-examples.md @@ -0,0 +1,12 @@ +--- +title: Sample Page with rule tags +permalink: rule_tag_samples.html +--- + +This is a link to the rule AvoidPrintStackTrace: {% rule "java/bestpractices/AvoidPrintStackTrace" %}. + +This is the same link, but the rule tag is not closed properly: {% rule "java/bestpractices/AvoidPrintStackTrace" %). + +Now this is link to a rule inside a category, which doesn't exist: {% rule "java/notexistingcategory/AvoidPrintStackTrace" %}. + +This is link to a rule, which doesn't exist: {% rule "java/bestpractices/NotExistingRule" %}. diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index 364d997e99..6e7ac5c3fa 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -1,4 +1,7 @@ /** + * Fix #1848 Local classes should preserve their modifiers + * Clément Fournier 05/2019 + *==================================================================== * Add support for Java 12 switch expressions and switch rules. * Andreas Dangel, Clément Fournier 03/2019 *==================================================================== @@ -442,6 +445,17 @@ public class JavaParser { return getToken(1).kind == IDENTIFIER && getToken(1).image.equals(keyword); } + private boolean shouldStartStatementInSwitch() { + switch (getToken(1).kind) { + case _DEFAULT: + case CASE: + case RBRACE: + return false; + default: + return true; + } + } + public Map<Integer, String> getSuppressMap() { return token_source.getSuppressMap(); } @@ -1606,17 +1620,27 @@ ASTCompilationUnit CompilationUnit() : { [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ( EmptyStatement() )* ] ( ImportDeclaration() ( EmptyStatement() )* )* - ( LOOKAHEAD(2) TypeDeclaration() ( EmptyStatement() )* )* - [ LOOKAHEAD({isKeyword("open") || isKeyword("module") || getToken(1).kind == AT}) ModuleDeclaration() ( EmptyStatement() )* ] + // the module decl lookahead needs to be before the type declaration branch, + // looking for annotations + "open" | "module" will fail faster if it's *not* + // a module (most common case) + [ LOOKAHEAD(ModuleDeclLahead()) ModuleDeclaration() ( EmptyStatement() )* ] + ( TypeDeclaration() ( EmptyStatement() )* )* ( < "\u001a" > )? - ( < "~[]" > )? + ( < "~[]" > )? // what's this for? Do you mean ( < ~[] > )*, i.e. "any character"? <EOF> + { + jjtThis.setComments(token_source.comments); + return jjtThis; + } +} + +private void ModuleDeclLahead() #void: +{} { - jjtThis.setComments(token_source.comments); - return jjtThis; -} + (Annotation())* LOOKAHEAD({isKeyword("open") || isKeyword("module")}) <IDENTIFIER> } + void PackageDeclaration() : {} { @@ -1688,8 +1712,7 @@ void ClassOrInterfaceDeclaration(int modifiers): inInterface = false; } { - ( /* See note about this optional final modifier in BlockStatement */ - ["final"|"abstract"] "class" | "interface" { jjtThis.setInterface(); inInterface = true; } ) + ( "class" | "interface" { jjtThis.setInterface(); inInterface = true; } ) t=<IDENTIFIER> { checkForBadTypeIdentifierUsage(t.image); jjtThis.setImage(t.image); } [ TypeParameters() ] [ ExtendsList() ] @@ -2413,13 +2436,26 @@ void BlockStatement(): | Statement() | - /* - TODO: Seems like we should be discarding the "final" - after using it in the lookahead; I added a ["final|abstract"] inside - ClassOrInterfaceDeclaration, but that seems like a hack that - could break other things... - */ - LOOKAHEAD( (Annotation())* ["final"|"abstract"] "class") (Annotation())* ClassOrInterfaceDeclaration(0) + // we don't need to lookahead further here + // the ambiguity between start of local class and local variable decl + // is already handled in the lookahead guarding LocalVariableDeclaration above. + LocalClassDecl() +} + +void LocalClassDecl() #void: +{int mods = 0;} +{ + // this preserves the modifiers of the local class. + // it allows for modifiers that are forbidden for local classes, + // but anyway we are *not* checking modifiers for incompatibilities + // anywhere else in this grammar (and indeed the production Modifiers + // accepts any modifier explicitly for the purpose of forgiving modifier errors, + // and reporting them later if needed --see its documentation). + + // In particular, it unfortunately allows local class declarations to start + // with a "default" modifier, which introduces an ambiguity with default + // switch labels. This is guarded by a custom lookahead around SwitchLabel + mods=Modifiers() ClassOrInterfaceDeclaration(mods) } /* @@ -2474,7 +2510,11 @@ void SwitchBlock() #void : ( "->" SwitchLabeledRulePart() (SwitchLabeledRule())* | - ":" (LOOKAHEAD(2) SwitchLabel() ":")* (BlockStatement())* (SwitchLabeledStatementGroup())* + ":" (LOOKAHEAD(2) SwitchLabel() ":")* + // the lookahead is to prevent choosing BlockStatement when the token is "default", + // which could happen as local class declarations accept the "default" modifier. + (LOOKAHEAD({shouldStartStatementInSwitch()}) BlockStatement())* + (SwitchLabeledStatementGroup())* ) )? "}" @@ -2502,7 +2542,10 @@ void SwitchLabeledRulePart() #void: void SwitchLabeledStatementGroup() #void: {} { - (LOOKAHEAD(2) SwitchLabel() ":")+ ( BlockStatement() )* + (LOOKAHEAD(2) SwitchLabel() ":")+ + // the lookahead is to prevent choosing BlockStatement when the token is "default", + // which could happen as local class declarations accept the "default" modifier. + (LOOKAHEAD({shouldStartStatementInSwitch()}) BlockStatement() )* } void SwitchLabel() : diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java index c83990377d..74b45439c8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/AbstractJavaHandler.java @@ -125,6 +125,7 @@ public abstract class AbstractJavaHandler extends AbstractPmdLanguageVersionHand }; } + @Deprecated @Override public VisitorStarter getMultifileFacade() { return new VisitorStarter() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java index 92572ed4a3..8f4246a557 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAdditiveExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAdditiveExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an addition operation on two or more values, or string concatenation. * This has a precedence greater than {@link ASTShiftExpression}, and lower @@ -20,10 +21,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTAdditiveExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTAdditiveExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTAdditiveExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java index e3ecbd8573..8932bc9aa3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAllocationExpression.java @@ -1,10 +1,10 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAllocationExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName; @@ -12,17 +12,18 @@ public class ASTAllocationExpression extends AbstractJavaTypeNode implements Jav private JavaTypeQualifiedName qualifiedName; + @InternalApi + @Deprecated public ASTAllocationExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTAllocationExpression(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -61,6 +62,8 @@ public class ASTAllocationExpression extends AbstractJavaTypeNode implements Jav return qualifiedName; } + @InternalApi + @Deprecated public void setQualifiedName(JavaTypeQualifiedName qname) { this.qualifiedName = qname; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java index 0ee092ba5c..c99bc83ec0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAndExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAndExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a non-shortcut boolean AND-expression. * This has a precedence greater than {@link ASTExclusiveOrExpression}, @@ -21,10 +22,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTAndExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTAndExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTAndExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java index df80a76fc4..dffe5c4bf4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAnnotation.java */ package net.sourceforge.pmd.lang.java.ast; @@ -9,6 +8,7 @@ import java.util.Arrays; import java.util.List; import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.annotation.InternalApi; /** @@ -22,19 +22,22 @@ import net.sourceforge.pmd.Rule; * | {@linkplain ASTMarkerAnnotation MarkerAnnotation} * * </pre> - * */ public class ASTAnnotation extends AbstractJavaTypeNode { private static final List<String> UNUSED_RULES - = Arrays.asList("UnusedPrivateField", "UnusedLocalVariable", "UnusedPrivateMethod", "UnusedFormalParameter"); + = Arrays.asList("UnusedPrivateField", "UnusedLocalVariable", "UnusedPrivateMethod", "UnusedFormalParameter"); private static final List<String> SERIAL_RULES = Arrays.asList("BeanMembersShouldSerialize", "MissingSerialVersionUID"); + @InternalApi + @Deprecated public ASTAnnotation(int id) { super(id); } + @InternalApi + @Deprecated public ASTAnnotation(JavaParser p, int id) { super(p, id); } @@ -82,10 +85,10 @@ public class ASTAnnotation extends AbstractJavaTypeNode { if (isSuppressWarnings()) { for (ASTLiteral element : findDescendantsOfType(ASTLiteral.class)) { if (element.hasImageEqualTo("\"PMD\"") || element.hasImageEqualTo("\"PMD." + rule.getName() + "\"") - // Check for standard annotations values - || element.hasImageEqualTo("\"all\"") - || element.hasImageEqualTo("\"serial\"") && SERIAL_RULES.contains(rule.getName()) - || element.hasImageEqualTo("\"unused\"") && UNUSED_RULES.contains(rule.getName())) { + // Check for standard annotations values + || element.hasImageEqualTo("\"all\"") + || element.hasImageEqualTo("\"serial\"") && SERIAL_RULES.contains(rule.getName()) + || element.hasImageEqualTo("\"unused\"") && UNUSED_RULES.contains(rule.getName())) { return true; } } @@ -96,7 +99,8 @@ public class ASTAnnotation extends AbstractJavaTypeNode { private boolean isSuppressWarnings() { - return "SuppressWarnings".equals(getAnnotationName()) || "java.lang.SuppressWarnings".equals(getAnnotationName()); + return "SuppressWarnings".equals(getAnnotationName()) + || "java.lang.SuppressWarnings".equals(getAnnotationName()); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java index 63bd533c65..a2ac31b3df 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationMethodDeclaration.java @@ -1,21 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAnnotationMethodDeclaration.java Version 4.1 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTAnnotationMethodDeclaration extends AbstractMethodLikeNode { + + @InternalApi + @Deprecated public ASTAnnotationMethodDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTAnnotationMethodDeclaration(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -33,7 +37,3 @@ public class ASTAnnotationMethodDeclaration extends AbstractMethodLikeNode { return MethodLikeKind.METHOD; } } -/* - * JavaCC - OriginalChecksum=f6dd440446f8aa5c9c191ae760080ee0 (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeBody.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeBody.java index e593d17d8d..9632f7e457 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeBody.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeBody.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAnnotationTypeBody.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTAnnotationTypeBody extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTAnnotationTypeBody(int id) { super(id); } + @InternalApi + @Deprecated public ASTAnnotationTypeBody(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeDeclaration.java index 09623a4a7f..bcdfb5c841 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeDeclaration.java @@ -1,26 +1,28 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAnnotationTypeDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTAnnotationTypeDeclaration extends AbstractAnyTypeDeclaration { + @InternalApi + @Deprecated public ASTAnnotationTypeDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTAnnotationTypeDeclaration(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeMemberDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeMemberDeclaration.java index 06017fef47..0cca44efe0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeMemberDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotationTypeMemberDeclaration.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAnnotationTypeMemberDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTAnnotationTypeMemberDeclaration extends AbstractTypeBodyDeclaration { + + @InternalApi + @Deprecated public ASTAnnotationTypeMemberDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTAnnotationTypeMemberDeclaration(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java index faab543e27..bd1c189281 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArgumentList.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTArgumentList.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTArgumentList extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTArgumentList(int id) { super(id); } + @InternalApi + @Deprecated public ASTArgumentList(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java index 656f82b8fa..6fcfcd728c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArguments.java @@ -1,15 +1,21 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTArguments.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTArguments extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTArguments(int id) { super(id); } + @InternalApi + @Deprecated public ASTArguments(JavaParser p, int id) { super(p, id); } @@ -21,9 +27,6 @@ public class ASTArguments extends AbstractJavaNode { return this.jjtGetChild(0).jjtGetNumChildren(); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java index 16f5aaab6d..ebade7ec39 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayDimsAndInits.java @@ -1,24 +1,27 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTArrayDimsAndInits.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTArrayDimsAndInits extends AbstractJavaNode implements Dimensionable { + private int arrayDepth; + @InternalApi + @Deprecated public ASTArrayDimsAndInits(int id) { super(id); } + @InternalApi + @Deprecated public ASTArrayDimsAndInits(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayInitializer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayInitializer.java index d1e0ec647f..9f2c3db3c3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayInitializer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTArrayInitializer.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTArrayInitializer.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTArrayInitializer extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTArrayInitializer(int id) { super(id); } + @InternalApi + @Deprecated public ASTArrayInitializer(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java index 06361dbe28..15ad44704c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssertStatement.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAssertStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an {@code assert} statement. * @@ -15,10 +16,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTAssertStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTAssertStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTAssertStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java index bbe4e3cf5f..89ddad02d0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAssignmentOperator.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTAssignmentOperator.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an assignment operator in an {@linkplain ASTExpression assignment expression}. * @@ -15,17 +16,24 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTAssignmentOperator extends AbstractJavaNode { + private boolean isCompound; + @InternalApi + @Deprecated public ASTAssignmentOperator(int id) { super(id); } + @InternalApi + @Deprecated public ASTAssignmentOperator(JavaParser p, int id) { super(p, id); } // TODO this could be determined from the image of the operator, no need to set it in the parser... + @InternalApi + @Deprecated public void setCompound() { isCompound = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java index 0979f1cbc9..040d971aba 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlock.java @@ -1,25 +1,27 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTBlock.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTBlock extends AbstractJavaNode { private boolean containsComment; + @InternalApi + @Deprecated public ASTBlock(int id) { super(id); } + @InternalApi + @Deprecated public ASTBlock(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -36,6 +38,8 @@ public class ASTBlock extends AbstractJavaNode { return this.containsComment; } + @InternalApi + @Deprecated public void setContainsComment() { this.containsComment = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java index a04fc10360..4f675103b7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBlockStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTBlockStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTBlockStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTBlockStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTBlockStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -33,7 +36,7 @@ public class ASTBlockStatement extends AbstractJavaNode { * Tells if this BlockStatement is an allocation statement. This is done by * * @return the result of - * containsDescendantOfType(ASTAllocationExpression.class) + * containsDescendantOfType(ASTAllocationExpression.class) */ public final boolean isAllocation() { return hasDescendantOfType(ASTAllocationExpression.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java index 91427c8837..5677c91199 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBooleanLiteral.java @@ -1,22 +1,29 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTBooleanLiteral.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTBooleanLiteral extends AbstractJavaTypeNode { private boolean isTrue; + @InternalApi + @Deprecated public ASTBooleanLiteral(int id) { super(id); } + @InternalApi + @Deprecated public ASTBooleanLiteral(JavaParser p, int id) { super(p, id); } + @InternalApi + @Deprecated public void setTrue() { isTrue = true; } @@ -25,9 +32,6 @@ public class ASTBooleanLiteral extends AbstractJavaTypeNode { return this.isTrue; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java index 7d44773098..ac2c22655d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTBreakStatement.java @@ -1,15 +1,21 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTBreakStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTBreakStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTBreakStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTBreakStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCastExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCastExpression.java index 5d5db2b4b8..c675456c17 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCastExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCastExpression.java @@ -1,21 +1,29 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTCastExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTCastExpression extends AbstractJavaTypeNode { + private boolean intersectionTypes = false; + @InternalApi + @Deprecated public ASTCastExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTCastExpression(JavaParser p, int id) { super(p, id); } + @InternalApi + @Deprecated public void setIntersectionTypes(boolean intersectionTypes) { this.intersectionTypes = intersectionTypes; } @@ -24,9 +32,6 @@ public class ASTCastExpression extends AbstractJavaTypeNode { return intersectionTypes; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java index 14d671826b..c688f5da1d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCatchStatement.java @@ -1,13 +1,14 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTCatchStatement.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.ArrayList; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Catch statement node. @@ -16,10 +17,15 @@ import java.util.List; * </pre> */ public class ASTCatchStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTCatchStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTCatchStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBody.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBody.java index 4342b94994..5faab9b424 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBody.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBody.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTClassOrInterfaceBody.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents the body of a {@linkplain ASTClassOrInterfaceDeclaration class or interface declaration}. * This includes anonymous classes, including those defined within an {@linkplain ASTEnumConstant enum constant}. @@ -16,17 +17,19 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTClassOrInterfaceBody extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTClassOrInterfaceBody(int id) { super(id); } + @InternalApi + @Deprecated public ASTClassOrInterfaceBody(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java index 03f6a93113..16810dde82 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceBodyDeclaration.java @@ -1,18 +1,22 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTClassOrInterfaceBodyDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.annotation.InternalApi; public class ASTClassOrInterfaceBodyDeclaration extends AbstractTypeBodyDeclaration implements CanSuppressWarnings, ASTAnyTypeBodyDeclaration { + @InternalApi + @Deprecated public ASTClassOrInterfaceBodyDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTClassOrInterfaceBodyDeclaration(JavaParser p, int id) { super(p, id); } @@ -35,9 +39,6 @@ public class ASTClassOrInterfaceBodyDeclaration extends AbstractTypeBodyDeclarat return false; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java index d6cc705c17..e7bd1e825f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclaration.java @@ -1,13 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTClassOrInterfaceDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Collections; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.util.CollectionUtil; @@ -25,7 +25,6 @@ import net.sourceforge.pmd.util.CollectionUtil; * {@linkplain ASTImplementsList ImplementsList}? * {@linkplain ASTClassOrInterfaceBody ClassOrInterfaceBody} * </pre> - * */ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration { @@ -34,10 +33,14 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration { private boolean isInterface; + @InternalApi + @Deprecated public ASTClassOrInterfaceDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTClassOrInterfaceDeclaration(JavaParser p, int id) { super(p, id); } @@ -47,14 +50,15 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration { return isNested() || isLocal(); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + @Override + public boolean isPackagePrivate() { + return super.isPackagePrivate() && !isLocal(); + } @Override public <T> void jjtAccept(SideEffectingVisitor<T> visitor, T data) { @@ -74,7 +78,7 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration { isLocal = false; break; } else if (current instanceof ASTMethodOrConstructorDeclaration - || current instanceof ASTInitializer) { + || current instanceof ASTInitializer) { isLocal = true; break; } @@ -92,6 +96,8 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration { return this.isInterface; } + @InternalApi + @Deprecated public void setInterface() { this.isInterface = true; } @@ -134,8 +140,8 @@ public class ASTClassOrInterfaceDeclaration extends AbstractAnyTypeDeclaration { public List<ASTClassOrInterfaceType> getSuperInterfacesTypeNodes() { Iterable<ASTClassOrInterfaceType> it = isInterface() - ? getFirstChildOfType(ASTExtendsList.class) - : getFirstChildOfType(ASTImplementsList.class); + ? getFirstChildOfType(ASTExtendsList.class) + : getFirstChildOfType(ASTImplementsList.class); return it == null ? Collections.<ASTClassOrInterfaceType>emptyList() : CollectionUtil.toList(it.iterator()); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java index 8116a519ee..55ab66222d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceType.java @@ -1,10 +1,10 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTClassOrInterfaceType.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; @@ -16,13 +16,17 @@ import net.sourceforge.pmd.lang.ast.Node; * ClassOrInterfaceType ::= <IDENTIFIER> {@linkplain ASTTypeArguments TypeArguments}? ( "." <IDENTIFIER> {@linkplain ASTTypeArguments TypeArguments}? )* * * </pre> - * */ public class ASTClassOrInterfaceType extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTClassOrInterfaceType(int id) { super(id); } + @InternalApi + @Deprecated public ASTClassOrInterfaceType(JavaParser p, int id) { super(p, id); } @@ -45,7 +49,7 @@ public class ASTClassOrInterfaceType extends AbstractJavaTypeNode { * to check this, if {@link #getType()} is null. * * @return <code>true</code> if this node referencing a type in the same - * compilation unit, <code>false</code> otherwise. + * compilation unit, <code>false</code> otherwise. */ public boolean isReferenceToClassSameCompilationUnit() { ASTCompilationUnit root = getFirstParentOfType(ASTCompilationUnit.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java index 6ddc7e71b7..b8f74408c3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTCompilationUnit.java @@ -1,12 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTCompilationUnit.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.java.typeresolution.ClassTypeResolver; @@ -17,10 +17,14 @@ public class ASTCompilationUnit extends AbstractJavaTypeNode implements RootNode private ClassTypeResolver classTypeResolver; private List<Comment> comments; + @InternalApi + @Deprecated public ASTCompilationUnit(int id) { super(id); } + @InternalApi + @Deprecated public ASTCompilationUnit(JavaParser p, int id) { super(p, id); } @@ -29,13 +33,12 @@ public class ASTCompilationUnit extends AbstractJavaTypeNode implements RootNode return comments; } + @InternalApi + @Deprecated public void setComments(List<Comment> comments) { this.comments = comments; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -64,6 +67,8 @@ public class ASTCompilationUnit extends AbstractJavaTypeNode implements RootNode return classTypeResolver; } + @InternalApi + @Deprecated public void setClassTypeResolver(ClassTypeResolver classTypeResolver) { this.classTypeResolver = classTypeResolver; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java index 51eb264b2e..55508e068f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalAndExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTConditionalAndExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a boolean AND-expression. This has a precedence greater than {@link ASTConditionalOrExpression}, * and lower than {@link ASTInclusiveOrExpression}. @@ -20,11 +21,16 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTConditionalAndExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTConditionalAndExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTConditionalAndExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalExpression.java index 50210c3d06..d26b531036 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalExpression.java @@ -1,10 +1,10 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTConditionalExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; @@ -21,15 +21,18 @@ import net.sourceforge.pmd.lang.ast.Node; * ConditionalExpression ::= {@linkplain ASTConditionalOrExpression ConditionalOrExpression} "?" {@linkplain ASTExpression Expression} ":" {@linkplain ASTConditionalExpression ConditionalExpression} * * </pre> - * */ public class ASTConditionalExpression extends AbstractJavaTypeNode { + @InternalApi + @Deprecated public ASTConditionalExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTConditionalExpression(JavaParser p, int id) { super(p, id); } @@ -38,6 +41,7 @@ public class ASTConditionalExpression extends AbstractJavaTypeNode { /** * @deprecated To be removed in 7.0.0 */ + @InternalApi @Deprecated public void setTernary() { // noop diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java index 97b737c9cc..178d96bbf5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConditionalOrExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTConditionalOrExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a boolean OR-expression. This has a precedence greater than {@link ASTConditionalExpression}, * and lower than {@link ASTConditionalAndExpression}. @@ -20,10 +21,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTConditionalOrExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTConditionalOrExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTConditionalOrExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java index 6f6dab9fd9..6e002e2e66 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTConstructorDeclaration.java @@ -1,19 +1,24 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTConstructorDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTConstructorDeclaration extends AbstractMethodOrConstructorDeclaration { private boolean containsComment; + @InternalApi + @Deprecated public ASTConstructorDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTConstructorDeclaration(JavaParser p, int id) { super(p, id); } @@ -24,9 +29,6 @@ public class ASTConstructorDeclaration extends AbstractMethodOrConstructorDeclar return MethodLikeKind.CONSTRUCTOR; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -43,6 +45,8 @@ public class ASTConstructorDeclaration extends AbstractMethodOrConstructorDeclar return this.containsComment; } + @InternalApi + @Deprecated public void setContainsComment() { this.containsComment = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java index e5e4437c05..dc6871cbc5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTContinueStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTContinueStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTContinueStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTContinueStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTContinueStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDefaultValue.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDefaultValue.java index 2a94d2a567..a4fd922344 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDefaultValue.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDefaultValue.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTDefaultValue.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTDefaultValue extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTDefaultValue(int id) { super(id); } + @InternalApi + @Deprecated public ASTDefaultValue(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java index 8d44fcf3bd..e2f2944645 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTDoStatement.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTDoStatement.java */ package net.sourceforge.pmd.lang.java.ast; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java index aad191e16b..20569e4c35 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEmptyStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTEmptyStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTEmptyStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTEmptyStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTEmptyStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumBody.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumBody.java index 0e31ee1d6e..98d7a15789 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumBody.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumBody.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTEnumBody.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTEnumBody extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTEnumBody(int id) { super(id); } + @InternalApi + @Deprecated public ASTEnumBody(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java index 8507264991..2349d57b4e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumConstant.java @@ -1,10 +1,10 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTEnumConstant.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName; @@ -23,17 +23,18 @@ public class ASTEnumConstant extends AbstractJavaNode implements JavaQualifiable private JavaTypeQualifiedName qualifiedName; + @InternalApi + @Deprecated public ASTEnumConstant(int id) { super(id); } + @InternalApi + @Deprecated public ASTEnumConstant(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -59,6 +60,8 @@ public class ASTEnumConstant extends AbstractJavaNode implements JavaQualifiable } + @InternalApi + @Deprecated public void setQualifiedName(JavaTypeQualifiedName qname) { this.qualifiedName = qname; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumDeclaration.java index ce17a6f24e..ab1128e0b4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEnumDeclaration.java @@ -1,19 +1,24 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTEnumDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTEnumDeclaration extends AbstractAnyTypeDeclaration { + @InternalApi + @Deprecated public ASTEnumDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTEnumDeclaration(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java index 13e9b2a98d..bcd8026bc0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTEqualityExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTEqualityExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an identity test between two values or more values. * This has a precedence greater than {@link ASTAndExpression}, @@ -21,10 +22,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTEqualityExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTEqualityExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTEqualityExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java index c7dc23348b..64f0d1ebc5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExclusiveOrExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTExclusiveOrExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a boolean XOR-expression. This has a precedence greater than {@link ASTInclusiveOrExpression}, * and lower than {@link ASTAndExpression}. @@ -20,10 +21,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTExclusiveOrExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTExclusiveOrExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTExclusiveOrExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java index 5df70a7ff5..098607503c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExplicitConstructorInvocation.java @@ -1,25 +1,27 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTExplicitConstructorInvocation.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTExplicitConstructorInvocation extends AbstractJavaNode { private String thisOrSuper; + @InternalApi + @Deprecated public ASTExplicitConstructorInvocation(int id) { super(id); } + @InternalApi + @Deprecated public ASTExplicitConstructorInvocation(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -40,10 +42,14 @@ public class ASTExplicitConstructorInvocation extends AbstractJavaNode { } } + @InternalApi + @Deprecated public void setIsThis() { this.thisOrSuper = "this"; } + @InternalApi + @Deprecated public void setIsSuper() { this.thisOrSuper = "super"; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpression.java index 547c9fc8a1..dc09381f79 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an expression, in the most general sense. * This corresponds roughly to the <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-AssignmentExpression">AssignmentExpression</a> @@ -18,17 +19,19 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTExpression(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -63,6 +66,6 @@ public class ASTExpression extends AbstractJavaTypeNode { // if it is not a string literal and not a null, then it is one of // byte, short, char, int, long, float, double, boolean return literal != null && !literal.isStringLiteral() - && (literal.jjtGetNumChildren() == 0 || !(literal.jjtGetChild(0) instanceof ASTNullLiteral)); + && (literal.jjtGetNumChildren() == 0 || !(literal.jjtGetChild(0) instanceof ASTNullLiteral)); } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExtendsList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExtendsList.java index 3ef76b1cec..f6b5a422a9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExtendsList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTExtendsList.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTExtendsList.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents the {@code extends} clause of a class or interface declaration. @@ -19,17 +20,19 @@ import java.util.Iterator; * </pre> */ public class ASTExtendsList extends AbstractJavaNode implements Iterable<ASTClassOrInterfaceType> { + + @InternalApi + @Deprecated public ASTExtendsList(int id) { super(id); } + @InternalApi + @Deprecated public ASTExtendsList(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java index f17f6256b9..a38b2b7680 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFieldDeclaration.java @@ -1,12 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTFieldDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.SignedNode; import net.sourceforge.pmd.lang.java.multifile.signature.JavaFieldSignature; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -15,7 +15,8 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin /** * Represents a field declaration in the body of a type declaration. * - * <p>This statement may define several variables, possibly of different types (see {@link ASTVariableDeclaratorId#getType()}). + * <p>This statement may define several variables, possibly of different types (see {@link + * ASTVariableDeclaratorId#getType()}). * The nodes corresponding to the declared variables are accessible through {@link #iterator()}. * * <p>{@link AccessNode} methods take into account the syntactic context of the @@ -40,17 +41,18 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D private JavaFieldSignature signature; + @InternalApi + @Deprecated public ASTFieldDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTFieldDeclaration(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -176,12 +178,10 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D * VariableDeclartorId node and returns its image or <code>null</code> if * the child node is not found. * + * @return a String representing the name of the variable * * @deprecated FieldDeclaration may declare several variables, so this is not exhaustive - * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead - * - * - * @return a String representing the name of the variable + * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead */ @Deprecated public String getVariableName() { @@ -215,7 +215,7 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D /** * @deprecated FieldDeclaration may declare several variables with a different type - * It won't implement TypeNode anymore come 7.0.0 + * It won't implement TypeNode anymore come 7.0.0 */ @Override @Deprecated @@ -225,9 +225,8 @@ public class ASTFieldDeclaration extends AbstractJavaAccessTypeNode implements D /** - * * @deprecated FieldDeclaration may declare several variables with a different type - * It won't implement TypeNode anymore come 7.0.0 + * It won't implement TypeNode anymore come 7.0.0 */ @Override @Deprecated diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java index 54aa3df731..13ef13e48b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFinallyStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTFinallyStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTFinallyStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTFinallyStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTFinallyStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java index 25db214206..c32e24f3b1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForInit.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTForInit.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTForInit extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTForInit(int id) { super(id); } + @InternalApi + @Deprecated public ASTForInit(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java index 6d7d58d615..cf4c5645a4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForStatement.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTForStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a {@code for}-loop, or a foreach loop. * @@ -18,11 +19,16 @@ package net.sourceforge.pmd.lang.java.ast; // TODO this should be split into two different nodes, otherwise // we can't enrich the API without returning null half the time public class ASTForStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTForStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTForStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java index 0a1e0d6878..09ee347c68 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTForUpdate.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTForUpdate.java */ package net.sourceforge.pmd.lang.java.ast; @@ -33,9 +32,6 @@ public class ASTForUpdate extends AbstractJavaNode { } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java index 7253b6cdf1..61493b452c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameter.java @@ -1,11 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTFormalParameter.java */ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -23,10 +23,14 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di private boolean isVarargs; + @InternalApi + @Deprecated public ASTFormalParameter(int id) { super(id); } + @InternalApi + @Deprecated public ASTFormalParameter(JavaParser p, int id) { super(p, id); } @@ -35,7 +39,7 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di /** * @deprecated Will be made private in 7.0.0 */ - // Should be made package-private + @InternalApi @Deprecated public void setVarargs() { isVarargs = true; @@ -112,8 +116,8 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di @Deprecated public boolean isArray() { return isVarargs() - || getTypeNode() != null && getTypeNode().isArray() - || getVariableDeclaratorId().isArray(); + || getTypeNode() != null && getTypeNode().isArray() + || getVariableDeclaratorId().isArray(); } @Override @@ -170,6 +174,8 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di * Noop, the type of this node is defined by the type * of the declarator id. */ + @InternalApi + @Deprecated @Override public void setTypeDefinition(JavaTypeDefinition type) { // see javadoc @@ -179,6 +185,8 @@ public class ASTFormalParameter extends AbstractJavaAccessTypeNode implements Di * Noop, the type of this node is defined by the type * of the declarator id. */ + @InternalApi + @Deprecated @Override public void setType(Class<?> type) { // see javadoc diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java index 9d3ef43fe7..a5416f1bd9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTFormalParameters.java @@ -1,19 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTFormalParameters.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTFormalParameters extends AbstractJavaNode implements Iterable<ASTFormalParameter> { + + @InternalApi + @Deprecated public ASTFormalParameters(int id) { super(id); } + @InternalApi + @Deprecated public ASTFormalParameters(JavaParser p, int id) { super(p, id); } @@ -21,12 +27,9 @@ public class ASTFormalParameters extends AbstractJavaNode implements Iterable<AS public int getParameterCount() { final List<ASTFormalParameter> parameters = findChildrenOfType(ASTFormalParameter.class); return !parameters.isEmpty() && parameters.get(0).isExplicitReceiverParameter() - ? parameters.size() - 1 : parameters.size(); + ? parameters.size() - 1 : parameters.size(); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java index 56cadb71f6..2fbb7958d9 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTIfStatement.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTIfStatement.java */ package net.sourceforge.pmd.lang.java.ast; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImplementsList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImplementsList.java index ca7b86dd46..c764017f42 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImplementsList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImplementsList.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTImplementsList.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents the {@code implements} clause of a class declaration. @@ -17,17 +18,19 @@ import java.util.Iterator; * </pre> */ public class ASTImplementsList extends AbstractJavaNode implements Iterable<ASTClassOrInterfaceType> { + + @InternalApi + @Deprecated public ASTImplementsList(int id) { super(id); } + @InternalApi + @Deprecated public ASTImplementsList(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImportDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImportDeclaration.java index 91a3115202..0b253842d0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImportDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImportDeclaration.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTImportDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an import declaration in a Java file. * @@ -15,7 +16,6 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> * * @see <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-7.html#jls-7.5">JLS 7.5</a> - * */ // TODO should this really be a type node? // E.g. for on-demand imports, what's the type of this node? There's no type name, just a package name @@ -30,10 +30,14 @@ public class ASTImportDeclaration extends AbstractJavaTypeNode { private boolean isStatic; private Package pkg; + @InternalApi + @Deprecated public ASTImportDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTImportDeclaration(JavaParser p, int id) { super(p, id); } @@ -42,6 +46,7 @@ public class ASTImportDeclaration extends AbstractJavaTypeNode { /** * @deprecated Will be made private with 7.0.0 */ + @InternalApi @Deprecated public void setImportOnDemand() { isImportOnDemand = true; @@ -69,6 +74,7 @@ public class ASTImportDeclaration extends AbstractJavaTypeNode { /** * @deprecated Will be made private with 7.0.0 */ + @InternalApi @Deprecated public void setStatic() { isStatic = true; @@ -83,8 +89,10 @@ public class ASTImportDeclaration extends AbstractJavaTypeNode { return isStatic; } - // TODO - this should go away, but the DuplicateImports rule still uses it - // (in a clunky way) + /** + * @deprecated this will be removed with PMD 7.0.0 + */ + @Deprecated public ASTName getImportedNameNode() { return (ASTName) jjtGetChild(0); } @@ -140,6 +148,8 @@ public class ASTImportDeclaration extends AbstractJavaTypeNode { visitor.visit(this, data); } + @InternalApi + @Deprecated public void setPackage(Package packge) { this.pkg = packge; } @@ -150,9 +160,10 @@ public class ASTImportDeclaration extends AbstractJavaTypeNode { * type or method imported by this declaration. This may be null if the * auxclasspath is not correctly set, as this method depends on correct * type resolution. + * + * @deprecated this will be removed with PMD 7.0.0 */ - // TODO deprecate? This is only used in a test. I don't think it's really - // useful and it gives work to ClassTypeResolver. + @Deprecated public Package getPackage() { return this.pkg; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java index b77b3a185d..f08c3fcccb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInclusiveOrExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTInclusiveOrExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a non-shortcut boolean OR-expression. This has a precedence * greater than {@link ASTConditionalAndExpression}, and lower than @@ -21,11 +22,16 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTInclusiveOrExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTInclusiveOrExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTInclusiveOrExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInitializer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInitializer.java index 586f1740c3..b464e7a878 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInitializer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInitializer.java @@ -1,25 +1,27 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTInitializer.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTInitializer extends AbstractJavaNode { private boolean isStatic; + @InternalApi + @Deprecated public ASTInitializer(int id) { super(id); } + @InternalApi + @Deprecated public ASTInitializer(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -36,6 +38,8 @@ public class ASTInitializer extends AbstractJavaNode { return isStatic; } + @InternalApi + @Deprecated public void setStatic() { isStatic = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java index 9ecb314a83..d7dcdf5e4f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTInstanceOfExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTInstanceOfExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a type test on an object. This has a precedence greater than {@link ASTEqualityExpression}, * and lower than {@link ASTShiftExpression}. This has the same precedence as a {@link ASTRelationalExpression}. @@ -20,11 +21,16 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTInstanceOfExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTInstanceOfExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTInstanceOfExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java index 6dd8d193b8..2ebeb079b0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLabeledStatement.java @@ -1,15 +1,21 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTLabeledStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTLabeledStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTLabeledStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTLabeledStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java index 9f49a2ede8..245ebcb2ff 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLambdaExpression.java @@ -1,17 +1,22 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTLambdaExpression.java Version 4.3 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTLambdaExpression extends AbstractMethodLikeNode { + + @InternalApi + @Deprecated public ASTLambdaExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTLambdaExpression(JavaParser p, int id) { super(p, id); } @@ -23,7 +28,6 @@ public class ASTLambdaExpression extends AbstractMethodLikeNode { } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -41,7 +45,3 @@ public class ASTLambdaExpression extends AbstractMethodLikeNode { return MethodLikeKind.LAMBDA; } } -/* - * JavaCC - OriginalChecksum=e706de031abe9a22c368b7cb52802f1b (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java index cd885077bc..0e88afb71b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLiteral.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTLiteral.java */ package net.sourceforge.pmd.lang.java.ast; @@ -9,6 +8,8 @@ import java.math.BigInteger; import java.util.Locale; import java.util.regex.Pattern; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTLiteral extends AbstractJavaTypeNode { private boolean isInt; @@ -21,19 +22,20 @@ public class ASTLiteral extends AbstractJavaTypeNode { * String. */ private static final Pattern SINGLE_CHAR_ESCAPE_PATTERN = Pattern - .compile("^\"\\\\(([ntbrf\\\\'\\\"])|([0-7][0-7]?)|([0-3][0-7][0-7]))\""); + .compile("^\"\\\\(([ntbrf\\\\'\\\"])|([0-7][0-7]?)|([0-3][0-7][0-7]))\""); + @InternalApi + @Deprecated public ASTLiteral(int id) { super(id); } + @InternalApi + @Deprecated public ASTLiteral(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -46,6 +48,8 @@ public class ASTLiteral extends AbstractJavaTypeNode { } + @InternalApi + @Deprecated public void setIntLiteral() { this.isInt = true; } @@ -75,6 +79,8 @@ public class ASTLiteral extends AbstractJavaTypeNode { return false; } + @InternalApi + @Deprecated public void setFloatLiteral() { this.isFloat = true; } @@ -184,6 +190,8 @@ public class ASTLiteral extends AbstractJavaTypeNode { return Double.NaN; } + @InternalApi + @Deprecated public void setCharLiteral() { this.isChar = true; } @@ -192,6 +200,8 @@ public class ASTLiteral extends AbstractJavaTypeNode { return isChar; } + @InternalApi + @Deprecated public void setStringLiteral() { this.isString = true; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java index 96b5ac3fd2..71c1fca5d6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTLocalVariableDeclaration.java @@ -1,13 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTLocalVariableDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.annotation.InternalApi; /** @@ -15,7 +15,8 @@ import net.sourceforge.pmd.Rule; * but the node is also used in {@linkplain ASTForInit for-loop initialisers} and * {@linkplain ASTForStatement foreach statements}. * - * <p>This statement may define several variables, possibly of different types (see {@link ASTVariableDeclaratorId#getType()}). + * <p>This statement may define several variables, possibly of different types (see {@link + * ASTVariableDeclaratorId#getType()}). * The nodes corresponding to the declared variables are accessible through {@link #iterator()}. * * <pre> @@ -26,10 +27,14 @@ import net.sourceforge.pmd.Rule; */ public class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implements Dimensionable, CanSuppressWarnings, Iterable<ASTVariableDeclaratorId> { + @InternalApi + @Deprecated public ASTLocalVariableDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTLocalVariableDeclaration(JavaParser p, int id) { super(p, id); } @@ -86,7 +91,9 @@ public class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implemen * Gets the type node for this variable declaration statement. * With Java10 and local variable type inference, there might be * no type node at all. + * * @return The type node or <code>null</code> + * * @see #isTypeInferred() */ public ASTType getTypeNode() { @@ -114,10 +121,10 @@ public class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implemen * VariableDeclartorId node and returns it's image or <code>null</code> if * the child node is not found. * - * @deprecated LocalVariableDeclaration may declare several variables, so this is not exhaustive - * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead - * * @return a String representing the name of the variable + * + * @deprecated LocalVariableDeclaration may declare several variables, so this is not exhaustive + * Iterate on the {@linkplain ASTVariableDeclaratorId VariableDeclaratorIds} instead */ // It would be nice to have a way to inform XPath users of the intended replacement // for a deprecated attribute. We may use another annotation for that. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java index 13fb7a2947..f8748709c2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMarkerAnnotation.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMarkerAnnotation.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an annotation with no declared member, e.g. {@code @Override}. * @@ -19,11 +20,15 @@ package net.sourceforge.pmd.lang.java.ast; */ public class ASTMarkerAnnotation extends AbstractJavaTypeNode { + @InternalApi + @Deprecated public ASTMarkerAnnotation(int id) { super(id); } + @InternalApi + @Deprecated public ASTMarkerAnnotation(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java index 9e9fb3338e..686a5e98b2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberSelector.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMemberSelector.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTMemberSelector extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTMemberSelector(int id) { super(id); } + @InternalApi + @Deprecated public ASTMemberSelector(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValue.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValue.java index ac4359b913..0c924428a6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValue.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValue.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMemberValue.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents the value of a member of an annotation. * This can appear in a {@linkplain ASTMemberValuePair member-value pair}, @@ -19,11 +20,16 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTMemberValue extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTMemberValue(int id) { super(id); } + @InternalApi + @Deprecated public ASTMemberValue(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValueArrayInitializer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValueArrayInitializer.java index 4705492e00..780d43c652 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValueArrayInitializer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValueArrayInitializer.java @@ -1,13 +1,14 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMemberValueArrayInitializer.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an array of member values in an annotation {@linkplain ASTMemberValue member value}. @@ -17,14 +18,17 @@ import java.util.Iterator; * MemberValueArrayInitializer ::= "{" ( {@linkplain ASTMemberValue MemberValue} ( "," {@linkplain ASTMemberValue MemberValue} )* ","? )? "}" * * </pre> - * - * */ public class ASTMemberValueArrayInitializer extends AbstractJavaNode implements Iterable<ASTMemberValue> { + + @InternalApi + @Deprecated public ASTMemberValueArrayInitializer(int id) { super(id); } + @InternalApi + @Deprecated public ASTMemberValueArrayInitializer(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java index 1d65d309fa..bce0987bde 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePair.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMemberValuePair.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a single member-value pair in an annotation. * @@ -15,11 +16,16 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTMemberValuePair extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTMemberValuePair(int id) { super(id); } + @InternalApi + @Deprecated public ASTMemberValuePair(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePairs.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePairs.java index 3c213f4d5f..a28ad012df 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePairs.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMemberValuePairs.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMemberValuePairs.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a list of member values in an {@linkplain ASTNormalAnnotation annotation}. @@ -18,11 +19,16 @@ import java.util.Iterator; * </pre> */ public class ASTMemberValuePairs extends AbstractJavaNode implements Iterable<ASTMemberValuePair> { + + @InternalApi + @Deprecated public ASTMemberValuePairs(int id) { super(id); } + @InternalApi + @Deprecated public ASTMemberValuePairs(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java index c6446e6cd6..7442dfe6e6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclaration.java @@ -1,10 +1,10 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMethodDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.dfa.DFAGraphMethod; @@ -15,15 +15,18 @@ import net.sourceforge.pmd.lang.dfa.DFAGraphMethod; * <pre> * MethodDeclaration := [ TypeParameters() ] (TypeAnnotation())* ResultType() MethodDeclarator() [ "throws" NameList() ] ( Block() | ";" ) * </pre> - * */ public class ASTMethodDeclaration extends AbstractMethodOrConstructorDeclaration implements DFAGraphMethod { + @InternalApi + @Deprecated public ASTMethodDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTMethodDeclaration(JavaParser p, int id) { super(p, id); } @@ -108,7 +111,7 @@ public class ASTMethodDeclaration extends AbstractMethodOrConstructorDeclaration Node potentialTypeDeclaration = getNthParent(3); return potentialTypeDeclaration instanceof ASTClassOrInterfaceDeclaration - && ((ASTClassOrInterfaceDeclaration) potentialTypeDeclaration).isInterface(); + && ((ASTClassOrInterfaceDeclaration) potentialTypeDeclaration).isInterface(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java index 4ebd3bbac9..b24d68d46f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodDeclarator.java @@ -1,15 +1,21 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMethodDeclarator.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTMethodDeclarator extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTMethodDeclarator(int id) { super(id); } + @InternalApi + @Deprecated public ASTMethodDeclarator(JavaParser p, int id) { super(p, id); } @@ -18,9 +24,6 @@ public class ASTMethodDeclarator extends AbstractJavaNode { return getFirstChildOfType(ASTFormalParameters.class).getParameterCount(); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodReference.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodReference.java index 6b7cd4f1bb..2f1b467ff5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodReference.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMethodReference.java @@ -1,21 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMethodReference.java Version 4.3 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTMethodReference extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTMethodReference(int id) { super(id); } + @InternalApi + @Deprecated public ASTMethodReference(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -27,7 +31,3 @@ public class ASTMethodReference extends AbstractJavaNode { visitor.visit(this, data); } } -/* - * JavaCC - OriginalChecksum=e706de031abe9a22c368b7cb52802f1b (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java index d58f014e19..fec197f978 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDeclaration.java @@ -1,23 +1,27 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTModuleDeclaration.java Version 4.3 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTModuleDeclaration extends AbstractJavaNode { + private boolean open; + @InternalApi + @Deprecated public ASTModuleDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTModuleDeclaration(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -30,6 +34,8 @@ public class ASTModuleDeclaration extends AbstractJavaNode { } + @InternalApi + @Deprecated public void setOpen(boolean open) { this.open = open; } @@ -38,4 +44,3 @@ public class ASTModuleDeclaration extends AbstractJavaNode { return open; } } -/* JavaCC - OriginalChecksum=752bbec72a6d0d96c4c69a2d08c73614 (do not edit this line) */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java index 73cff303ac..898546fa89 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleDirective.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTModuleDirective.java Version 4.3 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTModuleDirective extends AbstractJavaNode { + public enum DirectiveType { REQUIRES, EXPORTS, OPENS, USES, PROVIDES; } @@ -19,15 +20,18 @@ public class ASTModuleDirective extends AbstractJavaNode { private RequiresModifier requiresModifier; + @InternalApi + @Deprecated public ASTModuleDirective(int id) { super(id); } + @InternalApi + @Deprecated public ASTModuleDirective(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -40,6 +44,8 @@ public class ASTModuleDirective extends AbstractJavaNode { } + @InternalApi + @Deprecated public void setType(DirectiveType type) { this.type = type; } @@ -48,6 +54,8 @@ public class ASTModuleDirective extends AbstractJavaNode { return String.valueOf(type); } + @InternalApi + @Deprecated public void setRequiresModifier(RequiresModifier requiresModifier) { this.requiresModifier = requiresModifier; } @@ -56,7 +64,3 @@ public class ASTModuleDirective extends AbstractJavaNode { return requiresModifier == null ? null : requiresModifier.name(); } } -/* - * JavaCC - OriginalChecksum=93c74930e5df0269e81ce18b4efa6378 (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java index 218ca2425e..e965bb5f05 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTModuleName.java @@ -2,21 +2,24 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTModuleName.java Version 4.3 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ - package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTModuleName extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTModuleName(int id) { super(id); } + @InternalApi + @Deprecated public ASTModuleName(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -28,7 +31,3 @@ public class ASTModuleName extends AbstractJavaNode { visitor.visit(this, data); } } -/* - * JavaCC - OriginalChecksum=7be9235079394543d4574d840ebb5235 (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java index 403dd9a3ae..7bb9609f6e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTMultiplicativeExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTMultiplicativeExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a multiplication, division, or modulo operation on * two or more values. This has a precedence greater than {@link ASTAdditiveExpression}, @@ -20,10 +21,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTMultiplicativeExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTMultiplicativeExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTMultiplicativeExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java index 14db46fd92..0bef4a2430 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTName.java @@ -1,24 +1,30 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTName.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.symboltable.NameDeclaration; public class ASTName extends AbstractJavaTypeNode { private NameDeclaration nd; + @InternalApi + @Deprecated public ASTName(int id) { super(id); } + @InternalApi + @Deprecated public ASTName(JavaParser p, int id) { super(p, id); } + @InternalApi + @Deprecated public void setNameDeclaration(NameDeclaration nd) { this.nd = nd; } @@ -27,9 +33,6 @@ public class ASTName extends AbstractJavaTypeNode { return this.nd; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java index 0890047ded..b19427917d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNameList.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTNameList.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTNameList extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTNameList(int id) { super(id); } + @InternalApi + @Deprecated public ASTNameList(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java index 0d459a170e..d4dba20674 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNormalAnnotation.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTNormalAnnotation.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an annotation that with a parenthesized list * of key-value pairs (possibly empty). @@ -19,11 +20,16 @@ package net.sourceforge.pmd.lang.java.ast; * @see ASTMarkerAnnotation */ public class ASTNormalAnnotation extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTNormalAnnotation(int id) { super(id); } + @InternalApi + @Deprecated public ASTNormalAnnotation(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNullLiteral.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNullLiteral.java index 886dbb5250..e54ee34ae4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNullLiteral.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTNullLiteral.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTNullLiteral.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTNullLiteral extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTNullLiteral(int id) { super(id); } + @InternalApi + @Deprecated public ASTNullLiteral(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java index 5a7c53fd84..7963975d2a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPackageDeclaration.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPackageDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTPackageDeclaration extends AbstractJavaAnnotatableNode { + + @InternalApi + @Deprecated public ASTPackageDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTPackageDeclaration(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPostfixExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPostfixExpression.java index 3e03af917a..5ef3f1e79f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPostfixExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPostfixExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPostfixExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a unary postfix operation on a value. * This is one of the {@linkplain ASTUnaryExpression PrefixExpression} @@ -18,10 +19,14 @@ package net.sourceforge.pmd.lang.java.ast; */ public class ASTPostfixExpression extends AbstractJavaTypeNode { + @InternalApi + @Deprecated public ASTPostfixExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTPostfixExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreDecrementExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreDecrementExpression.java index fc605b6f0b..047f57f5ee 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreDecrementExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreDecrementExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPreDecrementExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a pre-decrement expression on a variable. * This has the same precedence as {@linkplain ASTUnaryExpression UnaryExpression} @@ -17,10 +18,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTPreDecrementExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTPreDecrementExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTPreDecrementExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreIncrementExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreIncrementExpression.java index fa255b27b0..f015f9aa27 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreIncrementExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPreIncrementExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPreIncrementExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a pre-increment expression on a variable. * This has the same precedence as {@linkplain ASTUnaryExpression UnaryExpression} @@ -17,10 +18,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTPreIncrementExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTPreIncrementExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTPreIncrementExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryExpression.java index ed9e221463..36dfa70945 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryExpression.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPrimaryExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTPrimaryExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTPrimaryExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTPrimaryExpression(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java index e8d94f016e..e6ae27f8d5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimaryPrefix.java @@ -1,23 +1,30 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPrimaryPrefix.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTPrimaryPrefix extends AbstractJavaTypeNode { private boolean usesThisModifier; private boolean usesSuperModifier; + @InternalApi + @Deprecated public ASTPrimaryPrefix(int id) { super(id); } + @InternalApi + @Deprecated public ASTPrimaryPrefix(JavaParser p, int id) { super(p, id); } + @InternalApi + @Deprecated public void setUsesThisModifier() { usesThisModifier = true; } @@ -26,6 +33,8 @@ public class ASTPrimaryPrefix extends AbstractJavaTypeNode { return this.usesThisModifier; } + @InternalApi + @Deprecated public void setUsesSuperModifier() { usesSuperModifier = true; } @@ -34,9 +43,6 @@ public class ASTPrimaryPrefix extends AbstractJavaTypeNode { return this.usesSuperModifier; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java index 34b126fe3a..1813066d48 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimarySuffix.java @@ -1,23 +1,30 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPrimarySuffix.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTPrimarySuffix extends AbstractJavaTypeNode { private boolean isArguments; private boolean isArrayDereference; + @InternalApi + @Deprecated public ASTPrimarySuffix(int id) { super(id); } + @InternalApi + @Deprecated public ASTPrimarySuffix(JavaParser p, int id) { super(p, id); } + @InternalApi + @Deprecated public void setIsArrayDereference() { isArrayDereference = true; } @@ -26,6 +33,8 @@ public class ASTPrimarySuffix extends AbstractJavaTypeNode { return isArrayDereference; } + @InternalApi + @Deprecated public void setIsArguments() { this.isArguments = true; } @@ -40,7 +49,7 @@ public class ASTPrimarySuffix extends AbstractJavaTypeNode { * called when there are no arguments it returns <code>-1</code>. * * @return A non-negative argument number when there are arguments, - * <code>-1</code> otherwise. + * <code>-1</code> otherwise. */ public int getArgumentCount() { if (!this.isArguments()) { @@ -49,9 +58,6 @@ public class ASTPrimarySuffix extends AbstractJavaTypeNode { return ((ASTArguments) jjtGetChild(jjtGetNumChildren() - 1)).getArgumentCount(); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java index 539f3e5ec9..e834980126 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTPrimitiveType.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTPrimitiveType.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a primitive type. * @@ -18,10 +19,14 @@ public class ASTPrimitiveType extends AbstractJavaTypeNode implements Dimensiona private int arrayDepth; + @InternalApi + @Deprecated public ASTPrimitiveType(int id) { super(id); } + @InternalApi + @Deprecated public ASTPrimitiveType(JavaParser p, int id) { super(p, id); } @@ -30,9 +35,6 @@ public class ASTPrimitiveType extends AbstractJavaTypeNode implements Dimensiona return "boolean".equals(getImage()); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java index 887c940f85..273ac9a5ab 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRSIGNEDSHIFT.java @@ -1,26 +1,29 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTRSIGNEDSHIFT.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * @deprecated Will be removed in 7.0.0. Use {@link ASTShiftExpression#getOperator()} */ @Deprecated public class ASTRSIGNEDSHIFT extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTRSIGNEDSHIFT(int id) { super(id); } + @InternalApi + @Deprecated public ASTRSIGNEDSHIFT(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java index 037a98dcdb..59c73e7f66 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRUNSIGNEDSHIFT.java @@ -1,26 +1,29 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTRUNSIGNEDSHIFT.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * @deprecated Will be removed in 7.0.0. Use {@link ASTShiftExpression#getOperator()} */ @Deprecated public class ASTRUNSIGNEDSHIFT extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTRUNSIGNEDSHIFT(int id) { super(id); } + @InternalApi + @Deprecated public ASTRUNSIGNEDSHIFT(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java index 95a705019e..f4aa6d55f1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReferenceType.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTReferenceType.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a reference type, i.e. a {@linkplain ASTClassOrInterfaceType class or interface type}, * or an array type. @@ -15,23 +16,23 @@ package net.sourceforge.pmd.lang.java.ast; * | {@linkplain ASTClassOrInterfaceType ClassOrInterfaceType} {@linkplain ASTAnnotation Annotation}* ( "[" "]" )* * * </pre> - * */ public class ASTReferenceType extends AbstractJavaTypeNode implements Dimensionable { private int arrayDepth; + @InternalApi + @Deprecated public ASTReferenceType(int id) { super(id); } + @InternalApi + @Deprecated public ASTReferenceType(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java index 2184e709d1..2fc5012eed 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTRelationalExpression.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTRelationalExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a comparison on two numeric values. This has a precedence greater than {@link ASTEqualityExpression}, * and lower than {@link ASTShiftExpression}. This has the same precedence as a {@link ASTInstanceOfExpression}. @@ -20,10 +21,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTRelationalExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTRelationalExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTRelationalExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java index 33ac96d950..712f5f962b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResource.java @@ -1,21 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTResource.java Version 4.1 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTResource extends ASTFormalParameter { + + @InternalApi + @Deprecated public ASTResource(int id) { super(id); } + @InternalApi + @Deprecated public ASTResource(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -30,7 +34,3 @@ public class ASTResource extends ASTFormalParameter { // TODO Should we deprecate all methods from ASTFormalParameter? } -/* - * JavaCC - OriginalChecksum=92734fc70bba91fd9422150dbf87d5c4 (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResourceSpecification.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResourceSpecification.java index 7b586a7a1f..17fba590c0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResourceSpecification.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResourceSpecification.java @@ -1,21 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTResourceSpecification.java Version 4.1 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTResourceSpecification extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTResourceSpecification(int id) { super(id); } + @InternalApi + @Deprecated public ASTResourceSpecification(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -27,7 +31,3 @@ public class ASTResourceSpecification extends AbstractJavaNode { visitor.visit(this, data); } } -/* - * JavaCC - OriginalChecksum=d495bcf34ff0f86f77e48f66b9c52e4d (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java index 0417047b9d..b672e8bd98 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResources.java @@ -1,21 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTResources.java Version 4.1 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=false,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY= */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTResources extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTResources(int id) { super(id); } + @InternalApi + @Deprecated public ASTResources(JavaParser p, int id) { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -27,7 +31,3 @@ public class ASTResources extends AbstractJavaNode { visitor.visit(this, data); } } -/* - * JavaCC - OriginalChecksum=e83b6cb79b9c5c88242c7dca5255e114 (do not edit this - * line) - */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java index e2723dae41..54a57b821c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTResultType.java @@ -1,15 +1,21 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTResultType.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTResultType extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTResultType(int id) { super(id); } + @InternalApi + @Deprecated public ASTResultType(JavaParser p, int id) { super(p, id); } @@ -22,9 +28,6 @@ public class ASTResultType extends AbstractJavaNode { return jjtGetNumChildren() == 0; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java index ba991f5f51..daf4fb90bc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTReturnStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTReturnStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTReturnStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTReturnStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTReturnStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java index 9d3eb145bf..1eb9abdb3d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTShiftExpression.java @@ -1,12 +1,14 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTShiftExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** - * Represents a shift expression on a numeric value. This has a precedence greater than {@link ASTRelationalExpression}, + * Represents a shift expression on a numeric value. This has a precedence greater than {@link + * ASTRelationalExpression}, * and lower than {@link ASTAdditiveExpression}. * * <p>Note that the children of this node are not necessarily {@link ASTAdditiveExpression}, @@ -21,10 +23,15 @@ package net.sourceforge.pmd.lang.java.ast; */ // TODO we could merge the productions for ASTRSIGNEDSHIFT and ASTRUNSIGNEDSHIFT into this node using a #void production that sets the image of the parent public class ASTShiftExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTShiftExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTShiftExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java index 2d38214071..84d59fdea5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSingleMemberAnnotation.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTSingleMemberAnnotation.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents an annotation using the shorthand syntax for the default member. * @@ -18,10 +19,15 @@ package net.sourceforge.pmd.lang.java.ast; * @see ASTNormalAnnotation */ public class ASTSingleMemberAnnotation extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTSingleMemberAnnotation(int id) { super(id); } + @InternalApi + @Deprecated public ASTSingleMemberAnnotation(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java index ee50ae9fdd..8fe7b03360 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java index 8691617321..0dd5ae5a55 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpression.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTStatementExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTStatementExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTStatementExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTStatementExpression(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java index b215188b35..e03d91f5c6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTStatementExpressionList.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTStatementExpressionList.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTStatementExpressionList extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTStatementExpressionList(int id) { super(id); } + @InternalApi + @Deprecated public ASTStatementExpressionList(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpression.java index ea929b3aa6..f8a577a783 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchExpression.java @@ -2,16 +2,20 @@ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTSwitchLabeledRule.java Version 4.3 */ -/* JavaCCOptions:MULTI=true,NODE_USES_PARSER=true,VISITOR=true,TRACK_TOKENS=true,NODE_PREFIX=AST,NODE_EXTENDS=,NODE_FACTORY=,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */ - package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTSwitchExpression extends AbstractJavaTypeNode { + + @Deprecated + @InternalApi ASTSwitchExpression(int id) { super(id); } + @Deprecated + @InternalApi ASTSwitchExpression(JavaParser p, int id) { super(p, id); } @@ -21,4 +25,3 @@ public class ASTSwitchExpression extends AbstractJavaTypeNode { return visitor.visit(this, data); } } -/* JavaCC - OriginalChecksum=8b1747ca53f66203ee212a3699a9a2f3 (do not edit this line) */ diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabel.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabel.java index 6483ed2abe..c5614cef3b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabel.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabel.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTSwitchLabel.java */ package net.sourceforge.pmd.lang.java.ast; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledBlock.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledBlock.java index 8ff927bef2..d128acda9a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledBlock.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledBlock.java @@ -4,12 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.AbstractNode; + public class ASTSwitchLabeledBlock extends AbstractJavaNode implements ASTSwitchLabeledRule { + @Deprecated + @InternalApi ASTSwitchLabeledBlock(int id) { super(id); } + @Deprecated + @InternalApi ASTSwitchLabeledBlock(JavaParser p, int id) { super(p, id); } @@ -18,4 +25,13 @@ public class ASTSwitchLabeledBlock extends AbstractJavaNode implements ASTSwitch public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public void jjtClose() { + super.jjtClose(); + if (jjtGetNumChildren() > 0) { + AbstractNode firstChild = (AbstractNode) jjtGetChild(0); + jjtSetFirstToken(firstChild.jjtGetFirstToken()); + } + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledExpression.java index b2ba1b17a6..b85209700f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledExpression.java @@ -4,12 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.AbstractNode; + public class ASTSwitchLabeledExpression extends AbstractJavaNode implements ASTSwitchLabeledRule { + @Deprecated + @InternalApi ASTSwitchLabeledExpression(int id) { super(id); } + @Deprecated + @InternalApi ASTSwitchLabeledExpression(JavaParser p, int id) { super(p, id); } @@ -18,4 +25,13 @@ public class ASTSwitchLabeledExpression extends AbstractJavaNode implements ASTS public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public void jjtClose() { + super.jjtClose(); + if (jjtGetNumChildren() > 0) { + AbstractNode firstChild = (AbstractNode) jjtGetChild(0); + jjtSetFirstToken(firstChild.jjtGetFirstToken()); + } + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledThrowStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledThrowStatement.java index d0a863f967..04d44028d7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledThrowStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchLabeledThrowStatement.java @@ -4,12 +4,19 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; +import net.sourceforge.pmd.lang.ast.AbstractNode; + public class ASTSwitchLabeledThrowStatement extends AbstractJavaNode implements ASTSwitchLabeledRule { + @Deprecated + @InternalApi ASTSwitchLabeledThrowStatement(int id) { super(id); } + @Deprecated + @InternalApi ASTSwitchLabeledThrowStatement(JavaParser p, int id) { super(p, id); } @@ -18,4 +25,13 @@ public class ASTSwitchLabeledThrowStatement extends AbstractJavaNode implements public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + @Override + public void jjtClose() { + super.jjtClose(); + if (jjtGetNumChildren() > 0) { + AbstractNode firstChild = (AbstractNode) jjtGetChild(0); + jjtSetFirstToken(firstChild.jjtGetFirstToken()); + } + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java index 8517636d3d..3cfd558ada 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSwitchStatement.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTSwitchStatement.java */ package net.sourceforge.pmd.lang.java.ast; @@ -10,6 +9,8 @@ import java.util.Set; import org.apache.commons.lang3.EnumUtils; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a {@code switch} statement. @@ -21,10 +22,15 @@ import org.apache.commons.lang3.EnumUtils; * </pre> */ public class ASTSwitchStatement extends AbstractJavaNode implements Iterable<ASTSwitchLabel> { + + @InternalApi + @Deprecated public ASTSwitchStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTSwitchStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java index fb648a6b93..9feeab6b09 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTSynchronizedStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTSynchronizedStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTSynchronizedStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTSynchronizedStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTSynchronizedStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java index a40f862b59..697a3293c2 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTThrowStatement.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTThrowStatement.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTThrowStatement extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTThrowStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTThrowStatement(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -40,7 +43,7 @@ public class ASTThrowStatement extends AbstractJavaNode { * <p>TODO - use symbol table (?)</p> * * @return the image of the first ASTClassOrInterfaceType node found or - * <code>null</code> + * <code>null</code> */ public final String getFirstClassOrInterfaceTypeImage() { final ASTClassOrInterfaceType t = getFirstDescendantOfType(ASTClassOrInterfaceType.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java index 8f285a5bae..6dc45c4506 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTryStatement.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTryStatement.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Try statement node. @@ -16,10 +17,14 @@ import java.util.List; */ public class ASTTryStatement extends AbstractJavaNode { + @InternalApi + @Deprecated public ASTTryStatement(int id) { super(id); } + @InternalApi + @Deprecated public ASTTryStatement(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java index 5ac6d9fdc4..fa72849f94 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTType.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTType.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a type reference. * @@ -17,17 +18,19 @@ package net.sourceforge.pmd.lang.java.ast; * Note: it is not exactly the same the "UnnanType" defined in JLS. */ public class ASTType extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTType(int id) { super(id); } + @InternalApi + @Deprecated public ASTType(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -52,7 +55,7 @@ public class ASTType extends AbstractJavaTypeNode { @Deprecated public int getArrayDepth() { if (jjtGetNumChildren() != 0 - && (jjtGetChild(0) instanceof ASTReferenceType || jjtGetChild(0) instanceof ASTPrimitiveType)) { + && (jjtGetChild(0) instanceof ASTReferenceType || jjtGetChild(0) instanceof ASTPrimitiveType)) { return ((Dimensionable) jjtGetChild(0)).getArrayDepth(); } return 0; // this is not an array @@ -60,7 +63,6 @@ public class ASTType extends AbstractJavaTypeNode { /** - * * @deprecated Use {@link #isArrayType()} */ @Deprecated @@ -71,7 +73,6 @@ public class ASTType extends AbstractJavaTypeNode { /** * Returns true if this type is an array type. - * */ public boolean isArrayType() { return getArrayDepth() > 0; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java index 3e34d1f915..ab685da81f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArgument.java @@ -1,11 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTypeArgument.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a single type argument in a {@linkplain ASTTypeArguments type arguments list}. * @@ -17,10 +18,15 @@ package net.sourceforge.pmd.lang.java.ast; */ // TODO should implement Annotatable when we use can use Java 8 mixins instead of an abstract class public class ASTTypeArgument extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTTypeArgument(int id) { super(id); } + @InternalApi + @Deprecated public ASTTypeArgument(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java index 5f2be750fe..3724a8d3b3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeArguments.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTypeArguments.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a list of type arguments. This is different from {@linkplain ASTTypeParameters type parameters}! @@ -16,13 +17,17 @@ import java.util.Iterator; * TypeArguments ::= "<" {@linkplain ASTTypeArgument TypeArgument} ( "," {@linkplain ASTTypeArgument TypeArgument} )* ">" * | "<" ">" * </pre> - * */ public class ASTTypeArguments extends AbstractJavaNode implements Iterable<ASTTypeArgument> { + + @InternalApi + @Deprecated public ASTTypeArguments(int id) { super(id); } + @InternalApi + @Deprecated public ASTTypeArguments(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java index 79e75217f5..030177033a 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeBound.java @@ -1,12 +1,13 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTypeBound.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a type bound on a {@linkplain ASTTypeParameter type parameter}. @@ -22,11 +23,16 @@ import java.util.List; * </pre> */ public class ASTTypeBound extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTTypeBound(int id) { super(id); } + @InternalApi + @Deprecated public ASTTypeBound(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeDeclaration.java index f8ca47bdb3..cb9f2fb6fc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeDeclaration.java @@ -1,17 +1,22 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTypeDeclaration.java */ package net.sourceforge.pmd.lang.java.ast; import net.sourceforge.pmd.Rule; +import net.sourceforge.pmd.annotation.InternalApi; public class ASTTypeDeclaration extends AbstractJavaTypeNode implements CanSuppressWarnings { + + @InternalApi + @Deprecated public ASTTypeDeclaration(int id) { super(id); } + @InternalApi + @Deprecated public ASTTypeDeclaration(JavaParser p, int id) { super(p, id); } @@ -29,9 +34,6 @@ public class ASTTypeDeclaration extends AbstractJavaTypeNode implements CanSuppr return false; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java index e2f9729020..30947dab25 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameter.java @@ -1,11 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTypeParameter.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a type parameter declaration of a method, constructor, class or interface declaration. * @@ -15,15 +16,20 @@ package net.sourceforge.pmd.lang.java.ast; * * </pre> * - * @see <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-4.html#jls-4.4">JLS</a> + * @see <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-4.html#jls-4.4">JLS</a> */ // TODO should implement Annotatable when we use can use Java 8 mixins instead of an abstract class public class ASTTypeParameter extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTTypeParameter(int id) { super(id); } + @InternalApi + @Deprecated public ASTTypeParameter(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameters.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameters.java index 057f00308e..0606ffa150 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameters.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTTypeParameters.java @@ -1,13 +1,14 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTTypeParameters.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a list of type parameters. @@ -17,14 +18,17 @@ import java.util.Iterator; * TypeParameters ::= "<" {@linkplain ASTTypeParameter TypeParameter} ( "," {@linkplain ASTTypeParameter TypeParameter} )* ">" * * </pre> - * - * */ public class ASTTypeParameters extends AbstractJavaNode implements Iterable<ASTTypeParameter> { + + @InternalApi + @Deprecated public ASTTypeParameters(int id) { super(id); } + @InternalApi + @Deprecated public ASTTypeParameters(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpression.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpression.java index 1c1c9c5500..7ee2f1fbfb 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpression.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpression.java @@ -1,11 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTUnaryExpression.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a unary prefix operation on a value. * This has a precedence greater than {@link ASTMultiplicativeExpression}. @@ -26,10 +27,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTUnaryExpression extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTUnaryExpression(int id) { super(id); } + @InternalApi + @Deprecated public ASTUnaryExpression(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java index 1c64d3be0d..4f8a0ad4c3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTUnaryExpressionNotPlusMinus.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTUnaryExpressionNotPlusMinus.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a boolean negation or bitwise inverse operation. * This has the same precedence as {@linkplain ASTUnaryExpression UnaryExpression} @@ -20,10 +21,15 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTUnaryExpressionNotPlusMinus extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTUnaryExpressionNotPlusMinus(int id) { super(id); } + @InternalApi + @Deprecated public ASTUnaryExpressionNotPlusMinus(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java index 65d8bc63c5..783d8eb2d3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclarator.java @@ -1,12 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTVariableDeclarator.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.Iterator; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; @@ -22,11 +22,16 @@ import net.sourceforge.pmd.lang.ast.Node; * </pre> */ public class ASTVariableDeclarator extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTVariableDeclarator(int id) { super(id); } + @InternalApi + @Deprecated public ASTVariableDeclarator(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java index 8b70ed1caf..55d2b94471 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableDeclaratorId.java @@ -1,12 +1,12 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTVariableDeclaratorId.java */ package net.sourceforge.pmd.lang.java.ast; import java.util.List; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; @@ -40,10 +40,14 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim private VariableNameDeclaration nameDeclaration; private boolean explicitReceiverParameter = false; + @InternalApi + @Deprecated public ASTVariableDeclaratorId(int id) { super(id); } + @InternalApi + @Deprecated public ASTVariableDeclaratorId(JavaParser p, int id) { super(p, id); } @@ -64,6 +68,8 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim return nameDeclaration; } + @InternalApi + @Deprecated public void setNameDeclaration(VariableNameDeclaration decl) { nameDeclaration = decl; } @@ -86,6 +92,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim /** * Returns true if the declared variable has an array type. + * * @deprecated Use {@link #hasArrayType()} */ @Override @@ -119,7 +126,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim */ public boolean isFormalParameter() { return jjtGetParent() instanceof ASTFormalParameter && !isExceptionBlockParameter() && !isResourceDeclaration() - || isLambdaParamWithNoType(); + || isLambdaParamWithNoType(); } @@ -137,7 +144,8 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim * is not necessarily inferred, see {@link #isTypeInferred()}. */ public boolean isLambdaParameter() { - return isLambdaParamWithNoType() || jjtGetParent() instanceof ASTFormalParameter && getNthParent(3) instanceof ASTLambdaExpression; + return isLambdaParamWithNoType() + || jjtGetParent() instanceof ASTFormalParameter && getNthParent(3) instanceof ASTLambdaExpression; } @@ -195,6 +203,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim /** * @deprecated Will be made private with 7.0.0 */ + @InternalApi @Deprecated public void setExplicitReceiverParameter() { explicitReceiverParameter = true; @@ -252,7 +261,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim private boolean isLambdaTypeInferred() { return getNthParent(3) instanceof ASTLambdaExpression - && jjtGetParent().getFirstChildOfType(ASTType.class) == null; + && jjtGetParent().getFirstChildOfType(ASTType.class) == null; } /** @@ -276,7 +285,7 @@ public class ASTVariableDeclaratorId extends AbstractJavaTypeNode implements Dim * node. See {@link #getType()} for an explanation. * * @return the type node, or {@code null} if there is no explicit type, - * e.g. if {@link #isTypeInferred()} returns true. + * e.g. if {@link #isTypeInferred()} returns true. */ public ASTType getTypeNode() { if (jjtGetParent() instanceof ASTFormalParameter) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableInitializer.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableInitializer.java index 85a1e99dd7..d4d6370b54 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableInitializer.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTVariableInitializer.java @@ -1,22 +1,25 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTVariableInitializer.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + public class ASTVariableInitializer extends AbstractJavaNode { + + @InternalApi + @Deprecated public ASTVariableInitializer(int id) { super(id); } + @InternalApi + @Deprecated public ASTVariableInitializer(JavaParser p, int id) { super(p, id); } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java index 36d9c127ee..4e9cd3c5ec 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWhileStatement.java @@ -1,7 +1,6 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTWhileStatement.java */ package net.sourceforge.pmd.lang.java.ast; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java index d3c79fd2c8..659490ece4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTWildcardBounds.java @@ -1,10 +1,11 @@ /** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ -/* Generated By:JJTree: Do not edit this line. ASTWildcardBounds.java */ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * Represents a type bound on a wildcard {@linkplain ASTTypeArgument type argument}. * @@ -15,11 +16,16 @@ package net.sourceforge.pmd.lang.java.ast; * </pre> */ public class ASTWildcardBounds extends AbstractJavaTypeNode { + + @InternalApi + @Deprecated public ASTWildcardBounds(int id) { super(id); } + @InternalApi + @Deprecated public ASTWildcardBounds(JavaParser p, int id) { super(p, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java index 2d56c46e39..7d59f6c0b4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractAnyTypeDeclaration.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.qname.JavaTypeQualifiedName; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; @@ -12,6 +13,8 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin /** * Abstract class for type declarations nodes. */ +@Deprecated +@InternalApi public abstract class AbstractAnyTypeDeclaration extends AbstractJavaAccessTypeNode implements ASTAnyTypeDeclaration { private JavaTypeQualifiedName qualifiedName; @@ -30,7 +33,7 @@ public abstract class AbstractAnyTypeDeclaration extends AbstractJavaAccessTypeN @Override public final boolean isNested() { return jjtGetParent() instanceof ASTClassOrInterfaceBodyDeclaration - || jjtGetParent() instanceof ASTAnnotationTypeMemberDeclaration; + || jjtGetParent() instanceof ASTAnnotationTypeMemberDeclaration; } @@ -80,6 +83,8 @@ public abstract class AbstractAnyTypeDeclaration extends AbstractJavaAccessTypeN } + @InternalApi + @Deprecated public void setQualifiedName(JavaTypeQualifiedName qualifiedName) { this.qualifiedName = qualifiedName; this.typeDefinition = JavaTypeDefinition.forClass(qualifiedName.getType()); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java index da3063423e..5ca6472b45 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessNode.java @@ -4,14 +4,22 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + +@Deprecated +@InternalApi public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode implements AccessNode { private int modifiers; + @Deprecated + @InternalApi public AbstractJavaAccessNode(int i) { super(i); } + @Deprecated + @InternalApi public AbstractJavaAccessNode(JavaParser parser, int i) { super(parser, i); } @@ -21,6 +29,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return this.modifiers; } + @InternalApi + @Deprecated @Override public void setModifiers(int modifiers) { this.modifiers = modifiers; @@ -31,6 +41,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(PUBLIC); } + @InternalApi + @Deprecated @Override public void setPublic(boolean isPublic) { setModifier(isPublic, PUBLIC); @@ -41,6 +53,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(PROTECTED); } + @InternalApi + @Deprecated @Override public void setProtected(boolean isProtected) { setModifier(isProtected, PROTECTED); @@ -51,6 +65,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(PRIVATE); } + @InternalApi + @Deprecated @Override public void setPrivate(boolean isPrivate) { setModifier(isPrivate, PRIVATE); @@ -61,6 +77,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(ABSTRACT); } + @InternalApi + @Deprecated @Override public void setAbstract(boolean isAbstract) { setModifier(isAbstract, ABSTRACT); @@ -71,6 +89,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(STATIC); } + @InternalApi + @Deprecated @Override public void setStatic(boolean isStatic) { setModifier(isStatic, STATIC); @@ -81,6 +101,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(FINAL); } + @InternalApi + @Deprecated @Override public void setFinal(boolean isFinal) { setModifier(isFinal, FINAL); @@ -91,6 +113,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(SYNCHRONIZED); } + @InternalApi + @Deprecated @Override public void setSynchronized(boolean isSynchronized) { setModifier(isSynchronized, SYNCHRONIZED); @@ -101,6 +125,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(NATIVE); } + @InternalApi + @Deprecated @Override public void setNative(boolean isNative) { setModifier(isNative, NATIVE); @@ -111,6 +137,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(TRANSIENT); } + @InternalApi + @Deprecated @Override public void setTransient(boolean isTransient) { setModifier(isTransient, TRANSIENT); @@ -121,6 +149,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(VOLATILE); } + @InternalApi + @Deprecated @Override public void setVolatile(boolean isVolative) { setModifier(isVolative, VOLATILE); @@ -131,6 +161,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(STRICTFP); } + @InternalApi + @Deprecated @Override public void setStrictfp(boolean isStrictfp) { setModifier(isStrictfp, STRICTFP); @@ -141,6 +173,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return isModifier(DEFAULT); } + @InternalApi + @Deprecated @Override public void setDefault(boolean isDefault) { setModifier(isDefault, DEFAULT); @@ -150,6 +184,8 @@ public abstract class AbstractJavaAccessNode extends AbstractJavaAnnotatableNode return (modifiers & mask) == mask; } + @InternalApi + @Deprecated private void setModifier(boolean enable, int mask) { if (enable) { this.modifiers |= mask; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java index 220a3c13dd..137d203cb0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAccessTypeNode.java @@ -4,18 +4,26 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; +@Deprecated +@InternalApi public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode implements TypeNode { + /** * Type definition, used to get the type of the node. */ protected JavaTypeDefinition typeDefinition; + @Deprecated + @InternalApi public AbstractJavaAccessTypeNode(int i) { super(i); } + @Deprecated + @InternalApi public AbstractJavaAccessTypeNode(JavaParser parser, int i) { super(parser, i); } @@ -29,6 +37,8 @@ public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode return null; } + @InternalApi + @Deprecated @Override public void setType(Class<?> type) { typeDefinition = JavaTypeDefinition.forClass(type); @@ -39,6 +49,8 @@ public abstract class AbstractJavaAccessTypeNode extends AbstractJavaAccessNode return typeDefinition; } + @InternalApi + @Deprecated @Override public void setTypeDefinition(JavaTypeDefinition typeDefinition) { this.typeDefinition = typeDefinition; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAnnotatableNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAnnotatableNode.java index 36ae852ba2..cc0e84bed7 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAnnotatableNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaAnnotatableNode.java @@ -9,6 +9,7 @@ import java.util.List; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +// package private abstract class AbstractJavaAnnotatableNode extends AbstractJavaNode implements Annotatable { AbstractJavaAnnotatableNode(int i) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java index 735b0b58aa..f2eea9c709 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaNode.java @@ -4,19 +4,27 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.symboltable.Scope; +@Deprecated +@InternalApi public abstract class AbstractJavaNode extends AbstractNode implements JavaNode { protected JavaParser parser; private Scope scope; private Comment comment; + @InternalApi + @Deprecated public AbstractJavaNode(int id) { super(id); } + @InternalApi + @Deprecated public AbstractJavaNode(JavaParser parser, int id) { super(id); this.parser = parser; @@ -32,7 +40,7 @@ public abstract class AbstractJavaNode extends AbstractNode implements JavaNode @Override public void jjtClose() { - if (beginLine == -1 && (children == null || children.length == 0)) { + if (beginLine == -1 && children.length == 0) { beginColumn = parser.token.beginColumn; } if (beginLine == -1) { @@ -42,9 +50,6 @@ public abstract class AbstractJavaNode extends AbstractNode implements JavaNode endColumn = parser.token.endColumn; } - /** - * Accept the visitor. * - */ @Override public Object jjtAccept(JavaParserVisitor visitor, Object data) { return visitor.visit(this, data); @@ -62,22 +67,20 @@ public abstract class AbstractJavaNode extends AbstractNode implements JavaNode */ @Override public Object childrenAccept(JavaParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - ((JavaNode) children[i]).jjtAccept(visitor, data); - } + for (Node child : children) { + ((JavaNode) child).jjtAccept(visitor, data); } + return data; } @Override public <T> void childrenAccept(SideEffectingVisitor<T> visitor, T data) { - if (children != null) { - for (int i = 0; i < children.length; i++) { - ((JavaNode) children[i]).jjtAccept(visitor, data); - } + for (Node child : children) { + ((JavaNode) child).jjtAccept(visitor, data); } + } @@ -89,11 +92,15 @@ public abstract class AbstractJavaNode extends AbstractNode implements JavaNode return scope; } + @InternalApi + @Deprecated @Override public void setScope(Scope scope) { this.scope = scope; } + @InternalApi + @Deprecated public void comment(Comment theComment) { comment = theComment; } @@ -103,7 +110,6 @@ public abstract class AbstractJavaNode extends AbstractNode implements JavaNode } - @Override public final String getXPathNodeName() { return JavaParserTreeConstants.jjtNodeName[id]; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java index 8ade1689e3..78d973ad76 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractJavaTypeNode.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; /** @@ -12,13 +13,20 @@ import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefin * @see AbstractJavaNode * @see TypeNode */ +@Deprecated +@InternalApi public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements TypeNode { + private JavaTypeDefinition typeDefinition; + @InternalApi + @Deprecated public AbstractJavaTypeNode(int i) { super(i); } + @InternalApi + @Deprecated public AbstractJavaTypeNode(JavaParser p, int i) { super(p, i); } @@ -28,6 +36,8 @@ public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements T return typeDefinition == null ? null : typeDefinition.getType(); } + @InternalApi + @Deprecated @Override public void setType(Class<?> type) { typeDefinition = JavaTypeDefinition.forClass(type); @@ -38,6 +48,8 @@ public abstract class AbstractJavaTypeNode extends AbstractJavaNode implements T return typeDefinition; } + @InternalApi + @Deprecated @Override public void setTypeDefinition(JavaTypeDefinition typeDefinition) { this.typeDefinition = typeDefinition; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodLikeNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodLikeNode.java index 6e60b8639b..377cb438ff 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodLikeNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodLikeNode.java @@ -4,10 +4,13 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.qname.JavaOperationQualifiedName; - +@Deprecated +@InternalApi public abstract class AbstractMethodLikeNode extends AbstractJavaAccessNode implements MethodLikeNode { + private JavaOperationQualifiedName qualifiedName; @@ -21,6 +24,8 @@ public abstract class AbstractMethodLikeNode extends AbstractJavaAccessNode impl } + @InternalApi + @Deprecated public void setQualifiedName(JavaOperationQualifiedName qualifiedName) { this.qualifiedName = qualifiedName; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodOrConstructorDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodOrConstructorDeclaration.java index 5eba9d6c09..3885bcdd89 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodOrConstructorDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractMethodOrConstructorDeclaration.java @@ -4,9 +4,12 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.multifile.signature.JavaOperationSignature; +@Deprecated +@InternalApi public abstract class AbstractMethodOrConstructorDeclaration extends AbstractMethodLikeNode implements ASTMethodOrConstructorDeclaration { private JavaOperationSignature signature; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java index 92eedb762a..39ee9e8ed1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AbstractTypeBodyDeclaration.java @@ -15,11 +15,15 @@ import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.Declar import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind.INTERFACE; import static net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind.METHOD; +import net.sourceforge.pmd.annotation.InternalApi; + /** * @author Clément Fournier * @since 6.2.0 */ +@Deprecated +@InternalApi abstract class AbstractTypeBodyDeclaration extends AbstractJavaNode implements ASTAnyTypeBodyDeclaration { private DeclarationKind kind; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java index 1f233512df..803d1f6f73 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/AccessNode.java @@ -4,6 +4,7 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.ast.Node; /** @@ -24,57 +25,110 @@ public interface AccessNode extends Node { int STRICTFP = 0x1000; int DEFAULT = 0x2000; + int getModifiers(); + + @Deprecated + @InternalApi void setModifiers(int modifiers); + boolean isPublic(); + + @Deprecated + @InternalApi void setPublic(boolean isPublic); + boolean isProtected(); + + @Deprecated + @InternalApi void setProtected(boolean isProtected); + boolean isPrivate(); + + @Deprecated + @InternalApi void setPrivate(boolean isPrivate); + boolean isAbstract(); + + @Deprecated + @InternalApi void setAbstract(boolean isAbstract); + boolean isStatic(); + + @Deprecated + @InternalApi void setStatic(boolean isStatic); + boolean isFinal(); + + @Deprecated + @InternalApi void setFinal(boolean isFinal); + boolean isSynchronized(); + + @Deprecated + @InternalApi void setSynchronized(boolean isSynchronized); + boolean isNative(); + + @Deprecated + @InternalApi void setNative(boolean isNative); + boolean isTransient(); + + @Deprecated + @InternalApi void setTransient(boolean isTransient); + boolean isVolatile(); + + @Deprecated + @InternalApi void setVolatile(boolean isVolatile); + boolean isStrictfp(); + + @Deprecated + @InternalApi void setStrictfp(boolean isStrictfp); + boolean isPackagePrivate(); + + @Deprecated + @InternalApi void setDefault(boolean isDefault); + boolean isDefault(); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DummyJavaNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DummyJavaNode.java index ae5f8cc56c..9dba937df5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DummyJavaNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/DummyJavaNode.java @@ -4,16 +4,24 @@ package net.sourceforge.pmd.lang.java.ast; +import net.sourceforge.pmd.annotation.InternalApi; + /** * This is a basic JavaNode implementation, useful when needing to create a * dummy node. */ +@Deprecated +@InternalApi public class DummyJavaNode extends AbstractJavaNode { + @InternalApi + @Deprecated public DummyJavaNode(int id) { super(id); } + @InternalApi + @Deprecated public DummyJavaNode(JavaParser parser, int id) { super(parser, id); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java index 9321589b9d..24fca2b766 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/JavaNode.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.ast; + +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.symboltable.Scope; import net.sourceforge.pmd.lang.symboltable.ScopedNode; @@ -59,5 +61,8 @@ public interface JavaNode extends ScopedNode { <T> void childrenAccept(SideEffectingVisitor<T> visitor, T data); + @InternalApi + @Deprecated void setScope(Scope scope); + } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeNode.java index 91a2518be5..55632f5e36 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/TypeNode.java @@ -4,13 +4,13 @@ package net.sourceforge.pmd.lang.java.ast; -import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.lang.java.typeresolution.typedefinition.JavaTypeDefinition; /** * This interface allows a Java Class to be associated with a node. */ -public interface TypeNode extends Node { +public interface TypeNode extends JavaNode { /** * Get the Java Class associated with this node. @@ -19,6 +19,7 @@ public interface TypeNode extends Node { */ Class<?> getType(); + /** * Get the TypeDefinition associated with this node. The Class object * contained in the TypeDefinition will always be equal to that which @@ -28,17 +29,23 @@ public interface TypeNode extends Node { */ JavaTypeDefinition getTypeDefinition(); + /** * Set the TypeDefinition associated with this node. * * @param type A TypeDefinition object */ + @Deprecated + @InternalApi void setTypeDefinition(JavaTypeDefinition type); + /** * Set the Java Class associated with this node. * * @param type A Java Class */ + @Deprecated + @InternalApi void setType(Class<?> type); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/package-info.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/package-info.java index bd306f8570..cffd277fd0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/package-info.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/package-info.java @@ -4,5 +4,27 @@ /** * Contains the classes and interfaces modelling the Java AST. + * + * <p>Note: from 6.16.0 on, the following usages have been deprecated: + * <ul> + * <li>Manual instantiation of nodes. Constructors of node classes are + * deprecated and marked {@link net.sourceforge.pmd.annotation.InternalApi}. + * Nodes should only be obtained from the parser, which for rules, + * means that never need to instantiate node themselves. Those + * constructors will be made package private with 7.0.0. + * <li>Subclassing of base node classes, or usage of their type. + * Version 7.0.0 will bring a new set of abstractions that will + * be public API, but the base classes are and will stay internal. + * You should not couple your code to them. + * <p>In the meantime you should use interfaces like {@link net.sourceforge.pmd.lang.java.ast.JavaNode} + * or {@link net.sourceforge.pmd.lang.ast.Node}, or the other published + * interfaces in this package, to refer to nodes generically. + * </li> + * <li>Setters found in any node class or interface. Rules should consider + * the AST immutable. We will make those setters package private + * with 7.0.0. + * </li> + * </ul> + * */ package net.sourceforge.pmd.lang.java.ast; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/VariableAccessVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/VariableAccessVisitor.java index ecd6348877..40caf39014 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/VariableAccessVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/dfa/VariableAccessVisitor.java @@ -4,7 +4,9 @@ package net.sourceforge.pmd.lang.java.dfa; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -14,10 +16,13 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.dfa.DataFlowNode; import net.sourceforge.pmd.lang.dfa.StartOrEndDataFlowNode; import net.sourceforge.pmd.lang.dfa.VariableAccess; +import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTFormalParameter; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.JavaParserVisitorAdapter; @@ -45,6 +50,8 @@ public class VariableAccessVisitor extends JavaParserVisitorAdapter { } private void computeNow(Node node) { + + DataFlowNode inode = node.getDataFlowNode(); List<VariableAccess> undefinitions = markUsages(inode); @@ -65,7 +72,6 @@ public class VariableAccessVisitor extends JavaParserVisitorAdapter { for (Map<VariableNameDeclaration, List<NameOccurrence>> declarations : variableDeclarations) { for (Map.Entry<VariableNameDeclaration, List<NameOccurrence>> entry : declarations.entrySet()) { VariableNameDeclaration vnd = entry.getKey(); - if (vnd.getAccessNodeParent() instanceof ASTFormalParameter) { // no definition/undefinition/references for parameters continue; @@ -76,8 +82,37 @@ public class VariableAccessVisitor extends JavaParserVisitorAdapter { } undefinitions.add(new VariableAccess(VariableAccess.UNDEFINITION, vnd.getImage())); + //Map the name occurrences to their assignment expressions, if any + List<SimpleEntry<Node, NameOccurrence>> occurrencesWithAssignmentExp = new ArrayList<>(); for (NameOccurrence occurrence : entry.getValue()) { - addAccess((JavaNameOccurrence) occurrence, inode); + // find the nearest assignment, if any + Node potentialAssignment = occurrence.getLocation().getFirstParentOfAnyType(ASTStatementExpression.class, + ASTExpression.class); + while (potentialAssignment != null + && (potentialAssignment.jjtGetNumChildren() < 2 + || !(potentialAssignment.jjtGetChild(1) instanceof ASTAssignmentOperator))) { + potentialAssignment = potentialAssignment.getFirstParentOfAnyType(ASTStatementExpression.class, + ASTExpression.class); + } + // at this point, potentialAssignment is either a assignment or null + occurrencesWithAssignmentExp.add(new SimpleEntry<>(potentialAssignment, occurrence)); + } + + //The name occurrences are in source code order, the means, the left hand side of + //the assignment is first. But this is not the order in which the data flows: first the + //right hand side is evaluated before the left hand side is assigned. + //Therefore move the name occurrences backwards if they belong to the same assignment expression. + for (int i = 0; i < occurrencesWithAssignmentExp.size() - 1; i++) { + SimpleEntry<Node, NameOccurrence> oc = occurrencesWithAssignmentExp.get(i); + SimpleEntry<Node, NameOccurrence> nextOc = occurrencesWithAssignmentExp.get(i + 1); + + if (oc.getKey() != null && oc.getKey().equals(nextOc.getKey())) { + Collections.swap(occurrencesWithAssignmentExp, i, i + 1); + } + } + + for (SimpleEntry<Node, NameOccurrence> oc : occurrencesWithAssignmentExp) { + addAccess((JavaNameOccurrence) oc.getValue(), inode); } } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/AtfdBaseVisitor.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/AtfdBaseVisitor.java index 93e864fb45..87be295218 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/AtfdBaseVisitor.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/metrics/internal/visitors/AtfdBaseVisitor.java @@ -29,28 +29,44 @@ public class AtfdBaseVisitor extends JavaParserVisitorAdapter { @Override public Object visit(ASTPrimaryExpression node, Object data) { - if (isForeignAttributeOrMethod(node) && (isAttributeAccess(node) - || isMethodCall(node) && isForeignGetterSetterCall(node))) { - - ((MutableInt) data).increment(); + if (isForeignAttributeOrMethod(node)) { + if (isAttributeAccess(node)) { + ((MutableInt) data).increment(); + } else { + ((MutableInt) data).add(countForeignGetterSetterCalls(node)); + } } return super.visit(node, data); } private boolean isForeignGetterSetterCall(ASTPrimaryExpression node) { - String methodOrAttributeName = getMethodOrAttributeName(node); + return isForeignGetterSetterCall(methodOrAttributeName); + } + + private boolean isForeignGetterSetterCall(String methodOrAttributeName) { return methodOrAttributeName != null && StringUtils.startsWithAny(methodOrAttributeName, "get", "is", "set"); } - private boolean isMethodCall(ASTPrimaryExpression node) { - boolean result = false; + private int countForeignGetterSetterCalls(ASTPrimaryExpression node) { + if (!isForeignGetterSetterCall(node) || !isForeignAttributeOrMethod(node)) { + return 0; + } + List<ASTPrimarySuffix> suffixes = node.findDescendantsOfType(ASTPrimarySuffix.class); - if (suffixes.size() == 1) { - result = suffixes.get(0).isArguments(); + int result = 0; + for (ASTPrimarySuffix suffix : suffixes) { + if (suffix.isArguments()) { + result++; + } else { + String methodOrAttributeName = getMethodOrAttributeName(suffix); + if (!isForeignGetterSetterCall(methodOrAttributeName)) { + break; + } + } } return result; } @@ -103,6 +119,11 @@ public class AtfdBaseVisitor extends JavaParserVisitorAdapter { } + private String getMethodOrAttributeName(ASTPrimarySuffix node) { + return node.getImage(); + } + + private boolean isAttributeAccess(ASTPrimaryExpression node) { return !node.hasDescendantOfType(ASTPrimarySuffix.class); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AbstractSunSecureRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AbstractSunSecureRule.java index 1e44a3959f..542a58dc2f 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AbstractSunSecureRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AbstractSunSecureRule.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTConditionalExpression; import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; @@ -15,7 +16,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; @@ -38,7 +38,7 @@ public abstract class AbstractSunSecureRule extends AbstractJavaRule { * @return <code>true</code> if there is a field in the type declaration * named varName, <code>false</code> in other case */ - protected final boolean isField(String varName, ASTTypeDeclaration typeDeclaration) { + protected final boolean isField(String varName, ASTAnyTypeDeclaration typeDeclaration) { final List<ASTFieldDeclaration> fds = typeDeclaration.findDescendantsOfType(ASTFieldDeclaration.class); if (fds != null) { for (ASTFieldDeclaration fd : fds) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java index 71170722eb..1e3eb552b8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/MethodReturnsInternalArrayRule.java @@ -10,6 +10,7 @@ import org.jaxen.JaxenException; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTArrayInitializer; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTExpression; @@ -20,7 +21,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; -import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; @@ -46,7 +46,7 @@ public class MethodReturnsInternalArrayRule extends AbstractSunSecureRule { return data; } List<ASTReturnStatement> returns = method.findDescendantsOfType(ASTReturnStatement.class); - ASTTypeDeclaration td = method.getFirstParentOfType(ASTTypeDeclaration.class); + ASTAnyTypeDeclaration td = method.getFirstParentOfType(ASTAnyTypeDeclaration.class); for (ASTReturnStatement ret : returns) { final String vn = getReturnedVariableName(ret); if (!isField(vn, td)) { @@ -111,7 +111,7 @@ public class MethodReturnsInternalArrayRule extends AbstractSunSecureRule { return false; } - private boolean isEmptyArray(String varName, ASTTypeDeclaration typeDeclaration) { + private boolean isEmptyArray(String varName, ASTAnyTypeDeclaration typeDeclaration) { final List<ASTFieldDeclaration> fds = typeDeclaration.findDescendantsOfType(ASTFieldDeclaration.class); if (fds != null) { for (ASTFieldDeclaration fd : fds) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java index 394acd77a8..51cdbaf53e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateFieldRule.java @@ -36,6 +36,7 @@ public class UnusedPrivateFieldRule extends AbstractLombokAwareRule { defaultValues.addAll(super.defaultSuppressionAnnotations()); defaultValues.add("java.lang.Deprecated"); defaultValues.add("javafx.fxml.FXML"); + defaultValues.add("lombok.experimental.Delegate"); return defaultValues; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java index 37c5eac750..2891b13843 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/CommentDefaultAccessModifierRule.java @@ -11,16 +11,18 @@ import java.util.List; import java.util.Set; import java.util.regex.Pattern; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; -import net.sourceforge.pmd.lang.java.ast.AbstractAnyTypeDeclaration; -import net.sourceforge.pmd.lang.java.ast.AbstractJavaAccessNode; +import net.sourceforge.pmd.lang.java.ast.AccessNode; +import net.sourceforge.pmd.lang.java.ast.Annotatable; import net.sourceforge.pmd.lang.java.ast.Comment; import net.sourceforge.pmd.lang.java.rule.AbstractIgnoredAnnotationRule; import net.sourceforge.pmd.properties.PropertyDescriptor; @@ -37,13 +39,17 @@ import net.sourceforge.pmd.properties.PropertyFactory; public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationRule { private static final PropertyDescriptor<Pattern> REGEX_DESCRIPTOR = PropertyFactory.regexProperty("regex") - .desc("Regular expression").defaultValue("\\/\\*\\s+(default|package)\\s+\\*\\/").build(); + .desc("Regular expression").defaultValue("\\/\\*\\s+(default|package)\\s+\\*\\/").build(); + private static final PropertyDescriptor<Boolean> TOP_LEVEL_TYPES = PropertyFactory.booleanProperty("checkTopLevelTypes") + .desc("Check for default access modifier in top-level classes, annotations, and enums") + .defaultValue(false).build(); private static final String MESSAGE = "To avoid mistakes add a comment " + "at the beginning of the %s %s if you want a default access modifier"; private final Set<Integer> interestingLineNumberComments = new HashSet<>(); public CommentDefaultAccessModifierRule() { definePropertyDescriptor(REGEX_DESCRIPTOR); + definePropertyDescriptor(TOP_LEVEL_TYPES); } @Override @@ -84,11 +90,28 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR return super.visit(decl, data); } + @Override + public Object visit(final ASTAnnotationTypeDeclaration decl, final Object data) { + if (!decl.isNested() && shouldReportTypeDeclaration(decl)) { // check for top-level annotation declarations + addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "top-level annotation")); + } + return super.visit(decl, data); + } + + @Override + public Object visit(final ASTEnumDeclaration decl, final Object data) { + if (!decl.isNested() && shouldReportTypeDeclaration(decl)) { // check for top-level enums + addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "top-level enum")); + } + return super.visit(decl, data); + } + @Override public Object visit(final ASTClassOrInterfaceDeclaration decl, final Object data) { - // check for nested classes - if (decl.isNested() && shouldReport(decl)) { + if (decl.isNested() && shouldReport(decl)) { // check for nested classes addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "nested class")); + } else if (!decl.isNested() && shouldReportTypeDeclaration(decl)) { // and for top-level ones + addViolationWithMessage(data, decl, String.format(MESSAGE, decl.getImage(), "top-level class")); } return super.visit(decl, data); } @@ -101,23 +124,39 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR return super.visit(decl, data); } - private boolean shouldReport(final AbstractJavaAccessNode decl) { - final AbstractAnyTypeDeclaration parentClassOrInterface = decl - .getFirstParentOfType(AbstractAnyTypeDeclaration.class); + private boolean shouldReport(final AccessNode decl) { + final ASTAnyTypeDeclaration parentClassOrInterface = decl + .getFirstParentOfType(ASTAnyTypeDeclaration.class); boolean isConcreteClass = parentClassOrInterface.getTypeKind() == ASTAnyTypeDeclaration.TypeKind.CLASS; - boolean isEnumConstructor = parentClassOrInterface.getTypeKind() == ASTAnyTypeDeclaration.TypeKind.ENUM - && decl instanceof ASTConstructorDeclaration; - // ignore if it's an Interface / Annotation / Enum constructor - return isConcreteClass && !isEnumConstructor - // check if the field/method/nested class has a default access - // modifier - && decl.isPackagePrivate() + // ignore if it's inside an interface / Annotation + return isConcreteClass && isMissingComment(decl); + } + + protected boolean hasIgnoredAnnotation(AccessNode node) { + if (node instanceof Annotatable) { + return hasIgnoredAnnotation((Annotatable) node); + } + return false; + } + + private boolean isMissingComment(AccessNode decl) { + // check if the class/method/field has a default access + // modifier + return decl.isPackagePrivate() // if is a default access modifier check if there is a comment // in this line && !interestingLineNumberComments.contains(decl.getBeginLine()) // that it is not annotated with e.g. @VisibleForTesting && !hasIgnoredAnnotation(decl); } + + private boolean shouldReportTypeDeclaration(ASTAnyTypeDeclaration decl) { + // don't report on interfaces + return decl.getTypeKind() != ASTAnyTypeDeclaration.TypeKind.INTERFACE + && isMissingComment(decl) + // either nested or top level and we should check it + && (decl.isNested() || getProperty(TOP_LEVEL_TYPES)); + } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/DuplicateImportsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/DuplicateImportsRule.java index 28963d7557..655cd8c600 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/DuplicateImportsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/DuplicateImportsRule.java @@ -87,19 +87,19 @@ public class DuplicateImportsRule extends AbstractJavaRule { @Override public Object visit(ASTImportDeclaration node, Object data) { ImportWrapper wrapper = new ImportWrapper(node.getImportedName(), node.getImportedName(), - node.getImportedNameNode(), node.isStatic() && node.isImportOnDemand()); + node, node.isStatic() && node.isImportOnDemand()); // blahhhh... this really wants to be ASTImportDeclaration to be // polymorphic... if (node.isImportOnDemand()) { if (importOnDemandImports.contains(wrapper)) { - addViolation(data, node.getImportedNameNode(), node.getImportedNameNode().getImage()); + addViolation(data, node, node.getImportedName()); } else { importOnDemandImports.add(wrapper); } } else { if (singleTypeImports.contains(wrapper)) { - addViolation(data, node.getImportedNameNode(), node.getImportedNameNode().getImage()); + addViolation(data, node, node.getImportedName()); } else { singleTypeImports.add(wrapper); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java index 74fff9114f..904b7dbdd4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldNamingConventionsRule.java @@ -26,7 +26,7 @@ public class FieldNamingConventionsRule extends AbstractNamingConventionRule<AST private static final PropertyDescriptor<List<String>> EXCLUDED_NAMES = PropertyFactory.stringListProperty("exclusions") .desc("Names of fields to whitelist.") - .defaultValues("serialVersionUID") + .defaultValues("serialVersionUID", "serialPersistentFields") .build(); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryFullyQualifiedNameRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryFullyQualifiedNameRule.java index 9353548a71..66e892edb0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryFullyQualifiedNameRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryFullyQualifiedNameRule.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.java.rule.codestyle; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import java.util.Map.Entry; import java.util.Objects; import java.util.Set; @@ -20,10 +21,13 @@ import net.sourceforge.pmd.lang.java.ast.ASTPackageDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.AbstractJavaTypeNode; import net.sourceforge.pmd.lang.java.ast.JavaNode; +import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.symboltable.SourceFileScope; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; +import net.sourceforge.pmd.lang.symboltable.Scope; public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule { @@ -102,8 +106,16 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule { return false; } - private void checkImports(AbstractJavaTypeNode node, Object data) { - String name = node.getImage(); + private void checkImports(TypeNode node, Object data) { + final String name = node.getImage(); + + // variable names shadow everything else + // If the first segment is a variable, then all + // the following are field accesses and it's not an FQCN + if (isVariable(node.getScope(), name)) { + return; + } + List<ASTImportDeclaration> matches = new ArrayList<>(); // Find all "matching" import declarations @@ -172,7 +184,7 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule { if (matches.isEmpty()) { if (isJavaLangImplicit(node)) { addViolation(data, node, new Object[] { node.getImage(), "java.lang.*", "implicit "}); - } else if (isSamePackage(node)) { + } else if (isSamePackage(node, name)) { addViolation(data, node, new Object[] { node.getImage(), currentPackage + ".*", "same package "}); } } else { @@ -211,12 +223,45 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule { return result; } - private boolean isSamePackage(AbstractJavaTypeNode node) { - String name = node.getImage(); - return name.substring(0, name.lastIndexOf('.')).equals(currentPackage); + private boolean isVariable(Scope scope, String name) { + String firstSegment = name.substring(0, name.indexOf('.')); + + while (scope != null) { + + for (Entry<VariableNameDeclaration, List<NameOccurrence>> entry : scope.getDeclarations(VariableNameDeclaration.class).entrySet()) { + if (entry.getKey().getName().equals(firstSegment)) { + return true; + } + } + + scope = scope.getParent(); + } + + return false; } - - private boolean isJavaLangImplicit(AbstractJavaTypeNode node) { + + private boolean isSamePackage(TypeNode node, String name) { + if (node.getType() != null) { + // with type resolution we can do an exact package match + Package packageOfType = node.getType().getPackage(); + if (packageOfType != null) { + return node.getType().getPackage().getName().equals(currentPackage); + } + } + + int i = name.lastIndexOf('.'); + while (i > 0) { + name = name.substring(0, i); + if (name.equals(currentPackage)) { + return true; + } + i = name.lastIndexOf('.'); + } + + return false; + } + + private boolean isJavaLangImplicit(TypeNode node) { String name = node.getImage(); boolean isJavaLang = name != null && name.startsWith("java.lang."); @@ -232,8 +277,8 @@ public class UnnecessaryFullyQualifiedNameRule extends AbstractJavaRule { return false; } - private boolean isAvoidingConflict(final AbstractJavaTypeNode node, final String name, - final ASTImportDeclaration firstMatch) { + private boolean isAvoidingConflict(final TypeNode node, final String name, + final ASTImportDeclaration firstMatch) { // is it a conflict between different imports? if (firstMatch.isImportOnDemand() && firstMatch.isStatic()) { final String methodCalled = name.substring(name.indexOf('.') + 1); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java index 056878a58f..82dab662ef 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java @@ -136,7 +136,7 @@ public class UnnecessaryLocalBeforeReturnRule extends AbstractJavaRule { final ASTBlockStatement location = occ.getLocation().getFirstParentOfType(ASTBlockStatement.class); // Is it used after initializing our "unnecessary" local but before the return statement? - if (isAfter(location, initializerStmt) && isAfter(rtnStmt, location)) { + if (location != null && isAfter(location, initializerStmt) && isAfter(rtnStmt, location)) { return true; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java index 69ccf0c6d8..48e096061d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SingularFieldRule.java @@ -6,6 +6,8 @@ package net.sourceforge.pmd.lang.java.rule.design; import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -47,6 +49,14 @@ public class SingularFieldRule extends AbstractLombokAwareRule { definePropertyDescriptor(DISALLOW_NOT_ASSIGNMENT); } + @Override + protected Collection<String> defaultSuppressionAnnotations() { + Collection<String> defaultValues = new ArrayList<>(); + defaultValues.addAll(super.defaultSuppressionAnnotations()); + defaultValues.add("lombok.experimental.Delegate"); + return defaultValues; + } + @SuppressWarnings("PMD.CompareObjectsWithEquals") @Override public Object visit(ASTFieldDeclaration node, Object data) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java index 6273d61bd0..a3fa7780bc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.java.rule.design; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; @@ -17,24 +19,35 @@ import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTResultType; -import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.rule.AbstractLombokAwareRule; -public class UseUtilityClassRule extends AbstractJavaRule { +public class UseUtilityClassRule extends AbstractLombokAwareRule { - public UseUtilityClassRule() { - addRuleChainVisit(ASTClassOrInterfaceBody.class); + @Override + protected Collection<String> defaultSuppressionAnnotations() { + return Arrays.asList("lombok.experimental.UtilityClass"); + } + + @Override + public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { + if (hasIgnoredAnnotation(node)) { + return data; + } + return super.visit(node, data); } @Override public Object visit(ASTClassOrInterfaceBody decl, Object data) { + Object result = super.visit(decl, data); + if (decl.jjtGetParent() instanceof ASTClassOrInterfaceDeclaration) { ASTClassOrInterfaceDeclaration parent = (ASTClassOrInterfaceDeclaration) decl.jjtGetParent(); if (parent.isAbstract() || parent.isInterface() || parent.getSuperClassTypeNode() != null) { - return data; + return result; } - if (isOkUsingLombok(parent)) { - return data; + if (hasLombokNoArgsConstructor(parent)) { + return result; } int i = decl.jjtGetNumChildren(); @@ -81,10 +94,10 @@ public class UseUtilityClassRule extends AbstractJavaRule { addViolation(data, decl); } } - return data; + return result; } - private boolean isOkUsingLombok(ASTClassOrInterfaceDeclaration parent) { + private boolean hasLombokNoArgsConstructor(ASTClassOrInterfaceDeclaration parent) { // check if there's a lombok no arg private constructor, if so skip the rest of the rules ASTAnnotation annotation = parent.getAnnotation("lombok.NoArgsConstructor"); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java index 56ab5c1e96..d14a2f7551 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/documentation/CommentRequiredRule.java @@ -56,6 +56,9 @@ public class CommentRequiredRule extends AbstractCommentRule { private static final PropertyDescriptor<CommentRequirement> SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR = requirementPropertyBuilder("serialVersionUIDCommentRequired", "Serial version UID comments") .defaultValue(CommentRequirement.Ignored).build(); + private static final PropertyDescriptor<CommentRequirement> SERIAL_PERSISTENT_FIELDS_CMT_REQUIREMENT_DESCRIPTOR + = requirementPropertyBuilder("serialPersistentFieldsCommentRequired", "Serial persistent fields comments") + .defaultValue(CommentRequirement.Ignored).build(); public CommentRequiredRule() { @@ -67,6 +70,7 @@ public class CommentRequiredRule extends AbstractCommentRule { definePropertyDescriptor(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(ENUM_CMT_REQUIREMENT_DESCRIPTOR); definePropertyDescriptor(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR); + definePropertyDescriptor(SERIAL_PERSISTENT_FIELDS_CMT_REQUIREMENT_DESCRIPTOR); } @@ -154,6 +158,8 @@ public class CommentRequiredRule extends AbstractCommentRule { public Object visit(ASTFieldDeclaration decl, Object data) { if (isSerialVersionUID(decl)) { checkCommentMeetsRequirement(data, decl, SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR); + } else if (isSerialPersistentFields(decl)) { + checkCommentMeetsRequirement(data, decl, SERIAL_PERSISTENT_FIELDS_CMT_REQUIREMENT_DESCRIPTOR); } else { checkCommentMeetsRequirement(data, decl, FIELD_CMT_REQUIREMENT_DESCRIPTOR); } @@ -169,6 +175,24 @@ public class CommentRequiredRule extends AbstractCommentRule { && field.getType() == long.class; } + /** + * Whether the given field is a serialPersistentFields variable. + * <p/> + * This field must be initialized with an array of ObjectStreamField objects. + * The modifiers for the field are required to be private, static, and final. + * + * @see <a href="https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html#6250">Oracle docs</a> + * @param field the field, must not be null + * @return true if the field ia a serialPersistentFields variable, otherwise false + */ + private boolean isSerialPersistentFields(final ASTFieldDeclaration field) { + return "serialPersistentFields".equals(field.getVariableName()) + && field.isPrivate() + && field.isStatic() + && field.isFinal() + && field.isArray() + && "ObjectStreamField".equals(field.jjtGetFirstToken().getImage()); // .getType() returns null + } @Override public Object visit(ASTEnumDeclaration decl, Object data) { @@ -192,7 +216,8 @@ public class CommentRequiredRule extends AbstractCommentRule { && getProperty(PUB_METHOD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored && getProperty(PROT_METHOD_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored && getProperty(ENUM_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored - && getProperty(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored; + && getProperty(SERIAL_VERSION_UID_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored + && getProperty(SERIAL_PERSISTENT_FIELDS_CMT_REQUIREMENT_DESCRIPTOR) == CommentRequirement.Ignored; } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java index 2febbcd39f..a9cad8b0ac 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloseResourceRule.java @@ -8,19 +8,23 @@ import static net.sourceforge.pmd.properties.PropertyFactory.booleanProperty; import static net.sourceforge.pmd.properties.PropertyFactory.stringListProperty; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.jaxen.JaxenException; +import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTBlock; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; -import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; @@ -29,13 +33,18 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.ASTReferenceType; +import net.sourceforge.pmd.lang.java.ast.ASTResourceSpecification; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression; import net.sourceforge.pmd.lang.java.ast.ASTTryStatement; -import net.sourceforge.pmd.lang.java.ast.ASTType; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.ASTVariableInitializer; +import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; +import net.sourceforge.pmd.lang.symboltable.NameOccurrence; import net.sourceforge.pmd.properties.PropertyDescriptor; /** @@ -69,37 +78,46 @@ public class CloseResourceRule extends AbstractJavaRule { private static final PropertyDescriptor<List<String>> TYPES_DESCRIPTOR = stringListProperty("types") .desc("Affected types") - .defaultValues("java.sql.Connection", "java.sql.Statement", "java.sql.ResultSet") + .defaultValues("java.lang.AutoCloseable", "java.sql.Connection", "java.sql.Statement", "java.sql.ResultSet") .delim(',').build(); private static final PropertyDescriptor<Boolean> USE_CLOSE_AS_DEFAULT_TARGET = booleanProperty("closeAsDefaultTarget") .desc("Consider 'close' as a target by default").defaultValue(true).build(); + private static final PropertyDescriptor<List<String>> ALLOWED_RESOURCE_TYPES = + stringListProperty("allowedResourceTypes") + .desc("Exact class names that do not need to be closed") + .defaultValues("java.io.ByteArrayOutputStream", "java.io.ByteArrayInputStream", "java.io.StringWriter", + "java.io.CharArrayWriter") + .build(); + public CloseResourceRule() { definePropertyDescriptor(CLOSE_TARGETS_DESCRIPTOR); definePropertyDescriptor(TYPES_DESCRIPTOR); definePropertyDescriptor(USE_CLOSE_AS_DEFAULT_TARGET); + definePropertyDescriptor(ALLOWED_RESOURCE_TYPES); } @Override - public Object visit(ASTCompilationUnit node, Object data) { - if (closeTargets.isEmpty() && getProperty(CLOSE_TARGETS_DESCRIPTOR) != null) { + public void start(RuleContext ctx) { + closeTargets.clear(); + simpleTypes.clear(); + types.clear(); + + if (getProperty(CLOSE_TARGETS_DESCRIPTOR) != null) { closeTargets.addAll(getProperty(CLOSE_TARGETS_DESCRIPTOR)); } if (getProperty(USE_CLOSE_AS_DEFAULT_TARGET) && !closeTargets.contains("close")) { closeTargets.add("close"); } - if (types.isEmpty() && getProperty(TYPES_DESCRIPTOR) != null) { + if (getProperty(TYPES_DESCRIPTOR) != null) { types.addAll(getProperty(TYPES_DESCRIPTOR)); - } - if (simpleTypes.isEmpty() && getProperty(TYPES_DESCRIPTOR) != null) { for (String type : getProperty(TYPES_DESCRIPTOR)) { simpleTypes.add(toSimpleType(type)); } } - return super.visit(node, data); } private static String toSimpleType(String fullyQualifiedClassName) { @@ -124,36 +142,120 @@ public class CloseResourceRule extends AbstractJavaRule { } private void checkForResources(Node node, Object data) { - List<ASTLocalVariableDeclaration> vars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class); - List<ASTVariableDeclaratorId> ids = new ArrayList<>(); + List<ASTLocalVariableDeclaration> localVars = node.findDescendantsOfType(ASTLocalVariableDeclaration.class); + List<ASTVariableDeclarator> vars = new ArrayList<>(); + Map<ASTVariableDeclaratorId, TypeNode> ids = new HashMap<>(); + + // find all variable declarators + for (ASTLocalVariableDeclaration localVar : localVars) { + vars.addAll(localVar.findChildrenOfType(ASTVariableDeclarator.class)); + } // find all variable references to Connection objects - for (ASTLocalVariableDeclaration var : vars) { - ASTType type = var.getTypeNode(); + for (ASTVariableDeclarator var : vars) { + // get the type of the local var declaration + TypeNode type = ((ASTLocalVariableDeclaration) var.jjtGetParent()).getTypeNode(); - if (type != null && type.jjtGetChild(0) instanceof ASTReferenceType) { - ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0); - if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) { - ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); - - if (clazz.getType() != null && types.contains(clazz.getType().getName()) - || clazz.getType() == null && simpleTypes.contains(toSimpleType(clazz.getImage())) - && !clazz.isReferenceToClassSameCompilationUnit() - || types.contains(clazz.getImage()) && !clazz.isReferenceToClassSameCompilationUnit()) { - - ASTVariableDeclaratorId id = var.getFirstDescendantOfType(ASTVariableDeclaratorId.class); - ids.add(id); + if (type != null && isResourceTypeOrSubtype(type)) { + if (var.hasInitializer()) { + // figure out the runtime type. If the variable is initialized, take the type from there + ASTExpression expression = var.getInitializer().getFirstChildOfType(ASTExpression.class); + TypeNode runtimeType = expression; + if (!isMethodCall(expression) && runtimeType != null && runtimeType.getType() != null) { + type = runtimeType; } + + // consider cases, when the streams are chained + // assumes, that the underlaying stream is always the first argument in the + // constructor call. + ASTExpression firstArgument = getAllocationFirstArgument(expression); + if (firstArgument != null) { + type = firstArgument; + } + } + + if (!isAllowedResourceType(type)) { + ids.put(var.getVariableId(), type); } } } // if there are connections, ensure each is closed. - for (ASTVariableDeclaratorId x : ids) { - ensureClosed((ASTLocalVariableDeclaration) x.jjtGetParent().jjtGetParent(), x, data); + for (Map.Entry<ASTVariableDeclaratorId, TypeNode> entry : ids.entrySet()) { + ASTVariableDeclaratorId variableId = entry.getKey(); + ensureClosed((ASTLocalVariableDeclaration) variableId.jjtGetParent().jjtGetParent(), variableId, + entry.getValue(), data); } } + private ASTExpression getAllocationFirstArgument(ASTExpression expression) { + List<ASTAllocationExpression> allocations = expression.findDescendantsOfType(ASTAllocationExpression.class); + ASTExpression firstArgument = null; + + if (!allocations.isEmpty()) { + ASTArgumentList argumentList = allocations.get(allocations.size() - 1).getFirstDescendantOfType(ASTArgumentList.class); + if (argumentList != null) { + firstArgument = argumentList.getFirstChildOfType(ASTExpression.class); + } + } + + // the argument must not be a literal, it needs to be a Name referring to a variable + if (firstArgument != null && firstArgument.getFirstDescendantOfType(ASTName.class) != null) { + ASTName name = firstArgument.getFirstDescendantOfType(ASTName.class); + + Map<VariableNameDeclaration, List<NameOccurrence>> vars = firstArgument.getScope() + .getDeclarations(VariableNameDeclaration.class); + for (VariableNameDeclaration nameDecl : vars.keySet()) { + if (nameDecl.getName().equals(name.getImage()) && isResourceTypeOrSubtype(firstArgument)) { + return firstArgument; + } + } + } + return null; + } + + private boolean isMethodCall(ASTExpression expression) { + return expression != null + && expression.jjtGetNumChildren() > 0 + && expression.jjtGetChild(0) instanceof ASTPrimaryExpression + && expression.jjtGetChild(0).getFirstChildOfType(ASTPrimarySuffix.class) != null; + } + + private boolean isResourceTypeOrSubtype(TypeNode refType) { + if (refType.getType() != null) { + for (String type : types) { + if (TypeHelper.isA(refType, type)) { + return true; + } + } + } else if (refType.jjtGetChild(0) instanceof ASTReferenceType) { + // no type information (probably missing auxclasspath) - use simple types + ASTReferenceType ref = (ASTReferenceType) refType.jjtGetChild(0); + if (ref.jjtGetChild(0) instanceof ASTClassOrInterfaceType) { + ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); + if (simpleTypes.contains(toSimpleType(clazz.getImage())) && !clazz.isReferenceToClassSameCompilationUnit() + || types.contains(clazz.getImage()) && !clazz.isReferenceToClassSameCompilationUnit()) { + return true; + } + } + } + return false; + } + + private boolean isAllowedResourceType(TypeNode refType) { + List<String> allowedResourceTypes = getProperty(ALLOWED_RESOURCE_TYPES); + if (refType.getType() != null && allowedResourceTypes != null) { + for (String type : allowedResourceTypes) { + // the check here must be a exact type match, since subclasses may override close() + // and actually require closing + if (TypeHelper.isExactlyA(refType, type)) { + return true; + } + } + } + return false; + } + private boolean hasNullInitializer(ASTLocalVariableDeclaration var) { ASTVariableInitializer init = var.getFirstDescendantOfType(ASTVariableInitializer.class); if (init != null) { @@ -168,7 +270,7 @@ public class CloseResourceRule extends AbstractJavaRule { return false; } - private void ensureClosed(ASTLocalVariableDeclaration var, ASTVariableDeclaratorId id, Object data) { + private void ensureClosed(ASTLocalVariableDeclaration var, ASTVariableDeclaratorId id, TypeNode type, Object data) { // What are the chances of a Connection being instantiated in a // for-loop init block? Anyway, I'm lazy! String variableToClose = id.getImage(); @@ -303,6 +405,15 @@ public class CloseResourceRule extends AbstractJavaRule { if (closed) { break; } + } else if (t.isTryWithResources()) { + // maybe the variable is used as a resource + List<ASTName> names = t.getFirstChildOfType(ASTResourceSpecification.class).findDescendantsOfType(ASTName.class); + for (ASTName potentialUsage : names) { + if (potentialUsage.hasImageEqualTo(variableToClose)) { + closed = true; + break; + } + } } } @@ -323,10 +434,15 @@ public class CloseResourceRule extends AbstractJavaRule { // if all is not well, complain if (!closed) { - ASTType type = var.getFirstChildOfType(ASTType.class); - ASTReferenceType ref = (ASTReferenceType) type.jjtGetChild(0); - ASTClassOrInterfaceType clazz = (ASTClassOrInterfaceType) ref.jjtGetChild(0); - addViolation(data, id, clazz.getImage()); + ASTLocalVariableDeclaration localVarDecl = id.getFirstParentOfType(ASTLocalVariableDeclaration.class); + Class<?> typeClass = type.getType(); + if (typeClass != null) { + addViolation(data, id, typeClass.getSimpleName()); + } else if (localVarDecl != null && localVarDecl.getTypeNode() != null) { + addViolation(data, id, localVarDecl.getTypeNode().getTypeImage()); + } else { + addViolation(data, id, id.getVariableName()); + } } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java index e4f43f3ecb..af9e04c26b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/UnsynchronizedStaticFormatterRule.java @@ -10,13 +10,17 @@ import java.util.List; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; +import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement; import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; /** * Using a Formatter (e.g. SimpleDateFormatter, DecimalFormatter) which is static can cause @@ -33,8 +37,16 @@ public class UnsynchronizedStaticFormatterRule extends AbstractJavaRule { "org.apache.commons.lang3.time.FastDateFormat" ); + private static final PropertyDescriptor<Boolean> ALLOW_METHOD_LEVEL_SYNC = + PropertyFactory.booleanProperty("allowMethodLevelSynchronization") + .desc("If true, method level synchronization is allowed as well as synchronized block. Otherwise" + + " only synchronized blocks are allowed.") + .defaultValue(false) + .build(); + public UnsynchronizedStaticFormatterRule() { addRuleChainVisit(ASTFieldDeclaration.class); + definePropertyDescriptor(ALLOW_METHOD_LEVEL_SYNC); } UnsynchronizedStaticFormatterRule(Class<?> formatterClassToCheck) { @@ -60,18 +72,32 @@ public class UnsynchronizedStaticFormatterRule extends AbstractJavaRule { } for (NameOccurrence occ : var.getUsages()) { Node n = occ.getLocation(); - if (n.getFirstParentOfType(ASTSynchronizedStatement.class) != null) { - continue; - } // ignore usages, that don't call a method. if (!n.getImage().contains(".")) { continue; } - ASTMethodDeclaration method = n.getFirstParentOfType(ASTMethodDeclaration.class); - if (method != null && !method.isSynchronized()) { - addViolation(data, n); + // is there a block-level synch? + ASTSynchronizedStatement syncStatement = n.getFirstParentOfType(ASTSynchronizedStatement.class); + if (syncStatement != null) { + ASTExpression expression = syncStatement.getFirstChildOfType(ASTExpression.class); + if (expression != null) { + ASTName name = expression.getFirstDescendantOfType(ASTName.class); + if (name != null && name.hasImageEqualTo(var.getVariableName())) { + continue; + } + } } + + // method level synch enabled and used? + if (getProperty(ALLOW_METHOD_LEVEL_SYNC)) { + ASTMethodDeclaration method = n.getFirstParentOfType(ASTMethodDeclaration.class); + if (method != null && method.isSynchronized() && method.isStatic()) { + continue; + } + } + + addViolation(data, n); } return data; } diff --git a/pmd-java/src/main/resources/category/java/bestpractices.xml b/pmd-java/src/main/resources/category/java/bestpractices.xml index 1a8dfe3948..3ab442e456 100644 --- a/pmd-java/src/main/resources/category/java/bestpractices.xml +++ b/pmd-java/src/main/resources/category/java/bestpractices.xml @@ -398,6 +398,45 @@ public class Foo { </example> </rule> + <rule name="DoubleBraceInitialization" + language="java" + since="6.16.0" + message="Double-brace initialization should be avoided" + class="net.sourceforge.pmd.lang.rule.XPathRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#doublebraceinitialization"> + <description> + Double brace initialisation is a pattern to initialise eg collections concisely. But it implicitly + generates a new .class file, and the object holds a strong reference to the enclosing object. For those + reasons, it is preferable to initialize the object normally, even though it's verbose. + + This rule counts any anonymous class which only has a single initializer as an instance of double-brace + initialization. There is currently no way to find out whether a method called in the initializer is not + accessible from outside the anonymous class, and those legit cases should be suppressed for the time being. + </description> + <priority>3</priority> + <properties> + <property name="version" value="2.0"/> + <property name="xpath"> + <value> + <![CDATA[ +//AllocationExpression/ClassOrInterfaceBody[count(*)=1]/*/Initializer[@Static=false()] +]]> + </value> + </property> + </properties> + <example><![CDATA[ +// this is double-brace initialization +return new ArrayList<String>(){{ addAll("a","b","c"); }}; + +// the better way is to not create an anonymous class: +List<String> a = new ArrayList<>(); +a.addAll("a","b","c"); +return a; +]]> + </example> + </rule> + + <rule name="ForLoopCanBeForeach" language="java" since="6.0.0" diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 05bd9f803b..d6b5793180 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -92,10 +92,24 @@ public class Fo$o { // not a recommended name <rule name="AvoidFinalLocalVariable" language="java" since="4.1" + deprecated="true" class="net.sourceforge.pmd.lang.rule.XPathRule" message="Avoid using final local variables, turn them into fields" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#avoidfinallocalvariable"> - <description>Avoid using final local variables, turn them into fields.</description> + <description> +Avoid using final local variables, turn them into fields. + +Note that this is a controversial rule which is merely useful to enforce a certain code style +(which is contradictory to good coding practices in most of the cases it's applied to) and +avoid local literals being declared in a scope smaller than the class. + +Also note, that this rule is the opposite of {% rule "java/codestyle/LocalVariableCouldBeFinal" %}. +Having both rules enabled results in contradictory violations being reported. + +This rule is deprecated and will be removed with PMD 7.0.0. There is no replacement planned. +If the goal is to avoid defining constants in a scope smaller than the class, then the rule +{% rule "java/errorprone/AvoidDuplicateLiterals" %} should be used instead. + </description> <priority>3</priority> <properties> <property name="xpath"> @@ -402,7 +416,7 @@ public class Éléphant {} message="Missing commented default access modifier" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#commentdefaultaccessmodifier"> <description> -To avoid mistakes if we want that a Method, Constructor, Field or Nested class have a default access modifier +To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default access modifier we must add a comment at the beginning of it's declaration. By default the comment must be `/* default */` or `/* package */`, if you want another, you have to provide a regular expression. This rule ignores by default all cases that have a @VisibleForTesting annotation. Use the @@ -2117,6 +2131,39 @@ public class Foo { </example> </rule> + <rule name="UseShortArrayInitializer" + language="java" + since="6.15.0" + message="Array initialization can be written shorter" + class="net.sourceforge.pmd.lang.rule.XPathRule" + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#useshortarrayinitializer"> + <description> +<![CDATA[ +When declaring and initializing array fields or variables, it is not necessary to explicitly create a new array +using `new`. Instead one can simply define the initial content of the array as a expression in curly braces. + +E.g. `int[] x = new int[] { 1, 2, 3 };` can be written as `int[] x = { 1, 2, 3 };`. +]]> + </description> + <priority>3</priority> + <properties> + <property name="xpath"> + <value><![CDATA[ +//VariableDeclarator + [VariableDeclaratorId[@ArrayType = true() and @TypeInferred = false()]] + [VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/AllocationExpression/ArrayDimsAndInits/ArrayInitializer] + ]]></value> + </property> + <property name="version" value="2.0"/> + </properties> + <example> +<![CDATA[ +Foo[] x = new Foo[] { ... }; // Overly verbose +Foo[] x = { ... }; //Equivalent to above line +]]> + </example> + </rule> + <rule name="VariableNamingConventions" since="1.2" deprecated="true" diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index c383419933..347908e37f 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -995,7 +995,7 @@ public class Foo extends Bar { This rule uses the NCSS (Non-Commenting Source Statements) metric to determine the number of lines of code in a class, method or constructor. NCSS ignores comments, blank lines, and only counts actual statements. For more details on the calculation, see the documentation of -the [NCSS metric](/pmd_java_metrics_index.html#non-commenting-source-statements-ncss). +the [NCSS metric](pmd_java_metrics_index.html#non-commenting-source-statements-ncss). </description> <priority>3</priority> <example> @@ -1106,7 +1106,7 @@ The NPath complexity of a method is the number of acyclic execution paths throug While cyclomatic complexity counts the number of decision points in a method, NPath counts the number of full paths from the beginning to the end of the block of the method. That metric grows exponentially, as it multiplies the complexity of statements in the same block. For more details on the calculation, see the -documentation of the [NPath metric](/pmd_java_metrics_index.html#npath-complexity-npath). +documentation of the [NPath metric](pmd_java_metrics_index.html#npath-complexity-npath). A threshold of 200 is generally considered the point where measures should be taken to reduce complexity and increase readability. diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index 23cfaefab8..74e40ae08e 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -1008,23 +1008,44 @@ public class MyClass implements Cloneable{ class="net.sourceforge.pmd.lang.java.rule.errorprone.CloseResourceRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#closeresource"> <description> -Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after use. +Ensure that resources (like `java.sql.Connection`, `java.sql.Statement`, and `java.sql.ResultSet` objects +and any subtype of `java.lang.AutoCloseable`) are always closed after use. +Failing to do so might result in resource leaks. + +Note: It suffices to configure the super type, e.g. `java.lang.AutoClosable`, so that this rule automatically triggers +on any subtype (e.g. `java.io.FileInputStream`). Additionally specifying `java.sql.Connection` helps in detecting +the types, if the type resolution / auxclasspath is not correctly setup. + +Note: Since PMD 6.16.0 the default value for the property `types` contains `java.lang.AutoCloseable` and detects +now cases where the standard `java.io.*Stream` classes are involved. In order to restore the old behaviour, +just remove "AutoCloseable" from the types. </description> <priority>3</priority> <example> <![CDATA[ public class Bar { - public void foo() { - Connection c = pool.getConnection(); - try { - // do stuff - } catch (SQLException ex) { - // handle exception - } finally { - // oops, should close the connection using 'close'! - // c.close(); + public void withSQL() { + Connection c = pool.getConnection(); + try { + // do stuff + } catch (SQLException ex) { + // handle exception + } finally { + // oops, should close the connection using 'close'! + // c.close(); + } + } + + public void withFile() { + InputStream file = new FileInputStream(new File("/tmp/foo")); + try { + int c = file.in(); + } catch (IOException e) { + // handle exception + } finally { + // TODO: close file + } } - } } ]]> </example> @@ -2180,9 +2201,13 @@ public class Foo extends TestCase { since="2.0" message="The Logger variable declaration does not contain the static and final modifiers" class="net.sourceforge.pmd.lang.rule.XPathRule" - externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#loggerisnotstaticfinal"> + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#loggerisnotstaticfinal" + deprecated="true"> <description> In most cases, the Logger reference can be declared as static and final. + +This rule is deprecated and will be removed with PMD 7.0.0. +The rule is replaced by {% rule java/errorprone/ProperLogger %}. </description> <priority>2</priority> <properties> @@ -2383,32 +2408,45 @@ public class Foo implements java.io.Serializable { externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#missingstaticmethodinnoninstantiatableclass"> <description> A class that has private constructors and does not have any static methods or fields cannot be used. + +When one of the private constructors is annotated with one of the annotations, then the class is not considered +non-instantiatable anymore and no violation will be reported. +See the property `annotations`. </description> <priority>3</priority> <properties> + <property name="annotations" type="List[String]" delimiter="," value="org.springframework.beans.factory.annotation.Autowired, javax.inject.Inject" description="If a constructor is annotated with one of these annotations, then the class is ignored."/> + <property name="version" value="2.0"/> <property name="xpath"> <value> <![CDATA[ -//ClassOrInterfaceDeclaration[@Nested='false'] +//ClassOrInterfaceDeclaration[@Nested=false()] [ ( + (: at least one constructor :) ./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration and - count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private='true']) + (: only private constructors :) + count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) = count(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Private=true()]) + and + (: all constructors must not be annotated :) + (every $x in $annotations satisfies + not(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration/ + ../Annotation/MarkerAnnotation/Name[pmd-java:typeIs($x)])) ) and - not(.//MethodDeclaration[@Static='true']) + not(.//MethodDeclaration[@Static=true()]) and - not(.//FieldDeclaration[@Private='false'][@Static='true']) + not(.//FieldDeclaration[@Private=false()][@Static=true()]) and - not(.//ClassOrInterfaceDeclaration[@Nested='true'] - [@Public='true'] - [@Static='true'] - [not(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) or ./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Public='true']] + not(.//ClassOrInterfaceDeclaration[@Nested=true()] + [@Public=true()] + [@Static=true()] + [not(./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration) or ./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/ConstructorDeclaration[@Public=true()]] [./ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration/MethodDeclaration - [@Public='true'] + [@Public=true()] [./ResultType/Type/ReferenceType/ClassOrInterfaceType - [@Image = //ClassOrInterfaceDeclaration[@Nested='false']/@Image] + [@Image = //ClassOrInterfaceDeclaration[@Nested=false()]/@Image] ] ] ) @@ -2501,10 +2539,11 @@ confusing. </description> <priority>3</priority> <properties> + <property name="version" value="2.0" /> <property name="xpath"> <value> <![CDATA[ -//Initializer[@Static='false'] +//Initializer[@Static=false()][not(ancestor::*[3][self::AllocationExpression or self::EnumConstant])] ]]> </value> </property> @@ -2625,31 +2664,50 @@ class Foo{ since="3.3" message="Logger should be defined private static final and have the correct class" class="net.sourceforge.pmd.lang.rule.XPathRule" - externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#properlogger"> + externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#properlogger" + typeResolution="true"> <description> A logger should normally be defined private static final and be associated with the correct class. -Private final Log log; is also allowed for rare cases where loggers need to be passed around, +`private final Log log;` is also allowed for rare cases where loggers need to be passed around, with the restriction that the logger needs to be passed into the constructor. </description> <priority>3</priority> <properties> + <property name="version" value="2.0"/> <property name="xpath"> <value> <![CDATA[ -//ClassOrInterfaceBodyDeclaration[FieldDeclaration//ClassOrInterfaceType[@Image='Log'] - and - not(FieldDeclaration[@Final='true'][@Static='true'][@Private='true'][.//VariableDeclaratorId[@Image=$staticLoggerName]] - and - //ArgumentList//ClassOrInterfaceType[@Image = ancestor::ClassOrInterfaceDeclaration/@Image or @Image = ancestor::EnumDeclaration/@Image]) - and - not(FieldDeclaration[@Final='true'][@Private='true'][.//VariableDeclaratorId[@Image='log']] - [count(.//VariableInitializer)=0] - [ancestor::ClassOrInterfaceBody//StatementExpression[.//PrimaryExpression/descendant::*[@Image='log']][count(.//AllocationExpression)=0]] - )] +//FieldDeclaration +[.//ClassOrInterfaceType[pmd-java:typeIs($loggerClass)]] +[ + (: check modifiers :) + (@Private = false() or @Final = false()) + (: check logger name :) + or (@Static and .//VariableDeclaratorId[@Image != $staticLoggerName]) + or (@Static = false() and .//VariableDeclaratorId[@Image != $loggerName]) + + (: check logger argument type matches class or enum name :) + or .//ArgumentList//ClassOrInterfaceType[@Image != ancestor::ClassOrInterfaceDeclaration/@Image] + or .//ArgumentList//ClassOrInterfaceType[@Image != ancestor::EnumDeclaration/@Image] +] +[not( + (: special case - final logger initialized inside constructor :) + count(.//VariableInitializer)=0 + and @Static = false() + and + ancestor::ClassOrInterfaceBody//ConstructorDeclaration//StatementExpression + [PrimaryExpression[PrimaryPrefix[@ThisModifier]]/PrimarySuffix[@Image=$loggerName]] + [AssignmentOperator[@Image = '=']] + [Expression/PrimaryExpression/PrimaryPrefix/Name[@Image = ancestor::ConstructorDeclaration//FormalParameter/VariableDeclaratorId/@Image]] + [count(.//AllocationExpression)=0] + ) +] ]]> </value> </property> <property name="staticLoggerName" type="String" description="Name of the static Logger variable" value="LOG"/> + <property name="loggerName" type="String" description="Name of the Logger instance variable" value="log"/> + <property name="loggerClass" type="String" description="Class name of the logger" value="Log"/> </properties> <example> <![CDATA[ @@ -3363,8 +3421,19 @@ class Test { class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#uselocalewithcaseconversions"> <description> -When doing String.toLowerCase()/toUpperCase() conversions, use Locales to avoids problems with languages that -have unusual conventions, i.e. Turkish. + When doing `String::toLowerCase()/toUpperCase()` conversions, use an explicit locale argument to specify the case transformation rules. + + Using `String::toLowerCase()` without arguments implicitly uses `Locale::getDefault()`. + The problem is that the default locale depends on the current JVM setup (and usually on the system in which it is running). + Using the system default may be exactly what you want (e.g. if you are manipulating strings you got through standard input), + but it may as well not be the case (e.g. if you are getting the string over the network or a file, and the encoding is well-defined + and independent of the environment). In the latter case, using the default locale makes the case transformation brittle, as + it may yield unexpected results on a machine whose locale has other case translation rules. For example, in Turkish, the + uppercase form of `i` is `İ` (U+0130, not ASCII) and not `I` (U+0049) as in English. + + The rule is intended to *force* developers to think about locales when dealing with strings. By taking a conscious decision about + the choice of locale at the time of writing, you reduce the risk of surprising behaviour down the line, and communicate your intent + to future readers. </description> <priority>3</priority> <properties> @@ -3390,20 +3459,20 @@ PrimarySuffix </properties> <example> <![CDATA[ -class Foo { - // BAD - if (x.toLowerCase().equals("list")) { } +// violation - implicitly system-dependent conversion +if (x.toLowerCase().equals("list")) {} - /* - * This will not match "LIST" when in Turkish locale - * The above could be - * if (x.toLowerCase(Locale.US).equals("list")) { } - * or simply - * if (x.equalsIgnoreCase("list")) { } - */ - // GOOD - String z = a.toLowerCase(Locale.EN); -} +// The above will not match "LIST" on a system with a Turkish locale. +// It could be replaced with +if (x.toLowerCase(Locale.US).equals("list")) { } +// or simply +if (x.equalsIgnoreCase("list")) { } + +// ok - system independent conversion +String z = a.toLowerCase(Locale.ROOT); + +// ok - explicit system-dependent conversion +String z2 = a.toLowerCase(Locale.getDefault()); ]]> </example> </rule> diff --git a/pmd-java/src/main/resources/category/java/multithreading.xml b/pmd-java/src/main/resources/category/java/multithreading.xml index 8ca9046a6a..95460df02a 100644 --- a/pmd-java/src/main/resources/category/java/multithreading.xml +++ b/pmd-java/src/main/resources/category/java/multithreading.xml @@ -266,7 +266,7 @@ public static Foo getFoo() { <description> SimpleDateFormat instances are not synchronized. Sun recommends using separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be -synchronized either on method or block level. +synchronized on block level. This rule has been deprecated in favor of the rule {% rule UnsynchronizedStaticFormatter %}. </description> @@ -278,8 +278,10 @@ public class Foo { void bar() { sdf.format(); // poor, no thread-safety } - synchronized void foo() { - sdf.format(); // preferred + void foo() { + synchronized (sdf) { // preferred + sdf.format(); + } } } ]]> @@ -295,7 +297,7 @@ public class Foo { Instances of `java.text.Format` are generally not synchronized. Sun recommends using separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be -synchronized either on method or block level. +synchronized on block level. </description> <priority>3</priority> <example> @@ -305,8 +307,10 @@ public class Foo { void bar() { sdf.format(); // poor, no thread-safety } - synchronized void foo() { - sdf.format(); // preferred + void foo() { + synchronized (sdf) { // preferred + sdf.format(); + } } } ]]> diff --git a/pmd-java/src/main/resources/rulesets/java/quickstart.xml b/pmd-java/src/main/resources/rulesets/java/quickstart.xml index a3e1aff5aa..8266a15230 100644 --- a/pmd-java/src/main/resources/rulesets/java/quickstart.xml +++ b/pmd-java/src/main/resources/rulesets/java/quickstart.xml @@ -17,6 +17,7 @@ <rule ref="category/java/bestpractices.xml/CheckResultSet"/> <rule ref="category/java/bestpractices.xml/ConstantsInInterface"/> <rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt"/> + <rule ref="category/java/bestpractices.xml/DoubleBraceInitialization"/> <rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach"/> <!-- <rule ref="category/java/bestpractices.xml/ForLoopVariableCount" /> --> <rule ref="category/java/bestpractices.xml/GuardLogStatement"/> diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/QuickstartRulesetTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/QuickstartRulesetTest.java index 8a08cd179e..816c98b918 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/QuickstartRulesetTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/QuickstartRulesetTest.java @@ -4,6 +4,11 @@ package net.sourceforge.pmd.lang.java; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +import org.junit.After; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -18,14 +23,35 @@ import net.sourceforge.pmd.util.ResourceLoader; public class QuickstartRulesetTest { @Rule - public final SystemErrRule systemErrRule = new SystemErrRule().enableLog(); + public final SystemErrRule systemErrRule = new SystemErrRule().enableLog().muteForSuccessfulTests(); + + @After + public void cleanup() { + Handler[] handlers = Logger.getLogger(RuleSetFactory.class.getName()).getHandlers(); + for (Handler handler : handlers) { + Logger.getLogger(RuleSetFactory.class.getName()).removeHandler(handler); + } + } @Test public void noDeprecations() throws RuleSetNotFoundException { + Logger.getLogger(RuleSetFactory.class.getName()).addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + Assert.fail("No Logging expected: " + record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); + RuleSetFactory ruleSetFactory = new RuleSetFactory(new ResourceLoader(), RulePriority.LOW, true, false); RuleSet quickstart = ruleSetFactory.createRuleSet("rulesets/java/quickstart.xml"); Assert.assertFalse(quickstart.getRules().isEmpty()); - - Assert.assertTrue(systemErrRule.getLog().isEmpty()); } } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclarationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclarationTest.java index 1781788e4b..0390203714 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclarationTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ASTClassOrInterfaceDeclarationTest.java @@ -29,6 +29,12 @@ public class ASTClassOrInterfaceDeclarationTest { private static final String LOCAL_CLASS_IN_INITIALIZER = "class Foo { { class Local {} } }"; + private static final String LOCAL_CLASS_WITH_MODIFIERS + = "class Foo { { abstract class Local {} } }"; + + private static final String LOCAL_CLASS_WITH_MIXED_MODIFIER_ANNOTATIONS + = "class Foo { { final @F class Local {} } }"; + private static final String LOCAL_CHILDREN_ARE_NOT_ALWAYS_LOCAL = "class Foo { { class Local { class Nested {} void bar() {class Local2 {}}}}}"; @@ -53,6 +59,44 @@ public class ASTClassOrInterfaceDeclarationTest { } + + @Test + public void testLocalAbstractClass() { + List<ASTClassOrInterfaceDeclaration> classes = ParserTstUtil.getOrderedNodes(ASTClassOrInterfaceDeclaration.class, LOCAL_CLASS_WITH_MODIFIERS); + assertTrue(classes.size() == 2); + + assertFalse("Local class false-positive", classes.get(0).isLocal()); + assertTrue("Local class false-negative", classes.get(1).isLocal()); + assertTrue("Local class should preserve its modifiers", classes.get(1).isAbstract()); + } + + + @Test + public void testLocalClassWithMixedModifiers() { + List<ASTClassOrInterfaceDeclaration> classes = ParserTstUtil.getOrderedNodes(ASTClassOrInterfaceDeclaration.class, LOCAL_CLASS_WITH_MIXED_MODIFIER_ANNOTATIONS); + assertTrue(classes.size() == 2); + + assertFalse("Local class false-positive", classes.get(0).isLocal()); + assertTrue("Local class false-negative", classes.get(1).isLocal()); + assertTrue("Local class should preserve its modifiers", classes.get(1).isFinal()); + } + + + + @Test + public void testLocalClassVisibility() { + List<ASTClassOrInterfaceDeclaration> classes = ParserTstUtil.getOrderedNodes(ASTClassOrInterfaceDeclaration.class, LOCAL_CLASS_WITH_MODIFIERS); + assertTrue(classes.size() == 2); + + assertFalse("Local class false-positive", classes.get(0).isLocal()); + assertTrue("Local class false-negative", classes.get(1).isLocal()); + assertFalse("Local class is not public", classes.get(1).isPublic()); + assertFalse("Local class is not private", classes.get(1).isPrivate()); + assertFalse("Local class is not protected", classes.get(1).isProtected()); + assertFalse("Local class is not package-private", classes.get(1).isPackagePrivate()); + } + + @Test public void testNestedClassIsNotLocal() { List<ASTClassOrInterfaceDeclaration> classes = ParserTstUtil.getOrderedNodes(ASTClassOrInterfaceDeclaration.class, NESTED_CLASS_IS_NOT_LOCAL); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/CommentTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/CommentTest.java index 2c586d5a2f..7af699a499 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/CommentTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/CommentTest.java @@ -100,6 +100,10 @@ public class CommentTest { Token t = new Token(); t.image = comment; Comment node = new Comment(t) { + @Override + public String getXPathNodeName() { + return "DummyComment"; + } }; return node.getFilteredComment(); } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java index c93605ddb8..2f39c71b1e 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/JDKVersionTest.java @@ -263,6 +263,11 @@ public class JDKVersionTest { parseJava9(loadSource("jdk9_module_info.java")); } + @Test + public void testAnnotatedModule() { + parseJava9(loadSource("jdk9_module_info_with_annot.java")); + } + @Test(expected = ParseException.class) public final void jdk9TryWithResourcesInJava8() { parseJava18(loadSource("jdk9_try_with_resources.java")); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/DoubleBraceInitializationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/DoubleBraceInitializationTest.java new file mode 100644 index 0000000000..2e7b29a342 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/DoubleBraceInitializationTest.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.bestpractices; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class DoubleBraceInitializationTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/UseShortArrayInitializerTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/UseShortArrayInitializerTest.java new file mode 100644 index 0000000000..be1a80e550 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/UseShortArrayInitializerTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class UseShortArrayInitializerTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryfullyqualifiedname/TestClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryfullyqualifiedname/TestClass.java new file mode 100644 index 0000000000..814ff50461 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryfullyqualifiedname/TestClass.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryfullyqualifiedname; + + + +public class TestClass { + +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryfullyqualifiedname/subpackage/MyClass.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryfullyqualifiedname/subpackage/MyClass.java new file mode 100644 index 0000000000..035b8728b1 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryfullyqualifiedname/subpackage/MyClass.java @@ -0,0 +1,10 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryfullyqualifiedname.subpackage; + + +public class MyClass { + +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/closeresource/CustomStringWriter.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/closeresource/CustomStringWriter.java new file mode 100644 index 0000000000..fc56da5596 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/closeresource/CustomStringWriter.java @@ -0,0 +1,18 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.errorprone.closeresource; + +import java.io.IOException; +import java.io.StringWriter; + +public class CustomStringWriter extends StringWriter { + + @Override + public void close() throws IOException { + getBuffer().setLength(0); + getBuffer().trimToSize(); + super.close(); + } +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info_with_annot.java b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info_with_annot.java new file mode 100644 index 0000000000..628f1c5cf2 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/ast/jdkversiontests/jdk9_module_info_with_annot.java @@ -0,0 +1,6 @@ +/* + * See §7.7 Module Declarations in JLS + */ +@Deprecated(since = "11", forRemoval = true) +module jdk.pack { +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml index cc74cf3e6f..d6615dbbe5 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/metrics/impl/xml/AtfdTest.xml @@ -188,4 +188,38 @@ public class StatementAndBraceFinder extends JavaParserVisitorAdapter { ]]></code> </test-code> + <test-code> + <description>ATFD without method call chains</description> + <expected-problems>2</expected-problems> + <expected-messages> + <message>'Foo' has value 2 highest 2.</message> + <message>'Foo#bar()' has value 2.</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public void bar() { + JFileChooser openDialog = createOpenFileChooser(); + FileFilter tmp = openDialog.getFileFilter(); + showStatus("Not a valid file format: " + tmp.getDescription()); + } +} + ]]></code> + </test-code> + + <test-code> + <description>ATFD with method call chains</description> + <expected-problems>2</expected-problems> + <expected-messages> + <message>'Foo' has value 2 highest 2.</message> + <message>'Foo#bar()' has value 2.</message> + </expected-messages> + <code><![CDATA[ +public class Foo { + public void bar() { + JFileChooser openDialog = createOpenFileChooser(); + showStatus("Not a valid file format: " + openDialog.getFileFilter().getDescription()); + } +} + ]]></code> + </test-code> </test-data> \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/DoubleBraceInitialization.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/DoubleBraceInitialization.xml new file mode 100644 index 0000000000..c8042cb7c5 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/DoubleBraceInitialization.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="UTF-8"?> +<test-data xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + <test-code> + <description>Pos in return</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>4</expected-linenumbers> + <code><![CDATA[ +class Foo { + + List<String> bar() { + return new ArrayList<String>(){{addAll("a","b","c");}}; + } + + +} + ]]></code> + </test-code> + + <test-code> + <description>Neg, override</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class Foo { + + List<String> bar() { + return new ArrayList<String>(){ + + {addAll("a","b","c");} + + void add(String x) { + throw new UnsupportedOperationException(); + } + }; + } + + +} + ]]></code> + </test-code> + + <test-code> + <description>Neg, new field</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class Foo { + + List<String> bar() { + return new ArrayList<String>(){ + + {addAll("a","b","c");} + + int field; + }; + } + + +} + ]]></code> + </test-code> + + <test-code> + <description>Neg, enum constant</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +enum Foo { + + A { + // neg in enum cons + {addAll("a","b","c");} + + + }; + + +} + ]]></code> + </test-code> + + <test-code> + <description>Neg, regular class</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class Foo { + + // neg in regular class + {addAll("a","b","c");} + + + + +} + ]]></code> + </test-code> + +</test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MethodReturnsInternalArray.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MethodReturnsInternalArray.xml index 25ec834be8..74dbe488ed 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MethodReturnsInternalArray.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/MethodReturnsInternalArray.xml @@ -220,4 +220,165 @@ public class MethodReturnsInternalArrayCase { } ]]></code> </test-code> + + <test-code> + <description> #1738 MethodReturnsInternalArray in inner classes</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Outer { + + public static class Inner { + private int[] arr2; + + public int[] getArr2() { + return arr2; + } + + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1845 Regression in MethodReturnsInternalArray not handling enums</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.util.Arrays; +public enum MethodReturnsInternalArrayCaseEnum { + ONE("One"), + TWO("Two", "Three"); + + private String[] titles; + + MethodReturnsInternalArrayCaseEnum(String... titles) { + this.titles = Arrays.copyOf(titles, titles.length); + } + + public String[] getTitles() { + return titles.clone(); + } + + @Override + public String toString() { + return titles[0]; + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner interface</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public interface OuterInterface { + interface InnerInterface { + String[] method(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner annotation</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Retention; +public final class I { + private I() { + } + @Retention(RetentionPolicy.RUNTIME) + public static @interface Inner { + String[] value(); + } +} + ]]> + </code> + </test-code> + + <test-code> + <description>Top-level annotation</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface TopLevelAnnotation { + + String[] value(); + +} + ]]></code> + </test-code> + + <test-code> + <description>Enum that returns array instead of copy</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public enum MethodReturnsInternalArrayCaseEnum { + ONE("One"), + TWO("Two", "Three"); + + private String[] titles; + + MethodReturnsInternalArrayCaseEnum(String... titles) { + this.titles = titles; + } + + public String[] getTitles() { + return titles; + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner enum that returns array instead of copy</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class OuterClass { + + public enum InnerEnum { + INNER_ENUM("first", "second"); + private String[] titles; + + InnerEnum(String... titles) { + this.titles = titles; + } + + public String[] getTitles() { + return titles; + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner enum that returns copy of array</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.util.Arrays; +public class OuterClass { + + public enum InnerEnum { + INNER_ENUM("first", "second"); + private String[] titles; + + InnerEnum(String... titles) { + this.titles = titles; + } + + public String[] getTitles() { + return Arrays.copyOf(titles, titles.length); + } + } +} + ]]></code> + </test-code> + </test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateField.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateField.xml index f5ff621713..00bf8a2157 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateField.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateField.xml @@ -620,6 +620,18 @@ public class IssueUnusedPrivateField { System.out.println("foo!"); } } +} + ]]></code> + </test-code> + + <test-code> + <description>#1703 UnusedPrivateField: False-positive with @Delegate</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import lombok.experimental.Delegate; + +public class Foo { + @Delegate private String bar; } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml index a01d2c9997..2cbe71f112 100755 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/CommentDefaultAccessModifier.xml @@ -115,6 +115,85 @@ public class Foo { <code-ref id="nested-class-with-default-access-modifier"/> </test-code> + <code-fragment id="top-level-annotations-with-default-access-modifier"><![CDATA[ +@interface Bar {} + +public @interface Foo {} + +@SomeAnnotation +@interface Baz {} + +@VisibleForTesting +@interface Foobar {} + +/* default */ @interface FoobarWithComment {} + ]]></code-fragment> + <test-code> + <description>Top-level annotations with default access modifier are ignored by default (#1880)</description> + <expected-problems>0</expected-problems> + <code-ref id="top-level-annotations-with-default-access-modifier"/> + </test-code> + + <test-code> + <description>Top-level annotations with default access modifier checks enabled with property</description> + <rule-property name="checkTopLevelTypes">true</rule-property> + <expected-problems>2</expected-problems> + <expected-linenumbers>1,6</expected-linenumbers> + <code-ref id="top-level-annotations-with-default-access-modifier"/> + </test-code> + + <code-fragment id="top-level-enums-with-default-access-modifier"><![CDATA[ +enum Bar {} + +public enum Foo {} + +@SomeAnnotation +enum Baz {} + +@VisibleForTesting +enum Foobar {} + +/* default */ enum FoobarWithComment {} + ]]></code-fragment> + <test-code> + <description>Top-level enums with default access modifier are ignored by default (#1880)</description> + <expected-problems>0</expected-problems> + <code-ref id="top-level-enums-with-default-access-modifier"/> + </test-code> + <test-code> + <description>Top-level enums with default access modifier checks enabled with property</description> + <rule-property name="checkTopLevelTypes">true</rule-property> + <expected-problems>2</expected-problems> + <expected-linenumbers>1,6</expected-linenumbers> + <code-ref id="top-level-enums-with-default-access-modifier"/> + </test-code> + + <code-fragment id="top-level-classes-with-default-access-modifier"><![CDATA[ +class Bar {} + +public class Foo {} + +@SomeAnnotation +class Baz {} + +@VisibleForTesting +class Foobar {} + +/* default */ class FoobarWithComment {} + ]]></code-fragment> + <test-code> + <description>Top-level classes with default access modifier are ignored by default (#1880)</description> + <expected-problems>0</expected-problems> + <code-ref id="top-level-classes-with-default-access-modifier"/> + </test-code> + <test-code> + <description>Top-level classes with default access modifier checks enabled with property</description> + <rule-property name="checkTopLevelTypes">true</rule-property> + <expected-problems>2</expected-problems> + <expected-linenumbers>1,6</expected-linenumbers> + <code-ref id="top-level-classes-with-default-access-modifier"/> + </test-code> + <code-fragment id="own-regex-to-default-access-modifier-rule"><![CDATA[ public class Foo { /* default */ final String stringValue = "stringValue"; @@ -275,4 +354,25 @@ public class Foo { </expected-messages> <code-ref id="constructor-with-default-access-modifier-rule"/> </test-code> + + <test-code> + <description>Nested classes inside interfaces</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public interface MyInterface { + class MyNestedClass {} // this is always implicitly public static +} + ]]></code> + </test-code> + + <test-code> + <description>Nested classes inside enum</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public enum MyEnum { + FOO; + class MyNestedClass {} +} + ]]></code> + </test-code> </test-data> \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml index 6f17f54b5e..1d6c277054 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldNamingConventions.xml @@ -193,6 +193,20 @@ ]]></code> </test-code> + <test-code> + <description>Exclude serialPersistentFields by default</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ + public class Foo implements Serializable { + + List next; + + private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("next", List.class)}; + + } + ]]></code> + </test-code> + <test-code> <description>More exclusions can be configured</description> <rule-property name="exclusions">m$mangled|serialVersionUID</rule-property> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml index 8f3d802135..034f13910c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryFullyQualifiedName.xml @@ -488,7 +488,7 @@ public class TestArrayType { } ]]></code> </test-code> - + <test-code> <description>#1199 false negative for same package FQCN</description> <expected-problems>1</expected-problems> @@ -499,6 +499,94 @@ package org.foo; public class SamePackage { public void convert(org.foo.Bar s) { // violation } +} + ]]></code> + </test-code> + + <test-code> + <description>#1951 false positive when package name is obscured by variable</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +package threads; + +public class FQNTest { + public static void main(String[] args) { + Thread[] threads = new Thread[5]; + int i = threads.length; + } +} + ]]></code> + </test-code> + + <test-code> + <description>False positive when package name is obscured by variable (2)</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +package threads; + +public class FQNTest { + public static void main(String[] args) { + Thread[] threads = new Thread[5]; + int i = threads.length.foo; + } +} + +class length { + static int foo; +} + ]]></code> + </test-code> + + <test-code> + <description>False negative when name refers to static field</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +package threads; + +public class FQNTest { + public static void main(String[] args) { + // threads.length is the class + int i = threads.length.foo; + } +} + +class length { + static int foo; +} + ]]></code> + </test-code> + + <test-code> + <description>False positive when type name is obscured by variable</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ + +public class FQNTest { + public static void main(String[] args) { + length length = new length(); + // the type name 'length' is obscured. + int i = length.foo; + } +} + +class length { + static int foo; +} + ]]></code> + </test-code> + + <test-code> + <description>False positive when subpackage is referenced</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>6</expected-linenumbers> + <code><![CDATA[ +package net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryfullyqualifiedname; + +public class FQNTest { + public void foo() { + new net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryfullyqualifiedname.subpackage.MyClass(); // no violation + new net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryfullyqualifiedname.TestClass(); // violation + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml index a97b4efc4d..eb5a8c6794 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml @@ -244,6 +244,23 @@ public class UnnecessaryLocalBeforeReturnFP { .make(i); return o; // true positive } +} + ]]></code> + </test-code> + + <test-code> + <description>#1804 [java] NPE with fields</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class ObjectCreator { + + private static final String A = ""; + private static final String B = "" + A; // the existence of this line causes the NPE. + + public Object create() { + final Object o = new Object(A); + return o; + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseShortArrayInitializer.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseShortArrayInitializer.xml new file mode 100644 index 0000000000..8c6cdad072 --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UseShortArrayInitializer.xml @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + + <test-code> + <description>simple failure case</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>3</expected-linenumbers> + <code><![CDATA[ +public class UseShortArrayExample { + void foo() { + int[] x = new int[] {1,2,3}; + } +} + ]]></code> + </test-code> + + <test-code> + <description>case with two initializers</description> + <expected-problems>2</expected-problems> + <expected-linenumbers>3,3</expected-linenumbers> + <code><![CDATA[ +public class UseShortArrayExample { + void foo() { + int ar[] = new int[] { 1,2,3}, foo[] = new int[] { 4, 5, 6 }; + } +} + ]]></code> + </test-code> + + <test-code> + <description>ok</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class UseShortArrayExample { + void foo() { + int[] x = {1,2,3}; + } +} + ]]></code> + </test-code> + + <test-code> + <description>assignment needs to use new</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class UseShortArrayExample { + void foo() { + int[] a = { 1 }; + a = new int[] { 2 }; // can't be replaced + } +} + ]]></code> + </test-code> + + <test-code> + <description>empty array initialization</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class UseShortArrayExample { + public void foo() { + int[] a = new int[3]; // no violation + } +} + ]]></code> + </test-code> + + <test-code> + <description>array initialization with fields</description> + <expected-problems>3</expected-problems> + <expected-linenumbers>2,3,3</expected-linenumbers> + <code><![CDATA[ +public class UseShortArrayExample { + private int[] f1 = new int[] {1,2,3}; + private int[] f2 = new int[] {1,2,3}, f3 = new int[] { 4,5,6 }; + + private int[] good = { 1,2,3 }; +} + ]]></code> + </test-code> + + <test-code> + <description>array initialization with var</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class UseShortArrayExample { + public void foo() { + var ar1 = new int[] { 1, 2 }; + //var ar2 = { 1, 2 }; // this is actually a compile-time error and is forbidden. See JLS 14.4. + } +} + ]]></code> + </test-code> +</test-data> \ No newline at end of file diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml index 007376dc33..dfdad47f50 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ImmutableField.xml @@ -479,6 +479,23 @@ public class Foo { public Foo() { x = 2; } +} + ]]></code> + </test-code> + + <test-code> + <description>#1792 Immutable field should still be detected with @Delegate</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import lombok.experimental.Delegate; + +public class Foo { + @Delegate + private String x; + + public Foo() { + x = "bar"; + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SingularField.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SingularField.xml index 4caef8662a..a7e1737c8c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SingularField.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SingularField.xml @@ -682,6 +682,22 @@ public class Source { o = new Object(); return o; } +} + ]]></code> + </test-code> + + <test-code> + <description>#1703 SingularField: False-positive with @Delegate</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import lombok.experimental.Delegate; + +public class Foo { + @Delegate private String bar; + + public void set(String s) { + bar = s; + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml index 2540573f5e..a57f064085 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml @@ -360,4 +360,73 @@ public class FooLocal extends ThreadLocal<Integer> { } ]]></code> </test-code> + + <test-code> + <description>#1094 [java] UseUtilityClass should be LombokAware</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import lombok.experimental.UtilityClass; + +@UtilityClass +public class MyUtil { + private final static int CONSTANT = 5; + + public static int addSomething(int in) { + return in + CONSTANT; + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner class in abstract class false-negative</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public abstract class Outer { + private static class Inner { + public static int getInt() { return 42; } + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner class in abstract class false-negative</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public abstract class Outer { + private static class Inner { + private static int answer; + public static int getInt() { return answer; } + } +} + ]]></code> + </test-code> + + + <test-code> + <description>Inner class in interface false-negative</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public interface Outer { + private static class Inner { + public static int getInt() { return 42; } + } +} + ]]></code> + </test-code> + + <test-code> + <description>Inner class in sub-class false-negative</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Outer extends Object { + private static class Inner { + public static boolean isYes(int a) { + return a != 0; + } + } +} + ]]></code> + </test-code> </test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml index d06fea79d7..cab2f7cdc9 100755 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml @@ -157,6 +157,85 @@ public class CommentRequired implements Serializable { ]]></code> </test-code> + <test-code> + <description>#1684 whitelist serialPersistentFields</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +/** The class comment */ +public class CommentRequired implements Serializable { + /** My list */ + List next; + private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("next", List.class)}; +} + ]]></code> + </test-code> + <test-code> + <description>#1684 comment required on serialPersistentFields of wrong type</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <code><![CDATA[ +/** The class comment */ +public class CommentRequired implements Serializable { + /** My list */ + List next; + private static final String[] serialPersistentFields = {"next"}; +} + ]]></code> + </test-code> + <test-code> + <description>#1684 comment required on serialPersistentFields of wrong visibility</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <code><![CDATA[ +/** The class comment */ +public class CommentRequired implements Serializable { + /** My list */ + List next; + static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("next", List.class)}; +} + ]]></code> + </test-code> + <test-code> + <description>#1684 comment required on serialPersistentFields not static</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <code><![CDATA[ +/** The class comment */ +public class CommentRequired implements Serializable { + /** My list */ + List next; + private final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("next", List.class)}; +} + ]]></code> + </test-code> + <test-code> + <description>#1684 comment required on serialPersistentFields not final</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <code><![CDATA[ +/** The class comment */ +public class CommentRequired implements Serializable { + /** My list */ + List next; + private static ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("next", List.class)}; +} + ]]></code> + </test-code> + <test-code> + <description>#1684 serialPersistentFields comment required</description> + <rule-property name="serialPersistentFieldsCommentRequired">Required</rule-property> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <code><![CDATA[ +/** The class comment */ +public class CommentRequired implements Serializable { + /** My list */ + List next; + private static final ObjectStreamField[] serialPersistentFields = {new ObjectStreamField("next", List.class)}; +} + ]]></code> + </test-code> + <test-code> <description>#1522 [java] CommentRequired: false positive</description> <expected-problems>0</expected-problems> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/BeanMembersShouldSerialize.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/BeanMembersShouldSerialize.xml index 983fca10cd..77e1de8734 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/BeanMembersShouldSerialize.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/BeanMembersShouldSerialize.xml @@ -263,6 +263,22 @@ public class Foo { @Data public class Foo { private String bar; +} + ]]></code> + </test-code> + <test-code> + <description>#1796 BeanMembersShouldSerialize should still report with @Delegate</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import lombok.experimental.Delegate; + +public class Foo { + @Delegate + private String bar; + + public String toString() { + return "Foo: " + bar; + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloseResource.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloseResource.xml index 46409718e9..008b5521b0 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloseResource.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloseResource.xml @@ -4,12 +4,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> <test-code> - <description><![CDATA[ -connection is closed, ok - ]]></description> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <description>connection is closed, ok</description> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Foo { void bar() { Connection c = pool.getConnection(); @@ -22,13 +22,15 @@ public class Foo { } ]]></code> </test-code> - <test-code> - <description><![CDATA[ -connection not closed, should have failed - ]]></description> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <test-code> + <description>connection not closed, should have failed</description> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>1</expected-problems> + <expected-linenumbers>4</expected-linenumbers> + <expected-messages> + <message>Ensure that resources like this Connection object are closed after use</message> + </expected-messages> <code><![CDATA[ import java.sql.*; public class Foo { @@ -42,11 +44,8 @@ public class Foo { ]]></code> </test-code> <test-code> - <description><![CDATA[ -ResultSet not closed, should have failed - ]]></description> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> - + <description>ResultSet not closed, should have failed</description> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>1</expected-problems> <code><![CDATA[ import java.sql.*; @@ -60,12 +59,9 @@ public class Foo { ]]></code> </test-code> <test-code> - <description><![CDATA[ -Statement not closed, should have failed - ]]></description> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <description>Statement not closed, should have failed</description> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>1</expected-problems> - <code><![CDATA[ import java.sql.*; public class Foo { @@ -92,29 +88,22 @@ public class Foo { } ]]></code-fragment> <test-code> - <description><![CDATA[ -Bad, no closeTargets properties for statements - ]]></description> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <description>Bad, no closeTargets properties for statements</description> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>2</expected-problems> <code-ref id="executeQuery"/> - </test-code> <test-code> - <description><![CDATA[ -Ok, closeTargets properties for statements - ]]></description> + <description>Ok, closeTargets properties for statements</description> <rule-property name="closeTargets">MyHelper.close,cleanup</rule-property> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>0</expected-problems> <code-ref id="executeQuery"/> </test-code> - + <test-code> - <description><![CDATA[ -Add type param - ]]></description> - <rule-property name="types">ObjectInputStream</rule-property> + <description>Add type param</description> + <rule-property name="types">java.io.ObjectInputStream</rule-property> <expected-problems>1</expected-problems> <code><![CDATA[ import java.io.*; @@ -129,13 +118,11 @@ readExternal(aStream); } ]]></code> </test-code> - <test-code> - <description><![CDATA[ -OK - ]]></description> + <test-code> + <description>OK with custom closeTargets</description> <rule-property name="closeTargets">MyHelper.close</rule-property> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ import java.sql.*; @@ -151,11 +138,9 @@ public class Foo { ]]></code> </test-code> <test-code> - <description><![CDATA[ -New use case - ]]></description> + <description>New use case: commit</description> <rule-property name="closeTargets">commit,close</rule-property> - <rule-property name="types">DAOTransaction,Connection,Statement,ResulSet</rule-property> + <rule-property name="types">DAOTransaction,java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>1</expected-problems> <expected-linenumbers>8</expected-linenumbers> <code><![CDATA[ @@ -184,13 +169,10 @@ public class Foo { ]]></code> </test-code> - <test-code> - <description><![CDATA[ -[1964798] 3 bugs in CloseResourceRule : Case failing with complete name - ]]></description> + <description>[1964798] 3 bugs in CloseResourceRule : Case failing with complete name</description> <rule-property name="closeTargets">MyHelper.MyClose</rule-property> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ import java.sql.*; @@ -205,14 +187,11 @@ public class Foo { } ]]></code> </test-code> - - + <test-code> - <description><![CDATA[ -[1964798] 3 bugs in CloseResourceRule : null object is passed to close conection method (1) - ]]></description> - <rule-property name="closeTargets">this.closeConnection</rule-property> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <description>[1964798] 3 bugs in CloseResourceRule : null object is passed to close conection method (1)</description> + <rule-property name="closeTargets">this.closeConnection</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>1</expected-problems> <code><![CDATA[ import java.sql.*; @@ -227,13 +206,11 @@ public class Foo { } } ]]></code> - </test-code> + </test-code> <test-code> - <description><![CDATA[ -[1964798] 3 bugs in CloseResourceRule : null object is passed to close conection method (2) - ]]></description> - <rule-property name="closeTargets">this.closeConnection</rule-property> - <rule-property name="types">Connection,Statement,ResultSet</rule-property> + <description>[1964798] 3 bugs in CloseResourceRule : null object is passed to close conection method (2)</description> + <rule-property name="closeTargets">this.closeConnection</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> <expected-problems>1</expected-problems> <code><![CDATA[ import java.sql.*; @@ -248,11 +225,9 @@ public class Foo { } } ]]></code> - </test-code> - <test-code> - <description><![CDATA[ -[1964798] 3 bugs in CloseResourceRule : If connection is returned, we should not log a violation. - ]]></description> + </test-code> + <test-code> + <description>[1964798] 3 bugs in CloseResourceRule : If connection is returned, we should not log a violation.</description> <rule-property name="types">Connection,Statement,ResultSet</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ @@ -264,14 +239,10 @@ public class Foo { } ]]></code> </test-code> - <test-code reinitializeRule="true"> - <description><![CDATA[ -invoke an external method that close the resource -bug 2920057 - ]]></description> - <rule-property name="closeTargets">closeStatement,closeStatement,closeResultSet,closeConnexion - </rule-property> - <rule-property name="types">PreparedStatement,Statement,ResultSet,Connection</rule-property> + <test-code reinitializeRule="true"> + <description>invoke an external method that close the resource: bug 2920057</description> + <rule-property name="closeTargets">closeStatement,closeStatement,closeResultSet,closeConnexion</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet,java.sql.PreparedStatement</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ import java.sql.*; @@ -301,13 +272,9 @@ public class StructureFactory { ]]></code> </test-code> <test-code reinitializeRule="true"> - <description><![CDATA[ -invoke an external method that closes the resource, but one is not the right method and an another is not the right variable -see bug 2920057 - ]]></description> - <rule-property name="closeTargets">closeStatement,closeStatement,closeResultSet,closeConnexion - </rule-property> - <rule-property name="types">PreparedStatement,Statement,ResultSet,Connection</rule-property> + <description>invoke an external method that closes the resource, but one is not the right method and an another is not the right variable: see bug 2920057</description> + <rule-property name="closeTargets">closeStatement,closeStatement,closeResultSet,closeConnexion</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet,java.sql.PreparedStatement</rule-property> <expected-problems>2</expected-problems> <code><![CDATA[ import java.sql.*; @@ -341,6 +308,8 @@ public class StructureFactory { <description>#1011 CloseResource Rule ignores Constructors</description> <expected-problems>1</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Test { public Test() { Connection c = pool.getConnection(); @@ -352,6 +321,8 @@ public class Test { <description>#1011 CloseResource Rule ignores Constructors - closed in finally</description> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Test { public Test() { Connection c; @@ -368,6 +339,8 @@ public class Test { <description>#1011 CloseResource Rule ignores Constructors - not a problem - instance variable</description> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Test { Connection c; public Test() { @@ -380,6 +353,8 @@ public class Test { <description>#1029 No instance level check in the close resource rule</description> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Test { Connection c; public void doIt() { @@ -392,6 +367,10 @@ public class Test { <description>#947 CloseResource rule fails if field is marked with annotation</description> <expected-problems>2</expected-problems> <code><![CDATA[ +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + public class CloseResourceRuleBug { public void foo() { try { @@ -427,9 +406,9 @@ public class Test { } ]]></code> </test-code> - + <test-code> - <description><![CDATA[Custom close method, should be ok]]></description> + <description>Custom close method, should be ok</description> <rule-property name="closeTargets">cleanup</rule-property> <rule-property name="types">MyClass</rule-property> <expected-problems>0</expected-problems> @@ -449,9 +428,11 @@ public class Foo { </test-code> <test-code> <description>bug #1131 CloseResource should complain if code between declaration of resource and try: Code between declaration and try, should fail</description> - <rule-property name="types">Connection</rule-property> + <rule-property name="types">java.sql.Connection</rule-property> <expected-problems>1</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Foo { void bar() { String test = ""; @@ -470,9 +451,11 @@ public class Foo { </test-code> <test-code> <description>bug #1131 CloseResource should complain if code between declaration of resource and try: Creation inside try, ok</description> - <rule-property name="types">Connection</rule-property> + <rule-property name="types">java.sql.Connection</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Foo { void bar() { String test = ""; @@ -495,9 +478,11 @@ public class Foo { </test-code> <test-code> <description>bug #1131 CloseResource should complain if code between declaration of resource and try: No sentences between creation and try, ok</description> - <rule-property name="types">Connection</rule-property> + <rule-property name="types">java.sql.Connection</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Foo { void bar() { String test = ""; @@ -521,6 +506,8 @@ public class Foo { <description>#1259 CloseResource rule ignores conditionals within finally blocks</description> <expected-problems>1</expected-problems> <code><![CDATA[ +import java.sql.Connection; + public class Bar { public void foo() { Connection c = pool.getConnection(); @@ -541,6 +528,9 @@ public class Bar { <description>#1375 CloseResource not detected properly - ok</description> <expected-problems>1</expected-problems> <code><![CDATA[ +import java.sql.ResultSet; +import java.sql.Statement; + public class Foo { void bar() { ResultSet rs; @@ -561,6 +551,9 @@ public class Foo { <description>#1375 CloseResource not detected properly - false negative</description> <expected-problems>1</expected-problems> <code><![CDATA[ +import java.sql.ResultSet; +import java.sql.Statement; + public class Foo { void bar() { ResultSet rs = null; @@ -579,11 +572,16 @@ public class Foo { </test-code> <test-code> <description>#1372 False Negative for CloseResource rule.</description> - <rule-property name="types">Connection,Statement,ResultSet,PreparedStatement</rule-property> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet,java.sql.PreparedStatement</rule-property> <rule-property name="closeTargets">closeLocalResources,closeResultSet</rule-property> <expected-problems>1</expected-problems> - <expected-linenumbers>8</expected-linenumbers> + <expected-linenumbers>13</expected-linenumbers> <code><![CDATA[ +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.sql.PreparedStatement; + public class CloseResourceTest { public Object selectOne(final int val, final int val2) { getCurrentSession().doWork(new Work() { @@ -616,6 +614,10 @@ public class CloseResourceTest { <rule-property name="closeTargets">closeConnection,closeCloseable,closeReader,closeResource,closeResultSet,closeStream,closeStatement</rule-property> <expected-problems>0</expected-problems> <code><![CDATA[ +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + public class CloseResource { public void querySomething(Connection connection) { Statement stmt = null; // it complains this is not closed @@ -645,6 +647,9 @@ public class CloseResource { <rule-property name="closeAsDefaultTarget">false</rule-property> <expected-problems>2</expected-problems> <code><![CDATA[ +import java.sql.ResultSet; +import java.sql.Statement; + public class CloseResource { public void doSomething() { Statement stmt = connection.createStatement(); @@ -671,6 +676,447 @@ public class Test { static class Statement { } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for input streams - not ok</description> + <rule-property name="types">java.io.InputStream</rule-property> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + InputStream in = null; + try { + in = new FileInputStream(new File("/tmp/foo")); + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for file input streams - not ok</description> + <rule-property name="types">java.io.InputStream</rule-property> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + FileInputStream in = null; + try { + in = new FileInputStream(new File("/tmp/foo")); + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for input streams - ok</description> + <rule-property name="types">java.io.InputStream</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + InputStream in = null; + try { + in = new FileInputStream(new File("/tmp/foo")); + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + in.close(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for input streams - ok try-with-resources</description> + <rule-property name="types">java.io.InputStream</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + try (InputStream in = new FileInputStream(new File("/tmp/foo"))) { + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for closable - not ok</description> + <rule-property name="types">java.io.Closeable</rule-property> + <expected-problems>2</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + InputStream in = null; + OutputStream in2 = null; + try { + in = new FileInputStream(new File("/tmp/foo")); + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for closable by default - not ok</description> + <expected-problems>3</expected-problems> + <expected-linenumbers>5,6,16</expected-linenumbers> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + InputStream in = null; + OutputStream in2 = null; + try { + in = new FileInputStream(new File("/tmp/foo")); + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void bar() { + InputStream file = new FileInputStream(new File("/tmp/foo")); + try { + int c = file.in(); + } catch (IOException e) { + // handle exception + } finally { + // TODO: close file + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>ByteArrayOutputStream and StringWriter do not need closing</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.io.OutputStream; + +public class CloseResourceWithExceptions { + public void bar() { + /*ByteArray*/OutputStream buffer = new ByteArrayOutputStream(); + try { + buffer.write(new byte[] {1, 2, 3}); + } catch (IOException e) { + throw new RuntimeException(e); + } + byte[] result = buffer.toByteArray(); + return result; + } + + public String baz() { + StringWriter writer = new StringWriter(); + writer.write("Test"); + return writer.toString(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>ByteArrayInputStream does not need closing</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class CloseResourceWithExceptions { + + { + ByteArrayInputStream bis = new ByteArrayInputStream("fooString".getBytes(StandardCharsets.UTF_8)); + } + + public int bar() { + /*ByteArray*/InputStream buffer = new ByteArrayInputStream(); + try { + return buffer.read(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return -1; + } +} + ]]></code> + </test-code> + + <test-code> + <description>CharArrayWriter does not need closing</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.Writer; +import java.io.CharArrayWriter; +import java.io.IOException; + +public class CloseResourceWithExceptions { + + public char[] bar() { + /*CharArray*/Writer buffer = new CharArrayWriter(); + try { + buffer.append("foo"); + return buffer.toCharArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + return null; + } +} + ]]></code> + </test-code> + + <test-code> + <description>A custom StringWriter does need closing</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import net.sourceforge.pmd.lang.java.rule.errorprone.closeresource.CustomStringWriter; + +public class CloseResourceWithExceptions { + public void bar() { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + try { + buffer.write(new byte[] {1, 2, 3}); + } catch (IOException e) { + throw new RuntimeException(e); + } + byte[] result = buffer.toByteArray(); + return result; + } + + public String baz() { + StringWriter writer = new CustomStringWriter(); + writer.write("Test"); + return writer.toString(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>connection not closed, should have failed - missing import</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +// without the import +//import java.sql.*; +// type resolution doesn't work, so the rule falls back to simple names +public class Foo { + void bar() { + Connection c = pool.getConnection(); + try { + } catch (Exception e) { + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>closed with try-with-resources</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class Foo { + public int bar() { + InputStream inputStream = getInputStreamFromSomewhere(); + if (inputStream != null) { + try (InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8")) { + char c = reader.read(); + return c; + } + } + return -1; + } +} + ]]></code> + </test-code> + + <test-code> + <description>Correctly determine the type with method calls</description> + <expected-problems>2</expected-problems> + <expected-linenumbers>6,7</expected-linenumbers> + <expected-messages> + <message>Ensure that resources like this Connection object are closed after use</message> + <message>Ensure that resources like this PreparedStatement object are closed after use</message> + </expected-messages> + <code><![CDATA[ +import java.sql.*; + +public class CloseResourceSQL { + public void run() { + try { + Connection con = DataSourceUtils.getConnection(ds); + PreparedStatement ps = con.prepareStatement("some SQL statement"); + DataSourceUtils.applyTransactionTimeout(ps, ds); + } catch (SQLException ex) { + throw new RuntimeException("", ex); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>JMS Connections without auxclasspath</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>10</expected-linenumbers> + <expected-messages> + <message>Ensure that resources like this Connection object are closed after use</message> + </expected-messages> + <code><![CDATA[ +// javax.jms.* is not on the (aux)classpath during unit tests +import javax.jms.Connection; +import javax.jms.Session; + +public class CloseResourceJMS { + public void run() { + Session session = resourceFactory.getSession(resourceHolder); + if (session != null) { + if (startConnection) { + Connection con = resourceFactory.getConnection(resourceHolder); + if (con != null) { + con.start(); + } + } + return session; + } + return null; + } +} + ]]></code> + </test-code> + + <test-code> + <description>CloseResource for closable - ignored if the types do not contain AutoClosable</description> + <rule-property name="types">java.sql.Connection,java.sql.Statement,java.sql.ResultSet</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourceTest { + public static void main(String[] args) { + InputStream in = null; + OutputStream in2 = null; + try { + in = new FileInputStream(new File("/tmp/foo")); + in.read(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void bar() { + InputStream file = new FileInputStream(new File("/tmp/foo")); + try { + int c = file.in(); + } catch (IOException e) { + // handle exception + } finally { + // TODO: close file + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>PrintWriter based on StringWriter</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.io.*; + +public class CloseResourcePrintWriter { + public String run1() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + pw.println("Foo"); + String result = sw.toString(); + return result; + } + + public String run2() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + + pw.println("Foo"); + String result = sw.toString(); + return result; + } + + public String run3() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(new BufferedWriter(sw)); + + pw.println("Foo"); + return sw.toString(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>Correctly determine the type for the message</description> + <expected-problems>3</expected-problems> + <expected-linenumbers>7,8,10</expected-linenumbers> + <expected-messages> + <message>Ensure that resources like this FileInputStream object are closed after use</message> + <message>Ensure that resources like this Scanner object are closed after use</message> + <message>Ensure that resources like this FileInputStream object are closed after use</message> + </expected-messages> + <code><![CDATA[ +import java.io.*; +import java.util.Scanner; + +public class CloseResourceCase { + public void run() { + try { + FileInputStream in = new FileInputStream("MyFile.txt"); + Scanner input = new Scanner(System.in, "utf-8"); + String file = "MyFile.txt"; + FileInputStream in2 = new FileInputStream(file); + } catch (Exception e) { + e.printStackTrace(); + } + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/DataflowAnomalyAnalysis.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/DataflowAnomalyAnalysis.xml index 76bd78ff95..620dfa4bc3 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/DataflowAnomalyAnalysis.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/DataflowAnomalyAnalysis.xml @@ -132,6 +132,248 @@ public class AssertTest { System.out.println(k); } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 1. DU-Anomaly(b)</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>6</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'b' (lines '6'-'7').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int a = 0 ; + int b = 0 ; + a = a + b ; + b = a + b ; + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 2. DU-Anomaly(a)</description> + <expected-problems>2</expected-problems> + <expected-linenumbers>3,5</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '3'-'7').</message> + <message>Found 'DU'-anomaly for variable 'a' (lines '5'-'7').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int a = 0 ; + for(int i = 0 ; i <= 10; i ++){ + a = a+3; + } + } +} + ]]></code> + </test-code> + + <test-code regressionTest="false"> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 3. DU-Anomaly(a)</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '5'-'7').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int[] b = new int[10]; + for(int a : b){ + a = a+3; + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 4. DU-Anomaly(a)</description> + <expected-problems>2</expected-problems> + <expected-linenumbers>3,6</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '3'-'9').</message> + <message>Found 'DU'-anomaly for variable 'a' (lines '6'-'9').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int a = 0 ; + int i = 0 ; + while(i < 30){ + a = a+3; + i += 3; + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 5. DU-Anomaly(a)</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>6</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '6'-'9').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int a = 0 ; + int i = 0 ; + do{ + a = a+3; + i += 3; + }while(i < 30); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 6. DU-Anomaly(a)</description> + <expected-problems>4</expected-problems> + <expected-linenumbers>6,8,10,12</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '6'-'14').</message> + <message>Found 'DU'-anomaly for variable 'a' (lines '8'-'14').</message> + <message>Found 'DU'-anomaly for variable 'a' (lines '10'-'14').</message> + <message>Found 'DU'-anomaly for variable 'a' (lines '12'-'14').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int a = 0 ; + int i = 0 ; + switch(i){ + case 1 : a = a+1; + break; + case 2 : a = a+2; + break; + case 3 : a = a+3; + break; + default : a = a + 0; + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 7. DU-Anomaly(a)</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>9</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '9'-'11').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int a = 0 ; + int i = 0 ; + switch(i){ + case 1 : a = a+1; + case 2 : a = a+2; + case 3 : a = a+3; + default : a = a + 0; + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 9. DU-Anomaly(t1)</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>5</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 't1' (lines '5'-'6').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int t1 = 0 ; + Test2 test = new Test2() ; + t1 = test.simpleTest(t1) ; + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 12. DU-Anomaly(t1)</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>6</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 't1' (lines '6'-'7').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int t1 = 0 ; + int t2 = 0 ; + Test2 test = new Test2(); + if((t1 = test.simpleTest(t1)) == t2); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 13</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int t1 = 0 ; + + Test2 test = new Test2(); + if( (t1 = test.simpleTest(t1)) == t1); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 14. DU-Anomaly(t1, t2)</description> + <expected-problems>2</expected-problems> + <expected-linenumbers>4,6</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 't2' (lines '4'-'7').</message> + <message>Found 'DU'-anomaly for variable 't1' (lines '6'-'7').</message> + </expected-messages> + <code><![CDATA[ +class Test{ + public static void main(String[] args){ + int t1 = 0; + int t2 = 0; + Test2 test = new Test2() ; + if( t1 == (t1 = test.simpleTest(t1))) ; + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1749 DD False Positive in DataflowAnomalyAnalysis</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>4</expected-linenumbers> + <expected-messages> + <message>Found 'DU'-anomaly for variable 'a' (lines '4'-'5').</message> + </expected-messages> + <code><![CDATA[ +public class Test { + public void test(){ + int a = 0; + a = a + 3; + } } ]]></code> </test-code> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml index 36945b2db8..caf8041500 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingStaticMethodInNonInstantiatableClass.xml @@ -247,4 +247,77 @@ public final class BacklogElementParameters { } ]]></code> </test-code> + + <test-code> + <description>#1832 Check constructor injection with @Autowired or @Inject </description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import javax.inject.Inject; +import org.springframework.beans.factory.annotation.Autowired; + +public class Foo { + + private String arg; + + @Autowired + private Foo() {} + + @Inject + private Foo(String arg) { + this.arg = arg; + } + + public void bar() {} +} + ]]></code> + </test-code> + + <test-code> + <description>#1832 fine with a least one constructor annotated with "Autowired</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.annotation.PersistenceConstructor; + +public class Foo { + + private String arg; + + @PersistenceConstructor + private Foo() {} + + @Autowired + private Foo(String arg) { + this.arg = arg; + } + + public void bar() {} +} + ]]></code> + </test-code> + + <test-code> + <description>#1832 but fail with both private constructors annotated with @PersistenceConstructor</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import org.springframework.data.annotation.PersistenceConstructor; + +public class Foo { + + private String arg; + + @PersistenceConstructor + private Foo() {} + + @PersistenceConstructor + private Foo(String arg) { + this.arg = arg; + } + + public void bar() {} +} + ]]></code> + </test-code> + + </test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/NonStaticInitializer.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/NonStaticInitializer.xml index cb058c6169..d66001be47 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/NonStaticInitializer.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/NonStaticInitializer.xml @@ -1,28 +1,101 @@ <?xml version="1.0" encoding="UTF-8"?> -<test-data - xmlns="http://pmd.sourceforge.net/rule-tests" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> +<test-data xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> <test-code> - <description><![CDATA[ -bad - ]]></description> + <description>bad</description> <expected-problems>1</expected-problems> <code><![CDATA[ public class Foo { {} } - ]]></code> + ]]></code> </test-code> + <test-code> - <description><![CDATA[ -static initializers are OK - ]]></description> + <description>static initializers are OK</description> <expected-problems>0</expected-problems> <code><![CDATA[ public class Foo { static {} } - ]]></code> + ]]></code> </test-code> + + <test-code> + <description>Allowed in anonymous classes</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +public class Foo { + public Animation getStatusTransition() { + return new Transition() { + + { + setCycleDuration(Duration.millis(1200)); + } + + @Override + protected void interpolate(double frac) { + // magic + } + }; + } +} + ]]></code> + </test-code> + + <test-code> + <description>Flag in local class</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>3</expected-linenumbers> + <code><![CDATA[ +public class Foo { + static { + class Local {{}} + } +} + ]]></code> + </test-code> + + <test-code> + <description>Allowed in enum constant</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>7</expected-linenumbers> + <code><![CDATA[ +public enum Foo { + A { + { setCycleDuration(Duration.millis(1200)); } + }; + + + { setCycleDuration(Duration.millis(1200)); } + +} + ]]></code> + </test-code> + + <test-code> + <description>Flag in nested local class</description> + <expected-problems>1</expected-problems> + <expected-linenumbers>7</expected-linenumbers> + <code><![CDATA[ +public class Foo { + public Animation getStatusTransition() { + return new Transition() { + + { + setCycleDuration(Duration.millis(1200)); + class ImInAnon {{}} // should be flagged + } + + @Override + protected void interpolate(double frac) { + // magic + } + }; + } +} + ]]></code> + </test-code> + </test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ProperLogger.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ProperLogger.xml index 73f92b6747..b7e0e77ed4 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ProperLogger.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ProperLogger.xml @@ -66,7 +66,7 @@ public class Foo { } ]]> </code> </test-code> - <test-code> + <test-code> <description><![CDATA[ Enums shoud be accepted for declaration ]]></description> @@ -90,4 +90,150 @@ public class Foo { } ]]> </code> </test-code> + <test-code> + <description>Custom logger-class with invalid logger variable name</description> + <rule-property name="loggerClass">MyLog</rule-property> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + private static final MyLog INVALID_LOG_NAME = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>Public logger</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + public static final Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>package-private logger</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + static final Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>package-private logger non static</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + final Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>package-private logger non static and non final</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>Public logger when static final required</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + public static final Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>Logger initialized as String constant from class name (java.util.logging)</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.util.logging.Logger; + +public class Foo { + private static final Logger LOG = Logger.getLogger(Foo.class.getName()); +} + ]]> </code> + </test-code> + <test-code> + <description>non-private Logger initialized as String constant from class name</description> + <rule-property name="loggerClass">java.util.logging.Logger</rule-property> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.util.logging.Logger; + +public class Foo { + Logger LOG = Logger.getLogger(Foo.class.getName()); +} + ]]> </code> + </test-code> + <test-code> + <description>Package-protected logger when static final is not required</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>Package-protected logger when static final is required</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + Log LOG = LogFactory.getLog(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>Check type resolution of logger</description> + <rule-property name="loggerClass">org.slf4j.Logger</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Foo { + private static final Logger LOG = LoggerFactory.getLogger(Foo.class); +} + ]]> </code> + </test-code> + <test-code> + <description>Check type resolution of logger with invalid logger specified</description> + <rule-property name="loggerClass">org.slf4j.Logger</rule-property> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Foo { + private static final Logger LOG = LoggerFactory.getLogger(Bar.class); +} + ]]> </code> + </test-code> + <test-code> + <description>similar to special case but with creating a new logger instead of passing in</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + private final Log log; + public Foo() { + this.log = LogFactory.getLog(Foo.class); + } +} + ]]></code> + </test-code> + <test-code> + <description>similar to special case but with creating a new logger instead of passing in</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +public class Foo { + private final Log log; + public Foo() { + this.log = new Log(Foo.class); + } +} + ]]></code> + </test-code> </test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml index aaad1b5dab..98ccfcd6de 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticDateFormatter.xml @@ -31,8 +31,8 @@ public class Foo { ]]></code> </test-code> <test-code> - <description>3, Inside synchronized, OK</description> - <expected-problems>0</expected-problems> + <description>3, Instance synchronized, Not OK - see #1815</description> + <expected-problems>1</expected-problems> <code><![CDATA[ import java.text.SimpleDateFormat; @@ -61,8 +61,8 @@ public class Foo { ]]></code> </test-code> <test-code> - <description>5, Use DateFormat, ok</description> - <expected-problems>0</expected-problems> + <description>5, Use DateFormat with instance Synchronized, not ok</description> + <expected-problems>1</expected-problems> <code><![CDATA[ import java.text.DateFormat; @@ -71,6 +71,22 @@ public class Foo { synchronized void bar() { sdf.format(); } +} + ]]></code> + </test-code> + <test-code> + <description>5a, Use DateFormat with synchronized block, ok</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.text.DateFormat; + +public class Foo { + private static final DateFormat sdf = new DateFormat(); + void bar() { + synchronized(sdf) { + sdf.format(); + } + } } ]]></code> </test-code> @@ -105,4 +121,51 @@ public class Test { } ]]></code> </test-code> + + <test-code> + <description>#1815 static synchronized, Not OK</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + synchronized void bar() { // not static + sdf.format(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, also Not OK</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + static synchronized void bar() { // not a synchronized blocks + sdf.format(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, OK</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + static void bar() { + synchronized(sdf) { + sdf.format(); + } + } +} + ]]></code> + </test-code> </test-data> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticFormatter.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticFormatter.xml index 5c9db4e1f0..e8a0677f0c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticFormatter.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/multithreading/xml/UnsynchronizedStaticFormatter.xml @@ -31,8 +31,8 @@ public class Foo { ]]></code> </test-code> <test-code> - <description>3, Inside synchronized, OK</description> - <expected-problems>0</expected-problems> + <description>3, Inside synchronized, Not OK</description> + <expected-problems>1</expected-problems> <code><![CDATA[ import java.text.SimpleDateFormat; @@ -61,8 +61,8 @@ public class Foo { ]]></code> </test-code> <test-code> - <description>5, Use DateFormat, ok</description> - <expected-problems>0</expected-problems> + <description>5, Use DateFormat, not ok</description> + <expected-problems>1</expected-problems> <code><![CDATA[ import java.text.DateFormat; @@ -71,6 +71,22 @@ public class Foo { synchronized void bar() { sdf.format(); } +} + ]]></code> + </test-code> + <test-code> + <description>5a, Use DateFormat, ok</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.text.DateFormat; + +public class Foo { + private static final DateFormat sdf = new DateFormat(); + void bar() { + synchronized(sdf) { + sdf.format(); + } + } } ]]></code> </test-code> @@ -146,6 +162,120 @@ public class Foo { public void format() { FDF.format(new Date()); } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, Not OK</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + synchronized void bar() { // not static + sdf.format(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, also Not OK</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + static synchronized void bar() { // not a synchronized blocks + sdf.format(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, OK if allowMethodLevelSynchronization</description> + <rule-property name="allowMethodLevelSynchronization">true</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + static synchronized void bar() { + sdf.format(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, Not OK if allowMethodLevelSynchronization</description> + <rule-property name="allowMethodLevelSynchronization">true</rule-property> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + synchronized void bar() { // should be static + sdf.format(); + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, OK</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + static void bar() { + synchronized(sdf) { + sdf.format(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1815 static synchronized, Not OK</description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + static void bar() { + synchronized(Foo.class) { // not synchronized on sdf + sdf.format(); + } + } +} + ]]></code> + </test-code> + + <test-code> + <description>#1903 - Block synch is valid even with allowMethodLevelSynchronization</description> + <rule-property name="allowMethodLevelSynchronization">true</rule-property> + <expected-problems>0</expected-problems> + <code><![CDATA[ +import java.text.SimpleDateFormat; + +public class Foo { + private static final SimpleDateFormat sdf = new SimpleDateFormat(); + private void bar() { + synchronized(sdf) { + sdf.format(); + } + } } ]]></code> </test-code> diff --git a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java index 671b83b2e7..b6df841ca0 100644 --- a/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java +++ b/pmd-javascript/src/main/java/net/sourceforge/pmd/lang/ecmascript/ast/AbstractEcmascriptNode.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.ecmascript.ast; import org.mozilla.javascript.ast.AstNode; import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.SourceCodePositioner; public abstract class AbstractEcmascriptNode<T extends AstNode> extends AbstractNode implements EcmascriptNode<T> { @@ -46,14 +47,12 @@ public abstract class AbstractEcmascriptNode<T extends AstNode> extends Abstract */ @Override public Object childrenAccept(EcmascriptParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - // we know that the children here - // are all EcmascriptNodes - @SuppressWarnings("unchecked") - EcmascriptNode<T> ecmascriptNode = (EcmascriptNode<T>) children[i]; - ecmascriptNode.jjtAccept(visitor, data); - } + for (Node child : children) { + // we know that the children here + // are all EcmascriptNodes + @SuppressWarnings("unchecked") + EcmascriptNode<T> ecmascriptNode = (EcmascriptNode<T>) child; + ecmascriptNode.jjtAccept(visitor, data); } return data; } diff --git a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java index 97c1d3de89..06491c8fc8 100644 --- a/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java +++ b/pmd-jsp/src/main/java/net/sourceforge/pmd/lang/jsp/ast/AbstractJspNode.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.jsp.ast; import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.Node; public class AbstractJspNode extends AbstractNode implements JspNode { @@ -29,7 +30,7 @@ public class AbstractJspNode extends AbstractNode implements JspNode { @Override public void jjtClose() { - if (beginLine == -1 && (children == null || children.length == 0)) { + if (beginLine == -1 && children.length == 0) { beginColumn = parser.token.beginColumn; } if (beginLine == -1) { @@ -52,11 +53,10 @@ public class AbstractJspNode extends AbstractNode implements JspNode { */ @Override public Object childrenAccept(JspParserVisitor visitor, Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - ((JspNode) children[i]).jjtAccept(visitor, data); - } + for (Node child : children) { + ((JspNode) child).jjtAccept(visitor, data); } + return data; } diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml index 8dff01d621..88cb7bd139 100644 --- a/pmd-lang-test/pom.xml +++ b/pmd-lang-test/pom.xml @@ -126,16 +126,8 @@ <dependency> <groupId>com.github.oowekyala.treeutils</groupId> <artifactId>tree-matchers</artifactId> - <version>2.0.1</version> + <version>2.0.2</version> <scope>compile</scope> </dependency> - - <!-- Use pmd-java for tests --> - <dependency> - <groupId>net.sourceforge.pmd</groupId> - <artifactId>pmd-java</artifactId> - <version>6.12.0</version> - <scope>test</scope> - </dependency> </dependencies> </project> diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/AstMatcherDslAdapter.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/AstMatcherDslAdapter.kt index 99ed28c236..fc9d2ac255 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/AstMatcherDslAdapter.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/AstMatcherDslAdapter.kt @@ -4,7 +4,7 @@ package net.sourceforge.pmd.lang.ast.test -import com.github.oowekyala.treeutils.TreeLikeAdapter +import com.github.oowekyala.treeutils.DoublyLinkedTreeLikeAdapter import com.github.oowekyala.treeutils.matchers.MatchingConfig import com.github.oowekyala.treeutils.matchers.TreeNodeWrapper import com.github.oowekyala.treeutils.matchers.baseShouldMatchSubtree @@ -12,10 +12,12 @@ import com.github.oowekyala.treeutils.printers.KotlintestBeanTreePrinter import net.sourceforge.pmd.lang.ast.Node /** An adapter for [baseShouldMatchSubtree]. */ -object NodeTreeLikeAdapter : TreeLikeAdapter<Node> { +object NodeTreeLikeAdapter : DoublyLinkedTreeLikeAdapter<Node> { override fun getChildren(node: Node): List<Node> = node.findChildrenOfType(Node::class.java) override fun nodeName(type: Class<out Node>): String = type.simpleName.removePrefix("AST") + + override fun getParent(node: Node): Node? = node.parent } /** A subtree matcher written in the DSL documented on [TreeNodeWrapper]. */ @@ -24,9 +26,15 @@ typealias NodeSpec<N> = TreeNodeWrapper<Node, N>.() -> Unit /** A function feedable to [io.kotlintest.should], which fails the test if an [AssertionError] is thrown. */ typealias Assertions<M> = (M) -> Unit +val DefaultMatchingConfig = MatchingConfig( + adapter = NodeTreeLikeAdapter, + errorPrinter = KotlintestBeanTreePrinter(NodeTreeLikeAdapter), + implicitAssertions = { it.assertTextRangeIsOk() } +) + /** A shorthand for [baseShouldMatchSubtree] providing the [NodeTreeLikeAdapter]. */ inline fun <reified N : Node> Node?.shouldMatchNode(ignoreChildren: Boolean = false, noinline nodeSpec: NodeSpec<N>) { - this.baseShouldMatchSubtree(MatchingConfig(adapter = NodeTreeLikeAdapter, errorPrinter = KotlintestBeanTreePrinter(NodeTreeLikeAdapter)), ignoreChildren, nodeSpec) + this.baseShouldMatchSubtree(DefaultMatchingConfig, ignoreChildren, nodeSpec) } /** diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt index c8e9ebaff7..464e9ef570 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/NodeExtensions.kt @@ -4,7 +4,10 @@ package net.sourceforge.pmd.lang.ast.test +import net.sourceforge.pmd.lang.ast.AbstractNode +import net.sourceforge.pmd.lang.ast.GenericToken import net.sourceforge.pmd.lang.ast.Node +import java.util.* /** Extension methods to make the Node API more Kotlin-like */ @@ -21,6 +24,16 @@ val Node.childIndex: Int val Node.parent: Node? get() = this.jjtGetParent() +val Node.containingFile: Node + get() = generateSequence(this) { it.parent }.last() + + +val Node.firstToken: GenericToken + get() = (this as AbstractNode).jjtGetFirstToken() + +val Node.lastToken: GenericToken + get() = (this as AbstractNode).jjtGetLastToken() + fun Node.getChild(i: Int) = jjtGetChild(i) @@ -29,3 +42,58 @@ fun Node.safeGetChild(i: Int): Node? = when { else -> null } +val Node.textRange: TextRange + get() = TextRange(beginPosition, endPosition) + +val Node.beginPosition: TextPosition + get() = TextPosition(beginLine, beginColumn) + +val Node.endPosition: TextPosition + get() = TextPosition(endLine, endColumn) + + +fun Node.assertTextRangeIsOk() { + + // they're defined + assert(beginLine >= 0) { "Begin line is not set" } + assert(endLine >= 0) { "End line is not set" } + assert(beginColumn >= 0) { "Begin column is not set" } + assert(endColumn >= 0) { "End column is not set" } + + // they're in the right order + textRange.assertOrdered() + + val parent = parent ?: return + + assert(textRange in parent.textRange) { + "The text range is not a subrange of that of the parent" + } +} + + +data class TextPosition(val line: Int, val column: Int) : Comparable<TextPosition> { + + override operator fun compareTo(other: TextPosition): Int = Comparator.compare(this, other) + + companion object { + val Comparator: Comparator<TextPosition> = + java.util.Comparator.comparingInt<TextPosition> { o -> o.line } + .thenComparingInt { o -> o.column } + + } +} + +data class TextRange(val beginPos: TextPosition, val endPos: TextPosition) { + + fun assertOrdered() { + assert(beginPos <= endPos) { + "The begin position should be lower than the end position" + } + } + + operator fun contains(position: TextPosition): Boolean = position in beginPos..endPos + + /** Result makes no sense if either of those text bounds is not ordered. */ + operator fun contains(other: TextRange): Boolean = other.beginPos in this && other.endPos in this + +} diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt index bd18c52b06..d4b49ccc3a 100644 --- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt +++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/TestUtils.kt @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ast.test import io.kotlintest.should import kotlin.reflect.KCallable +import kotlin.reflect.jvm.isAccessible import io.kotlintest.shouldBe as ktShouldBe /** @@ -21,6 +22,7 @@ private fun <N, V> assertWrapper(callable: KCallable<N>, right: V, asserter: (N, fun formatName() = "::" + callable.name.removePrefix("get").decapitalize() val value: N = try { + callable.isAccessible = true callable.call() } catch (e: Exception) { throw RuntimeException("Couldn't fetch value for property ${formatName()}", e) @@ -52,4 +54,3 @@ private fun <N, V> assertWrapper(callable: KCallable<N>, right: V, asserter: (N, infix fun <N, V : N> KCallable<N>.shouldBe(expected: V?) = this.shouldEqual(expected) infix fun <T> KCallable<T>.shouldMatch(expected: T.() -> Unit) = assertWrapper(this, expected) { n, v -> n should v } - diff --git a/pmd-lua/pom.xml b/pmd-lua/pom.xml new file mode 100644 index 0000000000..88a46ec574 --- /dev/null +++ b/pmd-lua/pom.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <artifactId>pmd-lua</artifactId> + <name>PMD Lua</name> + + <parent> + <groupId>net.sourceforge.pmd</groupId> + <artifactId>pmd</artifactId> + <version>7.0.0-SNAPSHOT</version> + </parent> + + <build> + <plugins> + <plugin> + <groupId>org.antlr</groupId> + <artifactId>antlr4-maven-plugin</artifactId> + </plugin> + + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <configuration> + <useDefaultDelimiters>false</useDefaultDelimiters> + <delimiters> + <delimiter>${*}</delimiter> + </delimiters> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.antlr</groupId> + <artifactId>antlr4-runtime</artifactId> + </dependency> + <dependency> + <groupId>net.sourceforge.pmd</groupId> + <artifactId>pmd-core</artifactId> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>net.sourceforge.pmd</groupId> + <artifactId>pmd-test</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 b/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 new file mode 100644 index 0000000000..497f11060e --- /dev/null +++ b/pmd-lua/src/main/antlr4/net/sourceforge/pmd/lang/lua/antlr4/Lua.g4 @@ -0,0 +1,335 @@ +/* +BSD License + +Copyright (c) 2013, Kazunori Sakamoto +Copyright (c) 2016, Alexander Alexeev +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the NAME of Rainer Schuster nor the NAMEs of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This grammar file derived from: + + Lua 5.3 Reference Manual + http://www.lua.org/manual/5.3/manual.html + + Lua 5.2 Reference Manual + http://www.lua.org/manual/5.2/manual.html + + Lua 5.1 grammar written by Nicolai Mainiero + http://www.antlr3.org/grammar/1178608849736/Lua.g + +Tested by Kazunori Sakamoto with Test suite for Lua 5.2 (http://www.lua.org/tests/5.2/) + +Tested by Alexander Alexeev with Test suite for Lua 5.3 http://www.lua.org/tests/lua-5.3.2-tests.tar.gz +*/ + +grammar Lua; + +chunk + : block EOF + ; + +block + : stat* retstat? + ; + +stat + : ';' + | varlist '=' explist + | functioncall + | label + | 'break' + | 'goto' NAME + | 'do' block 'end' + | 'while' exp 'do' block 'end' + | 'repeat' block 'until' exp + | 'if' exp 'then' block ('elseif' exp 'then' block)* ('else' block)? 'end' + | 'for' NAME '=' exp ',' exp (',' exp)? 'do' block 'end' + | 'for' namelist 'in' explist 'do' block 'end' + | 'function' funcname funcbody + | 'local' 'function' NAME funcbody + | 'local' namelist ('=' explist)? + ; + +retstat + : 'return' explist? ';'? + ; + +label + : '::' NAME '::' + ; + +funcname + : NAME ('.' NAME)* (':' NAME)? + ; + +varlist + : var (',' var)* + ; + +namelist + : NAME (',' NAME)* + ; + +explist + : exp (',' exp)* + ; + +exp + : 'nil' | 'false' | 'true' + | number + | string + | '...' + | functiondef + | prefixexp + | tableconstructor + | <assoc=right> exp operatorPower exp + | operatorUnary exp + | exp operatorMulDivMod exp + | exp operatorAddSub exp + | <assoc=right> exp operatorStrcat exp + | exp operatorComparison exp + | exp operatorAnd exp + | exp operatorOr exp + | exp operatorBitwise exp + ; + +prefixexp + : varOrExp nameAndArgs* + ; + +functioncall + : varOrExp nameAndArgs+ + ; + +varOrExp + : var | '(' exp ')' + ; + +var + : (NAME | '(' exp ')' varSuffix) varSuffix* + ; + +varSuffix + : nameAndArgs* ('[' exp ']' | '.' NAME) + ; + +nameAndArgs + : (':' NAME)? args + ; + +/* +var + : NAME | prefixexp '[' exp ']' | prefixexp '.' NAME + ; + +prefixexp + : var | functioncall | '(' exp ')' + ; + +functioncall + : prefixexp args | prefixexp ':' NAME args + ; +*/ + +args + : '(' explist? ')' | tableconstructor | string + ; + +functiondef + : 'function' funcbody + ; + +funcbody + : '(' parlist? ')' block 'end' + ; + +parlist + : namelist (',' '...')? | '...' + ; + +tableconstructor + : '{' fieldlist? '}' + ; + +fieldlist + : field (fieldsep field)* fieldsep? + ; + +field + : '[' exp ']' '=' exp | NAME '=' exp | exp + ; + +fieldsep + : ',' | ';' + ; + +operatorOr + : 'or'; + +operatorAnd + : 'and'; + +operatorComparison + : '<' | '>' | '<=' | '>=' | '~=' | '=='; + +operatorStrcat + : '..'; + +operatorAddSub + : '+' | '-'; + +operatorMulDivMod + : '*' | '/' | '%' | '//'; + +operatorBitwise + : '&' | '|' | '~' | '<<' | '>>'; + +operatorUnary + : 'not' | '#' | '-' | '~'; + +operatorPower + : '^'; + +number + : INT | HEX | FLOAT | HEX_FLOAT + ; + +string + : NORMALSTRING | CHARSTRING | LONGSTRING + ; + +// LEXER + +NAME + : [a-zA-Z_][a-zA-Z_0-9]* + ; + +NORMALSTRING + : '"' ( EscapeSequence | ~('\\'|'"') )* '"' + ; + +CHARSTRING + : '\'' ( EscapeSequence | ~('\''|'\\') )* '\'' + ; + +LONGSTRING + : '[' NESTED_STR ']' + ; + +fragment +NESTED_STR + : '=' NESTED_STR '=' + | '[' .*? ']' + ; + +INT + : Digit+ + ; + +HEX + : '0' [xX] HexDigit+ + ; + +FLOAT + : Digit+ '.' Digit* ExponentPart? + | '.' Digit+ ExponentPart? + | Digit+ ExponentPart + ; + +HEX_FLOAT + : '0' [xX] HexDigit+ '.' HexDigit* HexExponentPart? + | '0' [xX] '.' HexDigit+ HexExponentPart? + | '0' [xX] HexDigit+ HexExponentPart + ; + +fragment +ExponentPart + : [eE] [+-]? Digit+ + ; + +fragment +HexExponentPart + : [pP] [+-]? Digit+ + ; + +fragment +EscapeSequence + : '\\' [abfnrtvz"'\\] + | '\\' '\r'? '\n' + | DecimalEscape + | HexEscape + | UtfEscape + ; + +fragment +DecimalEscape + : '\\' Digit + | '\\' Digit Digit + | '\\' [0-2] Digit Digit + ; + +fragment +HexEscape + : '\\' 'x' HexDigit HexDigit + ; + +fragment +UtfEscape + : '\\' 'u{' HexDigit+ '}' + ; + +fragment +Digit + : [0-9] + ; + +fragment +HexDigit + : [0-9a-fA-F] + ; + +COMMENT + : '--[' NESTED_STR ']' -> channel(HIDDEN) + ; + +LINE_COMMENT + : '--' + ( // -- + | '[' '='* // --[== + | '[' '='* ~('='|'['|'\r'|'\n') ~('\r'|'\n')* // --[==AA + | ~('['|'\r'|'\n') ~('\r'|'\n')* // --AAA + ) ('\r\n'|'\r'|'\n'|EOF) + -> channel(HIDDEN) + ; + +WS + : [ \t\u000C\r\n]+ -> skip + ; + +SHEBANG + : '#' '!' ~('\n'|'\r')* -> channel(HIDDEN) + ; diff --git a/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaLanguage.java b/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaLanguage.java new file mode 100644 index 0000000000..e2a87ec878 --- /dev/null +++ b/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaLanguage.java @@ -0,0 +1,18 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +/** + * Language implementation for Lua + */ +public class LuaLanguage extends AbstractLanguage { + + /** + * Creates a new Lua Language instance. + */ + public LuaLanguage() { + super("Lua", "lua", new LuaTokenizer(), ".lua"); + } +} diff --git a/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java b/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java new file mode 100644 index 0000000000..23c292dbe7 --- /dev/null +++ b/pmd-lua/src/main/java/net/sourceforge/pmd/cpd/LuaTokenizer.java @@ -0,0 +1,28 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +import org.antlr.v4.runtime.CharStream; + +import net.sourceforge.pmd.cpd.token.AntlrTokenFilter; +import net.sourceforge.pmd.lang.antlr.AntlrTokenManager; +import net.sourceforge.pmd.lang.lua.antlr4.LuaLexer; + +/** + * The Lua Tokenizer + */ +public class LuaTokenizer extends AntlrTokenizer { + + @Override + protected AntlrTokenManager getLexerForSource(SourceCode sourceCode) { + CharStream charStream = AntlrTokenizer.getCharStreamFromSourceCode(sourceCode); + return new AntlrTokenManager(new LuaLexer(charStream), sourceCode.getFileName()); + } + + @Override + protected AntlrTokenFilter getTokenFilter(final AntlrTokenManager tokenManager) { + return new AntlrTokenFilter(tokenManager); + } +} diff --git a/pmd-lua/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language b/pmd-lua/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language new file mode 100644 index 0000000000..ff792867ee --- /dev/null +++ b/pmd-lua/src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language @@ -0,0 +1 @@ +net.sourceforge.pmd.cpd.LuaLanguage diff --git a/pmd-lua/src/test/java/net/sourceforge/pmd/cpd/LuaTokenizerTest.java b/pmd-lua/src/test/java/net/sourceforge/pmd/cpd/LuaTokenizerTest.java new file mode 100644 index 0000000000..5328e71823 --- /dev/null +++ b/pmd-lua/src/test/java/net/sourceforge/pmd/cpd/LuaTokenizerTest.java @@ -0,0 +1,56 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cpd; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; + +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import net.sourceforge.pmd.testframework.AbstractTokenizerTest; + +@RunWith(Parameterized.class) +public class LuaTokenizerTest extends AbstractTokenizerTest { + + private final String filename; + private final int nExpectedTokens; + + public LuaTokenizerTest(String filename, int nExpectedTokens) { + this.filename = filename; + this.nExpectedTokens = nExpectedTokens; + } + + @Parameterized.Parameters + public static Collection<Object[]> data() { + return Arrays.asList( + new Object[] { "factorial.lua", 44 }, + new Object[] { "helloworld.lua", 5 } + ); + } + + @Before + @Override + public void buildTokenizer() throws IOException { + this.tokenizer = new LuaTokenizer(); + this.sourceCode = new SourceCode(new SourceCode.StringCodeLoader(this.getSampleCode(), this.filename)); + } + + @Override + public String getSampleCode() throws IOException { + return IOUtils.toString(LuaTokenizer.class.getResourceAsStream(this.filename), StandardCharsets.UTF_8); + } + + @Test + public void tokenizeTest() throws IOException { + this.expectedTokenCount = nExpectedTokens; + super.tokenizeTest(); + } +} diff --git a/pmd-lua/src/test/resources/net/sourceforge/pmd/cpd/factorial.lua b/pmd-lua/src/test/resources/net/sourceforge/pmd/cpd/factorial.lua new file mode 100644 index 0000000000..f2f2d82661 --- /dev/null +++ b/pmd-lua/src/test/resources/net/sourceforge/pmd/cpd/factorial.lua @@ -0,0 +1,13 @@ +-- defines a factorial function + function fact (n) + if n == 0 then + return 1 + else + return n * fact(n-1) + end + end + + print("enter a number:") + a = io.read("*number") -- read a number + print(fact(a)) + diff --git a/pmd-lua/src/test/resources/net/sourceforge/pmd/cpd/helloworld.lua b/pmd-lua/src/test/resources/net/sourceforge/pmd/cpd/helloworld.lua new file mode 100644 index 0000000000..45d4840a9f --- /dev/null +++ b/pmd-lua/src/test/resources/net/sourceforge/pmd/cpd/helloworld.lua @@ -0,0 +1,2 @@ + print("Hello World") + diff --git a/pmd-matlab/etc/grammar/matlab.jj b/pmd-matlab/etc/grammar/matlab.jj index 6f61dd0d42..31aca621e7 100644 --- a/pmd-matlab/etc/grammar/matlab.jj +++ b/pmd-matlab/etc/grammar/matlab.jj @@ -41,11 +41,11 @@ PARSER_END(MatlabParser) "\n" : DEFAULT } -MORE: +<DEFAULT, TRANSPOSE> MORE: { "%{": IN_COMMENT } -SPECIAL_TOKEN: -{ <SINGLE_LINE_COMMENT: "%"(~["\n","\r"])* ("\n"|"\r"|"\r\n")?> } +<DEFAULT, TRANSPOSE> SPECIAL_TOKEN: +{ <SINGLE_LINE_COMMENT: "%"~["{"](~["\n","\r"])* ("\n"|"\r"|"\r\n")?> } <IN_COMMENT> SPECIAL_TOKEN: { <MULTI_LINE_COMMENT: "%}">: DEFAULT } @@ -65,6 +65,7 @@ SPECIAL_TOKEN: | < AT: "@" > : DEFAULT | < DOT: "." > : TRANSPOSE | < COMMA: "," > : DEFAULT +| < QUESTIONMARK: "?" > : DEFAULT } <DEFAULT, TRANSPOSE> TOKEN : /* OPERATORS AND ASSIGNMENTS */ @@ -139,6 +140,7 @@ SPECIAL_TOKEN: <DEFAULT> TOKEN : { < STRING: "'" ( <ESC_SEQ> | "'" "'" | ~["\\","'","\n"] )* "'" > +| < DSTRING: "\"" ( "\\" | "\"" "\"" | ~["\\","\"","\n"] )* "\"" > | < #ESC_SEQ: "\\" ( "b" | "t" | "n" | "f" | "r" | "\"" | "'" | "\\" ) | <UNICODE_ESC> diff --git a/pmd-matlab/src/test/java/net/sourceforge/pmd/cpd/MatlabTokenizerTest.java b/pmd-matlab/src/test/java/net/sourceforge/pmd/cpd/MatlabTokenizerTest.java index 50fdb1832e..cc45bfb48f 100644 --- a/pmd-matlab/src/test/java/net/sourceforge/pmd/cpd/MatlabTokenizerTest.java +++ b/pmd-matlab/src/test/java/net/sourceforge/pmd/cpd/MatlabTokenizerTest.java @@ -51,7 +51,55 @@ public class MatlabTokenizerTest extends AbstractTokenizerTest { )); Tokens tokens = new Tokens(); tokenizer.tokenize(sourceCode, tokens); - TokenEntry.getEOF(); assertEquals(2, tokens.size()); // 2 tokens: "end" + EOF } + + @Test + public void testComments() throws IOException { + SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("classdef LC" + PMD.EOL + + " methods" + PMD.EOL + + " function [obj, c,t, s ] = Classification( obj,m,t, cm )%#codegen" + PMD.EOL + + " end" + PMD.EOL + + " end" + PMD.EOL + + "end")); + Tokens tokens = new Tokens(); + tokenizer.tokenize(sourceCode, tokens); // should not result in parse error + assertEquals(28, tokens.size()); + } + + @Test + public void testBlockComments() throws IOException { + SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("%{" + PMD.EOL + + " Name: helloworld.m\n" + PMD.EOL + + " Purpose: Say \"Hello World!\" in two different ways" + PMD.EOL + + "%}" + PMD.EOL + + PMD.EOL + + "% Do it the good ol' fashioned way...command window" + PMD.EOL + + "disp('Hello World!');\n" + PMD.EOL + + "%" + PMD.EOL + + "% Do it the new hip GUI way...with a message box" + PMD.EOL + + "msgbox('Hello World!','Hello World!');")); + Tokens tokens = new Tokens(); + tokenizer.tokenize(sourceCode, tokens); // should not result in parse error + assertEquals(13, tokens.size()); + } + + @Test + public void testQuestionMark() throws IOException { + SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("classdef Class1" + PMD.EOL + + "properties (SetAccess = ?Class2)")); + Tokens tokens = new Tokens(); + tokenizer.tokenize(sourceCode, tokens); + assertEquals(10, tokens.size()); + } + + @Test + public void testDoubleQuotedStrings() throws IOException { + SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader( + "error(\"This is a double-quoted string\");")); + Tokens tokens = new Tokens(); + tokenizer.tokenize(sourceCode, tokens); + assertEquals("\"This is a double-quoted string\"", tokens.getTokens().get(2).toString()); + assertEquals(6, tokens.size()); + } } diff --git a/pmd-plsql/etc/grammar/PldocAST.jjt b/pmd-plsql/etc/grammar/PldocAST.jjt index 19b8548887..6f3477722a 100644 --- a/pmd-plsql/etc/grammar/PldocAST.jjt +++ b/pmd-plsql/etc/grammar/PldocAST.jjt @@ -27,6 +27,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** + * Various fixes for expression lists, join clauses, case expression + * + * Hugo Araya Nash 06/2019 + *==================================================================== + * Various fixes for INSERT INTO with records, implicit cursor attributes + * and trim expression. + * + * Hugo Araya Nash 05/2019 + *==================================================================== * Added support for XMLTABLE, XMLEXISTS, XMLCAST, XMLQUERY, CAST, XMLFOREST * and XMLELEMENT * @@ -1172,9 +1181,9 @@ void RestOfStatement() #void : [ WhereClause() ] [ HierarchicalQueryClause() ] [ GroupByClause() ] - + (LOOKAHEAD(2) ( SubqueryOperation() ) Subquery() )* - + [ OrderByClause() ] [ RowLimitingClause() ] } @@ -1315,9 +1324,7 @@ ASTCondition Condition() : {} { ( - LOOKAHEAD(4) CompoundCondition() - | - LOOKAHEAD(4) Condition2() + CompoundCondition() ) { return jjtThis; } } @@ -1327,9 +1334,6 @@ void Condition2() #void : {} { ( - // a IS OF Type condition that starts with a function... - LOOKAHEAD(FunctionCall() <IS> [<NOT>] <OF>) IsOfTypeCondition() - | LOOKAHEAD(<REGEXP_LIKE>) RegexpLikeCondition() | LOOKAHEAD(<EXISTS>) ExistsCondition() @@ -1346,7 +1350,7 @@ void Condition2() #void : | LOOKAHEAD(BetweenCondition()) BetweenCondition() | - LOOKAHEAD(Name() <IS> [<NOT>] <NULL>) IsNullCondition() + LOOKAHEAD(PrimaryExpression() <IS> [<NOT>] <NULL>) IsNullCondition() | LOOKAHEAD(PrimaryExpression() <IS> [<NOT>] <OF>) IsOfTypeCondition() | @@ -1440,11 +1444,14 @@ ASTCompoundCondition CompoundCondition() : {} { ( - LOOKAHEAD(3) "(" Condition() ")" (LOOKAHEAD(2) ( <AND> | <OR> ) { jjtThis.setType(token.getImage()); } Condition() )* + LOOKAHEAD(1) <NOT> { jjtThis.setType(token.getImage()); } Condition() | - LOOKAHEAD(3) <NOT> { jjtThis.setType(token.getImage()); } Condition() + // this might be a expression list + LOOKAHEAD("(" SqlExpression() ",") Condition2() (LOOKAHEAD(2) ( <AND> | <OR> ) { jjtThis.setType(token.getImage()); } Condition() )* | - LOOKAHEAD(3) Condition2() (LOOKAHEAD(2) ( <AND> | <OR> ) { jjtThis.setType(token.getImage()); } Condition() )* + LOOKAHEAD(1) "(" Condition() ")" (LOOKAHEAD(2) ( <AND> | <OR> ) { jjtThis.setType(token.getImage()); } Condition() )* + | + Condition2() (LOOKAHEAD(2) ( <AND> | <OR> ) { jjtThis.setType(token.getImage()); } Condition() )* ) { return jjtThis; } } @@ -1536,11 +1543,14 @@ ASTSimpleExpression SimpleExpression() : ( "*" | Column() ) { sb.append(token.image); } | // Named Cursor: https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/named-cursor-attribute.html#GUID-CD8D8415-FF19-4D81-99BA-7825FD40CC96 + // Implicit Cursor: https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/implicit-cursor-attribute.html#GUID-5A938EE7-E8D2-468C-B60F-81898F110BE1 LOOKAHEAD(3) Column() { sb.append(token.image); } "%" ( LOOKAHEAD({isKeyword("isopen")}) KEYWORD("ISOPEN") | LOOKAHEAD({isKeyword("found")}) KEYWORD("FOUND") | LOOKAHEAD({isKeyword("notfound")}) KEYWORD("NOTFOUND") | LOOKAHEAD({isKeyword("rowcount")}) KEYWORD("ROWCOUNT") + | LOOKAHEAD({isKeyword("bulk_rowcount")}) KEYWORD("BULK_ROWCOUNT") + | LOOKAHEAD({isKeyword("bulk_exceptions")}) KEYWORD("BULK_EXCEPTIONS") ) { sb.append('%').append(token.image); } | LOOKAHEAD(2) @@ -1552,6 +1562,20 @@ ASTSimpleExpression SimpleExpression() : } } +ASTOuterJoinExpression OuterJoinExpression() : +{ StringBuilder sb = new StringBuilder(); } +{ + [ LOOKAHEAD(6) SchemaName() { sb.append(token.image); } "." { sb.append(token.image); } ] + [ LOOKAHEAD(4) TableName() { sb.append(token.image); } "." { sb.append(token.image); } ] + Column() { sb.append(token.image); } + "(" "+" ")" + + { + jjtThis.setImage(sb.toString()); + return jjtThis; + } +} + /** * Built-in function call or a user defined function call. * See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Functions.html#GUID-D079EFD3-C683-441F-977E-2C9503089982 @@ -1801,15 +1825,12 @@ void FromClauseEntry() #void : {} { ( - LOOKAHEAD(JoinClause()) JoinClause() - | - // using lookahead to avoid misinterpreting the token after the identifier - // as a table alias rather than as a keyword - LOOKAHEAD(<IDENTIFIER> (<PARTITION>|<NATURAL>|<OUTER>|<JOIN>|<RIGHT>|<CROSS>|<FULL>)) JoinClause() + LOOKAHEAD([ SchemaName() "." ] TableName() [<IDENTIFIER>] + (<PARTITION>|<NATURAL>|<OUTER>|<INNER>|<JOIN>|<LEFT>|<RIGHT>|<CROSS>|<FULL>)) JoinClause() | LOOKAHEAD(<IDENTIFIER> "(", {isKeyword("XMLTABLE")}) XMLTable() [ LOOKAHEAD(2) TableAlias() ] | - LOOKAHEAD(3) TableReference() + LOOKAHEAD(3) (TableReference() (JoinClausePart())*) #JoinClause(>1) | "(" JoinClause() ")" ) @@ -1946,12 +1967,25 @@ ASTTableReference TableReferenceInJoin() #TableReference : { QueryTableExpression() - [ LOOKAHEAD(1, ID(), {getToken(1).kind != NATURAL - && getToken(1).kind != CROSS - && getToken(1).kind != ON + [ LOOKAHEAD(1, ID(), { + // ON / USING might follow a table reference inside a inner cross join + getToken(1).kind != ON + && getToken(1).kind != USING + + // PARTITION might follow a table reference inside a outer join + // or it might precede a outer join && getToken(1).kind != PARTITION + + // join clauses can be repeated + && getToken(1).kind != INNER + && getToken(1).kind != JOIN + && getToken(1).kind != CROSS + && getToken(1).kind != NATURAL + && getToken(1).kind != FULL + && getToken(1).kind != LEFT && getToken(1).kind != RIGHT - && getToken(1).kind != FULL}) + && getToken(1).kind != OUTER + }) TableAlias() ] @@ -1980,32 +2014,30 @@ ASTJoinClause JoinClause() : {} { TableReferenceInJoin() - ( + (JoinClausePart())+ + { return jjtThis; } +} + +void JoinClausePart() #void : +{} +{ LOOKAHEAD(2) InnerCrossJoinClause() | LOOKAHEAD(2) OuterJoinClause() | LOOKAHEAD(2) CrossOuterApplyClause() - )+ - { return jjtThis; } } ASTInnerCrossJoinClause InnerCrossJoinClause() : {} { ( - [ <INNER> ] <JOIN> TableReferenceInJoin() - ( - <ON> ConditionalOrExpression() - | - <USING> "(" Column() ("," Column() )* ")" - ) + [<INNER>] <JOIN> TableReferenceInJoin() + (<ON> ConditionalOrExpression() + |<USING> "(" Column() ("," Column() )* ")") | - ( - <CROSS> { jjtThis.setCross(true); } - | - <NATURAL> { jjtThis.setNatural(true); } [ <INNER> ] - ) + (<CROSS> { jjtThis.setCross(true); } + |<NATURAL> { jjtThis.setNatural(true); } [<INNER>] ) <JOIN> TableReferenceInJoin() ) { return jjtThis; } @@ -2268,21 +2300,33 @@ ASTInsertStatement InsertStatement() : ASTSingleTableInsert SingleTableInsert() : {} { - InsertIntoClause() ( ValuesClause() | Subquery() ) + InsertIntoClause() ( ValuesClause() [ ReturningClause() ] | Subquery() ) { return jjtThis; } } ASTInsertIntoClause InsertIntoClause() : {} { - <INTO> DMLTableExpressionClause() [ LOOKAHEAD(2) TableAlias() ] [ LOOKAHEAD(2) "(" Column() ( "," Column() )* ")" ] + <INTO> DMLTableExpressionClause() + [ LOOKAHEAD(2) TableAlias() ] + [ + LOOKAHEAD(2) "(" + [ LOOKAHEAD(2) TableName() "." ] Column() + ( "," [ LOOKAHEAD(2) TableName() "." ] Column() )* + ")" + ] { return jjtThis; } } ASTValuesClause ValuesClause() : {} { - <VALUES> "(" ( Expression() | <_DEFAULT> ) ( "," ( Expression() | <_DEFAULT> ) )* ")" + <VALUES> + ( + "(" ( Expression() | <_DEFAULT> ) ( "," ( Expression() | <_DEFAULT> ) )* ")" + | + ID() // that's a record variable name + ) { return jjtThis; } } ASTMultiTableInsert MultiTableInsert() : @@ -2373,7 +2417,7 @@ ASTUpdateSetClause UpdateSetClause() : ( ( "(" ( [ LOOKAHEAD(2) TableName() "." ] Column() (",")? )+ ")" "=" "(" Subquery() ")" ) | - ( [ LOOKAHEAD(2) TableName() "." ] Column() "=" ( LOOKAHEAD(1) "(" Subquery() ")" | Expression() | <_DEFAULT> ) ) + ( [ LOOKAHEAD(2) TableName() "." ] Column() "=" ( LOOKAHEAD(2) "(" Subquery() ")" | Expression() | <_DEFAULT> ) ) ) (",")? )+ @@ -2796,10 +2840,10 @@ ASTExpression Expression() : { // Need syntactic lookahead to discriminate between Assignment and a procedure call ( - LOOKAHEAD( PrimaryExpression() ":" "=" ) (simpleNode = Assignment()) {sb.append(simpleNode.getImage()); } - | (simpleNode = ConditionalOrExpression() ) {sb.append(simpleNode.getImage()); } - | (simpleNode = CompilationExpression() ) {sb.append(simpleNode.getImage()); } - ) + LOOKAHEAD( PrimaryExpression() ":" "=" ) (simpleNode = Assignment()) + | (simpleNode = ConditionalOrExpression() ) + | (simpleNode = CompilationExpression() ) + ) {sb.append(simpleNode.getImage()); } { jjtThis.setImage(sb.toString()); return jjtThis; } @@ -2851,24 +2895,14 @@ ASTAssignment Assignment() : } ASTCaseExpression CaseExpression() : -{ Token thisToken; PLSQLNode simpleNode = null; StringBuilder sb = new StringBuilder() ; } +{} { - ( - thisToken = <CASE> { sb.append(thisToken.image);} - ( simpleNode = Expression() { sb.append(" "); sb.append(simpleNode.getImage()); } )? - ( thisToken = <WHEN> { sb.append(" "); sb.append(thisToken.image); } - simpleNode = Expression() { sb.append(" "); sb.append(simpleNode.getImage()); } - thisToken = <THEN> { sb.append(" "); sb.append(thisToken.image); } - Expression() { sb.append(" "); sb.append(simpleNode.getImage()); } - )+ - [ thisToken = <ELSE> { sb.append(" "); sb.append(thisToken.image);} - Expression() { sb.append(" "); sb.append(simpleNode.getImage()); } - ] - thisToken = <END> { sb.append(" "); sb.append(thisToken.image);} - ) - { - jjtThis.setImage(sb.toString()); return jjtThis; - } + <CASE> + ( Expression() ( <WHEN> Expression() <THEN> Expression() )+ + | ( <WHEN> Condition() <THEN> Expression() )+ ) + [ <ELSE> Expression() ] + <END> + { return jjtThis; } } /* @@ -2903,12 +2937,14 @@ ASTTrimExpression TrimExpression() : { PLSQLNode simpleNode = null; StringBuilder sb = new StringBuilder() ; } { ( - "(" { sb.append("(");} - [ ( <LEADING> | <TRAILING> | <BOTH> ){ sb.append(" "); sb.append(token.toString()); } ] - [ simpleNode = StringExpression() { sb.append(" "); sb.append(simpleNode.getImage()); } ] - ( <FROM> ) { sb.append(token.image);} - simpleNode = StringExpression() { sb.append(" "); sb.append(simpleNode.getImage()); } - ")" { sb.append(")");} + "(" { sb.append("(");} + [ LOOKAHEAD(2) + [ ( <LEADING> | <TRAILING> | <BOTH> ) { sb.append(" "); sb.append(token.toString()); } ] + [ simpleNode = StringExpression() { sb.append(" "); sb.append(simpleNode.getImage()); } ] + ( <FROM> ) { sb.append(" ").append(token.image); } + ] + simpleNode = StringExpression() { sb.append(" "); sb.append(simpleNode.getImage()); } + ")" { sb.append(")");} ) { jjtThis.setImage(sb.toString()); return jjtThis; @@ -2974,14 +3010,13 @@ ASTEqualityExpression EqualityExpression() #EqualityExpression(>1) : //RelationalExpression() ( ( "=" | "!=" | "<>" | <IS>) RelationalExpression() )* ( ( - simpleNode = RelationalExpression() + simpleNode = RelationalExpression() ) {sb.append(simpleNode.getImage());} ( ( ("=" ) {sb.append(" = ");} | ("!" "=" ) {sb.append(" != ");} // Now unde RelationalExpression | ("<" ">" ) {sb.append(" <> ");} - | (<IS>) {sb.append(" IS ");} - ) + | (<IS>) {sb.append(" IS ");}) ( simpleNode = RelationalExpression() ) {sb.append(simpleNode.getImage());} @@ -3132,39 +3167,55 @@ ASTUnaryExpression UnaryExpression(boolean isUnarySign) #UnaryExpression(>1) : } } +ASTExtractExpression ExtractExpression() : +{} +{ + <EXTRACT> "(" + ( <MONTH> | <YEAR> | <DAY> |<HOUR> | <MINUTE> | <SECOND> + | <TIMEZONE_HOUR> | <TIMEZONE_MINUTE> + | <TIMEZONE_REGION> | <TIMEZONE_ABBR> ) + <FROM> + (LOOKAHEAD(2) FunctionCall() + |LOOKAHEAD(2) DateTimeLiteral() + |LOOKAHEAD(1) Name() ) ")" + { return jjtThis ; } +} + ASTUnaryExpressionNotPlusMinus UnaryExpressionNotPlusMinus() #UnaryExpressionNotPlusMinus(>1) : { PLSQLNode simpleNode = null; StringBuilder sb = new StringBuilder() ; } { ( - (<NOT>) {sb.append(" NOT "); } - (simpleNode = UnaryExpression(false) ) { sb.append(simpleNode.getImage()); } + <NOT> {sb.append(" NOT "); } simpleNode = UnaryExpression(false) | - (simpleNode = IsNullCondition() ) {sb.append(simpleNode.getImage()); } - ) + LOOKAHEAD(2) simpleNode = ExtractExpression() + | + LOOKAHEAD(2) simpleNode = IsNullCondition() + ) {sb.append(simpleNode.getImage()); } { jjtThis.setImage(sb.toString()); return jjtThis; } } + ASTIsNullCondition IsNullCondition() #IsNullCondition(>1) : //yanzin { PLSQLNode simpleNode = null; PLSQLNode name = null; StringBuilder sb = new StringBuilder(); } { ( - LOOKAHEAD(Name() <IS> [<NOT>] <NULL>) + LOOKAHEAD(PrimaryExpression() <IS> [<NOT>] <NULL>) ( - (name = Name()) {sb.append(name.getImage());} <IS> {sb.append(" IS");} [<NOT> {sb.append(" NOT");}] <NULL> {sb.append(" NULL");} - ) + (name = PrimaryExpression() #Name) {sb.append(name.getImage());} <IS> {sb.append(" IS");} [<NOT> {sb.append(" NOT");}] <NULL> {sb.append(" NULL");} + ) | - ( - simpleNode = IsOfTypeCondition() - ) - { - sb.append(simpleNode.getImage()); - } + ( + simpleNode = IsOfTypeCondition() + ) + { + sb.append(simpleNode.getImage()); + } ) { jjtThis.setImage(sb.toString()); return jjtThis; - } + } } ASTIsOfTypeCondition IsOfTypeCondition() #IsOfTypeCondition(>1) : @@ -3221,14 +3272,15 @@ ASTPrimaryPrefix PrimaryPrefix() : } { ( + LOOKAHEAD(OuterJoinExpression()) ( simpleNode = OuterJoinExpression() ) { sb.append(simpleNode.getImage()); } // Note: AnalyticClause and WithinClause are only allowed for specific functions, but this grammar allows it for all functions. - LOOKAHEAD(FunctionName() "(") ( simpleNode = FunctionCall() [ AnalyticClause() ] [ WithinClause() ] ) { sb.append(simpleNode.getImage()); } +| LOOKAHEAD(FunctionName() "(") ( simpleNode = FunctionCall() [ AnalyticClause() ] [ WithinClause() ] ) { sb.append(simpleNode.getImage()); } | LOOKAHEAD(MultiSetCondition()) simpleNode = MultiSetCondition() -| LOOKAHEAD(CaseExpression()) ( simpleNode =CaseExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110520 +| LOOKAHEAD(<CASE>) ( simpleNode =CaseExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110520 | LOOKAHEAD(ObjectExpression() ) ( simpleNode = ObjectExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110604 //| LOOKAHEAD(LikeExpression()) ( simpleNode = LikeExpression() ) { sb.append(simpleNode.getImage()) ; } //SRT 20110604 -| LOOKAHEAD(SimpleExpression()) ( simpleNode = SimpleExpression() ) { sb.append(simpleNode.getImage()); } | LOOKAHEAD(Literal()) ( simpleNode = Literal() ) { sb.append(simpleNode.getImage()) ; } +| LOOKAHEAD(SimpleExpression()) ( simpleNode = SimpleExpression() ) { sb.append(simpleNode.getImage()); } | ( simpleNode =Name() ) { sb.append(simpleNode.getImage()) ; } | SelectStatement() | LOOKAHEAD("(" <SELECT>) "(" SelectStatement() ")" @@ -3625,18 +3677,21 @@ ASTAccessibleByClause AccessibleByClause() : // SRT * ASTTable Table() : - { } { <CREATE> [ ( <GLOBAL> | <PRIVATE> ) <TEMPORARY> | <SHARDED> | <DUPLICATED> ] <TABLE> ObjectNameDeclaration() [ <SHARING> "=" ( <METADATA> | <DATA> | <EXTENDED> <DATA> | <NONE> ) ] + //object_table + ( <OF> Datatype() [ [ <NOT> ] <SUBSTITUTABLE> <AT> <ALL> KEYWORD("LEVELS") ]| + //relational_table [ "(" ( LOOKAHEAD(2) OutOfLineConstraint() | TableColumn() ) ("," ( LOOKAHEAD(2) OutOfLineConstraint() | TableColumn() ))* ")" ] [LOOKAHEAD(4) <ON> <COMMIT> (<DROP> | <PRESERVE>) <DEFINITION>] - [LOOKAHEAD(4) <ON> <COMMIT> (<DELETE> | <PRESERVE>) <ROWS>] - //### [physicalProperties()] - //### [tableProperties()] + [LOOKAHEAD(4) <ON> <COMMIT> (<DELETE> | <PRESERVE>) <ROWS>] ) + //### [PhysicalProperties()] + //### [TableProperties()] + Skip2NextOccurrence(";") [";"] { return jjtThis ; } @@ -3646,10 +3701,30 @@ ASTTableColumn TableColumn() : { } { - ID() Datatype() [<_DEFAULT> Expression()] [[<NOT> ] <NULL>] + ID() Datatype() + [ ( <_DEFAULT> [ <ON> <NULL> ] (LOOKAHEAD(FunctionName() "(") FunctionCall()|LOOKAHEAD(1) UnaryExpression(true)) + | LOOKAHEAD(2) <GENERATED> [ ( <BY> <_DEFAULT> [ <ON> <NULL>] | KEYWORD("ALWAYS")) ] + <AS> KEYWORD("IDENTITY") ) ] + (LOOKAHEAD(1) InlineConstraint())* { return jjtThis ; } } +ASTInlineConstraint InlineConstraint() : +{} +{ + [ <CONSTRAINT> ID() ] + ( [<NOT>] <NULL> + | <UNIQUE> { jjtThis.setType(ConstraintType.UNIQUE); } + | <PRIMARY> { jjtThis.setType(ConstraintType.PRIMARY); } <KEY> + | <CHECK> { jjtThis.setType(ConstraintType.CHECK); } "(" Condition() ")" + | <WITH> <ROWID> + | <SCOPE> <IS> [ LOOKAHEAD(2) TableName() "." ] Column() + | ReferencesClause() + ) + (ConstraintState())* + { return jjtThis; } +} + ASTOutOfLineConstraint OutOfLineConstraint() : {} { @@ -3657,16 +3732,31 @@ ASTOutOfLineConstraint OutOfLineConstraint() : ( <UNIQUE> { jjtThis.setType(ConstraintType.UNIQUE); } "(" ID() ("," ID())* ")" | <PRIMARY> { jjtThis.setType(ConstraintType.PRIMARY); } <KEY> "(" ID() ("," ID())* ")" | <FOREIGN> { jjtThis.setType(ConstraintType.FOREIGN); } <KEY> "(" ID() ("," ID())* ")" ReferencesClause() - | <CHECK> { jjtThis.setType(ConstraintType.CHECK); } "(" Statement() ")" + | <CHECK> { jjtThis.setType(ConstraintType.CHECK); } "(" Condition() ")" ) + (ConstraintState())* { return jjtThis; } } +void ConstraintState() #void: +{} +{ + ( <USING> <INDEX> + ( LOOKAHEAD(2) <IDENTIFIER> + | LOOKAHEAD(2) "(" <CREATE> <UNIQUE> <INDEX> <IDENTIFIER> <ON> TableName() "(" Column() ("," Column())* ")" ")" + | LOOKAHEAD(2) ( <PCTFREE> NumericLiteral() + | <IDENTIFIER> ( <IDENTIFIER> | Skip2NextTerminator("(",")") ) )* ) + | <INITIALLY> (<IMMEDIATE>|<DEFERRED>) + | <DEFERRABLE> + | <ENABLE> + | <DISABLE> ) +} + ASTReferencesClause ReferencesClause() : {} { <REFERENCES> ObjectNameDeclaration() - [ "(" ID() ( LOOKAHEAD(2) "," ID())* ] + [ "(" ID() ( LOOKAHEAD(2) "," ID() )* ")" ] [ <ON> <DELETE> ( <CASCADE> | <SET> <NULL> ) ] { return jjtThis; } } @@ -3682,7 +3772,8 @@ ASTView View() : ["(" ViewColumn() ("," ViewColumn())* ")"] //### OF ... WITH OBJECT IDENTIFIER... <AS> - SqlStatement(null,";") + Subquery() + [ SubqueryRestrictionClause() ] (";" | "/") { jjtThis.setImage(simpleNode.getImage()) ; return jjtThis ; } @@ -4821,7 +4912,12 @@ TOKEN [IGNORE_CASE]: <FOREACHROW: "FOR EACH ROW"> | <REFERENCING: "REFERENCING"> | <OLD: "OLD"> | -<PARENT: "PARENT"> +<PARENT: "PARENT"> | +<GENERATED: "GENERATED"> | +<SCOPE: "SCOPE"> | +<INITIALLY: "INITIALLY"> | +<DEFERRABLE: "DEFERRABLE"> | +<DEFERRED: "DEFERRED"> | <CC_IF: "$IF"> | <CC_THEN: "$THEN"> @@ -5300,8 +5396,8 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {} //| <DECLARE> //| <DECREMENT> //| <DECRYPT> -//| <DEFERRABLE> -//| <DEFERRED> +| <DEFERRABLE> +| <DEFERRED> | <DEFINE>// SQL*Plus command //| <DEFINED> | <DEFINER> @@ -5416,7 +5512,7 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {} //| <G> //| <GATHER_PLAN_STATISTICS> //| <GBY_CONC_ROLLUP> -//| <GENERATED> +| <GENERATED> | <GLOBAL> //| <GLOBAL_NAME> //| <GLOBAL_TOPIC_ENABLED> @@ -5483,7 +5579,7 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {} //| <INFORMATIONAL> //| <INITIAL> //| <INITIALIZED> -//| <INITIALLY> +| <INITIALLY> //| <INITRANS> //| <INLINE> //| <INLINE_XMLTYPE_NT> @@ -5526,7 +5622,6 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {} | <LENGTH> //| <LESS> | <LEVEL> -//| <LEVELS> | <LIBRARY> //| <LIKE_EXPAND> | <LIKE2> @@ -5943,7 +6038,7 @@ ASTKEYWORD_UNRESERVED KEYWORD_UNRESERVED (): {} | <SCHEMA> //| <SCN> //| <SCN_ASCENDING> -//| <SCOPE> +| <SCOPE> //| <SD_ALL> //| <SD_INHIBIT> //| <SD_SHOW> diff --git a/pmd-plsql/src/main/ant/alljavacc.xml b/pmd-plsql/src/main/ant/alljavacc.xml index eddee3573d..d22c66587a 100644 --- a/pmd-plsql/src/main/ant/alljavacc.xml +++ b/pmd-plsql/src/main/ant/alljavacc.xml @@ -56,6 +56,7 @@ <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTName.java" /> <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTOuterJoinClause.java" /> <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTOuterJoinType.java" /> + <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTInlineConstraint.java" /> <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTOutOfLineConstraint.java" /> <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTPackageBody.java" /> <delete file="${target}/net/sourceforge/pmd/lang/plsql/ast/ASTPackageSpecification.java" /> diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTInlineConstraint.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTInlineConstraint.java new file mode 100644 index 0000000000..ab1273b363 --- /dev/null +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTInlineConstraint.java @@ -0,0 +1,42 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.plsql.ast; + +public class ASTInlineConstraint extends AbstractPLSQLNode { + private ConstraintType type; + + ASTInlineConstraint(int id) { + super(id); + } + + ASTInlineConstraint(PLSQLParser p, int id) { + super(p, id); + } + + void setType(ConstraintType type) { + this.type = type; + } + + public ConstraintType getType() { + return type; + } + + public boolean isUnique() { + return type == ConstraintType.UNIQUE; + } + + public boolean isPrimaryKey() { + return type == ConstraintType.PRIMARY; + } + + public boolean isCheck() { + return type == ConstraintType.CHECK; + } + + @Override + public Object jjtAccept(PLSQLParserVisitor visitor, Object data) { + return visitor.visit(this, data); + } +} diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTSelectStatement.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTSelectStatement.java index e6bee8060c..e007d03f74 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTSelectStatement.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/ASTSelectStatement.java @@ -16,10 +16,12 @@ public class ASTSelectStatement extends AbstractSelectStatement { super(p, id); } - /** Accept the visitor. **/ @Override public Object jjtAccept(PLSQLParserVisitor visitor, Object data) { return visitor.visit(this, data); } + + public ASTFromClause getFromClause() { + return getFirstChildOfType(ASTFromClause.class); + } } -/* JavaCC - OriginalChecksum=6a27b24d958d9811f9cd9229a7d3a3ac (do not edit this line) */ diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java index aebc968098..791229a093 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/AbstractPLSQLNode.java @@ -7,6 +7,7 @@ package net.sourceforge.pmd.lang.plsql.ast; +import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.symboltable.Scope; public abstract class AbstractPLSQLNode extends net.sourceforge.pmd.lang.ast.AbstractNode implements PLSQLNode { @@ -33,7 +34,7 @@ public abstract class AbstractPLSQLNode extends net.sourceforge.pmd.lang.ast.Abs @Override public void jjtClose() { - if (beginLine == -1 && (children == null || children.length == 0)) { + if (beginLine == -1 && children.length == 0) { beginColumn = parser.token.beginColumn; } if (beginLine == -1) { @@ -92,12 +93,10 @@ public abstract class AbstractPLSQLNode extends net.sourceforge.pmd.lang.ast.Abs public void dump(String prefix) { System.out.println(toString(prefix)); - if (children != null) { - for (int i = 0; i < children.length; ++i) { - AbstractPLSQLNode n = (AbstractPLSQLNode) children[i]; - if (n != null) { - n.dump(prefix + " "); - } + for (Node child : children) { + AbstractPLSQLNode n = (AbstractPLSQLNode) child; + if (n != null) { + n.dump(prefix + " "); } } } diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java index 3b274382f4..e70249f69d 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/ast/PLSQLParserVisitorAdapter.java @@ -426,6 +426,11 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTExtractExpression node, Object data) { + return visit((PLSQLNode) node, data); + } + @Override public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { return visit((PLSQLNode) node, data); @@ -546,6 +551,11 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTInlineConstraint node, Object data) { + return visit((PLSQLNode) node, data); + } + @Override public Object visit(ASTView node, Object data) { return visit((PLSQLNode) node, data); @@ -1096,4 +1106,9 @@ public class PLSQLParserVisitorAdapter implements PLSQLParserVisitor { public Object visit(ASTXMLElement node, Object data) { return visit((PLSQLNode) node, data); } + + @Override + public Object visit(ASTOuterJoinExpression node, Object data) { + return visit((PLSQLNode) node, data); + } } diff --git a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java index 4cf3e6c4fd..9581cfb6f0 100644 --- a/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java +++ b/pmd-plsql/src/main/java/net/sourceforge/pmd/lang/plsql/rule/AbstractPLSQLRule.java @@ -528,6 +528,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTExtractExpression node, Object data) { + return visit((PLSQLNode) node, data); + } + @Override public Object visit(ASTUnaryExpressionNotPlusMinus node, Object data) { return visit((PLSQLNode) node, data); @@ -638,6 +643,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTInlineConstraint node, Object data) { + return visit((PLSQLNode) node, data); + } + @Override public Object visit(ASTTableColumn node, Object data) { return visit((PLSQLNode) node, data); @@ -1202,6 +1212,11 @@ public abstract class AbstractPLSQLRule extends AbstractRule implements PLSQLPar return visit((PLSQLNode) node, data); } + @Override + public Object visit(ASTOuterJoinExpression node, Object data) { + return visit((PLSQLNode) node, data); + } + /* * Treat all Executable Code */ diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CreateTableTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CreateTableTest.java index 381efe7a78..0052faf081 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CreateTableTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CreateTableTest.java @@ -20,5 +20,18 @@ public class CreateTableTest extends AbstractPLSQLParserTst { StandardCharsets.UTF_8); ASTInput input = parsePLSQL(code); Assert.assertNotNull(input); + + // 5th column of first table statement has a inline constraint of type check + ASTTableColumn columnStatus = input.findChildrenOfType(ASTTable.class).get(0).findChildrenOfType(ASTTableColumn.class).get(4); + Assert.assertEquals("status", columnStatus.getFirstChildOfType(ASTID.class).getImage()); + Assert.assertEquals(ConstraintType.CHECK, columnStatus.getFirstChildOfType(ASTInlineConstraint.class).getType()); + } + + @Test + public void parseCreateOrganizedTable() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("CreateOrganizedTable.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); } } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesTest.java index 4e4dc6ea60..a7e232484b 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesTest.java @@ -19,4 +19,11 @@ public class CursorAttributesTest extends AbstractPLSQLParserTst { Assert.assertEquals("TestSearch%notfound", exp.getImage()); } + @Test + public void parseImplicitCursorAttributeBulkExceptions() { + String code = loadTestResource("CursorAttributesBulkExceptions.pls"); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); + } + } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java index 99d01bd2a2..ea78ede269 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/FunctionsTest.java @@ -22,4 +22,11 @@ public class FunctionsTest extends AbstractPLSQLParserTst { Assert.assertNotNull(input); } + @Test + public void parseSelectExtractExpression() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("ExtractExpressions.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); + } } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseTest.java new file mode 100644 index 0000000000..16b8614eef --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseTest.java @@ -0,0 +1,40 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.plsql.ast; + +import java.nio.charset.StandardCharsets; + +import org.apache.commons.io.IOUtils; +import org.junit.Assert; +import org.junit.Test; + +import net.sourceforge.pmd.lang.plsql.AbstractPLSQLParserTst; + +public class InsertIntoClauseTest extends AbstractPLSQLParserTst { + + @Test + public void parseInsertInto() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("InsertIntoClause.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); + } + + @Test + public void parseInsertIntoReturning() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("InsertIntoClauseReturning.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); + } + + @Test + public void parseInsertIntoWithRecord() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("InsertIntoClauseRecord.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); + } +} diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/JoinClauseTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/JoinClauseTest.java index a86ef0d759..a15ceaa7dd 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/JoinClauseTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/JoinClauseTest.java @@ -43,7 +43,7 @@ public class JoinClauseTest extends AbstractPLSQLParserTst { StandardCharsets.UTF_8); ASTInput input = parsePLSQL(code); List<ASTInnerCrossJoinClause> joins = input.findDescendantsOfType(ASTInnerCrossJoinClause.class); - Assert.assertEquals(1, joins.size()); + Assert.assertEquals(3, joins.size()); Assert.assertFalse(joins.get(0).isCross()); Assert.assertFalse(joins.get(0).isNatural()); List<ASTColumn> columns = joins.get(0).findChildrenOfType(ASTColumn.class); @@ -71,11 +71,27 @@ public class JoinClauseTest extends AbstractPLSQLParserTst { StandardCharsets.UTF_8); ASTInput input = parsePLSQL(code); List<ASTOuterJoinClause> joins = input.findDescendantsOfType(ASTOuterJoinClause.class); - Assert.assertEquals(1, joins.size()); + Assert.assertEquals(2, joins.size()); ASTOuterJoinType type = joins.get(0).getFirstChildOfType(ASTOuterJoinType.class); Assert.assertEquals(ASTOuterJoinType.Type.RIGHT, type.getType()); } + @Test + public void testLeftOuterJoin() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("LeftOuterJoin.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + List<ASTOuterJoinClause> joins = input.findDescendantsOfType(ASTOuterJoinClause.class); + Assert.assertEquals(2, joins.size()); + ASTOuterJoinType type = joins.get(0).getFirstChildOfType(ASTOuterJoinType.class); + Assert.assertEquals(ASTOuterJoinType.Type.LEFT, type.getType()); + + List<ASTSelectStatement> selects = input.findDescendantsOfType(ASTSelectStatement.class); + Assert.assertEquals(2, selects.size()); + Assert.assertTrue(selects.get(0).getFromClause().jjtGetChild(0) instanceof ASTJoinClause); + Assert.assertTrue(selects.get(1).getFromClause().jjtGetChild(0) instanceof ASTJoinClause); + } + @Test public void testNaturalRightOuterJoin() throws Exception { String code = IOUtils.toString(this.getClass().getResourceAsStream("NaturalRightOuterJoin.pls"), @@ -113,4 +129,14 @@ public class JoinClauseTest extends AbstractPLSQLParserTst { StandardCharsets.UTF_8); ASTInput input = parsePLSQL(code); } + + @Test + public void testJoinOperator() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("JoinOperator.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + List<ASTOuterJoinExpression> expressions = input.findDescendantsOfType(ASTOuterJoinExpression.class); + Assert.assertEquals(4, expressions.size()); + Assert.assertEquals("h.opp_id", expressions.get(3).getImage()); + } } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ViewTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ViewTest.java index 79595e9d86..c794a19099 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ViewTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/ViewTest.java @@ -21,4 +21,12 @@ public class ViewTest extends AbstractPLSQLParserTst { ASTInput input = parsePLSQL(code); Assert.assertNotNull(input); } + + @Test + public void parseCreateView() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("CreateViewWithSubquery.pls"), + StandardCharsets.UTF_8); + ASTInput input = parsePLSQL(code); + Assert.assertNotNull(input); + } } diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java index 12fc655ca3..038fa3e5e6 100644 --- a/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/lang/plsql/ast/WhereClauseTest.java @@ -104,4 +104,11 @@ public class WhereClauseTest extends AbstractPLSQLParserTst { StandardCharsets.UTF_8); ASTInput input = parsePLSQL(code); } + + @Test + public void testParentheses() throws Exception { + String code = IOUtils.toString(this.getClass().getResourceAsStream("WhereClauseParens.pls"), + StandardCharsets.UTF_8); + parsePLSQL(code); + } } diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateOrganizedTable.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateOrganizedTable.pls new file mode 100644 index 0000000000..ac32084672 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateOrganizedTable.pls @@ -0,0 +1,252 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +-- FIXED records +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (RECORDS FIXED 20 FIELDS (first_name CHAR(7), + last_name CHAR(8), + year_of_birth CHAR(4))) + LOCATION ('info.dat')); + +-- VARIABLE records +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (RECORDS VARIABLE 2 FIELDS TERMINATED BY ',' + (first_name CHAR(7), + last_name CHAR(8), + year_of_birth CHAR(4))) + LOCATION ('info.dat')); + +-- DELIMITED BY records +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (RECORDS DELIMITED BY '|' FIELDS TERMINATED BY ',' + (first_name CHAR(7), + last_name CHAR(8), + year_of_birth CHAR(4))) + LOCATION ('info.dat')); + +-- without any access parameters +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir LOCATION ('info.dat')); + +-- External Table with Terminating Delimiters +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (FIELDS TERMINATED BY WHITESPACE) + LOCATION ('info.dat')); + +-- External Table with Enclosure and Terminator Delimiters +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (FIELDS TERMINATED BY "," ENCLOSED BY "(" AND ")") + LOCATION ('info.dat')); + +-- Example: External Table with Optional Enclosure Delimiters +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (FIELDS TERMINATED BY ',' + OPTIONALLY ENCLOSED BY '(' and ')' + LRTRIM) + LOCATION ('info.dat')); + +-- all data is fixed-length +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), +year_of_birth CHAR(4)) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (FIELDS LTRIM) + LOCATION ('info.dat')); + +-- MISSING FIELD VALUES ARE NULL +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth INT) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (FIELDS TERMINATED BY "," + MISSING FIELD VALUES ARE NULL) + LOCATION ('info.dat')); + +-- external table with no field_list and a delim_spec +CREATE TABLE emp_load (first_name CHAR(15), last_name CHAR(20), year_of_birth INT) + ORGANIZATION EXTERNAL (TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS (FIELDS TERMINATED BY "|") + LOCATION ('info.dat')); + +-- various ways of using pos_spec +CREATE TABLE emp_load (first_name CHAR(15), + last_name CHAR(20), + year_of_birth INT, + phone CHAR(12), + area_code CHAR(3), + exchange CHAR(3), + extension CHAR(4)) + ORGANIZATION EXTERNAL + (TYPE ORACLE_LOADER + DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS + (FIELDS RTRIM + (first_name (1:15) CHAR(15), + last_name (*:+20), + year_of_birth (36:39), + phone (40:52), + area_code (*-12: +3), + exchange (*+1: +3), + extension (*+1: +4))) + LOCATION ('info.dat')); + +-- Use of the CHAR clause. +CREATE TABLE emp_load + (employee_number CHAR(5), + employee_dob CHAR(20), + employee_last_name CHAR(20), + employee_first_name CHAR(15), + employee_middle_name CHAR(15), + employee_hire_date DATE) + ORGANIZATION EXTERNAL + (TYPE ORACLE_LOADER + DEFAULT DIRECTORY def_dir1 + ACCESS PARAMETERS + (RECORDS DELIMITED BY NEWLINE + FIELDS (employee_number CHAR(2), + employee_dob CHAR(20), + employee_last_name CHAR(18), + employee_first_name CHAR(11), + employee_middle_name CHAR(11), + employee_hire_date CHAR(10) date_format DATE mask "mm/dd/yyyy" + ) + ) + LOCATION ('info.dat') + ); + +-- Use of a complex DATE character string and a TIMESTAMP character string +CREATE TABLE emp_load + (employee_number CHAR(5), + employee_dob CHAR(20), + employee_last_name CHAR(20), + employee_first_name CHAR(15), + employee_middle_name CHAR(15), + employee_hire_date DATE, + rec_creation_date TIMESTAMP WITH TIME ZONE) +ORGANIZATION EXTERNAL + (TYPE ORACLE_LOADER + DEFAULT DIRECTORY def_dir1 + ACCESS PARAMETERS + (RECORDS DELIMITED BY NEWLINE + FIELDS (employee_number CHAR(2), + employee_dob CHAR(20), + employee_last_name CHAR(18), + employee_first_name CHAR(11), + employee_middle_name CHAR(11), + employee_hire_date CHAR(22) date_format DATE mask "mm/dd/yyyy hh:mi:ss AM", + rec_creation_date CHAR(35) date_format TIMESTAMP WITH TIMEZONE mask "DD-MON-RR HH.MI.SSXFF AM TZH:TZM" + ) + ) + LOCATION ('infoc.dat') + ); + +-- Uses of VARCHAR and VARRAW +CREATE TABLE emp_load + (first_name CHAR(15), + last_name CHAR(20), + resume CHAR(2000), + picture RAW(2000)) + ORGANIZATION EXTERNAL + (TYPE ORACLE_LOADER + DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS + (RECORDS + VARIABLE 2 + DATA IS BIG ENDIAN + CHARACTERSET US7ASCII + FIELDS (first_name VARCHAR(2,12), + last_name VARCHAR(2,20), + resume VARCHAR(4,10000), + picture VARRAW(4,100000))) + LOCATION ('info.dat')); + +-- Uses of VARCHARC and VARRAWC +CREATE TABLE emp_load + (first_name CHAR(15), + last_name CHAR(20), + resume CHAR(2000), + picture RAW (2000)) + ORGANIZATION EXTERNAL + (TYPE ORACLE_LOADER + DEFAULT DIRECTORY ext_tab_dir + ACCESS PARAMETERS + (FIELDS (first_name VARCHARC(5,12), + last_name VARCHARC(2,20), + resume VARCHARC(4,10000), + picture VARRAWC(4,100000))) + LOCATION ('info.dat')); + +CREATE TABLE lob_tab ( + colid NUMBER(10), + clob_content CLOB +) +ORGANIZATION EXTERNAL +( + TYPE ORACLE_LOADER + DEFAULT DIRECTORY temp_dir + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY NEWLINE + BADFILE temp_dir:'data.bad' + LOGFILE temp_dir:'data.log' + FIELDS TERMINATED BY ',' + MISSING FIELD VALUES ARE NULL + ( + colid CHAR(10), + clob_filename CHAR(100) + ) + COLUMN TRANSFORMS (clob_content FROM LOBFILE (clob_filename) FROM (temp_dir) CLOB) + ) + LOCATION ('data.txt') +) +--PARALLEL 2 +REJECT LIMIT UNLIMITED; + +CREATE TABLE dept_external ( + deptno NUMBER(6), + dname VARCHAR2(20), + loc VARCHAR2(25) +) +ORGANIZATION EXTERNAL +(TYPE ORACLE_LOADER + DEFAULT DIRECTORY admin + ACCESS PARAMETERS + ( + RECORDS DELIMITED BY newline + BADFILE 'ulcase1.bad' + DISCARDFILE 'ulcase1.dis' + LOGFILE 'ulcase1.log' + SKIP 20 + FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' + ( + deptno INTEGER EXTERNAL(6), + dname CHAR(20), + loc CHAR(25) + ) + ) + LOCATION ('ulcase1.ctl') +) +REJECT LIMIT UNLIMITED; + +CREATE TABLE countries_demo + ( country_id CHAR(2) + , country_name VARCHAR2(40) + , currency_name VARCHAR2(25) + , currency_symbol VARCHAR2(3) + , region VARCHAR2(15) ) + ORGANIZATION INDEX + STORAGE + ( INITIAL 4K ) + PCTTHRESHOLD 2 + INCLUDING country_name + OVERFLOW + STORAGE + ( INITIAL 4K ); + +create table toys_heap ( + toy_name varchar2(100) +) organization heap; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateTable.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateTable.pls index 5d996edfc8..a99a0651c5 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateTable.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateTable.pls @@ -4,8 +4,306 @@ -- this is the customers.sql file: CREATE TABLE customers -( customer_id number(10) NOT NULL, -customer_name varchar2(50) NOT NULL, -city varchar2(50), -CONSTRAINT customers_pk PRIMARY KEY (customer_id) -); + ( customer_id number(10) primary key enable + , customer_name varchar2(50) NOT NULL + , zip NUMBER DEFAULT 10001 NOT NULL + , city varchar2(50) default on null 'New York' + , status VARCHAR2(1) CONSTRAINT status_chk CHECK (status in ('X', 'Y', 'Z')) + , registration_date timestamp default CURRENT_TIMESTAMP not null + , expiration_date date default TO_DATE('12-31-2999','mm-dd-yyyy') not null + , CONSTRAINT customers_pk PRIMARY KEY (customer_id) + ); + +CREATE TABLE employees_demo + ( employee_id NUMBER(6) + , first_name VARCHAR2(20) + , last_name VARCHAR2(25) + CONSTRAINT emp_last_name_nn_demo NOT NULL + , email VARCHAR2(25) + CONSTRAINT emp_email_nn_demo NOT NULL + , phone_number VARCHAR2(20) + , hire_date DATE DEFAULT SYSDATE + CONSTRAINT emp_hire_date_nn_demo NOT NULL + , job_id VARCHAR2(10) + CONSTRAINT emp_job_nn_demo NOT NULL + , salary NUMBER(8,2) + CONSTRAINT emp_salary_nn_demo NOT NULL + , commission_pct NUMBER(2,2) + , manager_id NUMBER(6) + , department_id NUMBER(4) + , dn VARCHAR2(300) + , CONSTRAINT emp_salary_min_demo + CHECK (salary > 0) + , CONSTRAINT emp_email_uk_demo + UNIQUE (email) + ) ; + +CREATE TABLE employees_demo + ( employee_id NUMBER(6) + , first_name VARCHAR2(20) + , last_name VARCHAR2(25) + CONSTRAINT emp_last_name_nn_demo NOT NULL + , email VARCHAR2(25) + CONSTRAINT emp_email_nn_demo NOT NULL + , phone_number VARCHAR2(20) + , hire_date DATE DEFAULT SYSDATE + CONSTRAINT emp_hire_date_nn_demo NOT NULL + , job_id VARCHAR2(10) + CONSTRAINT emp_job_nn_demo NOT NULL + , salary NUMBER(8,2) + CONSTRAINT emp_salary_nn_demo NOT NULL + , commission_pct NUMBER(2,2) + , manager_id NUMBER(6) + , department_id NUMBER(4) + , dn VARCHAR2(300) + , CONSTRAINT emp_salary_min_demo + CHECK (salary > 0) + , CONSTRAINT emp_email_uk_demo + UNIQUE (email) + ) + TABLESPACE example + STORAGE (INITIAL 8M); + +CREATE TABLE t1 (id NUMBER GENERATED AS IDENTITY); + +CREATE GLOBAL TEMPORARY TABLE today_sales + ON COMMIT PRESERVE ROWS + AS SELECT * FROM orders WHERE order_date = SYSDATE; + +CREATE TABLE later (col1 NUMBER, col2 VARCHAR2(20)) SEGMENT CREATION DEFERRED; + +CREATE TABLE persons OF person_t; + +CREATE TABLE persons OF person_t SUBSTITUTABLE AT ALL LEVELS; + +CREATE TABLE persons OF person_t NOT SUBSTITUTABLE AT ALL LEVELS; + +CREATE TABLE books (title VARCHAR2(100), author person_t); + +CREATE TABLE dept_80 + PARALLEL + AS SELECT * FROM employees + WHERE department_id = 80; + +CREATE TABLE dept_80 + AS SELECT * FROM employees + WHERE department_id = 80; + +CREATE TABLE departments_demo + ( department_id NUMBER(4) + , department_name VARCHAR2(30) + CONSTRAINT dept_name_nn NOT NULL + , manager_id NUMBER(6) + , location_id NUMBER(4) + , dn VARCHAR2(300) + ) ; + +CREATE TABLE departments_demo + ( department_id NUMBER(4) PRIMARY KEY DISABLE + , department_name VARCHAR2(30) + CONSTRAINT dept_name_nn NOT NULL + , manager_id NUMBER(6) + , location_id NUMBER(4) + , dn VARCHAR2(300) + ) ; + +CREATE TABLE print_media + ( product_id NUMBER(6) + , ad_id NUMBER(6) + , ad_composite BLOB + , ad_sourcetext CLOB + , ad_finaltext CLOB + , ad_fltextn NCLOB + , ad_textdocs_ntab textdoc_tab + , ad_photo BLOB + , ad_graphic BFILE + , ad_header adheader_typ + ) NESTED TABLE ad_textdocs_ntab STORE AS textdocs_nestedtab; + +CREATE TABLE business_contacts ( + company_name VARCHAR2(25), + company_reps customer_list) + NESTED TABLE company_reps STORE AS outer_ntab + (NESTED TABLE phones STORE AS inner_ntab); + +CREATE TABLE my_customers ( + name VARCHAR2(25), + phone_numbers phone_list) + NESTED TABLE phone_numbers STORE AS outer_ntab + (NESTED TABLE COLUMN_VALUE STORE AS inner_ntab); + +CREATE TABLE print_media_new + ( product_id NUMBER(6) + , ad_id NUMBER(6) + , ad_composite BLOB + , ad_sourcetext CLOB + , ad_finaltext CLOB + , ad_fltextn NCLOB + , ad_textdocs_ntab textdoc_tab + , ad_photo BLOB + , ad_graphic BFILE + , ad_header adheader_typ + ) NESTED TABLE ad_textdocs_ntab STORE AS textdocs_nestedtab_new + LOB (ad_sourcetext, ad_finaltext) STORE AS + (TABLESPACE example + STORAGE (INITIAL 6144) + CHUNK 4000 + NOCACHE LOGGING); + +CREATE TABLE promotions_var1 + ( promo_id NUMBER(6) + CONSTRAINT promo_id_u UNIQUE + , promo_name VARCHAR2(20) + , promo_category VARCHAR2(15) + , promo_cost NUMBER(10,2) + , promo_begin_date DATE + , promo_end_date DATE + ) ; + +CREATE TABLE promotions_var2 + ( promo_id NUMBER(6) + , promo_name VARCHAR2(20) + , promo_category VARCHAR2(15) + , promo_cost NUMBER(10,2) + , promo_begin_date DATE + , promo_end_date DATE + , CONSTRAINT promo_id_u UNIQUE (promo_id) + USING INDEX PCTFREE 20 + TABLESPACE stocks + STORAGE (INITIAL 8M) ); + +CREATE TABLE locations_demo + ( location_id NUMBER(4) CONSTRAINT loc_id_pk PRIMARY KEY + , street_address VARCHAR2(40) + , postal_code VARCHAR2(12) + , city VARCHAR2(30) + , state_province VARCHAR2(25) + , country_id CHAR(2) + ) ; + +CREATE TABLE locations_demo + ( location_id NUMBER(4) + , street_address VARCHAR2(40) + , postal_code VARCHAR2(12) + , city VARCHAR2(30) + , state_province VARCHAR2(25) + , country_id CHAR(2) + , CONSTRAINT loc_id_pk PRIMARY KEY (location_id)); + +CREATE TABLE dept_20 + (employee_id NUMBER(4), + last_name VARCHAR2(10), + job_id VARCHAR2(9), + manager_id NUMBER(4), + hire_date DATE, + salary NUMBER(7,2), + commission_pct NUMBER(7,2), + --department_id, + CONSTRAINT fk_deptno + FOREIGN KEY (department_id) + REFERENCES departments(department_id) ); + +CREATE TABLE dept_20 + (employee_id NUMBER(4) PRIMARY KEY, + last_name VARCHAR2(10), + job_id VARCHAR2(9), + manager_id NUMBER(4) CONSTRAINT fk_mgr + REFERENCES employees ON DELETE SET NULL, + hire_date DATE, + salary NUMBER(7,2), + commission_pct NUMBER(7,2), + department_id NUMBER(2) CONSTRAINT fk_deptno + REFERENCES departments(department_id) + ON DELETE CASCADE ); + +CREATE TABLE divisions + (div_no NUMBER CONSTRAINT check_divno + CHECK (div_no BETWEEN 10 AND 99) + DISABLE, + div_name VARCHAR2(9) CONSTRAINT check_divname + CHECK (div_name = UPPER(div_name)) + DISABLE, + office VARCHAR2(10) CONSTRAINT check_office + CHECK (office IN ('DALLAS','BOSTON', + 'PARIS','TOKYO')) + DISABLE); + +CREATE TABLE dept_20 + (employee_id NUMBER(4) PRIMARY KEY, + last_name VARCHAR2(10), + job_id VARCHAR2(9), + manager_id NUMBER(4), + salary NUMBER(7,2), + commission_pct NUMBER(7,2), + department_id NUMBER(2), + CONSTRAINT check_sal CHECK (salary * commission_pct <= 5000)); + +CREATE TABLE order_detail + (CONSTRAINT pk_od PRIMARY KEY (order_id, part_no), + order_id NUMBER + CONSTRAINT fk_oid + REFERENCES oe.orders(order_id), + part_no NUMBER + CONSTRAINT fk_pno + REFERENCES oe.product_information(product_id), + quantity NUMBER + CONSTRAINT nn_qty NOT NULL + CONSTRAINT check_qty CHECK (quantity > 0), + cost NUMBER + CONSTRAINT check_cost CHECK (cost > 0) ); + +CREATE TYPE person_name AS OBJECT + (first_name VARCHAR2(30), last_name VARCHAR2(30)); +/ + +CREATE TABLE students (name person_name, age INTEGER, + CHECK (name.first_name IS NOT NULL AND + name.last_name IS NOT NULL)); + +CREATE TYPE cust_address_typ_new AS OBJECT + ( street_address VARCHAR2(40) + , postal_code VARCHAR2(10) + , city VARCHAR2(30) + , state_province VARCHAR2(10) + , country_id CHAR(2) + ); +/ +CREATE TABLE address_table OF cust_address_typ_new; + +CREATE TABLE customer_addresses ( + add_id NUMBER, + address REF cust_address_typ_new + SCOPE IS address_table); + +CREATE TABLE customer_addresses ( + add_id NUMBER, + address REF cust_address_typ REFERENCES address_table); + +CREATE TABLE employees_obj + ( e_name VARCHAR2(100), + e_number NUMBER, + e_dept REF department_typ SCOPE IS departments_obj_t ); + +CREATE TABLE employees_obj + ( e_name VARCHAR2(100), + e_number NUMBER, + e_dept REF department_typ REFERENCES departments_obj_t); + +CREATE TABLE promotions_var3 + ( promo_id NUMBER(6) + , promo_name VARCHAR2(20) + , promo_category VARCHAR2(15) + , promo_cost NUMBER(10,2) + , promo_begin_date DATE + , promo_end_date DATE + , CONSTRAINT promo_id_u UNIQUE (promo_id, promo_cost) + USING INDEX (CREATE UNIQUE INDEX promo_ix1 + ON promotions_var3 (promo_id, promo_cost)) + , CONSTRAINT promo_id_u2 UNIQUE (promo_cost, promo_id) + USING INDEX promo_ix1); + +CREATE TABLE games (scores NUMBER CHECK (scores >= 0)); + +CREATE TABLE games + (scores NUMBER, CONSTRAINT unq_num UNIQUE (scores) + INITIALLY DEFERRED DEFERRABLE); diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateViewWithSubquery.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateViewWithSubquery.pls new file mode 100644 index 0000000000..04d7d2dd4b --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CreateViewWithSubquery.pls @@ -0,0 +1,9 @@ +-- +-- BSD-style license; for more info see http://pmd.sourceforge.net/license.html +-- + +CREATE OR REPLACE VIEW EMP_DETAILS_VIEW AS +( +SELECT * +FROM DUAL +) WITH READ ONLY; \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributes.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributes.pls index 79dec6cdca..aac0a01d2a 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributes.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributes.pls @@ -29,4 +29,28 @@ begin end testif; end lpe_test; +/ + +-- +-- Implicit cursor attributes +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/implicit-cursor-attribute.html#GUID-5A938EE7-E8D2-468C-B60F-81898F110BE1 +-- Example from: https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-optimization-and-tuning.html#GUID-DDB5CCDA-8060-4511-BA20-4D1F2C478412 +-- + +DECLARE + TYPE NumList IS TABLE OF NUMBER; + depts NumList := NumList(30, 50, 60); +BEGIN + FORALL j IN depts.FIRST..depts.LAST + DELETE FROM emp_temp WHERE department_id = depts(j); + + FOR i IN depts.FIRST..depts.LAST LOOP + DBMS_OUTPUT.PUT_LINE ( + 'Statement #' || i || ' deleted ' || + SQL%BULK_ROWCOUNT(i) || ' rows.' + ); + END LOOP; + + DBMS_OUTPUT.PUT_LINE('Total rows deleted: ' || SQL%ROWCOUNT); +END; / \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesBulkExceptions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesBulkExceptions.pls new file mode 100644 index 0000000000..a87cbe1860 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/CursorAttributesBulkExceptions.pls @@ -0,0 +1,55 @@ +-- +-- Implicit cursor attributes +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/implicit-cursor-attribute.html#GUID-5A938EE7-E8D2-468C-B60F-81898F110BE1 +-- Example from: https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-optimization-and-tuning.html#GUID-DAF46F06-EF3F-4B1A-A518-5238B80C69FA +-- + +CREATE OR REPLACE PROCEDURE p AUTHID DEFINER AS + TYPE NumList IS TABLE OF NUMBER; + depts NumList := NumList(10, 20, 30); + + error_message VARCHAR2(100); + bad_stmt_no PLS_INTEGER; + bad_deptno emp_temp.deptno%TYPE; + bad_job emp_temp.job%TYPE; + + dml_errors EXCEPTION; + PRAGMA EXCEPTION_INIT(dml_errors, -24381); +BEGIN + -- Populate table: + + INSERT INTO emp_temp (deptno, job) VALUES (10, 'Clerk'); + INSERT INTO emp_temp (deptno, job) VALUES (20, 'Bookkeeper'); + INSERT INTO emp_temp (deptno, job) VALUES (30, 'Analyst'); + COMMIT; + + -- Append 9-character string to each job: + + FORALL j IN depts.FIRST..depts.LAST SAVE EXCEPTIONS + UPDATE emp_temp SET job = job || ' (Senior)' + WHERE deptno = depts(j); + +EXCEPTION + WHEN dml_errors THEN + FOR i IN 1..SQL%BULK_EXCEPTIONS.COUNT LOOP + error_message := SQLERRM(-(SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); + DBMS_OUTPUT.PUT_LINE (error_message); + + bad_stmt_no := SQL%BULK_EXCEPTIONS(i).ERROR_INDEX; + DBMS_OUTPUT.PUT_LINE('Bad statement #: ' || bad_stmt_no); + + bad_deptno := depts(bad_stmt_no); + DBMS_OUTPUT.PUT_LINE('Bad department #: ' || bad_deptno); + + SELECT job INTO bad_job FROM emp_temp WHERE deptno = bad_deptno; + + DBMS_OUTPUT.PUT_LINE('Bad job: ' || bad_job); + END LOOP; + + COMMIT; -- Commit results of successful updates + + WHEN OTHERS THEN + DBMS_OUTPUT.PUT_LINE('Unrecognized error.'); + RAISE; +END; +/ \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls new file mode 100644 index 0000000000..0e4e7f3b90 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/ExtractExpressions.pls @@ -0,0 +1,21 @@ +-- +-- Subqueries / Expressions in the SelectList +-- + +SELECT EXTRACT(month FROM order_date) "Month", + COUNT(order_date) "No. of Orders" + FROM orders + GROUP BY EXTRACT(month FROM order_date) + ORDER BY "No. of Orders" DESC; + +SELECT EXTRACT(YEAR FROM DATE '1998-03-07') FROM DUAL; + +SELECT last_name, employee_id, hire_date + FROM employees + WHERE EXTRACT(YEAR FROM + TO_DATE(hire_date, 'DD-MON-RR')) > 1998 + ORDER BY hire_date; + +SELECT EXTRACT(TIMEZONE_REGION + FROM TIMESTAMP '1999-01-01 10:00:00 -08:00') + FROM DUAL; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InnerJoinUsing.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InnerJoinUsing.pls index fb426ab8dc..74109d3464 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InnerJoinUsing.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InnerJoinUsing.pls @@ -3,5 +3,22 @@ SELECT department_id AS d_e_dept_id, e.last_name INTO r_record FROM departments d JOIN employees e USING (department_id); + +SELECT department_id AS d_e_dept_id, e.last_name +INTO r_record + FROM departments d INNER JOIN employees e + USING (department_id); + +-- +-- https://github.com/pmd/pmd/issues/1878 +-- + +SELECT COUNT(qsec_id) + FROM quots_sections qsec + INNER JOIN quots_sections_lang USING (qsec_id) + WHERE qsec.wsh_id = 11 + AND qsec.revision = 1 + AND lang_code = 'en'; + END; / diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClause.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClause.pls new file mode 100644 index 0000000000..0c480fa168 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClause.pls @@ -0,0 +1,32 @@ +-- +-- See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423 +-- +BEGIN + +INSERT INTO departments + VALUES (280, 'Recreation', 121, 1700); + +INSERT INTO departments + VALUES (280, 'Recreation', DEFAULT, 1700); + +INSERT INTO employees (employee_id, last_name, email, + hire_date, job_id, salary, commission_pct) + VALUES (207, 'Gregory', 'pgregory@example.com', + sysdate, 'PU_CLERK', 1.2E3, NULL); + +INSERT INTO + (SELECT employee_id, last_name, email, hire_date, job_id, + salary, commission_pct FROM employees) + VALUES (207, 'Gregory', 'pgregory@example.com', + sysdate, 'PU_CLERK', 1.2E3, NULL); + +INSERT INTO bonuses + SELECT employee_id, salary*1.1 + FROM employees + WHERE commission_pct > 0.25; + +INSERT INTO emp_job a + (a.employee_id, a.job_id) + VALUES (emp_id, emp_jobid); +END; +/ diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseRecord.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseRecord.pls new file mode 100644 index 0000000000..509b35c43a --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseRecord.pls @@ -0,0 +1,17 @@ +-- +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/INSERT-statement-extension.html#GUID-D81224C4-06DE-4635-A850-41D29D4A8E1B +-- https://blogs.oracle.com/oraclemagazine/working-with-records +-- + +DECLARE + l_employee omag_employees%ROWTYPE; +BEGIN + l_employee.employee_id := 500; + l_employee.last_name := 'Mondrian'; + l_employee.salary := 2000; + + INSERT + INTO omag_employees + VALUES l_employee; +END; +/ diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseReturning.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseReturning.pls new file mode 100644 index 0000000000..5ded5b9572 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/InsertIntoClauseReturning.pls @@ -0,0 +1,14 @@ +-- +-- See https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423 +-- +BEGIN + +INSERT INTO employees + (employee_id, last_name, email, hire_date, job_id, salary) + VALUES + (employees_seq.nextval, 'Doe', 'john.doe@example.com', + SYSDATE, 'SH_CLERK', 2400) + RETURNING salary*12, job_id INTO :bnd1, :bnd2; + +END; +/ diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/JoinOperator.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/JoinOperator.pls new file mode 100644 index 0000000000..02c089a9c7 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/JoinOperator.pls @@ -0,0 +1,28 @@ +-- +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Joins.html +-- + +BEGIN + +SELECT e1.employee_id, e1.manager_id, e2.employee_id + FROM employees e1, employees e2 + WHERE e1.manager_id(+) = e2.employee_id + ORDER BY e1.employee_id, e1.manager_id, e2.employee_id; + +SELECT * FROM A, B, D + WHERE A.c1 = B.c2(+) and D.c3 = B.c4(+); + +-- From https://github.com/pmd/pmd/issues/1902 +SELECT DISTINCT + o.op_id + FROM + opportunities o, + v_opp_bundles b, + jopportunities h + WHERE + o.opp_id = b.opp_id + AND b.bun_id = p_bun_id + AND o.opp_id = h.opp_id (+); + +END; +/ \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/LeftOuterJoin.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/LeftOuterJoin.pls new file mode 100644 index 0000000000..cabb81ed05 --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/LeftOuterJoin.pls @@ -0,0 +1,22 @@ +-- +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__I2107296 +-- + +BEGIN + +SELECT d.department_id, e.last_name + FROM departments d LEFT OUTER JOIN employees e + ON d.department_id = e.department_id + ORDER BY d.department_id, e.last_name; + +SELECT cv.hidden + FROM (SELECT CONNECT_BY_ROOT dep_id dep_id, LEVEL as dep_level + FROM departments + WHERE dep_id = c.dep_id + CONNECT BY PRIOR dep_id = parent_dep_id + ORDER BY LEVEL) dep + LEFT JOIN config_visibility cv ON (cv.dep_id = dep.dep_id AND cv.app_id = p_app_id) + ORDER BY dep.dep_level; + +END; +/ \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RightOuterJoin.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RightOuterJoin.pls index 6b40ad95d1..2c0517076c 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RightOuterJoin.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/RightOuterJoin.pls @@ -1,3 +1,7 @@ +-- +-- https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__I2107296 +-- + BEGIN SELECT times.time_id, product, quantity INTO r_record @@ -5,4 +9,10 @@ FROM inventory RIGHT OUTER JOIN times ON (times.time_id = inventory.time_id) ORDER BY 2,1; END; + +SELECT d.department_id, e.last_name + FROM departments d RIGHT OUTER JOIN employees e + ON d.department_id = e.department_id + ORDER BY d.department_id, e.last_name; + / \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectExpressions.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectExpressions.pls index 813c3deef4..11da9a6493 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectExpressions.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/SelectExpressions.pls @@ -54,25 +54,58 @@ SELECT department_id "Dept", hire_date "Date", last_name "Name", INTO some_record FROM employees WHERE hire_date < '01-SEP-2003' + AND hire_date > timestamp '2001-01-01 00:00:00' + AND hire_date < sysdate - interval '50' minute + AND hire_date < sysdate - interval '5' year + AND hire_date < sysdate - interval '3' month ORDER BY "Dept", "Date", "Name"; SELECT listagg(e.email,',') within group (order by e.email )INTO v_task_resp FROM sso_auth_employees e; -select listagg(asap_func_loc_number,'; ') within group (order by 1) +SELECT listagg(asap_func_loc_number,'; ') within group (order by 1) INTO my_record FROM company_asap_func_locs WHERE cmp_id = cmp_id_in; +SELECT listagg(asap_func_loc_number,'; ') within group (order by 1) + INTO my_record + FROM company_asap_func_locs + WHERE cmp_id = cmp_id_in + AND function_call() is null; + SELECT CASE WHEN priv != 'Y' AND my_package.my_function(param1, TO_NUMBER(TO_CHAR(SYSDATE, 'yyyy'))) >= 100 THEN 'Y' ELSE 'N' - END + END INTO my_result FROM DUAL; +SELECT CASE WHEN EXISTS(SELECT * + FROM DUAL + WHERE 1 = 1) + THEN 1 + ELSE 0 + END isExists + INTO VAL + FROM dual; + +SELECT CASE WHEN EXISTS(SELECT * + FROM DUAL) + THEN 1 + ELSE 0 + END isExists + INTO VAL + FROM dual; + +SELECT CASE + WHEN f1(x) IS NULL THEN 1 + ELSE 0 + END isExists + INTO VAL + FROM dual; END; / \ No newline at end of file diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TrimFunction.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TrimFunction.pls index 93679e1840..a2c0ca52cf 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TrimFunction.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/TrimFunction.pls @@ -11,4 +11,9 @@ select max(cmp_id) from companies where trim(leading '0' from sap_number) = trim(leading '0' from v_sap_nr); +select max(cmp_id) + into v_cmp_id + from companies + where trim(sap_number) = trim(v_sap_nr); + END; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/UpdateStatementExample2.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/UpdateStatementExample2.pls index 272fc16109..570ac1943b 100644 --- a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/UpdateStatementExample2.pls +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/UpdateStatementExample2.pls @@ -58,4 +58,9 @@ update xsearch_wsh_active and revision = p_rev returning opp_id into v_opp_id; +update employees + set salary = salary + sal_raise, + salary = (salary - discounts) * sal_raise + where employee_id = emp_id; + END; diff --git a/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereClauseParens.pls b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereClauseParens.pls new file mode 100644 index 0000000000..be96b4a02d --- /dev/null +++ b/pmd-plsql/src/test/resources/net/sourceforge/pmd/lang/plsql/ast/WhereClauseParens.pls @@ -0,0 +1,23 @@ +-- +-- Where Clause With Parentheses +-- See https://github.com/pmd/pmd/issues/1828 +-- + +BEGIN + +select * +from dual +where (dummy = X or 1 = 2) +and 1=1; + +select * +from dual +where (dummy <= X or 1 = 2) +and 1=1; + +select * +FROM dual +WHERE (dummy, 'X') in (select dummy, 'X' from dual); + +END; +/ diff --git a/pmd-python/etc/grammar/python.jj b/pmd-python/etc/grammar/python.jj index 60f723870c..1f97f9d948 100644 --- a/pmd-python/etc/grammar/python.jj +++ b/pmd-python/etc/grammar/python.jj @@ -52,6 +52,7 @@ TOKEN : /* SEPARATORS */ | < COMMA: "," > | < DOT: "." > | < COLON: ":" > +| < BACKTICK: "`" > } @@ -280,4 +281,4 @@ MORE : /* Strings */ | <"\r"> { image.setCharAt(image.length()-1, '\n'); } | <~["\n","\r"]> | <"\\" ~["\n","\r"]> -} \ No newline at end of file +} diff --git a/pmd-python/src/test/java/net/sourceforge/pmd/cpd/PythonTokenizerTest.java b/pmd-python/src/test/java/net/sourceforge/pmd/cpd/PythonTokenizerTest.java index 58d771f7eb..6896a14d62 100644 --- a/pmd-python/src/test/java/net/sourceforge/pmd/cpd/PythonTokenizerTest.java +++ b/pmd-python/src/test/java/net/sourceforge/pmd/cpd/PythonTokenizerTest.java @@ -53,4 +53,16 @@ public class PythonTokenizerTest extends AbstractTokenizerTest { TokenEntry.getEOF(); assertEquals(3, tokens.size()); // 3 tokens: "import" + "logging" + EOF } + + @Test + public void testBackticks() throws IOException { + SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader("test = 'hello'" + PMD.EOL + + "quoted = `test`" + PMD.EOL + + "print quoted" + PMD.EOL + )); + Tokens tokens = new Tokens(); + tokenizer.tokenize(sourceCode, tokens); // should not result in parse error + TokenEntry.getEOF(); + assertEquals(3, tokens.getTokens().get(tokens.getTokens().size() - 2).getBeginLine()); + } } diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index f84fd9490f..1a36cd7acf 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -10,12 +10,38 @@ <version>7.0.0-SNAPSHOT</version> </parent> + <properties> + <antlr4.visitor>true</antlr4.visitor> + </properties> + <build> <plugins> <plugin> + <!-- this needs to run before the ant task --> <groupId>org.antlr</groupId> <artifactId>antlr4-maven-plugin</artifactId> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-antrun-plugin</artifactId> + <inherited>true</inherited> + <executions> + <execution> + <id>antlr-generation</id> + <phase>generate-sources</phase> + <configuration> + <target> + <ant antfile="src/main/ant/antlr4.xml"> + <property name="target" value="${project.build.directory}/generated-sources/antlr4" /> + </ant> + </target> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> diff --git a/pmd-swift/src/main/ant/antlr4.xml b/pmd-swift/src/main/ant/antlr4.xml new file mode 100644 index 0000000000..223ee17f10 --- /dev/null +++ b/pmd-swift/src/main/ant/antlr4.xml @@ -0,0 +1,19 @@ +<project name="pmd" default="antlr4" basedir="../../../../"> + + <property name="target-package-dir" value="${target}/net/sourceforge/pmd/lang/swift/antlr4" /> + + <target name="antlr4" description="Generates all Antlr4 aspects within PMD"> + <replace file="${target-package-dir}/SwiftParser.java" + token="extends ParserRuleContext" + value="extends net.sourceforge.pmd.lang.ast.AntlrBaseNode" /> + <replace file="${target-package-dir}/SwiftBaseVisitor.java" + token="extends AbstractParseTreeVisitor" + value="extends AbstractAntlrVisitor" /> + <replace file="${target-package-dir}/SwiftBaseVisitor.java" + token="public class SwiftBaseVisitor" + value="public abstract class SwiftBaseVisitor" /> + <replace file="${target-package-dir}/SwiftBaseVisitor.java" + token="import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;" + value="import net.sourceforge.pmd.lang.antlr.AbstractAntlrVisitor;" /> + </target> +</project> \ No newline at end of file diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java new file mode 100644 index 0000000000..62c94cc4a6 --- /dev/null +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java @@ -0,0 +1,14 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift; + +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftBaseVisitor; + +public abstract class AbstractSwiftRule<T> extends SwiftBaseVisitor<T> { + public AbstractSwiftRule() { + super.setLanguage(LanguageRegistry.getLanguage(SwiftLanguageModule.NAME)); + } +} diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftHandler.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftHandler.java new file mode 100644 index 0000000000..0ed33998ab --- /dev/null +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftHandler.java @@ -0,0 +1,31 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift; + +import net.sourceforge.pmd.lang.AbstractPmdLanguageVersionHandler; +import net.sourceforge.pmd.lang.Parser; +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.XPathHandler; +import net.sourceforge.pmd.lang.antlr.AntlrRuleViolationFactory; +import net.sourceforge.pmd.lang.ast.xpath.DefaultASTXPathHandler; +import net.sourceforge.pmd.lang.rule.RuleViolationFactory; + +public class SwiftHandler extends AbstractPmdLanguageVersionHandler { + + @Override + public XPathHandler getXPathHandler() { + return new DefaultASTXPathHandler(); + } + + @Override + public RuleViolationFactory getRuleViolationFactory() { + return AntlrRuleViolationFactory.INSTANCE; + } + + @Override + public Parser getParser(final ParserOptions parserOptions) { + return new SwiftParserAdapter(parserOptions); + } +} diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java index 76fa53d5a6..abb1a9406c 100644 --- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java @@ -5,13 +5,11 @@ package net.sourceforge.pmd.lang.swift; import net.sourceforge.pmd.lang.BaseLanguageModule; +import net.sourceforge.pmd.lang.antlr.AntlrRuleChainVisitor; /** * Language Module for Swift - * - * @deprecated There is no full PMD support for Swift. */ -@Deprecated public class SwiftLanguageModule extends BaseLanguageModule { /** The name. */ @@ -23,7 +21,7 @@ public class SwiftLanguageModule extends BaseLanguageModule { * Create a new instance of Swift Language Module. */ public SwiftLanguageModule() { - super(NAME, null, TERSE_NAME, null, "swift"); - addVersion("", null, true); + super(NAME, null, TERSE_NAME, AntlrRuleChainVisitor.class, "swift"); + addVersion("", new SwiftHandler(), true); } } diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftParserAdapter.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftParserAdapter.java new file mode 100644 index 0000000000..c7082ef804 --- /dev/null +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftParserAdapter.java @@ -0,0 +1,48 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift; + +import java.io.IOException; +import java.io.Reader; + +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.Lexer; + +import net.sourceforge.pmd.lang.ParserOptions; +import net.sourceforge.pmd.lang.antlr.AntlrBaseParser; +import net.sourceforge.pmd.lang.ast.AntlrBaseNode; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftLexer; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser; + +/** + * Adapter for the SwiftParser. + */ +public class SwiftParserAdapter extends AntlrBaseParser<SwiftParser> { + + public SwiftParserAdapter(final ParserOptions parserOptions) { + super(parserOptions); + } + + @Override + protected AntlrBaseNode getRootNode(final SwiftParser parser) { + return parser.topLevel(); + } + + @Override + protected Lexer getLexer(final Reader source) throws IOException { + return new SwiftLexer(CharStreams.fromReader(source)); + } + + @Override + protected SwiftParser getParser(final Lexer lexer) { + return new SwiftParser(new CommonTokenStream(lexer)); + } + + @Override + public boolean canParse() { + return true; + } +} diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderRule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderRule.java new file mode 100644 index 0000000000..494c92e0a9 --- /dev/null +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderRule.java @@ -0,0 +1,54 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift.rule.bestpractices; + +import java.util.List; + +import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.swift.AbstractSwiftRule; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser.FunctionHeadContext; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser.VariableDeclarationHeadContext; + +public class ProhibitedInterfaceBuilderRule extends AbstractSwiftRule<Void> { + + private static final String IBACTION = "@IBAction"; + private static final String IBOUTLET = "@IBOutlet"; + + public ProhibitedInterfaceBuilderRule() { + super(); + addRuleChainVisit(FunctionHeadContext.class); + addRuleChainVisit(VariableDeclarationHeadContext.class); + } + + @Override + public Void visitFunctionHead(FunctionHeadContext ctx) { + if (ctx == null || ctx.attributes() == null) { + return null; + } + + return visitDeclarationHead(ctx, ctx.attributes().attribute(), IBACTION); + } + + @Override + public Void visitVariableDeclarationHead(final VariableDeclarationHeadContext ctx) { + if (ctx == null || ctx.attributes() == null) { + return null; + } + + return visitDeclarationHead(ctx, ctx.attributes().attribute(), IBOUTLET); + } + + private Void visitDeclarationHead(final Node node, final List<SwiftParser.AttributeContext> attributes, + final String match) { + + final boolean violate = attributes.stream().anyMatch(atr -> match.equals(atr.getText())); + if (violate) { + addViolation(data, node); + } + + return null; + } +} diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java new file mode 100644 index 0000000000..5033ac773a --- /dev/null +++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java @@ -0,0 +1,70 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift.rule.bestpractices; + +import java.util.List; + +import net.sourceforge.pmd.lang.swift.AbstractSwiftRule; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser.FunctionDeclarationContext; +import net.sourceforge.pmd.lang.swift.antlr4.SwiftParser.InitializerDeclarationContext; + +public class UnavailableFunctionRule extends AbstractSwiftRule<Void> { + + private static final String AVAILABLE_UNAVAILABLE = "@available(*,unavailable)"; + private static final String FATAL_ERROR = "fatalError"; + + public UnavailableFunctionRule() { + super(); + addRuleChainVisit(FunctionDeclarationContext.class); + addRuleChainVisit(InitializerDeclarationContext.class); + } + + @Override + public Void visitFunctionDeclaration(final FunctionDeclarationContext ctx) { + if (ctx == null) { + return null; + } + + if (shouldIncludeUnavailableModifier(ctx.functionBody().codeBlock())) { + final SwiftParser.AttributesContext attributes = ctx.functionHead().attributes(); + if (attributes == null || !hasUnavailableModifier(attributes.attribute())) { + addViolation(data, ctx); + } + } + + return null; + } + + @Override + public Void visitInitializerDeclaration(final InitializerDeclarationContext ctx) { + if (ctx == null) { + return null; + } + + if (shouldIncludeUnavailableModifier(ctx.initializerBody().codeBlock())) { + final SwiftParser.AttributesContext attributes = ctx.initializerHead().attributes(); + if (attributes == null || !hasUnavailableModifier(attributes.attribute())) { + addViolation(data, ctx); + } + } + + return null; + } + + private boolean shouldIncludeUnavailableModifier(final SwiftParser.CodeBlockContext ctx) { + if (ctx == null || ctx.statements() == null) { + return false; + } + + final List<SwiftParser.StatementContext> statements = ctx.statements().statement(); + + return statements.size() == 1 && FATAL_ERROR.equals(statements.get(0).getStart().getText()); + } + + private boolean hasUnavailableModifier(final List<SwiftParser.AttributeContext> attributes) { + return attributes.stream().anyMatch(atr -> AVAILABLE_UNAVAILABLE.equals(atr.getText())); + } +} diff --git a/pmd-swift/src/main/resources/category/swift/bestpractices.xml b/pmd-swift/src/main/resources/category/swift/bestpractices.xml new file mode 100644 index 0000000000..31aa7bd1e7 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/bestpractices.xml @@ -0,0 +1,61 @@ +<?xml version="1.0"?> + +<ruleset name="Best Practices" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> +Rules which enforce generally accepted best practices. + </description> + + <rule name="ProhibitedInterfaceBuilder" + since="7.0" + message="Creating views using Interface Builder should be avoided." + class="net.sourceforge.pmd.lang.swift.rule.bestpractices.ProhibitedInterfaceBuilderRule" + externalInfoUrl="http://pmd.github.io/pmd/pmd_rules_swift_bestpractices.html#prohibitedinterfacebuilder"> + <description> + Creating views using Interface Builder should be avoided. + Defining views by code allows the compiler to detect issues that otherwise will be runtime errors. + It's difficult to review the auto-generated code and allow concurrent modifications of those files. + Consider building views programmatically. + </description> + <priority>2</priority> + <example> + <![CDATA[ +class ViewController: UIViewController { + @IBOutlet var label: UILabel! // violation, referencing a IBOutlet +} + +class ViewController: UIViewController { + var label: UILabel! +} +]]> + </example> + </rule> + + <rule name="UnavailableFunction" + since="7.0" + message="Unimplemented functions should be marked as unavailable." + class="net.sourceforge.pmd.lang.swift.rule.bestpractices.UnavailableFunctionRule" + externalInfoUrl="http://pmd.github.io/pmd/pmd_rules_swift_bestpractices.html#unavailablefunction"> + <description> + Due to Objective-C and Swift interoperability some functions are often required to be implemented but + aren't really needed. It is extremely common that the sole implementation of the functions consist of throwing + a fatal error. Marking these functions as unavailable prevents them from being executed while still making + the compiler happy. + </description> + <priority>3</priority> + <example> + <![CDATA[ +required init?(coder _: NSCoder) { // violation, no unavailable attribute added to the function declaration + fatalError("init(coder:) has not been implemented") +} + +@available(*, unavailable) // no violation +required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") +]]> + </example> + </rule> +</ruleset> diff --git a/pmd-swift/src/main/resources/category/swift/categories.properties b/pmd-swift/src/main/resources/category/swift/categories.properties new file mode 100644 index 0000000000..a1e3c2cf48 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/categories.properties @@ -0,0 +1,17 @@ +# +# BSD-style license; for more info see http://pmd.sourceforge.net/license.html +# + +rulesets.filenames=\ + category/swift/bestpractices.xml,\ + category/swift/errorprone.xml + +# +# categories without rules +# +# category/swift/codestyle.xml +# category/swift/design.xml +# category/swift/documentation.xml +# category/swift/multithreading.xml +# category/swift/performance.xml +# category/swift/security.xml diff --git a/pmd-swift/src/main/resources/category/swift/codestyle.xml b/pmd-swift/src/main/resources/category/swift/codestyle.xml new file mode 100644 index 0000000000..f23dab5a5d --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/codestyle.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> + +<ruleset name="Code Style" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> + Rules which enforce a specific coding style. + </description> +</ruleset> diff --git a/pmd-swift/src/main/resources/category/swift/design.xml b/pmd-swift/src/main/resources/category/swift/design.xml new file mode 100644 index 0000000000..3ffd0d0602 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/design.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> + +<ruleset name="Design" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> +Rules that help you discover design issues. + </description> +</ruleset> diff --git a/pmd-swift/src/main/resources/category/swift/documentation.xml b/pmd-swift/src/main/resources/category/swift/documentation.xml new file mode 100644 index 0000000000..9417a47809 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/documentation.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> + +<ruleset name="Documentation" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> +Rules that are related to code documentation. + </description> +</ruleset> \ No newline at end of file diff --git a/pmd-swift/src/main/resources/category/swift/errorprone.xml b/pmd-swift/src/main/resources/category/swift/errorprone.xml new file mode 100644 index 0000000000..288b3ed278 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/errorprone.xml @@ -0,0 +1,72 @@ +<?xml version="1.0"?> + +<ruleset name="Error Prone" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> + Rules to detect constructs that are either broken, extremely confusing or prone to runtime errors. + </description> + + <rule name="ForceCast" + language="swift" + since="7.0" + message="Force casts should be avoided." + class="net.sourceforge.pmd.lang.rule.XPathRule" + externalInfoUrl="http://pmd.github.io/pmd/pmd_rules_swift_errorprone.html#forcecast"> + <description> + Force casts should be avoided. This may lead to a crash if it's not used carefully. + For example assuming a JSON property has a given type, or your reused Cell has a certain contract. + Consider using conditional casting and handling the resulting optional. + </description> + <priority>3</priority> + <properties> + <property name="xpath"> + <value> + <![CDATA[ +//TypeCastingOperator[starts-with(@Text,'as!')] +]]> + </value> + </property> + <property name="version" value="2.0"/> + </properties> + <example> + <![CDATA[ +NSNumber() as! Int // violation, force casting + +NSNumber() as? Int // no violation +]]> + </example> + </rule> + + <rule name="ForceTry" + language="swift" + since="7.0" + message="Force tries should be avoided." + class="net.sourceforge.pmd.lang.rule.XPathRule" + externalInfoUrl="http://pmd.github.io/pmd/pmd_rules_swift_errorprone.html#forcetry"> + <description> + Force tries should be avoided. If the code being wrapped happens to raise and exception, our application will crash. + Consider using a conditional try and handling the resulting optional, or wrapping the try statement in a do-catch block. + </description> + <priority>3</priority> + <properties> + <property name="xpath"> + <value> +<![CDATA[ +//TryOperator[@Text='try!'] +]]> + </value> + </property> + <property name="version" value="2.0"/> + </properties> + <example> + <![CDATA[ +let x = try! someThrowingFunction() // violation, force trying + +let x = try? someThrowingFunction() // no violation +]]> + </example> + </rule> +</ruleset> \ No newline at end of file diff --git a/pmd-swift/src/main/resources/category/swift/multithreading.xml b/pmd-swift/src/main/resources/category/swift/multithreading.xml new file mode 100644 index 0000000000..3b25979bb6 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/multithreading.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> + +<ruleset name="Multithreading" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> +Rules that flag issues when dealing with multiple threads of execution. + </description> +</ruleset> \ No newline at end of file diff --git a/pmd-swift/src/main/resources/category/swift/performance.xml b/pmd-swift/src/main/resources/category/swift/performance.xml new file mode 100644 index 0000000000..be669f985c --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/performance.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> + +<ruleset name="Performance" + xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> +Rules that flag suboptimal code. + </description> +</ruleset> diff --git a/pmd-swift/src/main/resources/category/swift/security.xml b/pmd-swift/src/main/resources/category/swift/security.xml new file mode 100644 index 0000000000..fae2a25682 --- /dev/null +++ b/pmd-swift/src/main/resources/category/swift/security.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> + +<ruleset name="Security" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> + + <description> +Rules that flag potential security flaws. + </description> +</ruleset> diff --git a/pmd-swift/src/main/resources/rulesets/swift/rulesets.properties b/pmd-swift/src/main/resources/rulesets/swift/rulesets.properties new file mode 100644 index 0000000000..9bf5871e03 --- /dev/null +++ b/pmd-swift/src/main/resources/rulesets/swift/rulesets.properties @@ -0,0 +1,18 @@ +# +# BSD-style license; for more info see http://pmd.sourceforge.net/license.html +# + +rulesets.filenames=\ + category/swift/bestpractices.xml,\ + category/swift/errorprone.xml + +# +# categories without rules +# +# category/swift/codestyle.xml +# category/swift/design.xml +# category/swift/documentation.xml +# category/swift/errorprone.xml +# category/swift/multithreading.xml +# category/swift/performance.xml +# category/swift/security.xml diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..9ddfb4d2af --- /dev/null +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,9 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + // no additional unit tests +} diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderTest.java new file mode 100644 index 0000000000..6f8d9723c8 --- /dev/null +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/ProhibitedInterfaceBuilderTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift.rule.bestpractices; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class ProhibitedInterfaceBuilderTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionTest.java new file mode 100644 index 0000000000..e1d00f69d5 --- /dev/null +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift.rule.bestpractices; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class UnavailableFunctionTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/errorprone/ForceCastTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/errorprone/ForceCastTest.java new file mode 100644 index 0000000000..3f5472591f --- /dev/null +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/errorprone/ForceCastTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift.rule.errorprone; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class ForceCastTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/errorprone/ForceTryTest.java b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/errorprone/ForceTryTest.java new file mode 100644 index 0000000000..391985dd62 --- /dev/null +++ b/pmd-swift/src/test/java/net/sourceforge/pmd/lang/swift/rule/errorprone/ForceTryTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.swift.rule.errorprone; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class ForceTryTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/ProhibitedInterfaceBuilder.xml b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/ProhibitedInterfaceBuilder.xml new file mode 100644 index 0000000000..2cf148474a --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/ProhibitedInterfaceBuilder.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + <test-code> + <description><![CDATA[ +Good example #1 + ]]></description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class ViewController: UIViewController { + var label: UILabel! +} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Good example #2 + ]]></description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class ViewController: UIViewController { + @objc func buttonTapped(_ sender: UIButton) {} +} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Bad example #1 + ]]></description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +class ViewController: UIViewController { + @IBOutlet var label: UILabel! +} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Bad example #2 + ]]></description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +class ViewController: UIViewController { + @IBAction func buttonTapped(_ sender: UIButton) {} +} + ]]></code> + <source-type>swift</source-type> + </test-code> +</test-data> \ No newline at end of file diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/UnavailableFunction.xml b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/UnavailableFunction.xml new file mode 100644 index 0000000000..8c9210ec87 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/bestpractices/xml/UnavailableFunction.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + <test-code> + <description><![CDATA[ +Good example #1 + ]]></description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +class ViewController: UIViewController { + @available(*, unavailable) + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Good example #2 + ]]></description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +func jsonValue(_ jsonString: String) -> NSObject { + let data = jsonString.data(using: .utf8)! + let result = try! JSONSerialization.jsonObject(with: data, options: []) + if let dict = (result as? [String: Any])?.bridge() { + return dict + } else if let array = (result as? [Any])?.bridge() { + return array + } + fatalError() +} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Bad example #1 + ]]></description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +class ViewController: UIViewController { + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Bad example #2 + ]]></description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +func doSomething() { + fatalError("doSomething() has not been implemented") +} + ]]></code> + <source-type>swift</source-type> + </test-code> +</test-data> \ No newline at end of file diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/errorprone/xml/ForceCast.xml b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/errorprone/xml/ForceCast.xml new file mode 100644 index 0000000000..6fb25a7c5f --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/errorprone/xml/ForceCast.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + <test-code> + <description><![CDATA[ +Good example #1 + ]]></description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +NSNumber() as? Int + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Bad example #1 + ]]></description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +NSNumber() as! Int + ]]></code> + <source-type>swift</source-type> + </test-code> +</test-data> \ No newline at end of file diff --git a/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/errorprone/xml/ForceTry.xml b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/errorprone/xml/ForceTry.xml new file mode 100644 index 0000000000..a283d4b263 --- /dev/null +++ b/pmd-swift/src/test/resources/net/sourceforge/pmd/lang/swift/rule/errorprone/xml/ForceTry.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<test-data + xmlns="http://pmd.sourceforge.net/rule-tests" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + <test-code> + <description><![CDATA[ +Good example #1 + ]]></description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +func a() throws {} +do { + try a() +} catch {} + ]]></code> + <source-type>swift</source-type> + </test-code> + <test-code> + <description><![CDATA[ +Bad example #1 + ]]></description> + <expected-problems>1</expected-problems> + <code><![CDATA[ +func a() throws {} +try! a() + ]]></code> + <source-type>swift</source-type> + </test-code> +</test-data> \ No newline at end of file diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java index 7420567b0b..b85e3f5184 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTestRunner.java @@ -28,8 +28,8 @@ import org.junit.runners.model.Statement; import net.sourceforge.pmd.Rule; /** - * A JUnit Runner, that executes all declared rule tests in the class. - * It supports Before and After methods as well as TestRules. + * A JUnit Runner, that executes all declared rule tests in the class. It supports Before and After methods as well as + * TestRules. * * @author Andreas Dangel */ @@ -37,20 +37,20 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> { private ConcurrentHashMap<TestDescriptor, Description> testDescriptions = new ConcurrentHashMap<>(); private final RuleTst instance; - public RuleTestRunner(Class<? extends RuleTst> testClass) throws InitializationError { + /* default */ RuleTestRunner(final Class<? extends RuleTst> testClass) throws InitializationError { super(testClass); instance = createTestClass(); instance.setUp(); } @Override - protected Description describeChild(TestDescriptor testCase) { + protected Description describeChild(final TestDescriptor testCase) { Description description = testDescriptions.get(testCase); if (description == null) { description = Description.createTestDescription(getTestClass().getJavaClass(), testCase.getRule().getName() + "::" - + testCase.getNumberInDocument() + " " - + testCase.getDescription().replaceAll("\n|\r", " ")); + + testCase.getNumberInDocument() + " " + + testCase.getDescription().replaceAll("\n|\r", " ")); testDescriptions.putIfAbsent(testCase, description); } return description; @@ -58,28 +58,22 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> { /** * Checks whether this test class has additionally unit test methods. + * * @return true if there is at least one unit test method. */ - public boolean hasUnitTests() { + /* default */ boolean hasUnitTests() { return !getTestClass().getAnnotatedMethods(Test.class).isEmpty(); } @Override protected List<TestDescriptor> getChildren() { - List<Rule> rules = new ArrayList<>(instance.getRules()); - Collections.sort(rules, new Comparator<Rule>() { - @Override - public int compare(Rule o1, Rule o2) { - return o1.getName().compareTo(o2.getName()); - } - }); + final List<Rule> rules = new ArrayList<>(instance.getRules()); + rules.sort(Comparator.comparing(Rule::getName)); - List<TestDescriptor> tests = new LinkedList<>(); - for (Rule r : rules) { - TestDescriptor[] ruleTests = instance.extractTestsFromXml(r); - for (TestDescriptor t : ruleTests) { - tests.add(t); - } + final List<TestDescriptor> tests = new LinkedList<>(); + for (final Rule r : rules) { + final TestDescriptor[] ruleTests = instance.extractTestsFromXml(r); + Collections.addAll(tests, ruleTests); } return tests; @@ -88,14 +82,14 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> { private RuleTst createTestClass() throws InitializationError { try { return (RuleTst) getTestClass().getOnlyConstructor().newInstance(); - } catch (Exception e) { + } catch (final Exception e) { throw new InitializationError(e); } } @Override - protected void runChild(TestDescriptor testCase, RunNotifier notifier) { - Description description = describeChild(testCase); + protected void runChild(final TestDescriptor testCase, final RunNotifier notifier) { + final Description description = describeChild(testCase); if (isIgnored(testCase)) { notifier.fireTestIgnored(description); } else { @@ -104,8 +98,7 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> { } /** - * Executes the actual test case. If there are Before, After, or TestRules present, - * they are executed accordingly. + * Executes the actual test case. If there are Before, After, or TestRules present, they are executed accordingly. * * @param testCase the PMD rule test case to be executed * @return a single statement which includes any rules, if present. @@ -113,7 +106,7 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> { private Statement ruleTestBlock(final TestDescriptor testCase) { Statement statement = new Statement() { @Override - public void evaluate() throws Throwable { + public void evaluate() { instance.runTest(testCase); } }; @@ -123,23 +116,24 @@ public class RuleTestRunner extends ParentRunner<TestDescriptor> { return statement; } - private Statement withBefores(Statement statement) { - List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(Before.class); + private Statement withBefores(final Statement statement) { + final List<FrameworkMethod> befores = getTestClass().getAnnotatedMethods(Before.class); return befores.isEmpty() ? statement : new RunBefores(statement, befores, instance); } - private Statement withAfters(Statement statement) { - List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods(After.class); + private Statement withAfters(final Statement statement) { + final List<FrameworkMethod> afters = getTestClass().getAnnotatedMethods(After.class); return afters.isEmpty() ? statement : new RunAfters(statement, afters, instance); } private Statement withRules(final TestDescriptor testCase, Statement statement) { - List<TestRule> testRules = getTestClass().getAnnotatedFieldValues(instance, org.junit.Rule.class, TestRule.class); + final List<TestRule> testRules = + getTestClass().getAnnotatedFieldValues(instance, org.junit.Rule.class, TestRule.class); return testRules.isEmpty() ? statement : new RunRules(statement, testRules, describeChild(testCase)); } @Override - protected boolean isIgnored(TestDescriptor child) { + protected boolean isIgnored(final TestDescriptor child) { return TestDescriptor.inRegressionTestMode() && !child.isRegressionTest(); } } diff --git a/pmd-test/src/main/resources/rule-tests_1_0_0.xsd b/pmd-test/src/main/resources/rule-tests_1_0_0.xsd index 62f352bdfc..5d5ce8041c 100644 --- a/pmd-test/src/main/resources/rule-tests_1_0_0.xsd +++ b/pmd-test/src/main/resources/rule-tests_1_0_0.xsd @@ -50,7 +50,7 @@ <element name="source-type" minOccurs="0" default="java"> <simpleType> <restriction base="string"> - <pattern value="(apex|ecmascript|java|jsp|plsql|pom|vf|vm|wsdl|xml|xsl)( [0-9.]+)?"></pattern> + <pattern value="(apex|ecmascript|java|jsp|plsql|pom|vf|vm|wsdl|xml|xsl|swift)( [0-9.]+)?"></pattern> </restriction> </simpleType> </element> diff --git a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java index 57e12782d3..4bb819aac8 100644 --- a/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java +++ b/pmd-visualforce/src/main/java/net/sourceforge/pmd/lang/vf/ast/AbstractVFNode.java @@ -5,6 +5,7 @@ package net.sourceforge.pmd.lang.vf.ast; import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.Node; public class AbstractVFNode extends AbstractNode implements VfNode { @@ -29,7 +30,7 @@ public class AbstractVFNode extends AbstractNode implements VfNode { @Override public void jjtClose() { - if (beginLine == -1 && (children == null || children.length == 0)) { + if (beginLine == -1 && children.length == 0) { beginColumn = parser.token.beginColumn; } if (beginLine == -1) { @@ -53,8 +54,8 @@ public class AbstractVFNode extends AbstractNode implements VfNode { @Override public Object childrenAccept(VfParserVisitor visitor, Object data) { if (children != null) { - for (int i = 0; i < children.length; ++i) { - ((VfNode) children[i]).jjtAccept(visitor, data); + for (Node child : children) { + ((VfNode) child).jjtAccept(visitor, data); } } return data; diff --git a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java index a640db2813..cec6af67fe 100644 --- a/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java +++ b/pmd-vm/src/main/java/net/sourceforge/pmd/lang/vm/ast/AbstractVmNode.java @@ -26,6 +26,7 @@ import java.io.Writer; import org.apache.commons.lang3.text.StrBuilder; import net.sourceforge.pmd.lang.ast.AbstractNode; +import net.sourceforge.pmd.lang.ast.Node; /** * @@ -115,11 +116,10 @@ public class AbstractVmNode extends AbstractNode implements VmNode { @Override public Object childrenAccept(final VmParserVisitor visitor, final Object data) { - if (children != null) { - for (int i = 0; i < children.length; ++i) { - ((VmNode) children[i]).jjtAccept(visitor, data); - } + for (Node child : children) { + ((VmNode) child).jjtAccept(visitor, data); } + return data; } @@ -151,13 +151,15 @@ public class AbstractVmNode extends AbstractNode implements VmNode { * children. * * @param prefix + * @deprecated This method will be removed with PMD 7. The rule designer is a better way to inspect nodes. */ + @Deprecated public void dump(final String prefix, final boolean recurse, final Writer writer) { final PrintWriter printWriter = writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter(writer); printWriter.println(toString(prefix)); - if (children != null && recurse) { - for (int i = 0; i < children.length; ++i) { - final AbstractVmNode n = (AbstractVmNode) children[i]; + if (recurse) { + for (Node child : children) { + final AbstractVmNode n = (AbstractVmNode) child; if (n != null) { n.dump(prefix + " ", recurse, printWriter); } diff --git a/pmd-xml/src/main/resources/category/xml/errorprone.xml b/pmd-xml/src/main/resources/category/xml/errorprone.xml index 18c01924d6..46f598d8e4 100644 --- a/pmd-xml/src/main/resources/category/xml/errorprone.xml +++ b/pmd-xml/src/main/resources/category/xml/errorprone.xml @@ -12,11 +12,11 @@ Rules to detect constructs that are either broken, extremely confusing or prone <rule name="MistypedCDATASection" language="xml" since="5.0" - message="Potentialy mistyped CDATA section with extra [ at beginning or ] at the end." + message="Potentially mistyped CDATA section with extra [ at beginning or ] at the end." class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_xml_errorprone.html#mistypedcdatasection"> <description> -An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and ends with a ]]> marker, which has only two ]. +An XML CDATA section begins with a <![CDATA[ marker, which has only one [, and ends with a ]]> marker, which has two ]. </description> <priority>3</priority> <properties> @@ -30,7 +30,18 @@ An XML CDATA section begins with a <!CDATA[ marker, which has only one [, and </properties> <example> <![CDATA[ -An extra [ looks like <!CDATA[[]]>, and an extra ] looks like <!CDATA[]]]>. +<root> + <child> + <![CDATA[[ character data ]]><![CDATA[]]]]><![CDATA[> - this cdata section is valid, but it contains an + additional square bracket at the beginning. + It should probably be just <![CDATA[ character data ]]><![CDATA[]]]]><![CDATA[>. + </child> + <child> + <![CDATA[ character data ]]]><![CDATA[]]]]><![CDATA[> - this cdata section is valid, but it contains an + additional square bracket in the end. + It should probably be just <![CDATA[ character data ]]><![CDATA[]]]]><![CDATA[>. + </child> +</root> ]]> </example> </rule> diff --git a/pmd-xml/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java b/pmd-xml/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java index 6d560cc89c..15955b0565 100644 --- a/pmd-xml/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java +++ b/pmd-xml/src/test/java/net/sourceforge/pmd/ant/PMDTaskTest.java @@ -15,6 +15,6 @@ public class PMDTaskTest extends AbstractAntTestHelper { @Test public void testXML() { executeTarget("testXML"); - assertOutputContaining("Potentialy mistyped CDATA section with extra [ at beginning or ] at the end."); + assertOutputContaining("Potentially mistyped CDATA section with extra [ at beginning or ] at the end."); } } diff --git a/pmd-xml/src/test/resources/net/sourceforge/pmd/lang/xml/rule/errorprone/xml/MistypedCDATASection.xml b/pmd-xml/src/test/resources/net/sourceforge/pmd/lang/xml/rule/errorprone/xml/MistypedCDATASection.xml index 45388522ab..c748e2e5e4 100644 --- a/pmd-xml/src/test/resources/net/sourceforge/pmd/lang/xml/rule/errorprone/xml/MistypedCDATASection.xml +++ b/pmd-xml/src/test/resources/net/sourceforge/pmd/lang/xml/rule/errorprone/xml/MistypedCDATASection.xml @@ -70,4 +70,34 @@ ]]></code> <source-type>xml</source-type> </test-code> + <test-code> + <description>Example code</description> + <expected-problems>2</expected-problems> + <expected-linenumbers>3,8</expected-linenumbers> + <code><![CDATA[ +<root> + <child> + <![CDATA[ character data ]]]><![CDATA[]]]]><![CDATA[> - this cdata section is valid, but it contains an + additional square bracket in the end. + It should probably be just <![CDATA[ character data ]]><![CDATA[]]]]><![CDATA[>. + </child> + <child> + <![CDATA[[ character data ]]><![CDATA[]]]]><![CDATA[> - this cdata section is valid, but it contains an + additional square bracket at the beginning. + It should probably be just <![CDATA[ character data ]]><![CDATA[]]]]><![CDATA[>. + </child> +</root> + ]]></code> + </test-code> + <test-code> + <description>Square bracket at end separate by space is ok</description> + <expected-problems>0</expected-problems> + <code><![CDATA[ +<root> + <child> + <![CDATA[ character data[] ]]><![CDATA[]]]]><![CDATA[> + </child> +</root> + ]]></code> + </test-code> </test-data> diff --git a/pom.xml b/pom.xml index 019b151bed..37ffd7df4a 100644 --- a/pom.xml +++ b/pom.xml @@ -8,9 +8,13 @@ <name>PMD</name> <description> -PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex, PLSQL, Salesforce.com Visualforce, Apache Velocity, XML, XSL. +PMD is a source code analyzer. It finds common programming flaws like unused variables, empty catch blocks, +unnecessary object creation, and so forth. It supports Java, JavaScript, Salesforce.com Apex, PLSQL, +Salesforce.com Visualforce, Apache Velocity, XML, XSL. -Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code in Java, C, C++, C#, Groovy, PHP, Ruby, Fortran, JavaScript, PLSQL, Apache Velocity, Scala, Objective C, Matlab, Python, Go, Swift and Salesforce.com Apex. +Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code in Java, C, C++, C#, +Groovy, PHP, Ruby, Fortran, JavaScript, PLSQL, Apache Velocity, Scala, Objective C, Matlab, Python, +Go, Swift and Salesforce.com Apex. </description> <url>https://pmd.github.io/</url> @@ -41,193 +45,10 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code </mailingLists> <developers> <developer> - <id>tomcopeland</id> - <name>Tom Copeland</name> - <email>tom@infoether.com</email> - <organization>InfoEther</organization> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>dpeugh</id> - <name>David Dixon-Peugh</name> - <email>ddp@apache.org</email> - <organization>Lockheed Martin Corporation</organization> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>olemartin</id> - <name>Ole-Martin Mork</name> - <email>olemartin@users.sourceforge.net</email> - <organization>Bekk Consulting</organization> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>mikkey</id> - <name>Miguel Griffa</name> - <email>mikkey@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>phherlin</id> - <name>Philippe Herlin</name> - <email>phherlin@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>jigerjava</id> - <name>Jiger Patel</name> - <email>jigerjava@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>kubacki</id> - <name>Radim Kubacki</name> - <email>kubacki@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>tomslot</id> - <name>Tomasz Slota</name> - <email>tomslot@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>ezust</id> - <name>Alan Ezust</name> - <email>ezust@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>nascif</id> - <name>Nascif Abousalh Neto</name> - <email>nascif@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>allancaplan</id> - <name>Allan Caplan</name> - <email>allancaplan@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>holobender</id> - <name>Sven Jacob</name> - <email>holobender@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>wfzelle</id> - <name>Wouter Zelle</name> - <email>wfzelle@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>hooperbloob</id> - <name>Brian Remedios</name> - <email>hooperbloob@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>xlv</id> - <name>Xavier Le Vourch</name> - <email>xlv@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>rgustav</id> - <name>Ryan Gustafson</name> - <email>rgustav@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>bluejohn</id> - <name>Johan Nagels</name> - <email>bluejohn@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>tkleiber</id> - <name>Torsten Kleiber</name> - <url>http://develishdevelopment.wordpress.com</url> - <email>tkleiber@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>rpelisse</id> - <name>Romain Pelisse</name> - <email>rpelisse@users.sourceforge.net</email> - <url>http://belaran.eu/</url> - <organization>Atos Origin</organization> - <organizationUrl>https://osc-service.si.fr.atosorigin.com/</organizationUrl> - <roles> - <role>Developer</role> - </roles> - <timezone>+1</timezone> - <properties> - <picUrl>http://belaran.eu/wordpress/wp-content/uploads/2008/05/RomainPELISSE.jpg</picUrl> - </properties> - </developer> - <developer> - <id>adangel</id> - <name>Andreas Dangel</name> - <email>adangel@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - <timezone>+1</timezone> - </developer> - <developer> - <id>acanda</id> - <name>Philip Graf</name> - <email>acanda@users.sourceforge.net</email> - <roles> - <role>Developer</role> - </roles> - </developer> - <developer> - <id>jsotuyod</id> - <name>Juan Martín Sotuyo Dodero</name> - <email>juansotuyo@gmail.com</email> - <roles> - <role>Developer</role> - </roles> - <timezone>-3</timezone> + <id>github</id> + <name>github contributors</name> + <organization>github</organization> + <organizationUrl>https://github.com/pmd/pmd/graphs/contributors</organizationUrl> </developer> </developers> <scm> @@ -283,9 +104,9 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <argLine>-Xmx512m -Dfile.encoding=${project.build.sourceEncoding}</argLine> - <pmd.build-tools.version>2</pmd.build-tools.version> + <pmd.build-tools.version>3</pmd.build-tools.version> - <pmd-designer.version>6.14.0</pmd-designer.version> + <pmd-designer.version>6.17.0</pmd-designer.version> </properties> <build> @@ -304,6 +125,8 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <goals> <goal>antlr4</goal> </goals> + <!-- This is default but let's be clear --> + <phase>generate-sources</phase> </execution> </executions> </plugin> @@ -369,9 +192,6 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> - <!-- Bug with incremental compilation --> - <!-- https://issues.apache.org/jira/browse/MCOMPILER-209 --> - <useIncrementalCompilation>false</useIncrementalCompilation> <release>${java.version}</release> </configuration> <executions> @@ -543,12 +363,12 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <dependency> <groupId>net.sourceforge.pmd</groupId> <artifactId>pmd-core</artifactId> - <version>6.13.0</version> + <version>6.15.0</version> </dependency> <dependency> <groupId>net.sourceforge.pmd</groupId> <artifactId>pmd-java</artifactId> - <version>6.13.0</version> + <version>6.15.0</version> </dependency> <!-- This contains the dogfood ruleset --> <dependency> @@ -917,13 +737,25 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> - <version>5.4.0</version> + <version>5.5.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> - <version>5.4.0</version> + <version>5.5.0</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-commons</artifactId> + <version>1.5.0</version> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-launcher</artifactId> + <version>1.5.0</version> <scope>test</scope> </dependency> @@ -931,7 +763,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> - <version>5.4.0</version> + <version>5.5.0</version> <scope>test</scope> </dependency> @@ -1144,6 +976,7 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code <module>pmd-fortran</module> <module>pmd-go</module> <module>pmd-groovy</module> + <module>pmd-lua</module> <module>pmd-java</module> <module>pmd-javascript</module> <module>pmd-jsp</module>